This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch branch-4.0
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-4.0 by this push:
new 844269ac3e1 branch-4.0: [fix](func)fix for nested type in function
param which has datetime or decimal #56625 (#56660)
844269ac3e1 is described below
commit 844269ac3e10b6cda7877de49d8378d837f91482
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Tue Sep 30 15:42:36 2025 +0800
branch-4.0: [fix](func)fix for nested type in function param which has
datetime or decimal #56625 (#56660)
Cherry-picked from #56625
Co-authored-by: amory <[email protected]>
---
be/src/vec/functions/function.cpp | 102 +++++++++++++++++----
be/src/vec/functions/function.h | 9 +-
.../sql_functions/struct_functions/sql/q02.out | 73 +++++++++++++++
.../sql_functions/struct_functions/sql/q02.sql | 72 +++++++++++++++
4 files changed, 237 insertions(+), 19 deletions(-)
diff --git a/be/src/vec/functions/function.cpp
b/be/src/vec/functions/function.cpp
index 55a70a6e40c..17ce7b846ee 100644
--- a/be/src/vec/functions/function.cpp
+++ b/be/src/vec/functions/function.cpp
@@ -25,6 +25,7 @@
#include <numeric>
#include "common/status.h"
+#include "runtime/define_primitive_type.h"
#include "runtime/primitive_type.h"
#include "vec/aggregate_functions/aggregate_function.h"
#include "vec/columns/column.h"
@@ -304,7 +305,37 @@ bool FunctionBuilderImpl::is_date_or_datetime_or_decimal(
is_time_type(func_return_type->get_primitive_type()));
}
-bool FunctionBuilderImpl::is_array_nested_type_date_or_datetime_or_decimal(
+bool contains_date_or_datetime_or_decimal(const DataTypePtr& type) {
+ auto type_ptr = type->is_nullable() ?
((DataTypeNullable*)type.get())->get_nested_type() : type;
+
+ switch (type_ptr->get_primitive_type()) {
+ case TYPE_ARRAY: {
+ const auto* array_type = assert_cast<const
DataTypeArray*>(type_ptr.get());
+ return
contains_date_or_datetime_or_decimal(array_type->get_nested_type());
+ }
+ case TYPE_MAP: {
+ const auto* map_type = assert_cast<const DataTypeMap*>(type_ptr.get());
+ return contains_date_or_datetime_or_decimal(map_type->get_key_type())
||
+
contains_date_or_datetime_or_decimal(map_type->get_value_type());
+ }
+ case TYPE_STRUCT: {
+ const auto* struct_type = assert_cast<const
DataTypeStruct*>(type_ptr.get());
+ const auto& elements = struct_type->get_elements();
+ return std::ranges::any_of(elements, [](const DataTypePtr& element) {
+ return contains_date_or_datetime_or_decimal(element);
+ });
+ }
+ default:
+ // For scalar types, check if it's date/datetime/decimal
+ return is_date_or_datetime(type_ptr->get_primitive_type()) ||
+ is_date_v2_or_datetime_v2(type_ptr->get_primitive_type()) ||
+ is_decimal(type_ptr->get_primitive_type()) ||
+ is_time_type(type_ptr->get_primitive_type());
+ }
+}
+
+// make sure array/map/struct and nested array/map/struct can be check
+bool FunctionBuilderImpl::is_nested_type_date_or_datetime_or_decimal(
const DataTypePtr& return_type, const DataTypePtr& func_return_type)
const {
auto return_type_ptr = return_type->is_nullable()
?
((DataTypeNullable*)return_type.get())->get_nested_type()
@@ -313,24 +344,63 @@ bool
FunctionBuilderImpl::is_array_nested_type_date_or_datetime_or_decimal(
func_return_type->is_nullable()
?
((DataTypeNullable*)func_return_type.get())->get_nested_type()
: func_return_type;
- if (!(return_type_ptr->get_primitive_type() == TYPE_ARRAY &&
- func_return_type_ptr->get_primitive_type() == TYPE_ARRAY)) {
+ // make sure that map/struct/array also need to check
+ if (return_type_ptr->get_primitive_type() !=
func_return_type_ptr->get_primitive_type()) {
return false;
}
- auto nested_nullable_return_type_ptr =
- (assert_cast<const
DataTypeArray*>(return_type_ptr.get()))->get_nested_type();
- auto nested_nullable_func_return_type =
- (assert_cast<const
DataTypeArray*>(func_return_type_ptr.get()))->get_nested_type();
- // There must be nullable inside array type.
- if (nested_nullable_return_type_ptr->is_nullable() &&
- nested_nullable_func_return_type->is_nullable()) {
- auto nested_return_type_ptr =
-
((DataTypeNullable*)(nested_nullable_return_type_ptr.get()))->get_nested_type();
- auto nested_func_return_type_ptr =
-
((DataTypeNullable*)(nested_nullable_func_return_type.get()))->get_nested_type();
- return is_date_or_datetime_or_decimal(nested_return_type_ptr,
nested_func_return_type_ptr);
+
+ // Check if this type contains date/datetime/decimal types
+ if (!contains_date_or_datetime_or_decimal(return_type_ptr)) {
+ // If no date/datetime/decimal types, just pass through
+ return true;
+ }
+
+ // If contains date/datetime/decimal types, recursively check each element
+ switch (return_type_ptr->get_primitive_type()) {
+ case TYPE_ARRAY: {
+ auto nested_return_type = remove_nullable(
+ (assert_cast<const
DataTypeArray*>(return_type_ptr.get()))->get_nested_type());
+ auto nested_func_type = remove_nullable(
+ (assert_cast<const
DataTypeArray*>(func_return_type_ptr.get()))->get_nested_type());
+ return is_nested_type_date_or_datetime_or_decimal(nested_return_type,
nested_func_type);
+ }
+ case TYPE_MAP: {
+ const auto* return_map = assert_cast<const
DataTypeMap*>(return_type_ptr.get());
+ const auto* func_map = assert_cast<const
DataTypeMap*>(func_return_type_ptr.get());
+
+ auto key_return = remove_nullable(return_map->get_key_type());
+ auto key_func = remove_nullable(func_map->get_key_type());
+ auto value_return = remove_nullable(return_map->get_value_type());
+ auto value_func = remove_nullable(func_map->get_value_type());
+
+ return is_nested_type_date_or_datetime_or_decimal(key_return,
key_func) &&
+ is_nested_type_date_or_datetime_or_decimal(value_return,
value_func);
+ }
+ case TYPE_STRUCT: {
+ const auto* return_struct = assert_cast<const
DataTypeStruct*>(return_type_ptr.get());
+ const auto* func_struct = assert_cast<const
DataTypeStruct*>(func_return_type_ptr.get());
+
+ auto return_elements = return_struct->get_elements();
+ auto func_elements = func_struct->get_elements();
+
+ if (return_elements.size() != func_elements.size()) {
+ return false;
+ }
+
+ for (size_t i = 0; i < return_elements.size(); i++) {
+ auto elem_return = remove_nullable(return_elements[i]);
+ auto elem_func = remove_nullable(func_elements[i]);
+
+ if (!is_nested_type_date_or_datetime_or_decimal(elem_return,
elem_func)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ default:
+ return is_date_or_datetime_or_decimal(return_type_ptr,
func_return_type_ptr);
}
- return false;
}
+
#include "common/compile_check_end.h"
} // namespace doris::vectorized
diff --git a/be/src/vec/functions/function.h b/be/src/vec/functions/function.h
index fd0862c73d5..3dab7b782ae 100644
--- a/be/src/vec/functions/function.h
+++ b/be/src/vec/functions/function.h
@@ -39,7 +39,10 @@
#include "vec/core/columns_with_type_and_name.h"
#include "vec/core/types.h"
#include "vec/data_types/data_type.h"
+#include "vec/data_types/data_type_array.h"
+#include "vec/data_types/data_type_map.h"
#include "vec/data_types/data_type_nullable.h"
+#include "vec/data_types/data_type_struct.h"
namespace doris::vectorized {
@@ -289,7 +292,7 @@ public:
->get_nested_type()
->get_primitive_type() == INVALID_TYPE) ||
is_date_or_datetime_or_decimal(return_type, func_return_type) ||
- is_array_nested_type_date_or_datetime_or_decimal(return_type,
func_return_type))) {
+ is_nested_type_date_or_datetime_or_decimal(return_type,
func_return_type))) {
throw doris::Exception(
ErrorCode::INTERNAL_ERROR,
"function return type check failed, function_name={}, "
@@ -356,8 +359,8 @@ protected:
private:
bool is_date_or_datetime_or_decimal(const DataTypePtr& return_type,
const DataTypePtr& func_return_type)
const;
- bool is_array_nested_type_date_or_datetime_or_decimal(
- const DataTypePtr& return_type, const DataTypePtr&
func_return_type) const;
+ bool is_nested_type_date_or_datetime_or_decimal(const DataTypePtr&
return_type,
+ const DataTypePtr&
func_return_type) const;
};
/// Previous function interface.
diff --git
a/regression-test/data/query_p0/sql_functions/struct_functions/sql/q02.out
b/regression-test/data/query_p0/sql_functions/struct_functions/sql/q02.out
new file mode 100644
index 00000000000..9f2da3af2f2
--- /dev/null
+++ b/regression-test/data/query_p0/sql_functions/struct_functions/sql/q02.out
@@ -0,0 +1,73 @@
+-- This file is automatically generated. You should know what you did if you
want to edit this
+-- !q02 --
+0
+
+-- !q02_2 --
+0
+
+-- !q02_3 --
+0
+
+-- !q02_4 --
+1
+
+-- !q02_5 --
+["2023-01-01", "2023-12-31"]
+
+-- !q02_6 --
+[["2023-01-01", "2023-12-31"]]
+
+-- !q02_7 --
+["2023-01-01 10:00:00", "2023-12-31 23:59:59"]
+
+-- !q02_8 --
+[["2023-01-01 10:00:00", "2023-12-31 23:59:59"]]
+
+-- !q02_9 --
+[123.45, 678.90]
+
+-- !q02_10 --
+[[123.45, 678.90]]
+
+-- !q02_11 --
+[["2023-01-01"], ["2023-12-31"]]
+
+-- !q02_12 --
+[[["2023-01-01"], ["2023-12-31"]]]
+
+-- !q02_13 --
+{"user1":"2023-01-01", "user2":"2023-12-31"}
+
+-- !q02_14 --
+{"first":"2023-01-01", "second":"2023-12-31"}
+
+-- !q02_15 --
+{"literal":"2023-01-01", "from_table":"2023-01-01"}
+
+-- !q02_16 --
+{"2023-01-01 10:00:00":123.45, "2023-12-31 23:59:59":678.90}
+
+-- !q02_17 --
+{"first":123.45, "second":678.90}
+
+-- !q02_18 --
+{"user1":["2023-01-01", "2023-12-31"], "user2":["2023-06-15"]}
+
+-- !q02_19 --
+{"first":["2023-01-01", "2023-12-31"], "second":["2023-06-15"]}
+
+-- !q02_20 --
+{"col1":"Alice", "col2":"1990-01-01", "col3":60000.00}
+
+-- !q02_21 --
+{"col1":{"name":"Charlie", "birth_date":"1985-05-15", "salary":50000.00}}
+
+-- !q02_22 --
+{"col1":"outer", "col2":{"name":"Charlie", "birth_date":"1985-05-15",
"salary":50000.00}, "col3":"literal", "col4":{"col1":"David",
"col2":"1988-03-20", "col3":80000.00}}
+
+-- !q02_23 --
+{"col1":{"2023-01-01":"2023-01-01 10:00:00.123456", "2023-12-31":"2023-12-31
23:59:59.999999"}, "col2":{"user1":"2023-01-01", "user2":"2023-12-31"}}
+
+-- !q02_24 --
+{"col1":{"user1":"2023-01-01", "user2":"2023-12-31"}, "col2":{"2023-01-01
10:00:00":123.45, "2023-12-31 23:59:59":678.90}}
+
diff --git
a/regression-test/suites/query_p0/sql_functions/struct_functions/sql/q02.sql
b/regression-test/suites/query_p0/sql_functions/struct_functions/sql/q02.sql
new file mode 100644
index 00000000000..fc1b177ef6c
--- /dev/null
+++ b/regression-test/suites/query_p0/sql_functions/struct_functions/sql/q02.sql
@@ -0,0 +1,72 @@
+use regression_test_query_p0_sql_functions_struct_functions;
+
+DROP TABLE IF EXISTS `test_nested_type_compatibility`;
+
+-- Create a simple table to test nested type compatibility
+CREATE TABLE IF NOT EXISTS `test_nested_type_compatibility` (
+ `id` int,
+ -- Test cases for ARRAY types
+ `arr_date` array<date>,
+ `arr_datetime` array<datetime>,
+ `arr_decimal` array<decimal(10,2)>,
+ `arr_nested_date` array<array<date>>,
+
+ -- Test cases for MAP types
+ `map_string_date` map<string, date>,
+ `map_datetime_decimal` map<datetime, decimal(10,2)>,
+ `map_nested_date` map<string, array<date>>,
+
+ -- Test cases for STRUCT types
+ `struct_mixed` struct<name:string, birth_date:date, salary:decimal(10,2)>,
+ `struct_map` struct<col: map<date, datetime(6)>, col1: map<string, date>>
+) ENGINE=OLAP
+DUPLICATE KEY(`id`)
+DISTRIBUTED BY HASH(`id`) BUCKETS 1
+PROPERTIES (
+ "replication_allocation" = "tag.location.default: 1"
+);
+
+-- Insert test data
+INSERT INTO `test_nested_type_compatibility` VALUES
+(1,
+ -- ARRAY data
+ ['2023-01-01', '2023-12-31'],
+ ['2023-01-01 10:00:00', '2023-12-31 23:59:59'],
+ [123.45, 678.90],
+ [['2023-01-01'], ['2023-12-31']],
+
+ -- MAP data
+ {'user1': '2023-01-01', 'user2': '2023-12-31'},
+ {'2023-01-01 10:00:00': 123.45, '2023-12-31 23:59:59': 678.90},
+ {'user1': ['2023-01-01', '2023-12-31'], 'user2': ['2023-06-15']},
+
+ -- STRUCT data
+ struct('Charlie', '1985-05-15', 50000.00),
+ struct(map('2023-01-01', '2023-01-01 10:00:00.123456', '2023-12-31',
'2023-12-31 23:59:59.999999'), map('user1', '2023-01-01', 'user2',
'2023-12-31'))
+);
+
+-- Test ARRAY constructors with date types - should trigger compatibility check
+select array('2023-01-01', '2023-12-31') from test_nested_type_compatibility
where id = 1;
+select array(arr_date) from test_nested_type_compatibility where id = 1;
+select array('2023-01-01 10:00:00', '2023-12-31 23:59:59') from
test_nested_type_compatibility where id = 1;
+select array(arr_datetime) from test_nested_type_compatibility where id = 1;
+select array(123.45, 678.90) from test_nested_type_compatibility where id = 1;
+select array(arr_decimal) from test_nested_type_compatibility where id = 1;
+select array(array('2023-01-01'), array('2023-12-31')) from
test_nested_type_compatibility where id = 1;
+select array(arr_nested_date) from test_nested_type_compatibility where id = 1;
+
+-- Test MAP constructors with date types - should trigger compatibility check
+select map('user1', '2023-01-01', 'user2', '2023-12-31') from
test_nested_type_compatibility where id = 1;
+select map('first', map_string_date['user1'], 'second',
map_string_date['user2']) from test_nested_type_compatibility where id = 1;
+select map('literal', '2023-01-01', 'from_table', map_string_date['user1'])
from test_nested_type_compatibility where id = 1;
+select map('2023-01-01 10:00:00', 123.45, '2023-12-31 23:59:59', 678.90) from
test_nested_type_compatibility where id = 1;
+select map('first', map_datetime_decimal['2023-01-01 10:00:00'], 'second',
map_datetime_decimal['2023-12-31 23:59:59']) from
test_nested_type_compatibility where id = 1;
+select map('user1', array('2023-01-01', '2023-12-31'), 'user2',
array('2023-06-15')) from test_nested_type_compatibility where id = 1;
+select map('first', map_nested_date['user1'], 'second',
map_nested_date['user2']) from test_nested_type_compatibility where id = 1;
+
+-- Test STRUCT constructors with date types - should trigger compatibility
check
+select struct('Alice', '1990-01-01', 60000.00) from
test_nested_type_compatibility where id = 1;
+select struct(struct_mixed) from test_nested_type_compatibility where id = 1;
+select struct('outer', struct_mixed, 'literal', struct('David', '1988-03-20',
80000.00)) from test_nested_type_compatibility where id = 1;
+select struct(map('2023-01-01', '2023-01-01 10:00:00.123456', '2023-12-31',
'2023-12-31 23:59:59.999999'), map('user1', '2023-01-01', 'user2',
'2023-12-31')) from test_nested_type_compatibility where id = 1;
+select struct(map_string_date, map_datetime_decimal) from
test_nested_type_compatibility where id = 1;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]