Coverage Report

Created: 2026-07-30 18:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exprs/function/array/function_array_difference.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
#include <fmt/format.h>
21
#include <glog/logging.h>
22
#include <stddef.h>
23
24
#include <algorithm>
25
#include <boost/iterator/iterator_facade.hpp>
26
#include <memory>
27
#include <ostream>
28
#include <string>
29
#include <utility>
30
31
#include "common/status.h"
32
#include "core/assert_cast.h"
33
#include "core/block/block.h"
34
#include "core/block/column_numbers.h"
35
#include "core/block/column_with_type_and_name.h"
36
#include "core/column/column.h"
37
#include "core/column/column_array.h"
38
#include "core/column/column_array_view.h"
39
#include "core/column/column_decimal.h"
40
#include "core/column/column_nullable.h"
41
#include "core/column/column_vector.h"
42
#include "core/data_type/data_type.h"
43
#include "core/data_type/data_type_array.h"
44
#include "core/data_type/data_type_nullable.h"
45
#include "core/data_type/data_type_number.h"
46
#include "core/types.h"
47
#include "exec/common/util.hpp"
48
#include "exprs/aggregate/aggregate_function.h"
49
#include "exprs/function/function.h"
50
51
namespace doris {
52
class FunctionContext;
53
} // namespace doris
54
55
namespace doris {
56
57
class FunctionArrayDifference : public IFunction {
58
public:
59
    static constexpr auto name = "array_difference";
60
61
2
    static FunctionPtr create() { return std::make_shared<FunctionArrayDifference>(); }
62
63
1
    String get_name() const override { return name; }
64
65
1
    bool is_variadic() const override { return false; }
66
67
0
    size_t get_number_of_arguments() const override { return 1; }
68
69
0
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
70
0
        DCHECK(arguments[0]->get_primitive_type() == TYPE_ARRAY)
71
0
                << "argument for function: " << name << " should be DataTypeArray but it has type "
72
0
                << arguments[0]->get_name() << ".";
73
0
        auto nested_type = assert_cast<const DataTypeArray&>(*(arguments[0])).get_nested_type();
74
0
        bool is_nullable = nested_type->is_nullable();
75
76
        //return type is promoted to prevent result overflow
77
        //like: input is int32 ---> return type will be int64
78
0
        DataTypePtr return_type = nullptr;
79
0
        switch (nested_type->get_primitive_type()) {
80
0
        case TYPE_BOOLEAN:
81
0
        case TYPE_TINYINT:
82
0
            return_type = std::make_shared<DataTypeInt16>();
83
0
            break;
84
0
        case TYPE_SMALLINT:
85
0
            return_type = std::make_shared<DataTypeInt32>();
86
0
            break;
87
0
        case TYPE_INT:
88
0
            return_type = std::make_shared<DataTypeInt64>();
89
0
            break;
90
0
        case TYPE_BIGINT:
91
0
        case TYPE_LARGEINT:
92
0
            return_type = std::make_shared<DataTypeInt128>();
93
0
            break;
94
0
        case TYPE_FLOAT:
95
0
        case TYPE_DOUBLE:
96
0
            return_type = std::make_shared<DataTypeFloat64>();
97
0
            break;
98
0
        case TYPE_DECIMAL32:
99
0
        case TYPE_DECIMAL64:
100
0
        case TYPE_DECIMALV2:
101
0
        case TYPE_DECIMAL128I:
102
0
        case TYPE_DECIMAL256:
103
0
            return arguments[0];
104
0
        default:
105
0
            break;
106
0
        }
107
0
        if (return_type) {
108
0
            return std::make_shared<DataTypeArray>(is_nullable ? make_nullable(return_type)
109
0
                                                               : return_type);
110
0
        }
111
0
        throw doris::Exception(ErrorCode::INVALID_ARGUMENT,
112
0
                               "Function of {}, return type get wrong: and input argument is: {}",
113
0
                               name, arguments[0]->get_name());
114
0
    }
115
116
    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
117
0
                        uint32_t result, size_t input_rows_count) const override {
118
0
        const ColumnWithTypeAndName& arg = block.get_by_position(arguments[0]);
119
0
        auto res_column = _execute_non_nullable(arg, input_rows_count);
120
0
        if (!res_column) {
121
0
            return Status::RuntimeError(
122
0
                    fmt::format("unsupported types for function {}({})", get_name(),
123
0
                                block.get_by_position(arguments[0]).type->get_name()));
124
0
        }
125
0
        DCHECK_EQ(arg.column->size(), res_column->size());
126
0
        block.replace_by_position(result, std::move(res_column));
127
0
        return Status::OK();
128
0
    }
129
130
private:
131
    template <typename Element, typename Result>
132
    NO_SANITIZE_UNDEFINED static void impl(const Element* __restrict src, Result* __restrict dst,
133
0
                                           size_t begin, size_t end) {
134
0
        if (begin < end) {
135
0
            Element prev_element = src[begin];
136
0
            dst[begin] = {};
137
0
            for (size_t curr_pos = begin + 1; curr_pos < end; ++curr_pos) {
138
0
                Element curr_element = src[curr_pos];
139
0
                dst[curr_pos] =
140
0
                        static_cast<Result>(curr_element) - static_cast<Result>(prev_element);
141
0
                prev_element = curr_element;
142
0
            }
143
0
        }
144
0
    }
Unexecuted instantiation: _ZN5doris23FunctionArrayDifference4implIhsEEvPKT_PT0_mm
Unexecuted instantiation: _ZN5doris23FunctionArrayDifference4implIasEEvPKT_PT0_mm
Unexecuted instantiation: _ZN5doris23FunctionArrayDifference4implIsiEEvPKT_PT0_mm
Unexecuted instantiation: _ZN5doris23FunctionArrayDifference4implIilEEvPKT_PT0_mm
Unexecuted instantiation: _ZN5doris23FunctionArrayDifference4implIlnEEvPKT_PT0_mm
Unexecuted instantiation: _ZN5doris23FunctionArrayDifference4implInnEEvPKT_PT0_mm
Unexecuted instantiation: _ZN5doris23FunctionArrayDifference4implIfdEEvPKT_PT0_mm
Unexecuted instantiation: _ZN5doris23FunctionArrayDifference4implIddEEvPKT_PT0_mm
Unexecuted instantiation: _ZN5doris23FunctionArrayDifference4implINS_7DecimalIiEES3_EEvPKT_PT0_mm
Unexecuted instantiation: _ZN5doris23FunctionArrayDifference4implINS_7DecimalIlEES3_EEvPKT_PT0_mm
Unexecuted instantiation: _ZN5doris23FunctionArrayDifference4implINS_12Decimal128V3ES2_EEvPKT_PT0_mm
Unexecuted instantiation: _ZN5doris23FunctionArrayDifference4implINS_14DecimalV2ValueES2_EEvPKT_PT0_mm
Unexecuted instantiation: _ZN5doris23FunctionArrayDifference4implINS_7DecimalIN4wide7integerILm256EiEEEES6_EEvPKT_PT0_mm
145
146
    template <PrimitiveType Element, PrimitiveType Result>
147
0
    ColumnPtr _execute_number_expanded(const ColumnArrayView<Element>& array_view) const {
148
0
        using ColVecResult = typename PrimitiveTypeTraits<Result>::ColumnType;
149
0
        typename ColVecResult::MutablePtr res_nested = nullptr;
150
151
0
        const auto& src_data = array_view.element_data.data;
152
0
        if constexpr (is_decimal(Result)) {
153
0
            res_nested = ColVecResult::create(0, src_data.get_scale());
154
0
        } else {
155
0
            res_nested = ColVecResult::create();
156
0
        }
157
0
        auto size = array_view.element_data.size();
158
0
        typename ColVecResult::Container& res_values = res_nested->get_data();
159
0
        res_values.resize(size);
160
161
0
        size_t pos = 0;
162
0
        for (auto offset : array_view.offsets) {
163
0
            impl(src_data.data(), res_values.data(), pos, offset);
164
0
            pos = offset;
165
0
        }
166
0
        auto null_map_col = ColumnUInt8::create(size, 0);
167
0
        auto& null_map_col_data = null_map_col->get_data();
168
0
        VectorizedUtils::update_null_map(null_map_col_data, array_view.nested_null_map);
169
0
        for (size_t row = 0; row < array_view.offsets.size(); ++row) {
170
0
            auto off = array_view.offsets[row - 1];
171
0
            auto len = array_view.offsets[row] - off;
172
0
            auto nested_pos = len ? len - 1 : 0;
173
0
            for (; nested_pos > 0; --nested_pos) {
174
0
                if (null_map_col_data[nested_pos + off - 1]) {
175
0
                    null_map_col_data[nested_pos + off] = 1;
176
0
                }
177
0
            }
178
0
        }
179
0
        return ColumnNullable::create(std::move(res_nested), std::move(null_map_col));
180
0
    }
Unexecuted instantiation: _ZNK5doris23FunctionArrayDifference24_execute_number_expandedILNS_13PrimitiveTypeE2ELS2_4EEENS_3COWINS_7IColumnEE13immutable_ptrIS4_EERKNS_15ColumnArrayViewIXT_EEE
Unexecuted instantiation: _ZNK5doris23FunctionArrayDifference24_execute_number_expandedILNS_13PrimitiveTypeE3ELS2_4EEENS_3COWINS_7IColumnEE13immutable_ptrIS4_EERKNS_15ColumnArrayViewIXT_EEE
Unexecuted instantiation: _ZNK5doris23FunctionArrayDifference24_execute_number_expandedILNS_13PrimitiveTypeE4ELS2_5EEENS_3COWINS_7IColumnEE13immutable_ptrIS4_EERKNS_15ColumnArrayViewIXT_EEE
Unexecuted instantiation: _ZNK5doris23FunctionArrayDifference24_execute_number_expandedILNS_13PrimitiveTypeE5ELS2_6EEENS_3COWINS_7IColumnEE13immutable_ptrIS4_EERKNS_15ColumnArrayViewIXT_EEE
Unexecuted instantiation: _ZNK5doris23FunctionArrayDifference24_execute_number_expandedILNS_13PrimitiveTypeE6ELS2_7EEENS_3COWINS_7IColumnEE13immutable_ptrIS4_EERKNS_15ColumnArrayViewIXT_EEE
Unexecuted instantiation: _ZNK5doris23FunctionArrayDifference24_execute_number_expandedILNS_13PrimitiveTypeE7ELS2_7EEENS_3COWINS_7IColumnEE13immutable_ptrIS4_EERKNS_15ColumnArrayViewIXT_EEE
Unexecuted instantiation: _ZNK5doris23FunctionArrayDifference24_execute_number_expandedILNS_13PrimitiveTypeE8ELS2_9EEENS_3COWINS_7IColumnEE13immutable_ptrIS4_EERKNS_15ColumnArrayViewIXT_EEE
Unexecuted instantiation: _ZNK5doris23FunctionArrayDifference24_execute_number_expandedILNS_13PrimitiveTypeE9ELS2_9EEENS_3COWINS_7IColumnEE13immutable_ptrIS4_EERKNS_15ColumnArrayViewIXT_EEE
Unexecuted instantiation: _ZNK5doris23FunctionArrayDifference24_execute_number_expandedILNS_13PrimitiveTypeE28ELS2_28EEENS_3COWINS_7IColumnEE13immutable_ptrIS4_EERKNS_15ColumnArrayViewIXT_EEE
Unexecuted instantiation: _ZNK5doris23FunctionArrayDifference24_execute_number_expandedILNS_13PrimitiveTypeE29ELS2_29EEENS_3COWINS_7IColumnEE13immutable_ptrIS4_EERKNS_15ColumnArrayViewIXT_EEE
Unexecuted instantiation: _ZNK5doris23FunctionArrayDifference24_execute_number_expandedILNS_13PrimitiveTypeE30ELS2_30EEENS_3COWINS_7IColumnEE13immutable_ptrIS4_EERKNS_15ColumnArrayViewIXT_EEE
Unexecuted instantiation: _ZNK5doris23FunctionArrayDifference24_execute_number_expandedILNS_13PrimitiveTypeE20ELS2_20EEENS_3COWINS_7IColumnEE13immutable_ptrIS4_EERKNS_15ColumnArrayViewIXT_EEE
Unexecuted instantiation: _ZNK5doris23FunctionArrayDifference24_execute_number_expandedILNS_13PrimitiveTypeE35ELS2_35EEENS_3COWINS_7IColumnEE13immutable_ptrIS4_EERKNS_15ColumnArrayViewIXT_EEE
181
182
    ColumnPtr _execute_non_nullable(const ColumnWithTypeAndName& arg,
183
0
                                    size_t input_rows_count) const {
184
        // check array nested column type and get data
185
0
        auto left_column = arg.column->convert_to_full_column_if_const();
186
0
        const auto& array_column = reinterpret_cast<const ColumnArray&>(*left_column);
187
0
        const auto& offsets = array_column.get_offsets();
188
0
        DCHECK(offsets.size() == input_rows_count);
189
190
0
        ColumnPtr res = nullptr;
191
0
        auto left_element_type =
192
0
                remove_nullable(assert_cast<const DataTypeArray&>(*arg.type).get_nested_type());
193
0
        switch (left_element_type->get_primitive_type()) {
194
0
        case TYPE_BOOLEAN:
195
0
            res = _execute_number_expanded<TYPE_BOOLEAN, TYPE_SMALLINT>(
196
0
                    ColumnArrayView<TYPE_BOOLEAN>::create(left_column));
197
0
            break;
198
0
        case TYPE_TINYINT:
199
0
            res = _execute_number_expanded<TYPE_TINYINT, TYPE_SMALLINT>(
200
0
                    ColumnArrayView<TYPE_TINYINT>::create(left_column));
201
0
            break;
202
0
        case TYPE_SMALLINT:
203
0
            res = _execute_number_expanded<TYPE_SMALLINT, TYPE_INT>(
204
0
                    ColumnArrayView<TYPE_SMALLINT>::create(left_column));
205
0
            break;
206
0
        case TYPE_INT:
207
0
            res = _execute_number_expanded<TYPE_INT, TYPE_BIGINT>(
208
0
                    ColumnArrayView<TYPE_INT>::create(left_column));
209
0
            break;
210
0
        case TYPE_BIGINT:
211
0
            res = _execute_number_expanded<TYPE_BIGINT, TYPE_LARGEINT>(
212
0
                    ColumnArrayView<TYPE_BIGINT>::create(left_column));
213
0
            break;
214
0
        case TYPE_LARGEINT:
215
0
            res = _execute_number_expanded<TYPE_LARGEINT, TYPE_LARGEINT>(
216
0
                    ColumnArrayView<TYPE_LARGEINT>::create(left_column));
217
0
            break;
218
0
        case TYPE_FLOAT:
219
0
            res = _execute_number_expanded<TYPE_FLOAT, TYPE_DOUBLE>(
220
0
                    ColumnArrayView<TYPE_FLOAT>::create(left_column));
221
0
            break;
222
0
        case TYPE_DOUBLE:
223
0
            res = _execute_number_expanded<TYPE_DOUBLE, TYPE_DOUBLE>(
224
0
                    ColumnArrayView<TYPE_DOUBLE>::create(left_column));
225
0
            break;
226
0
        case TYPE_DECIMAL32:
227
0
            res = _execute_number_expanded<TYPE_DECIMAL32, TYPE_DECIMAL32>(
228
0
                    ColumnArrayView<TYPE_DECIMAL32>::create(left_column));
229
0
            break;
230
0
        case TYPE_DECIMAL64:
231
0
            res = _execute_number_expanded<TYPE_DECIMAL64, TYPE_DECIMAL64>(
232
0
                    ColumnArrayView<TYPE_DECIMAL64>::create(left_column));
233
0
            break;
234
0
        case TYPE_DECIMAL128I:
235
0
            res = _execute_number_expanded<TYPE_DECIMAL128I, TYPE_DECIMAL128I>(
236
0
                    ColumnArrayView<TYPE_DECIMAL128I>::create(left_column));
237
0
            break;
238
0
        case TYPE_DECIMALV2:
239
0
            res = _execute_number_expanded<TYPE_DECIMALV2, TYPE_DECIMALV2>(
240
0
                    ColumnArrayView<TYPE_DECIMALV2>::create(left_column));
241
0
            break;
242
0
        case TYPE_DECIMAL256:
243
0
            res = _execute_number_expanded<TYPE_DECIMAL256, TYPE_DECIMAL256>(
244
0
                    ColumnArrayView<TYPE_DECIMAL256>::create(left_column));
245
0
            break;
246
0
        default:
247
0
            return nullptr;
248
0
        }
249
0
        return ColumnArray::create(res, array_column.get_offsets_ptr());
250
0
    }
251
};
252
253
} // namespace doris