diff --git a/src/common/tracing/src/structlog.rs b/src/common/tracing/src/structlog.rs index bdcf8c909e73..0dd965687838 100644 --- a/src/common/tracing/src/structlog.rs +++ b/src/common/tracing/src/structlog.rs @@ -164,8 +164,8 @@ fn build_trees(spans: &[&SpanRecord]) -> Vec { let roots = raw.keys().filter(|id| !span_ids.contains(id)).cloned(); roots - .flat_map(|root| build_sub_tree(root, &raw).pop()) - .collect_vec() + .filter_map(|root| build_sub_tree(root, &raw).pop()) + .collect() } fn build_sub_tree(parent_id: SpanId, raw: &HashMap>) -> Vec { diff --git a/src/query/functions/src/scalars/array.rs b/src/query/functions/src/scalars/array.rs index bfa28db192ed..95e3f3d4b5f2 100644 --- a/src/query/functions/src/scalars/array.rs +++ b/src/query/functions/src/scalars/array.rs @@ -16,8 +16,6 @@ use std::hash::Hash; use std::ops::Range; use std::sync::Arc; -use databend_common_expression::type_check::common_super_type; -use databend_common_expression::types::array::ArrayColumn; use databend_common_expression::types::array::ArrayColumnBuilder; use databend_common_expression::types::boolean::BooleanDomain; use databend_common_expression::types::nullable::NullableDomain; @@ -72,7 +70,6 @@ use siphasher::sip128::SipHasher24; use crate::aggregates::eval_aggr; use crate::AggregateFunctionFactory; -use crate::BUILTIN_FUNCTIONS; const ARRAY_AGGREGATE_FUNCTIONS: &[(&str, &str); 14] = &[ ("array_avg", "avg"), @@ -243,10 +240,10 @@ pub fn register(registry: &mut FunctionRegistry) { ), ); - registry.register_2_arg_core::, NullableType, EmptyArrayType, _, _>( + registry.register_2_arg::( "array_concat", |_, _, _| FunctionDomain::Full, - |_, _, _| Value::Scalar(()), + |_, _, _| (), ); registry.register_passthrough_nullable_2_arg::>, ArrayType>, ArrayType>, _, _>( @@ -431,183 +428,57 @@ pub fn register(registry: &mut FunctionRegistry) { ), ); - registry.register_function_factory("array_prepend", |_, args_type| { - if args_type.len() != 2 { - return None; - } - let (common_type, return_type) = match args_type[1].remove_nullable() { - DataType::EmptyArray => ( - args_type[0].clone(), - DataType::Array(Box::new(args_type[0].clone())), - ), - DataType::Array(box inner_type) => { - let common_type = common_super_type( - inner_type.clone(), - args_type[0].clone(), - &BUILTIN_FUNCTIONS.default_cast_rules, - )?; - (common_type.clone(), DataType::Array(Box::new(common_type))) - } - _ => { - return None; - } - }; - let args_type = vec![ - common_type, - if args_type[1].is_nullable() { - return_type.wrap_nullable() - } else { - return_type.clone() - }, - ]; - Some(Arc::new(Function { - signature: FunctionSignature { - name: "array_prepend".to_string(), - args_type, - return_type: return_type.clone(), - }, - eval: FunctionEval::Scalar { - calc_domain: Box::new(|_, args_domain| { - let array_domain = match &args_domain[1] { - Domain::Nullable(nullable_domain) => nullable_domain.value.clone(), - other => Some(Box::new(other.clone())), - }; - let inner_domain = match array_domain { - Some(box Domain::Array(Some(box inner_domain))) => { - inner_domain.merge(&args_domain[0]) - } - _ => args_domain[0].clone(), - }; - FunctionDomain::Domain(Domain::Array(Some(Box::new(inner_domain)))) - }), - eval: Box::new(move |args, _| { - let len = args.iter().find_map(|arg| match arg { - ValueRef::Column(col) => Some(col.len()), - _ => None, - }); - - let mut offsets = Vec::with_capacity(len.unwrap_or(1) + 1); - offsets.push(0); - let inner_type = return_type.as_array().unwrap(); - let mut builder = ColumnBuilder::with_capacity(inner_type, len.unwrap_or(1)); - - for idx in 0..(len.unwrap_or(1)) { - let val = match &args[0] { - ValueRef::Scalar(scalar) => scalar.clone(), - ValueRef::Column(col) => unsafe { col.index_unchecked(idx) }, - }; - builder.push(val.clone()); - let array_col = match &args[1] { - ValueRef::Scalar(scalar) => scalar.clone(), - ValueRef::Column(col) => unsafe { col.index_unchecked(idx).clone() }, - }; - if let ScalarRef::Array(col) = array_col { - for val in col.iter() { - builder.push(val.clone()); - } - } - offsets.push(builder.len() as u64); - } - match len { - Some(_) => Value::Column(Column::Array(Box::new(ArrayColumn { - values: builder.build(), - offsets: offsets.into(), - }))), - None => Value::Scalar(Scalar::Array(builder.build())), + registry.register_2_arg_core::, NullableType>>, ArrayType>, _, _>( + "array_prepend", + |_, item_domain, array_domain| { + let domain = array_domain + .value + .as_ref() + .map(|box inner_domain| { + inner_domain + .as_ref() + .map(|inner_domain| inner_domain.merge(item_domain)) + .unwrap_or(item_domain.clone()) + }); + FunctionDomain::Domain(domain) + }, + vectorize_with_builder_2_arg::, NullableType>>, ArrayType>>( + |val, arr, output, _| { + output.put_item(val); + if let Some(arr) = arr { + for item in arr.iter() { + output.put_item(item); } - }), - }, - })) - }); - - registry.register_function_factory("array_append", |_, args_type| { - if args_type.len() != 2 { - return None; - } - let (common_type, return_type) = match args_type[0].remove_nullable() { - DataType::EmptyArray => ( - args_type[1].clone(), - DataType::Array(Box::new(args_type[1].clone())), - ), - DataType::Array(box inner_type) => { - let common_type = common_super_type( - inner_type.clone(), - args_type[1].clone(), - &BUILTIN_FUNCTIONS.default_cast_rules, - )?; - (common_type.clone(), DataType::Array(Box::new(common_type))) - } - _ => { - return None; - } - }; - let args_type = vec![ - if args_type[0].is_nullable() { - return_type.wrap_nullable() - } else { - return_type.clone() - }, - common_type, - ]; - Some(Arc::new(Function { - signature: FunctionSignature { - name: "array_append".to_string(), - args_type, - return_type: return_type.clone(), - }, - eval: FunctionEval::Scalar { - calc_domain: Box::new(|_, args_domain| { - let array_domain = match &args_domain[0] { - Domain::Nullable(nullable_domain) => nullable_domain.value.clone(), - other => Some(Box::new(other.clone())), - }; - let inner_domain = match array_domain { - Some(box Domain::Array(Some(box inner_domain))) => { - inner_domain.merge(&args_domain[1]) - } - _ => args_domain[1].clone(), - }; - FunctionDomain::Domain(Domain::Array(Some(Box::new(inner_domain)))) - }), - eval: Box::new(move |args, _| { - let len = args.iter().find_map(|arg| match arg { - ValueRef::Column(col) => Some(col.len()), - _ => None, - }); - - let mut offsets = Vec::with_capacity(len.unwrap_or(1) + 1); - offsets.push(0); - let inner_type = return_type.as_array().unwrap(); - let mut builder = ColumnBuilder::with_capacity(inner_type, len.unwrap_or(1)); + } + output.commit_row() + }) + ); - for idx in 0..(len.unwrap_or(1)) { - let array_col = match &args[0] { - ValueRef::Scalar(scalar) => scalar.clone(), - ValueRef::Column(col) => unsafe { col.index_unchecked(idx).clone() }, - }; - if let ScalarRef::Array(col) = array_col { - for val in col.iter() { - builder.push(val.clone()); - } - } - let val = match &args[1] { - ValueRef::Scalar(scalar) => scalar.clone(), - ValueRef::Column(col) => unsafe { col.index_unchecked(idx) }, - }; - builder.push(val.clone()); - offsets.push(builder.len() as u64); - } - match len { - Some(_) => Value::Column(Column::Array(Box::new(ArrayColumn { - values: builder.build(), - offsets: offsets.into(), - }))), - None => Value::Scalar(Scalar::Array(builder.build())), + registry.register_2_arg_core::>>, GenericType<0>, ArrayType>, _, _>( + "array_append", + |_, array_domain, item_domain| { + let domain = array_domain + .value + .as_ref() + .map(|box inner_domain| { + inner_domain + .as_ref() + .map(|inner_domain| inner_domain.merge(item_domain)) + .unwrap_or(item_domain.clone()) + }); + FunctionDomain::Domain(domain) + }, + vectorize_with_builder_2_arg::>>, GenericType<0>, ArrayType>>( + |arr, val, output, _| { + if let Some(arr) = arr { + for item in arr.iter() { + output.put_item(item); } - }), - }, - })) - }); + } + output.put_item(val); + output.commit_row() + }) + ); fn eval_contains( lhs: ValueRef>, @@ -791,12 +662,14 @@ pub fn register(registry: &mut FunctionRegistry) { } ); - registry.register_2_arg_core::>, GenericType<0>, BooleanType, _, _>( + registry.register_2_arg_core::>>, GenericType<0>, BooleanType, _, _>( "contains", |_, _, _| FunctionDomain::Full, - vectorize_2_arg::>, GenericType<0>, BooleanType>(|lhs, rhs, _| { - lhs.iter().contains(&rhs) - }), + vectorize_2_arg::>>, GenericType<0>, BooleanType>( + |lhs, rhs, _| { + lhs.map(|col| col.iter().contains(&rhs)).unwrap_or(false) + } + ) ); registry.register_passthrough_nullable_1_arg::( diff --git a/src/query/functions/tests/it/scalars/array.rs b/src/query/functions/tests/it/scalars/array.rs index 41cfca267b84..edc1c8c3093d 100644 --- a/src/query/functions/tests/it/scalars/array.rs +++ b/src/query/functions/tests/it/scalars/array.rs @@ -226,6 +226,16 @@ fn test_array_prepend(file: &mut impl Write) { run_ast(file, "array_prepend(1, [])", &[]); run_ast(file, "array_prepend(1, [2, 3, NULL, 4])", &[]); run_ast(file, "array_prepend('a', ['b', NULL, NULL, 'c', 'd'])", &[]); + run_ast( + file, + "array_prepend(NULL, CAST([2, 3] AS Array(INT8 NULL) NULL))", + &[], + ); + run_ast( + file, + "array_prepend(1, CAST([2, 3] AS Array(INT8 NULL) NULL))", + &[], + ); run_ast(file, "array_prepend(a, [b, c])", &[ ("a", Int16Type::from_data(vec![0i16, 1, 2])), ("b", Int16Type::from_data(vec![3i16, 4, 5])), @@ -237,6 +247,16 @@ fn test_array_append(file: &mut impl Write) { run_ast(file, "array_append([], 1)", &[]); run_ast(file, "array_append([2, 3, NULL, 4], 5)", &[]); run_ast(file, "array_append(['b', NULL, NULL, 'c', 'd'], 'e')", &[]); + run_ast( + file, + "array_append(CAST([1, 2] AS Array(INT8 NULL) NULL), NULL)", + &[], + ); + run_ast( + file, + "array_append(CAST([1, 2] AS Array(INT8 NULL) NULL), 3)", + &[], + ); run_ast(file, "array_append([b, c], a)", &[ ("a", Int16Type::from_data(vec![0i16, 1, 2])), ("b", Int16Type::from_data(vec![3i16, 4, 5])), diff --git a/src/query/functions/tests/it/scalars/testdata/array.txt b/src/query/functions/tests/it/scalars/testdata/array.txt index f8c34db714c9..4436f84ef4f3 100644 --- a/src/query/functions/tests/it/scalars/testdata/array.txt +++ b/src/query/functions/tests/it/scalars/testdata/array.txt @@ -513,8 +513,8 @@ evaluation (internal): ast : contains([1,2,null], nullable_col) raw expr : contains(array(1, 2, NULL), nullable_col::Int64 NULL) -checked expr : contains(CAST(array(CAST(1_u8 AS UInt8 NULL), CAST(2_u8 AS UInt8 NULL), CAST(NULL AS UInt8 NULL)) AS Array(Int64 NULL)), nullable_col) -optimized expr : contains([1, 2, NULL], nullable_col) +checked expr : contains(CAST(array(CAST(1_u8 AS UInt8 NULL), CAST(2_u8 AS UInt8 NULL), CAST(NULL AS UInt8 NULL)) AS Array(Int64 NULL) NULL), nullable_col) +optimized expr : contains([1, 2, NULL], nullable_col) evaluation: +--------+-------------------+---------------+ | | nullable_col | Output | @@ -537,7 +537,7 @@ evaluation (internal): ast : contains([(1,'2', 3, false), (1,'2', 4, true), null], (1,'2', 3, false)) raw expr : contains(array(tuple(1, '2', 3, false), tuple(1, '2', 4, true), NULL), tuple(1, '2', 3, false)) -checked expr : contains(array(CAST(tuple(1_u8, "2", 3_u8, false) AS Tuple(UInt8, String, UInt8, Boolean) NULL), CAST(tuple(1_u8, "2", 4_u8, true) AS Tuple(UInt8, String, UInt8, Boolean) NULL), CAST(NULL AS Tuple(UInt8, String, UInt8, Boolean) NULL)), CAST(tuple(1_u8, "2", 3_u8, false) AS Tuple(UInt8, String, UInt8, Boolean) NULL)) +checked expr : contains(CAST(array(CAST(tuple(1_u8, "2", 3_u8, false) AS Tuple(UInt8, String, UInt8, Boolean) NULL), CAST(tuple(1_u8, "2", 4_u8, true) AS Tuple(UInt8, String, UInt8, Boolean) NULL), CAST(NULL AS Tuple(UInt8, String, UInt8, Boolean) NULL)) AS Array(Tuple(UInt8, String, UInt8, Boolean) NULL) NULL), CAST(tuple(1_u8, "2", 3_u8, false) AS Tuple(UInt8, String, UInt8, Boolean) NULL)) optimized expr : true output type : Boolean output domain : {TRUE} @@ -717,7 +717,7 @@ evaluation (internal): ast : array_concat([], []) raw expr : array_concat(array(), array()) -checked expr : array_concat(CAST(array<>() AS Array(Nothing) NULL), CAST(array<>() AS Array(Nothing) NULL)) +checked expr : array_concat(array<>(), array<>()) optimized expr : [] :: Array(Nothing) output type : Array(Nothing) output domain : [] @@ -749,9 +749,10 @@ error: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no overload satisfies `array_concat(Array(Boolean), Array(UInt8))` has tried possible overloads: - array_concat(Array(Nothing) NULL, Array(Nothing) NULL) :: Array(Nothing) : unable to unify `Array(Boolean)` with `Array(Nothing)` - array_concat(Array(T0), Array(T0)) :: Array(T0) : unable to find a common super type for `Boolean` and `UInt8` - array_concat(Array(T0) NULL, Array(T0) NULL) :: Array(T0) NULL : unable to find a common super type for `Boolean` and `UInt8` + array_concat(Array(Nothing), Array(Nothing)) :: Array(Nothing) : unable to unify `Array(Boolean)` with `Array(Nothing)` + array_concat(Array(Nothing) NULL, Array(Nothing) NULL) :: Array(Nothing) NULL : unable to unify `Array(Boolean)` with `Array(Nothing)` + array_concat(Array(T0), Array(T0)) :: Array(T0) : unable to find a common super type for `Boolean` and `UInt8` + array_concat(Array(T0) NULL, Array(T0) NULL) :: Array(T0) NULL : unable to find a common super type for `Boolean` and `UInt8` @@ -822,7 +823,7 @@ evaluation (internal): ast : array_prepend(1, []) raw expr : array_prepend(1, array()) -checked expr : array_prepend(1_u8, CAST(array<>() AS Array(UInt8))) +checked expr : array_prepend(1_u8, CAST(array<>() AS Array(UInt8) NULL)) optimized expr : [1] output type : Array(UInt8) output domain : [{1..=1}] @@ -831,7 +832,7 @@ output : [1] ast : array_prepend(1, [2, 3, NULL, 4]) raw expr : array_prepend(1, array(2, 3, NULL, 4)) -checked expr : array_prepend(CAST(1_u8 AS UInt8 NULL), array(CAST(2_u8 AS UInt8 NULL), CAST(3_u8 AS UInt8 NULL), CAST(NULL AS UInt8 NULL), CAST(4_u8 AS UInt8 NULL))) +checked expr : array_prepend(CAST(1_u8 AS UInt8 NULL), CAST(array(CAST(2_u8 AS UInt8 NULL), CAST(3_u8 AS UInt8 NULL), CAST(NULL AS UInt8 NULL), CAST(4_u8 AS UInt8 NULL)) AS Array(UInt8 NULL) NULL)) optimized expr : [1, 2, 3, NULL, 4] output type : Array(UInt8 NULL) output domain : [{0..=4} ∪ {NULL}] @@ -840,16 +841,34 @@ output : [1, 2, 3, NULL, 4] ast : array_prepend('a', ['b', NULL, NULL, 'c', 'd']) raw expr : array_prepend('a', array('b', NULL, NULL, 'c', 'd')) -checked expr : array_prepend(CAST("a" AS String NULL), array(CAST("b" AS String NULL), CAST(NULL AS String NULL), CAST(NULL AS String NULL), CAST("c" AS String NULL), CAST("d" AS String NULL))) +checked expr : array_prepend(CAST("a" AS String NULL), CAST(array(CAST("b" AS String NULL), CAST(NULL AS String NULL), CAST(NULL AS String NULL), CAST("c" AS String NULL), CAST("d" AS String NULL)) AS Array(String NULL) NULL)) optimized expr : ['a', 'b', NULL, NULL, 'c', 'd'] output type : Array(String NULL) output domain : [{""..="d"} ∪ {NULL}] output : ['a', 'b', NULL, NULL, 'c', 'd'] +ast : array_prepend(NULL, CAST([2, 3] AS Array(INT8 NULL) NULL)) +raw expr : array_prepend(NULL, CAST(array(2, 3) AS Array(Int8 NULL) NULL)) +checked expr : array_prepend(CAST(NULL AS Int8 NULL), CAST(array(2_u8, 3_u8) AS Array(Int8 NULL) NULL)) +optimized expr : [NULL, 2, 3] +output type : Array(Int8 NULL) +output domain : [{0..=3} ∪ {NULL}] +output : [NULL, 2, 3] + + +ast : array_prepend(1, CAST([2, 3] AS Array(INT8 NULL) NULL)) +raw expr : array_prepend(1, CAST(array(2, 3) AS Array(Int8 NULL) NULL)) +checked expr : array_prepend(CAST(1_u8 AS Int16 NULL), CAST(CAST(array(2_u8, 3_u8) AS Array(Int8 NULL) NULL) AS Array(Int16 NULL) NULL)) +optimized expr : [1, 2, 3] +output type : Array(Int16 NULL) +output domain : [{1..=3}] +output : [1, 2, 3] + + ast : array_prepend(a, [b, c]) raw expr : array_prepend(a::Int16, array(b::Int16, c::Int16)) -checked expr : array_prepend(a, array(b, c)) +checked expr : array_prepend(a, CAST(array(b, c) AS Array(Int16) NULL)) evaluation: +--------+---------+---------+---------+--------------+ | | a | b | c | Output | @@ -873,7 +892,7 @@ evaluation (internal): ast : array_append([], 1) raw expr : array_append(array(), 1) -checked expr : array_append(CAST(array<>() AS Array(UInt8)), 1_u8) +checked expr : array_append(CAST(array<>() AS Array(UInt8) NULL), 1_u8) optimized expr : [1] output type : Array(UInt8) output domain : [{1..=1}] @@ -882,7 +901,7 @@ output : [1] ast : array_append([2, 3, NULL, 4], 5) raw expr : array_append(array(2, 3, NULL, 4), 5) -checked expr : array_append(array(CAST(2_u8 AS UInt8 NULL), CAST(3_u8 AS UInt8 NULL), CAST(NULL AS UInt8 NULL), CAST(4_u8 AS UInt8 NULL)), CAST(5_u8 AS UInt8 NULL)) +checked expr : array_append(CAST(array(CAST(2_u8 AS UInt8 NULL), CAST(3_u8 AS UInt8 NULL), CAST(NULL AS UInt8 NULL), CAST(4_u8 AS UInt8 NULL)) AS Array(UInt8 NULL) NULL), CAST(5_u8 AS UInt8 NULL)) optimized expr : [2, 3, NULL, 4, 5] output type : Array(UInt8 NULL) output domain : [{0..=5} ∪ {NULL}] @@ -891,16 +910,34 @@ output : [2, 3, NULL, 4, 5] ast : array_append(['b', NULL, NULL, 'c', 'd'], 'e') raw expr : array_append(array('b', NULL, NULL, 'c', 'd'), 'e') -checked expr : array_append(array(CAST("b" AS String NULL), CAST(NULL AS String NULL), CAST(NULL AS String NULL), CAST("c" AS String NULL), CAST("d" AS String NULL)), CAST("e" AS String NULL)) +checked expr : array_append(CAST(array(CAST("b" AS String NULL), CAST(NULL AS String NULL), CAST(NULL AS String NULL), CAST("c" AS String NULL), CAST("d" AS String NULL)) AS Array(String NULL) NULL), CAST("e" AS String NULL)) optimized expr : ['b', NULL, NULL, 'c', 'd', 'e'] output type : Array(String NULL) output domain : [{""..="e"} ∪ {NULL}] output : ['b', NULL, NULL, 'c', 'd', 'e'] +ast : array_append(CAST([1, 2] AS Array(INT8 NULL) NULL), NULL) +raw expr : array_append(CAST(array(1, 2) AS Array(Int8 NULL) NULL), NULL) +checked expr : array_append(CAST(array(1_u8, 2_u8) AS Array(Int8 NULL) NULL), CAST(NULL AS Int8 NULL)) +optimized expr : [1, 2, NULL] +output type : Array(Int8 NULL) +output domain : [{0..=2} ∪ {NULL}] +output : [1, 2, NULL] + + +ast : array_append(CAST([1, 2] AS Array(INT8 NULL) NULL), 3) +raw expr : array_append(CAST(array(1, 2) AS Array(Int8 NULL) NULL), 3) +checked expr : array_append(CAST(CAST(array(1_u8, 2_u8) AS Array(Int8 NULL) NULL) AS Array(Int16 NULL) NULL), CAST(3_u8 AS Int16 NULL)) +optimized expr : [1, 2, 3] +output type : Array(Int16 NULL) +output domain : [{1..=3}] +output : [1, 2, 3] + + ast : array_append([b, c], a) raw expr : array_append(array(b::Int16, c::Int16), a::Int16) -checked expr : array_append(array(b, c), a) +checked expr : array_append(CAST(array(b, c) AS Array(Int16) NULL), a) evaluation: +--------+---------+---------+---------+--------------+ | | a | b | c | Output | diff --git a/src/query/functions/tests/it/scalars/testdata/function_list.txt b/src/query/functions/tests/it/scalars/testdata/function_list.txt index a2aec3045433..278fe8cf4d31 100644 --- a/src/query/functions/tests/it/scalars/testdata/function_list.txt +++ b/src/query/functions/tests/it/scalars/testdata/function_list.txt @@ -115,12 +115,13 @@ Functions overloads: 0 array() :: Array(Nothing) 1 array FACTORY 0 array_any FACTORY -0 array_append FACTORY +0 array_append(Array(T0) NULL, T0) :: Array(T0) 0 array_approx_count_distinct FACTORY 0 array_avg FACTORY -0 array_concat(Array(Nothing) NULL, Array(Nothing) NULL) :: Array(Nothing) -1 array_concat(Array(T0), Array(T0)) :: Array(T0) -2 array_concat(Array(T0) NULL, Array(T0) NULL) :: Array(T0) NULL +0 array_concat(Array(Nothing), Array(Nothing)) :: Array(Nothing) +1 array_concat(Array(Nothing) NULL, Array(Nothing) NULL) :: Array(Nothing) NULL +2 array_concat(Array(T0), Array(T0)) :: Array(T0) +3 array_concat(Array(T0) NULL, Array(T0) NULL) :: Array(T0) NULL 0 array_count FACTORY 0 array_distinct(Array(Nothing)) :: Array(Nothing) 1 array_distinct(Array(Nothing) NULL) :: Array(Nothing) NULL @@ -135,7 +136,7 @@ Functions overloads: 0 array_max FACTORY 0 array_median FACTORY 0 array_min FACTORY -0 array_prepend FACTORY +0 array_prepend(T0, Array(T0) NULL) :: Array(T0) 0 array_remove_first(Array(Nothing)) :: Array(Nothing) 1 array_remove_first(Array(Nothing) NULL) :: Array(Nothing) NULL 2 array_remove_first(Array(T0)) :: Array(T0) @@ -1188,7 +1189,7 @@ Functions overloads: 25 contains(Array(Timestamp) NULL, Timestamp NULL) :: Boolean NULL 26 contains(Array(Boolean), Boolean) :: Boolean 27 contains(Array(Boolean) NULL, Boolean NULL) :: Boolean NULL -28 contains(Array(T0), T0) :: Boolean +28 contains(Array(T0) NULL, T0) :: Boolean 0 cos(Float64) :: Float64 1 cos(Float64 NULL) :: Float64 NULL 0 cosine_distance(Array(Float32), Array(Float32)) :: Float32