From 2d5aca18fba1d57881d6a558fa17e9714cf7a2a5 Mon Sep 17 00:00:00 2001 From: carlvinhust2012 Date: Mon, 18 Jul 2022 10:52:42 +0800 Subject: [PATCH] [feature-wip](array) add the array_sort function (#10598) Co-authored-by: hucheng01 --- be/src/vec/CMakeLists.txt | 1 + .../array/function_array_register.cpp | 6 +- .../functions/array/function_array_sort.cpp | 28 ++ .../vec/functions/array/function_array_sort.h | 288 ++++++++++++++++++ .../array-functions/array_sort.md | 78 +++++ .../array-functions/array_sort.md | 78 +++++ gensrc/script/doris_builtins_functions.py | 13 + .../array_functions/test_array_functions.out | 15 + .../test_array_functions.groovy | 2 + 9 files changed, 507 insertions(+), 2 deletions(-) create mode 100644 be/src/vec/functions/array/function_array_sort.cpp create mode 100644 be/src/vec/functions/array/function_array_sort.h create mode 100644 docs/en/docs/sql-manual/sql-functions/array-functions/array_sort.md create mode 100644 docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array_sort.md diff --git a/be/src/vec/CMakeLists.txt b/be/src/vec/CMakeLists.txt index e9646b2729..6ac009cc73 100644 --- a/be/src/vec/CMakeLists.txt +++ b/be/src/vec/CMakeLists.txt @@ -134,6 +134,7 @@ set(VEC_FILES functions/array/function_array_register.cpp functions/array/function_array_size.cpp functions/array/function_array_aggregation.cpp + functions/array/function_array_sort.cpp functions/array/function_array_utils.cpp functions/array/function_arrays_overlap.cpp functions/array/function_array_distinct.cpp diff --git a/be/src/vec/functions/array/function_array_register.cpp b/be/src/vec/functions/array/function_array_register.cpp index 573870144b..cc8092114f 100644 --- a/be/src/vec/functions/array/function_array_register.cpp +++ b/be/src/vec/functions/array/function_array_register.cpp @@ -26,18 +26,20 @@ void register_function_array_element(SimpleFunctionFactory&); void register_function_array_index(SimpleFunctionFactory&); void register_function_array_size(SimpleFunctionFactory&); void register_function_array_aggregation(SimpleFunctionFactory&); -void register_function_arrays_overlap(SimpleFunctionFactory&); void register_function_array_distinct(SimpleFunctionFactory&); void register_function_array_remove(SimpleFunctionFactory&); +void register_function_array_sort(SimpleFunctionFactory&); +void register_function_arrays_overlap(SimpleFunctionFactory&); void register_function_array(SimpleFunctionFactory& factory) { register_function_array_element(factory); register_function_array_index(factory); register_function_array_size(factory); register_function_array_aggregation(factory); - register_function_arrays_overlap(factory); register_function_array_distinct(factory); register_function_array_remove(factory); + register_function_array_sort(factory); + register_function_arrays_overlap(factory); } } // namespace doris::vectorized diff --git a/be/src/vec/functions/array/function_array_sort.cpp b/be/src/vec/functions/array/function_array_sort.cpp new file mode 100644 index 0000000000..932cc2a1f0 --- /dev/null +++ b/be/src/vec/functions/array/function_array_sort.cpp @@ -0,0 +1,28 @@ +// 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 "vec/functions/array/function_array_sort.h" + +#include "vec/functions/simple_function_factory.h" + +namespace doris::vectorized { + +void register_function_array_sort(SimpleFunctionFactory& factory) { + factory.register_function(); +} + +} // namespace doris::vectorized \ No newline at end of file diff --git a/be/src/vec/functions/array/function_array_sort.h b/be/src/vec/functions/array/function_array_sort.h new file mode 100644 index 0000000000..e8dee4a9bc --- /dev/null +++ b/be/src/vec/functions/array/function_array_sort.h @@ -0,0 +1,288 @@ +// 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. +// This file is copied from +// https://github.com/ClickHouse/ClickHouse/blob/master/src/Functions/array/arraySort.cpp +// and modified by Doris +#pragma once + +#include "vec/columns/column_array.h" +#include "vec/columns/column_const.h" +#include "vec/data_types/data_type_array.h" +#include "vec/data_types/data_type_number.h" +#include "vec/functions/function.h" +#include "vec/functions/function_helpers.h" + +namespace doris::vectorized { + +class FunctionArraySort : public IFunction { +public: + static constexpr auto name = "array_sort"; + static FunctionPtr create() { return std::make_shared(); } + using NullMapType = PaddedPODArray; + + /// Get function name. + String get_name() const override { return name; } + + bool is_variadic() const override { return false; } + + size_t get_number_of_arguments() const override { return 1; } + + DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { + DCHECK(is_array(arguments[0])) + << "first argument for function: " << name << " should be DataTypeArray" + << " and arguments[0] is " << arguments[0]->get_name(); + return arguments[0]; + } + + Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, + size_t result, size_t input_rows_count) override { + ColumnPtr src_column = + block.get_by_position(arguments[0]).column->convert_to_full_column_if_const(); + const auto& src_column_array = check_and_get_column(*src_column); + if (!src_column_array) { + return Status::RuntimeError( + fmt::format("unsupported types for function {}({})", get_name(), + block.get_by_position(arguments[0]).type->get_name())); + } + const auto& src_offsets = src_column_array->get_offsets(); + const auto* src_nested_column = &src_column_array->get_data(); + DCHECK(src_nested_column != nullptr); + + DataTypePtr src_column_type = block.get_by_position(arguments[0]).type; + auto nested_type = assert_cast(*src_column_type).get_nested_type(); + auto dest_column_ptr = ColumnArray::create(nested_type->create_column(), + ColumnArray::ColumnOffsets::create()); + IColumn* dest_nested_column = &dest_column_ptr->get_data(); + ColumnArray::Offsets& dest_offsets = dest_column_ptr->get_offsets(); + DCHECK(dest_nested_column != nullptr); + dest_nested_column->reserve(src_nested_column->size()); + dest_offsets.reserve(input_rows_count); + + const NullMapType* src_null_map = nullptr; + if (src_nested_column->is_nullable()) { + const ColumnNullable* src_nested_nullable_col = + check_and_get_column(*src_nested_column); + src_nested_column = src_nested_nullable_col->get_nested_column_ptr(); + src_null_map = &src_nested_nullable_col->get_null_map_column().get_data(); + } + + NullMapType* dest_null_map = nullptr; + if (dest_nested_column->is_nullable()) { + ColumnNullable* dest_nested_nullable_col = + reinterpret_cast(dest_nested_column); + dest_nested_column = dest_nested_nullable_col->get_nested_column_ptr(); + dest_null_map = &dest_nested_nullable_col->get_null_map_column().get_data(); + } + + auto res_val = _execute_by_type(*src_nested_column, src_offsets, *dest_nested_column, + dest_offsets, src_null_map, dest_null_map, nested_type); + if (!res_val) { + return Status::RuntimeError( + fmt::format("execute failed or unsupported types for function {}({})", + get_name(), block.get_by_position(arguments[0]).type->get_name())); + } + + block.replace_by_position(result, std::move(dest_column_ptr)); + return Status::OK(); + } + +private: + // sort the non-null element according to the permutation + template + void _sort_by_permutation(ColumnArray::Offset& prev_offset, + const ColumnArray::Offset& curr_offset, + const SrcDataType* src_data_concrete, const IColumn& src_column, + const NullMapType* src_null_map, IColumn::Permutation& permutation) { + for (ColumnArray::Offset j = prev_offset; j < curr_offset - 1; ++j) { + if (src_null_map && (*src_null_map)[j]) { + continue; + } + for (ColumnArray::Offset k = j + 1; k < curr_offset; ++k) { + if (src_null_map && (*src_null_map)[k]) { + continue; + } + int result = src_data_concrete->compare_at(permutation[j], permutation[k], + src_column, 1); + if (result > 0) { + auto temp = permutation[j]; + permutation[j] = permutation[k]; + permutation[k] = temp; + } + } + } + return; + } + + template + bool _execute_number(const IColumn& src_column, const ColumnArray::Offsets& src_offsets, + IColumn& dest_column, ColumnArray::Offsets& dest_offsets, + const NullMapType* src_null_map, NullMapType* dest_null_map) { + using NestType = typename ColumnType::value_type; + const ColumnType* src_data_concrete = reinterpret_cast(&src_column); + if (!src_data_concrete) { + return false; + } + const PaddedPODArray& src_datas = src_data_concrete->get_data(); + + ColumnType& dest_data_concrete = reinterpret_cast(dest_column); + PaddedPODArray& dest_datas = dest_data_concrete.get_data(); + + ColumnArray::Offset prev_src_offset = 0; + IColumn::Permutation permutation(src_column.size()); + for (size_t i = 0; i < src_column.size(); ++i) { + permutation[i] = i; + } + + for (auto curr_src_offset : src_offsets) { + // filter and insert null element first + for (ColumnArray::Offset j = prev_src_offset; j < curr_src_offset; ++j) { + if (src_null_map && (*src_null_map)[j]) { + DCHECK(dest_null_map != nullptr); + (*dest_null_map).push_back(true); + dest_datas.push_back(NestType()); + } + } + + _sort_by_permutation(prev_src_offset, curr_src_offset, src_data_concrete, + src_column, src_null_map, permutation); + + // insert non-null element after sort by permutation + for (ColumnArray::Offset j = prev_src_offset; j < curr_src_offset; ++j) { + if (src_null_map && (*src_null_map)[j]) { + continue; + } + + dest_datas.push_back(src_datas[permutation[j]]); + if (dest_null_map) { + (*dest_null_map).push_back(false); + } + } + dest_offsets.push_back(curr_src_offset); + prev_src_offset = curr_src_offset; + } + + return true; + } + + bool _execute_string(const IColumn& src_column, const ColumnArray::Offsets& src_offsets, + IColumn& dest_column, ColumnArray::Offsets& dest_offsets, + const NullMapType* src_null_map, NullMapType* dest_null_map) { + const ColumnString* src_data_concrete = reinterpret_cast(&src_column); + if (!src_data_concrete) { + return false; + } + + ColumnString& dest_column_string = reinterpret_cast(dest_column); + ColumnString::Chars& column_string_chars = dest_column_string.get_chars(); + ColumnString::Offsets& column_string_offsets = dest_column_string.get_offsets(); + column_string_chars.reserve(src_column.size()); + + ColumnArray::Offset prev_src_offset = 0; + IColumn::Permutation permutation(src_column.size()); + for (size_t i = 0; i < src_column.size(); ++i) { + permutation[i] = i; + } + + for (auto curr_src_offset : src_offsets) { + // filter and insert null element first + for (ColumnArray::Offset j = prev_src_offset; j < curr_src_offset; ++j) { + if (src_null_map && (*src_null_map)[j]) { + DCHECK(dest_null_map != nullptr); + column_string_offsets.push_back(column_string_offsets.back()); + (*dest_null_map).push_back(true); + } + } + + _sort_by_permutation(prev_src_offset, curr_src_offset, src_data_concrete, + src_column, src_null_map, permutation); + + // insert non-null element after sort by permutation + for (ColumnArray::Offset j = prev_src_offset; j < curr_src_offset; ++j) { + if (src_null_map && (*src_null_map)[j]) { + continue; + } + + StringRef src_str_ref = src_data_concrete->get_data_at(permutation[j]); + // copy the src data to column_string_chars + const size_t old_size = column_string_chars.size(); + const size_t new_size = old_size + src_str_ref.size + 1; + column_string_chars.resize(new_size); + if (src_str_ref.size > 0) { + memcpy(column_string_chars.data() + old_size, src_str_ref.data, + src_str_ref.size); + } + column_string_chars[old_size + src_str_ref.size] = 0; + column_string_offsets.push_back(new_size); + + if (dest_null_map) { + (*dest_null_map).push_back(false); + } + } + dest_offsets.push_back(curr_src_offset); + prev_src_offset = curr_src_offset; + } + return true; + } + + bool _execute_by_type(const IColumn& src_column, const ColumnArray::Offsets& src_offsets, + IColumn& dest_column, ColumnArray::Offsets& dest_offsets, + const NullMapType* src_null_map, NullMapType* dest_null_map, + DataTypePtr& nested_type) { + bool res = false; + WhichDataType which(remove_nullable(nested_type)); + if (which.is_uint8()) { + res = _execute_number(src_column, src_offsets, dest_column, dest_offsets, + src_null_map, dest_null_map); + } else if (which.is_int8()) { + res = _execute_number(src_column, src_offsets, dest_column, dest_offsets, + src_null_map, dest_null_map); + } else if (which.is_int16()) { + res = _execute_number(src_column, src_offsets, dest_column, dest_offsets, + src_null_map, dest_null_map); + } else if (which.is_int32()) { + res = _execute_number(src_column, src_offsets, dest_column, dest_offsets, + src_null_map, dest_null_map); + } else if (which.is_int64()) { + res = _execute_number(src_column, src_offsets, dest_column, dest_offsets, + src_null_map, dest_null_map); + } else if (which.is_int128()) { + res = _execute_number(src_column, src_offsets, dest_column, dest_offsets, + src_null_map, dest_null_map); + } else if (which.is_float32()) { + res = _execute_number(src_column, src_offsets, dest_column, dest_offsets, + src_null_map, dest_null_map); + } else if (which.is_float64()) { + res = _execute_number(src_column, src_offsets, dest_column, dest_offsets, + src_null_map, dest_null_map); + } else if (which.is_date()) { + res = _execute_number(src_column, src_offsets, dest_column, dest_offsets, + src_null_map, dest_null_map); + } else if (which.is_date_time()) { + res = _execute_number(src_column, src_offsets, dest_column, + dest_offsets, src_null_map, dest_null_map); + } else if (which.is_decimal128()) { + res = _execute_number(src_column, src_offsets, dest_column, + dest_offsets, src_null_map, dest_null_map); + } else if (which.is_string()) { + res = _execute_string(src_column, src_offsets, dest_column, dest_offsets, src_null_map, + dest_null_map); + } + return res; + } +}; + +} // namespace doris::vectorized \ No newline at end of file diff --git a/docs/en/docs/sql-manual/sql-functions/array-functions/array_sort.md b/docs/en/docs/sql-manual/sql-functions/array-functions/array_sort.md new file mode 100644 index 0000000000..1ef5a08000 --- /dev/null +++ b/docs/en/docs/sql-manual/sql-functions/array-functions/array_sort.md @@ -0,0 +1,78 @@ +--- +{ + "title": "array_sort", + "language": "en" +} +--- + + + +## array_sort + +### description + +#### Syntax + +``` +ARRAY array_sort(ARRAY arr) +``` + +Return the array which has been sorted in ascending order. Return NULL for NULL input. +If the element of array is NULL, it will be placed in the front of the sorted array. + +### notice + +`Only supported in vectorized engine` + +### example + +``` +mysql> set enable_vectorized_engine=true; +mysql> select k1, k2, array_sort(k2) array_test; ++------+-----------------------------+-----------------------------+ +| k1 | k2 | array_sort(`k2`) | ++------+-----------------------------+-----------------------------+ +| 1 | [1, 2, 3, 4, 5] | [1, 2, 3, 4, 5] | +| 2 | [6, 7, 8] | [6, 7, 8] | +| 3 | [] | [] | +| 4 | NULL | NULL | +| 5 | [1, 2, 3, 4, 5, 4, 3, 2, 1] | [1, 1, 2, 2, 3, 3, 4, 4, 5] | +| 6 | [1, 2, 3, NULL] | [NULL, 1, 2, 3] | +| 7 | [1, 2, 3, NULL, NULL] | [NULL, NULL, 1, 2, 3] | +| 8 | [1, 1, 2, NULL, NULL] | [NULL, NULL, 1, 1, 2] | +| 9 | [1, NULL, 1, 2, NULL, NULL] | [NULL, NULL, NULL, 1, 1, 2] | ++------+-----------------------------+-----------------------------+ + +mysql> select k1, k2, array_sort(k2) from array_test01; ++------+------------------------------------------+------------------------------------------+ +| k1 | k2 | array_sort(`k2`) | ++------+------------------------------------------+------------------------------------------+ +| 1 | ['a', 'b', 'c', 'd', 'e'] | ['a', 'b', 'c', 'd', 'e'] | +| 2 | ['f', 'g', 'h'] | ['f', 'g', 'h'] | +| 3 | [''] | [''] | +| 3 | [NULL] | [NULL] | +| 5 | ['a', 'b', 'c', 'd', 'e', 'a', 'b', 'c'] | ['a', 'a', 'b', 'b', 'c', 'c', 'd', 'e'] | +| 6 | NULL | NULL | +| 7 | ['a', 'b', NULL] | [NULL, 'a', 'b'] | +| 8 | ['a', 'b', NULL, NULL] | [NULL, NULL, 'a', 'b'] | ++------+------------------------------------------+------------------------------------------+ +``` + +### keywords + +ARRAY, SORT, ARRAY_SORT \ No newline at end of file diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array_sort.md b/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array_sort.md new file mode 100644 index 0000000000..dbfbc78652 --- /dev/null +++ b/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array_sort.md @@ -0,0 +1,78 @@ +--- +{ + "title": "array_sort", + "language": "zh-CN" +} +--- + + + +## array_sort + +### description + +#### Syntax + +``` +ARRAY array_sort(ARRAY arr) +``` + +返回按升序排列后的数组,如果输入数组为NULL,则返回NULL。 +如果数组元素包含NULL, 则输出的排序数组会将NULL放在最前面。 + +### notice + +`仅支持向量化引擎中使用` + +### example + +``` +mysql> set enable_vectorized_engine=true; +mysql> select k1, k2, array_sort(k2) array_test; ++------+-----------------------------+-----------------------------+ +| k1 | k2 | array_sort(`k2`) | ++------+-----------------------------+-----------------------------+ +| 1 | [1, 2, 3, 4, 5] | [1, 2, 3, 4, 5] | +| 2 | [6, 7, 8] | [6, 7, 8] | +| 3 | [] | [] | +| 4 | NULL | NULL | +| 5 | [1, 2, 3, 4, 5, 4, 3, 2, 1] | [1, 1, 2, 2, 3, 3, 4, 4, 5] | +| 6 | [1, 2, 3, NULL] | [NULL, 1, 2, 3] | +| 7 | [1, 2, 3, NULL, NULL] | [NULL, NULL, 1, 2, 3] | +| 8 | [1, 1, 2, NULL, NULL] | [NULL, NULL, 1, 1, 2] | +| 9 | [1, NULL, 1, 2, NULL, NULL] | [NULL, NULL, NULL, 1, 1, 2] | ++------+-----------------------------+-----------------------------+ + +mysql> select k1, k2, array_sort(k2) from array_test01; ++------+------------------------------------------+------------------------------------------+ +| k1 | k2 | array_sort(`k2`) | ++------+------------------------------------------+------------------------------------------+ +| 1 | ['a', 'b', 'c', 'd', 'e'] | ['a', 'b', 'c', 'd', 'e'] | +| 2 | ['f', 'g', 'h'] | ['f', 'g', 'h'] | +| 3 | [''] | [''] | +| 3 | [NULL] | [NULL] | +| 5 | ['a', 'b', 'c', 'd', 'e', 'a', 'b', 'c'] | ['a', 'a', 'b', 'b', 'c', 'c', 'd', 'e'] | +| 6 | NULL | NULL | +| 7 | ['a', 'b', NULL] | [NULL, 'a', 'b'] | +| 8 | ['a', 'b', NULL, NULL] | [NULL, NULL, 'a', 'b'] | ++------+------------------------------------------+------------------------------------------+ +``` + +### keywords + +ARRAY, SORT, ARRAY_SORT \ No newline at end of file diff --git a/gensrc/script/doris_builtins_functions.py b/gensrc/script/doris_builtins_functions.py index 249638831b..8a4aad385c 100755 --- a/gensrc/script/doris_builtins_functions.py +++ b/gensrc/script/doris_builtins_functions.py @@ -185,6 +185,19 @@ visible_functions = [ [['array_distinct'], 'ARRAY_DECIMALV2', ['ARRAY_DECIMALV2'], '', '', '', 'vec', ''], [['array_distinct'], 'ARRAY_VARCHAR', ['ARRAY_VARCHAR'], '', '', '', 'vec', ''], [['array_distinct'], 'ARRAY_STRING', ['ARRAY_STRING'], '', '', '', 'vec', ''], + + [['array_sort'], 'ARRAY_TINYINT', ['ARRAY_TINYINT'], '', '', '', 'vec', ''], + [['array_sort'], 'ARRAY_SMALLINT', ['ARRAY_SMALLINT'], '', '', '', 'vec', ''], + [['array_sort'], 'ARRAY_INT', ['ARRAY_INT'], '', '', '', 'vec', ''], + [['array_sort'], 'ARRAY_BIGINT', ['ARRAY_BIGINT'], '', '', '', 'vec', ''], + [['array_sort'], 'ARRAY_LARGEINT', ['ARRAY_LARGEINT'], '', '', '', 'vec', ''], + [['array_sort'], 'ARRAY_DATETIME', ['ARRAY_DATETIME'], '', '', '', 'vec', ''], + [['array_sort'], 'ARRAY_DATE', ['ARRAY_DATE'], '', '', '', 'vec', ''], + [['array_sort'], 'ARRAY_FLOAT', ['ARRAY_FLOAT'], '', '', '', 'vec', ''], + [['array_sort'], 'ARRAY_DOUBLE', ['ARRAY_DOUBLE'], '', '', '', 'vec', ''], + [['array_sort'], 'ARRAY_DECIMALV2', ['ARRAY_DECIMALV2'], '', '', '', 'vec', ''], + [['array_sort'], 'ARRAY_VARCHAR', ['ARRAY_VARCHAR'], '', '', '', 'vec', ''], + [['array_sort'], 'ARRAY_STRING', ['ARRAY_STRING'], '', '', '', 'vec', ''], [['array_min'], 'TINYINT', ['ARRAY_TINYINT'], '', '', '', 'vec', 'ALWAYS_NULLABLE'], [['array_min'], 'SMALLINT', ['ARRAY_SMALLINT'], '', '', '', 'vec', 'ALWAYS_NULLABLE'], diff --git a/regression-test/data/query/sql_functions/array_functions/test_array_functions.out b/regression-test/data/query/sql_functions/array_functions/test_array_functions.out index e0830f69b1..02dd5d80e4 100644 --- a/regression-test/data/query/sql_functions/array_functions/test_array_functions.out +++ b/regression-test/data/query/sql_functions/array_functions/test_array_functions.out @@ -6,6 +6,7 @@ 4 9 0 5 0 7 6 9 7 +7 5 5 -- !select -- 1 3 3 @@ -14,6 +15,7 @@ 4 9 0 5 0 7 6 9 7 +7 5 5 -- !select -- 1 true @@ -22,6 +24,7 @@ 4 false 5 \N 6 \N +7 \N -- !select -- 1 [1, 2, 3] ['a', 'b', ''] @@ -30,6 +33,7 @@ 4 [1, 2, 3, 4, 5] [] 5 [] ['a', 'b', 'c', 'd'] 6 [1, 2, 3, 4, 5] ['a', 'b', 'c', 'd'] +7 [8, 9, NULL, 10, NULL] ['f', NULL, 'g', NULL, 'h'] -- !select -- [2, 3] 1 @@ -38,3 +42,14 @@ [1, 2, 3, 5, 3, 2, 1] 4 [] 5 [1, 2, 3, 4, 5, 4, 3, 2, 1] 6 +[8, 9, NULL, 10, NULL] 7 + +-- !select -- +1 [1, 2, 3] ['', 'a', 'b'] [1, 2] +2 [4] \N [5] +3 [] [] \N +4 [1, 1, 2, 2, 3, 3, 4, 4, 5] [] [] +5 [] ['a', 'a', 'b', 'b', 'c', 'c', 'd'] \N +6 [1, 1, 2, 2, 3, 3, 4, 4, 5] ['a', 'a', 'b', 'b', 'c', 'c', 'd'] \N +7 [NULL, NULL, 8, 9, 10] [NULL, NULL, 'f', 'g', 'h'] \N + diff --git a/regression-test/suites/query/sql_functions/array_functions/test_array_functions.groovy b/regression-test/suites/query/sql_functions/array_functions/test_array_functions.groovy index 75e16a5c2f..20ae65a6ed 100644 --- a/regression-test/suites/query/sql_functions/array_functions/test_array_functions.groovy +++ b/regression-test/suites/query/sql_functions/array_functions/test_array_functions.groovy @@ -43,10 +43,12 @@ suite("test_array_functions", "query") { sql """ INSERT INTO ${tableName} VALUES(4, [1, 2, 3, 4, 5, 4, 3, 2, 1], [], []) """ sql """ INSERT INTO ${tableName} VALUES(5, [], ["a", "b", "c", "d", "c", "b", "a"], NULL) """ sql """ INSERT INTO ${tableName} VALUES(6, [1, 2, 3, 4, 5, 4, 3, 2, 1], ["a", "b", "c", "d", "c", "b", "a"], NULL) """ + sql """ INSERT INTO ${tableName} VALUES(7, [8, 9, NULL, 10, NULL], ["f", NULL, "g", NULL, "h"], NULL) """ qt_select "SELECT k1, size(k2), size(k3) FROM ${tableName} ORDER BY k1" qt_select "SELECT k1, cardinality(k2), cardinality(k3) FROM ${tableName} ORDER BY k1" qt_select "SELECT k1, arrays_overlap(k2, k4) FROM ${tableName} ORDER BY k1" qt_select "SELECT k1, array_distinct(k2), array_distinct(k3) FROM ${tableName} ORDER BY k1" qt_select "SELECT array_remove(k2, k1), k1 FROM ${tableName} ORDER BY k1" + qt_select "SELECT k1, array_sort(k2), array_sort(k3), array_sort(k4) FROM ${tableName} ORDER BY k1" }