summaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Functions/array/arraySort.cpp
diff options
context:
space:
mode:
authorvitalyisaev <[email protected]>2023-11-14 09:58:56 +0300
committervitalyisaev <[email protected]>2023-11-14 10:20:20 +0300
commitc2b2dfd9827a400a8495e172a56343462e3ceb82 (patch)
treecd4e4f597d01bede4c82dffeb2d780d0a9046bd0 /contrib/clickhouse/src/Functions/array/arraySort.cpp
parentd4ae8f119e67808cb0cf776ba6e0cf95296f2df7 (diff)
YQ Connector: move tests from yql to ydb (OSS)
Перенос папки с тестами на Коннектор из папки yql в папку ydb (синхронизируется с github).
Diffstat (limited to 'contrib/clickhouse/src/Functions/array/arraySort.cpp')
-rw-r--r--contrib/clickhouse/src/Functions/array/arraySort.cpp146
1 files changed, 146 insertions, 0 deletions
diff --git a/contrib/clickhouse/src/Functions/array/arraySort.cpp b/contrib/clickhouse/src/Functions/array/arraySort.cpp
new file mode 100644
index 00000000000..a853289e8cc
--- /dev/null
+++ b/contrib/clickhouse/src/Functions/array/arraySort.cpp
@@ -0,0 +1,146 @@
+#include <Functions/array/arraySort.h>
+#include <Functions/FunctionFactory.h>
+
+namespace DB
+{
+
+namespace ErrorCodes
+{
+ extern const int LOGICAL_ERROR;
+}
+
+namespace
+{
+
+template <bool positive>
+struct Less
+{
+ const IColumn & column;
+
+ explicit Less(const IColumn & column_) : column(column_) { }
+
+ bool operator()(size_t lhs, size_t rhs) const
+ {
+ if constexpr (positive)
+ return column.compareAt(lhs, rhs, column, 1) < 0;
+ else
+ return column.compareAt(lhs, rhs, column, -1) > 0;
+ }
+};
+
+}
+
+template <bool positive, bool is_partial>
+ColumnPtr ArraySortImpl<positive, is_partial>::execute(
+ const ColumnArray & array,
+ ColumnPtr mapped,
+ const ColumnWithTypeAndName * fixed_arguments)
+{
+ [[maybe_unused]] const auto limit = [&]() -> size_t
+ {
+ if constexpr (is_partial)
+ {
+ if (!fixed_arguments)
+ throw Exception(
+ ErrorCodes::LOGICAL_ERROR,
+ "Expected fixed arguments to get the limit for partial array sort"
+ );
+ return fixed_arguments[0].column.get()->getUInt(0);
+ }
+ return 0;
+ }();
+
+ const ColumnArray::Offsets & offsets = array.getOffsets();
+
+ size_t size = offsets.size();
+ size_t nested_size = array.getData().size();
+ IColumn::Permutation permutation(nested_size);
+
+ for (size_t i = 0; i < nested_size; ++i)
+ permutation[i] = i;
+
+ ColumnArray::Offset current_offset = 0;
+ for (size_t i = 0; i < size; ++i)
+ {
+ auto next_offset = offsets[i];
+ if constexpr (is_partial)
+ {
+ if (limit)
+ {
+ const auto effective_limit = std::min<size_t>(limit, next_offset - current_offset);
+ ::partial_sort(&permutation[current_offset], &permutation[current_offset + effective_limit], &permutation[next_offset], Less<positive>(*mapped));
+ }
+ else
+ ::sort(&permutation[current_offset], &permutation[next_offset], Less<positive>(*mapped));
+ }
+ else
+ ::sort(&permutation[current_offset], &permutation[next_offset], Less<positive>(*mapped));
+ current_offset = next_offset;
+ }
+
+ return ColumnArray::create(array.getData().permute(permutation, 0), array.getOffsetsPtr());
+}
+
+REGISTER_FUNCTION(ArraySort)
+{
+ factory.registerFunction<FunctionArraySort>();
+ factory.registerFunction<FunctionArrayReverseSort>();
+
+ factory.registerFunction<FunctionArrayPartialSort>(FunctionDocumentation{
+ .description=R"(
+Returns an array of the same size as the original array where elements in range `[1..limit]`
+are sorted in ascending order. Remaining elements `(limit..N]` shall contain elements in unspecified order.
+[example:simple_int]
+[example:simple_string]
+
+To retain only the sorted elements use `arrayResize`:
+[example:retain_sorted]
+
+If the `func` function is specified, sorting order is determined by the result of the `func`
+function applied to the elements of the array.
+[example:lambda_simple]
+
+If `func` accepts multiple arguments, the `arrayPartialSort` function is passed several arrays
+that the arguments of `func` will correspond to.
+[example:lambda_complex]
+
+For more details see documentation of `arraySort`.
+)",
+ .examples{
+ {"simple_int", "SELECT arrayPartialSort(2, [5, 9, 1, 3])", ""},
+ {"simple_string", "SELECT arrayPartialSort(2, ['expenses','lasso','embolism','gladly'])", ""},
+ {"retain_sorted", "SELECT arrayResize(arrayPartialSort(2, [5, 9, 1, 3]), 2)", ""},
+ {"lambda_simple", "SELECT arrayPartialSort((x) -> -x, 2, [5, 9, 1, 3])", ""},
+ {"lambda_complex", "SELECT arrayPartialSort((x, y) -> -y, 1, [0, 1, 2], [1, 2, 3]) as res", ""}},
+ .categories{"Array"}});
+
+ factory.registerFunction<FunctionArrayPartialReverseSort>(FunctionDocumentation{
+ .description=R"(
+Returns an array of the same size as the original array where elements in range `[1..limit]`
+are sorted in descending order. Remaining elements `(limit..N]` shall contain elements in unspecified order.
+[example:simple_int]
+[example:simple_string]
+
+To retain only the sorted elements use `arrayResize`:
+[example:retain_sorted]
+
+If the `func` function is specified, sorting order is determined by the result of the `func`
+function applied to the elements of the array.
+[example:lambda_simple]
+
+If `func` accepts multiple arguments, the `arrayPartialSort` function is passed several arrays
+that the arguments of `func` will correspond to.
+[example:lambda_complex]
+
+For more details see documentation of `arraySort`.
+)",
+ .examples{
+ {"simple_int", "SELECT arrayPartialReverseSort(2, [5, 9, 1, 3])", ""},
+ {"simple_string", "SELECT arrayPartialReverseSort(2, ['expenses','lasso','embolism','gladly'])", ""},
+ {"retain_sorted", "SELECT arrayResize(arrayPartialReverseSort(2, [5, 9, 1, 3]), 2)", ""},
+ {"lambda_simple", "SELECT arrayPartialReverseSort((x) -> -x, 2, [5, 9, 1, 3])", ""},
+ {"lambda_complex", "SELECT arrayPartialReverseSort((x, y) -> -y, 1, [0, 1, 2], [1, 2, 3]) as res", ""}},
+ .categories{"Array"}});
+}
+
+}