Coverage Report

Created: 2026-07-12 00:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exprs/function/function_regexp.cpp
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
#include <glog/logging.h>
19
#include <re2/re2.h>
20
#include <re2/stringpiece.h>
21
#include <stddef.h>
22
23
#include <boost/regex.hpp>
24
#include <memory>
25
#include <string>
26
#include <string_view>
27
#include <type_traits>
28
#include <utility>
29
#include <vector>
30
31
#include "common/status.h"
32
#include "core/block/block.h"
33
#include "core/block/column_numbers.h"
34
#include "core/block/column_with_type_and_name.h"
35
#include "core/column/column.h"
36
#include "core/column/column_array.h"
37
#include "core/column/column_const.h"
38
#include "core/column/column_execute_util.h"
39
#include "core/column/column_nullable.h"
40
#include "core/column/column_string.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/data_type/data_type_string.h"
47
#include "core/string_ref.h"
48
#include "core/types.h"
49
#include "exec/common/stringop_substring.h"
50
#include "exprs/aggregate/aggregate_function.h"
51
#include "exprs/function/function.h"
52
#include "exprs/function/simple_function_factory.h"
53
#include "exprs/function_context.h"
54
#include "exprs/string_functions.h"
55
56
namespace doris {
57
58
// Helper structure to hold either RE2 or Boost.Regex
59
struct RegexpExtractEngine {
60
    std::unique_ptr<re2::RE2> re2_regex;
61
    std::unique_ptr<boost::regex> boost_regex;
62
63
18
    bool is_boost() const { return boost_regex != nullptr; }
64
384
    bool is_re2() const { return re2_regex != nullptr; }
65
66
    // Try to compile with RE2 first, fallback to Boost.Regex if RE2 fails
67
    static bool compile(const StringRef& pattern, std::string* error_str,
68
299
                        RegexpExtractEngine& engine, bool enable_extended_regex) {
69
299
        re2::RE2::Options options;
70
299
        options.set_log_errors(false); // avoid RE2 printing to stderr; we handle errors ourselves
71
299
        options.set_dot_nl(true); // make '.' match '\n' by default, consistent with REGEXP/LIKE
72
299
        engine.re2_regex =
73
299
                std::make_unique<re2::RE2>(re2::StringPiece(pattern.data, pattern.size), options);
74
75
299
        if (engine.re2_regex->ok()) {
76
276
            return true;
77
276
        } else if (!enable_extended_regex) {
78
5
            *error_str = fmt::format(
79
5
                    "Invalid regex pattern: {}. Error: {}. If you need advanced regex features, "
80
5
                    "try setting enable_extended_regex=true",
81
5
                    std::string(pattern.data, pattern.size), engine.re2_regex->error());
82
5
            return false;
83
5
        }
84
85
        // RE2 failed, try Boost.Regex for advanced features like zero-width assertions
86
18
        engine.re2_regex.reset();
87
18
        try {
88
18
            boost::regex::flag_type flags = boost::regex::normal;
89
18
            engine.boost_regex = std::make_unique<boost::regex>(pattern.data,
90
18
                                                                pattern.data + pattern.size, flags);
91
18
            return true;
92
18
        } catch (const boost::regex_error& e) {
93
0
            if (error_str) {
94
0
                *error_str = fmt::format("Invalid regex pattern: {}. Error: {}",
95
0
                                         std::string(pattern.data, pattern.size), e.what());
96
0
            }
97
0
            return false;
98
0
        }
99
18
    }
100
101
    // Get number of capturing groups
102
270
    int number_of_capturing_groups() const {
103
270
        if (is_re2()) {
104
261
            return re2_regex->NumberOfCapturingGroups();
105
261
        } else if (is_boost()) {
106
9
            return static_cast<int>(boost_regex->mark_count());
107
9
        }
108
0
        return 0;
109
270
    }
110
111
    // Match function for extraction
112
52
    bool match_and_extract(const char* data, size_t size, int index, std::string& result) const {
113
52
        if (is_re2()) {
114
47
            int max_matches = 1 + re2_regex->NumberOfCapturingGroups();
115
47
            if (index >= max_matches) {
116
0
                return false;
117
0
            }
118
47
            std::vector<re2::StringPiece> matches(max_matches);
119
47
            bool success = re2_regex->Match(re2::StringPiece(data, size), 0, size,
120
47
                                            re2::RE2::UNANCHORED, matches.data(), max_matches);
121
47
            if (success && index < matches.size()) {
122
34
                const re2::StringPiece& match = matches[index];
123
34
                result.assign(match.data(), match.size());
124
34
                return true;
125
34
            }
126
13
            return false;
127
47
        } else if (is_boost()) {
128
5
            boost::cmatch matches;
129
5
            bool success = boost::regex_search(data, data + size, matches, *boost_regex);
130
5
            if (success && index < matches.size()) {
131
5
                result = matches[index].str();
132
5
                return true;
133
5
            }
134
0
            return false;
135
5
        }
136
0
        return false;
137
52
    }
138
139
    // Match all occurrences and extract the first capturing group
140
    void match_all_and_extract(const char* data, size_t size,
141
62
                               std::vector<std::string>& results) const {
142
62
        if (is_re2()) {
143
58
            int max_matches = 1 + re2_regex->NumberOfCapturingGroups();
144
58
            if (max_matches < 2) {
145
0
                return; // No capturing groups
146
0
            }
147
148
58
            size_t pos = 0;
149
160
            while (pos < size) {
150
122
                const char* str_pos = data + pos;
151
122
                size_t str_size = size - pos;
152
122
                std::vector<re2::StringPiece> matches(max_matches);
153
122
                bool success = re2_regex->Match(re2::StringPiece(str_pos, str_size), 0, str_size,
154
122
                                                re2::RE2::UNANCHORED, matches.data(), max_matches);
155
122
                if (!success) {
156
20
                    break;
157
20
                }
158
102
                if (matches[0].empty()) {
159
17
                    pos += 1;
160
17
                    continue;
161
17
                }
162
                // Extract first capturing group
163
85
                if (matches.size() > 1 && !matches[1].empty()) {
164
85
                    results.emplace_back(matches[1].data(), matches[1].size());
165
85
                }
166
                // Move position forward
167
85
                auto offset = std::string(str_pos, str_size)
168
85
                                      .find(std::string(matches[0].data(), matches[0].size()));
169
85
                pos += offset + matches[0].size();
170
85
            }
171
58
        } else if (is_boost()) {
172
4
            const char* search_start = data;
173
4
            const char* search_end = data + size;
174
4
            boost::match_results<const char*> matches;
175
176
13
            while (boost::regex_search(search_start, search_end, matches, *boost_regex)) {
177
9
                if (matches.size() > 1 && matches[1].matched) {
178
9
                    results.emplace_back(matches[1].str());
179
9
                }
180
9
                if (matches[0].length() == 0) {
181
0
                    if (search_start == search_end) {
182
0
                        break;
183
0
                    }
184
0
                    search_start += 1;
185
9
                } else {
186
9
                    search_start = matches[0].second;
187
9
                }
188
9
            }
189
4
        }
190
62
    }
191
};
192
193
struct RegexpCountImpl {
194
    using StringColumnView = ColumnView<TYPE_STRING>;
195
196
    static void execute_impl(FunctionContext* context, ColumnPtr argument_columns[],
197
28
                             size_t input_rows_count, ColumnInt32::Container& result_data) {
198
28
        auto str_col = StringColumnView::create(argument_columns[0]);
199
28
        auto pattern_col = StringColumnView::create(argument_columns[1]);
200
79
        for (size_t i = 0; i < input_rows_count; ++i) {
201
51
            DCHECK(!str_col.is_null_at(i));
202
51
            DCHECK(!pattern_col.is_null_at(i));
203
51
            result_data[i] = _execute_inner_loop(context, str_col, pattern_col, i);
204
51
        }
205
28
    }
206
    static int _execute_inner_loop(FunctionContext* context, const StringColumnView& str_col,
207
51
                                   const StringColumnView& pattern_col, const size_t index_now) {
208
51
        re2::RE2* re = reinterpret_cast<re2::RE2*>(
209
51
                context->get_function_state(FunctionContext::THREAD_LOCAL));
210
51
        std::unique_ptr<re2::RE2> scoped_re;
211
51
        if (re == nullptr) {
212
24
            std::string error_str;
213
24
            const auto pattern = pattern_col.value_at(index_now);
214
24
            bool st = StringFunctions::compile_regex(pattern, &error_str, StringRef(), StringRef(),
215
24
                                                     scoped_re);
216
24
            if (!st) {
217
0
                context->add_warning(error_str.c_str());
218
0
                throw Exception(Status::InvalidArgument(error_str));
219
0
                return 0;
220
0
            }
221
24
            re = scoped_re.get();
222
24
        }
223
224
51
        const auto str = str_col.value_at(index_now);
225
51
        int count = 0;
226
51
        size_t pos = 0;
227
171
        while (pos < str.size) {
228
151
            auto str_pos = str.data + pos;
229
151
            auto str_size = str.size - pos;
230
151
            re2::StringPiece str_sp_current = re2::StringPiece(str_pos, str_size);
231
151
            re2::StringPiece match;
232
233
151
            bool success = re->Match(str_sp_current, 0, str_size, re2::RE2::UNANCHORED, &match, 1);
234
151
            if (!success) {
235
31
                break;
236
31
            }
237
120
            if (match.empty()) {
238
24
                pos += 1;
239
24
                continue;
240
24
            }
241
96
            count++;
242
96
            size_t match_start = match.data() - str_sp_current.data();
243
96
            pos += match_start + match.size();
244
96
        }
245
246
51
        return count;
247
51
    }
248
};
249
250
class FunctionRegexpCount : public IFunction {
251
public:
252
    static constexpr auto name = "regexp_count";
253
254
43
    static FunctionPtr create() { return std::make_shared<FunctionRegexpCount>(); }
255
256
1
    String get_name() const override { return name; }
257
258
34
    size_t get_number_of_arguments() const override { return 2; }
259
260
34
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
261
34
        return std::make_shared<DataTypeInt32>();
262
34
    }
263
264
95
    Status open(FunctionContext* context, FunctionContext::FunctionStateScope scope) override {
265
95
        if (scope == FunctionContext::THREAD_LOCAL) {
266
61
            if (context->is_col_constant(1)) {
267
46
                DCHECK(!context->get_function_state(scope));
268
46
                const auto pattern_col = context->get_constant_col(1)->column_ptr;
269
46
                const auto& pattern = pattern_col->get_data_at(0);
270
46
                if (pattern.size == 0) {
271
8
                    return Status::OK();
272
8
                }
273
274
38
                std::string error_str;
275
38
                std::unique_ptr<re2::RE2> scoped_re;
276
38
                bool st = StringFunctions::compile_regex(pattern, &error_str, StringRef(),
277
38
                                                         StringRef(), scoped_re);
278
38
                if (!st) {
279
0
                    context->set_error(error_str.c_str());
280
0
                    return Status::InvalidArgument(error_str);
281
0
                }
282
38
                std::shared_ptr<re2::RE2> re(scoped_re.release());
283
38
                context->set_function_state(scope, re);
284
38
            }
285
61
        }
286
87
        return Status::OK();
287
95
    }
288
289
    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
290
28
                        uint32_t result, size_t input_rows_count) const override {
291
28
        auto result_data_column = ColumnInt32::create(input_rows_count);
292
28
        auto& result_data = result_data_column->get_data();
293
294
28
        ColumnPtr argument_columns[2];
295
296
28
        argument_columns[0] = block.get_by_position(arguments[0]).column;
297
28
        argument_columns[1] = block.get_by_position(arguments[1]).column;
298
28
        RegexpCountImpl::execute_impl(context, argument_columns, input_rows_count, result_data);
299
300
28
        block.get_by_position(result).column = std::move(result_data_column);
301
28
        return Status::OK();
302
28
    }
303
};
304
305
struct ThreeParamTypes {
306
16
    static DataTypes get_variadic_argument_types() {
307
16
        return {std::make_shared<DataTypeString>(), std::make_shared<DataTypeString>(),
308
16
                std::make_shared<DataTypeString>()};
309
16
    }
310
};
311
312
struct FourParamTypes {
313
16
    static DataTypes get_variadic_argument_types() {
314
16
        return {std::make_shared<DataTypeString>(), std::make_shared<DataTypeString>(),
315
16
                std::make_shared<DataTypeString>(), std::make_shared<DataTypeString>()};
316
16
    }
317
};
318
319
// template FunctionRegexpFunctionality is used for regexp_replace/regexp_replace_one
320
template <typename Impl, typename ParamTypes>
321
class FunctionRegexpReplace : public IFunction {
322
public:
323
    static constexpr auto name = Impl::name;
324
325
92
    static FunctionPtr create() { return std::make_shared<FunctionRegexpReplace>(); }
_ZN5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb0EEENS_15ThreeParamTypesEE6createEv
Line
Count
Source
325
33
    static FunctionPtr create() { return std::make_shared<FunctionRegexpReplace>(); }
_ZN5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb0EEENS_14FourParamTypesEE6createEv
Line
Count
Source
325
17
    static FunctionPtr create() { return std::make_shared<FunctionRegexpReplace>(); }
_ZN5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb1EEENS_15ThreeParamTypesEE6createEv
Line
Count
Source
325
24
    static FunctionPtr create() { return std::make_shared<FunctionRegexpReplace>(); }
_ZN5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb1EEENS_14FourParamTypesEE6createEv
Line
Count
Source
325
18
    static FunctionPtr create() { return std::make_shared<FunctionRegexpReplace>(); }
326
327
0
    String get_name() const override { return name; }
Unexecuted instantiation: _ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb0EEENS_15ThreeParamTypesEE8get_nameB5cxx11Ev
Unexecuted instantiation: _ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb0EEENS_14FourParamTypesEE8get_nameB5cxx11Ev
Unexecuted instantiation: _ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb1EEENS_15ThreeParamTypesEE8get_nameB5cxx11Ev
Unexecuted instantiation: _ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb1EEENS_14FourParamTypesEE8get_nameB5cxx11Ev
328
329
0
    size_t get_number_of_arguments() const override {
330
0
        return get_variadic_argument_types_impl().size();
331
0
    }
Unexecuted instantiation: _ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb0EEENS_15ThreeParamTypesEE23get_number_of_argumentsEv
Unexecuted instantiation: _ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb0EEENS_14FourParamTypesEE23get_number_of_argumentsEv
Unexecuted instantiation: _ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb1EEENS_15ThreeParamTypesEE23get_number_of_argumentsEv
Unexecuted instantiation: _ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb1EEENS_14FourParamTypesEE23get_number_of_argumentsEv
332
333
60
    bool is_variadic() const override { return true; }
_ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb0EEENS_15ThreeParamTypesEE11is_variadicEv
Line
Count
Source
333
25
    bool is_variadic() const override { return true; }
_ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb0EEENS_14FourParamTypesEE11is_variadicEv
Line
Count
Source
333
9
    bool is_variadic() const override { return true; }
_ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb1EEENS_15ThreeParamTypesEE11is_variadicEv
Line
Count
Source
333
16
    bool is_variadic() const override { return true; }
_ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb1EEENS_14FourParamTypesEE11is_variadicEv
Line
Count
Source
333
10
    bool is_variadic() const override { return true; }
334
335
56
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
336
56
        return make_nullable(std::make_shared<DataTypeString>());
337
56
    }
_ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb0EEENS_15ThreeParamTypesEE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS9_EE
Line
Count
Source
335
24
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
336
24
        return make_nullable(std::make_shared<DataTypeString>());
337
24
    }
_ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb0EEENS_14FourParamTypesEE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS9_EE
Line
Count
Source
335
8
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
336
8
        return make_nullable(std::make_shared<DataTypeString>());
337
8
    }
_ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb1EEENS_15ThreeParamTypesEE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS9_EE
Line
Count
Source
335
15
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
336
15
        return make_nullable(std::make_shared<DataTypeString>());
337
15
    }
_ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb1EEENS_14FourParamTypesEE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS9_EE
Line
Count
Source
335
9
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
336
9
        return make_nullable(std::make_shared<DataTypeString>());
337
9
    }
338
339
32
    DataTypes get_variadic_argument_types_impl() const override {
340
32
        return ParamTypes::get_variadic_argument_types();
341
32
    }
_ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb0EEENS_15ThreeParamTypesEE32get_variadic_argument_types_implEv
Line
Count
Source
339
8
    DataTypes get_variadic_argument_types_impl() const override {
340
8
        return ParamTypes::get_variadic_argument_types();
341
8
    }
_ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb0EEENS_14FourParamTypesEE32get_variadic_argument_types_implEv
Line
Count
Source
339
8
    DataTypes get_variadic_argument_types_impl() const override {
340
8
        return ParamTypes::get_variadic_argument_types();
341
8
    }
_ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb1EEENS_15ThreeParamTypesEE32get_variadic_argument_types_implEv
Line
Count
Source
339
8
    DataTypes get_variadic_argument_types_impl() const override {
340
8
        return ParamTypes::get_variadic_argument_types();
341
8
    }
_ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb1EEENS_14FourParamTypesEE32get_variadic_argument_types_implEv
Line
Count
Source
339
8
    DataTypes get_variadic_argument_types_impl() const override {
340
8
        return ParamTypes::get_variadic_argument_types();
341
8
    }
342
343
335
    Status open(FunctionContext* context, FunctionContext::FunctionStateScope scope) override {
344
335
        if (scope == FunctionContext::THREAD_LOCAL) {
345
279
            if (context->is_col_constant(1)) {
346
141
                DCHECK(!context->get_function_state(scope));
347
141
                const auto pattern_col = context->get_constant_col(1)->column_ptr;
348
141
                const auto& pattern = pattern_col->get_data_at(0);
349
141
                if (pattern.size == 0) {
350
6
                    return Status::OK();
351
6
                }
352
353
135
                std::string error_str;
354
135
                std::unique_ptr<re2::RE2> scoped_re;
355
135
                StringRef options_value;
356
135
                if constexpr (std::is_same_v<FourParamTypes, ParamTypes>) {
357
86
                    DCHECK_EQ(context->get_num_args(), 4);
358
86
                    DCHECK(context->is_col_constant(3));
359
86
                    const auto options_col = context->get_constant_col(3)->column_ptr;
360
86
                    options_value = options_col->get_data_at(0);
361
86
                }
362
363
135
                bool st = StringFunctions::compile_regex(pattern, &error_str, StringRef(),
364
135
                                                         options_value, scoped_re);
365
135
                if (!st) {
366
0
                    context->set_error(error_str.c_str());
367
0
                    return Status::InvalidArgument(error_str);
368
0
                }
369
135
                std::shared_ptr<re2::RE2> re(scoped_re.release());
370
135
                context->set_function_state(scope, re);
371
135
            }
372
279
        }
373
329
        return Status::OK();
374
335
    }
_ZN5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb0EEENS_15ThreeParamTypesEE4openEPNS_15FunctionContextENS5_18FunctionStateScopeE
Line
Count
Source
343
89
    Status open(FunctionContext* context, FunctionContext::FunctionStateScope scope) override {
344
89
        if (scope == FunctionContext::THREAD_LOCAL) {
345
65
            if (context->is_col_constant(1)) {
346
41
                DCHECK(!context->get_function_state(scope));
347
41
                const auto pattern_col = context->get_constant_col(1)->column_ptr;
348
41
                const auto& pattern = pattern_col->get_data_at(0);
349
41
                if (pattern.size == 0) {
350
4
                    return Status::OK();
351
4
                }
352
353
37
                std::string error_str;
354
37
                std::unique_ptr<re2::RE2> scoped_re;
355
37
                StringRef options_value;
356
                if constexpr (std::is_same_v<FourParamTypes, ParamTypes>) {
357
                    DCHECK_EQ(context->get_num_args(), 4);
358
                    DCHECK(context->is_col_constant(3));
359
                    const auto options_col = context->get_constant_col(3)->column_ptr;
360
                    options_value = options_col->get_data_at(0);
361
                }
362
363
37
                bool st = StringFunctions::compile_regex(pattern, &error_str, StringRef(),
364
37
                                                         options_value, scoped_re);
365
37
                if (!st) {
366
0
                    context->set_error(error_str.c_str());
367
0
                    return Status::InvalidArgument(error_str);
368
0
                }
369
37
                std::shared_ptr<re2::RE2> re(scoped_re.release());
370
37
                context->set_function_state(scope, re);
371
37
            }
372
65
        }
373
85
        return Status::OK();
374
89
    }
_ZN5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb0EEENS_14FourParamTypesEE4openEPNS_15FunctionContextENS5_18FunctionStateScopeE
Line
Count
Source
343
90
    Status open(FunctionContext* context, FunctionContext::FunctionStateScope scope) override {
344
90
        if (scope == FunctionContext::THREAD_LOCAL) {
345
82
            if (context->is_col_constant(1)) {
346
43
                DCHECK(!context->get_function_state(scope));
347
43
                const auto pattern_col = context->get_constant_col(1)->column_ptr;
348
43
                const auto& pattern = pattern_col->get_data_at(0);
349
43
                if (pattern.size == 0) {
350
0
                    return Status::OK();
351
0
                }
352
353
43
                std::string error_str;
354
43
                std::unique_ptr<re2::RE2> scoped_re;
355
43
                StringRef options_value;
356
43
                if constexpr (std::is_same_v<FourParamTypes, ParamTypes>) {
357
43
                    DCHECK_EQ(context->get_num_args(), 4);
358
43
                    DCHECK(context->is_col_constant(3));
359
43
                    const auto options_col = context->get_constant_col(3)->column_ptr;
360
43
                    options_value = options_col->get_data_at(0);
361
43
                }
362
363
43
                bool st = StringFunctions::compile_regex(pattern, &error_str, StringRef(),
364
43
                                                         options_value, scoped_re);
365
43
                if (!st) {
366
0
                    context->set_error(error_str.c_str());
367
0
                    return Status::InvalidArgument(error_str);
368
0
                }
369
43
                std::shared_ptr<re2::RE2> re(scoped_re.release());
370
43
                context->set_function_state(scope, re);
371
43
            }
372
82
        }
373
90
        return Status::OK();
374
90
    }
_ZN5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb1EEENS_15ThreeParamTypesEE4openEPNS_15FunctionContextENS5_18FunctionStateScopeE
Line
Count
Source
343
53
    Status open(FunctionContext* context, FunctionContext::FunctionStateScope scope) override {
344
53
        if (scope == FunctionContext::THREAD_LOCAL) {
345
38
            if (context->is_col_constant(1)) {
346
14
                DCHECK(!context->get_function_state(scope));
347
14
                const auto pattern_col = context->get_constant_col(1)->column_ptr;
348
14
                const auto& pattern = pattern_col->get_data_at(0);
349
14
                if (pattern.size == 0) {
350
2
                    return Status::OK();
351
2
                }
352
353
12
                std::string error_str;
354
12
                std::unique_ptr<re2::RE2> scoped_re;
355
12
                StringRef options_value;
356
                if constexpr (std::is_same_v<FourParamTypes, ParamTypes>) {
357
                    DCHECK_EQ(context->get_num_args(), 4);
358
                    DCHECK(context->is_col_constant(3));
359
                    const auto options_col = context->get_constant_col(3)->column_ptr;
360
                    options_value = options_col->get_data_at(0);
361
                }
362
363
12
                bool st = StringFunctions::compile_regex(pattern, &error_str, StringRef(),
364
12
                                                         options_value, scoped_re);
365
12
                if (!st) {
366
0
                    context->set_error(error_str.c_str());
367
0
                    return Status::InvalidArgument(error_str);
368
0
                }
369
12
                std::shared_ptr<re2::RE2> re(scoped_re.release());
370
12
                context->set_function_state(scope, re);
371
12
            }
372
38
        }
373
51
        return Status::OK();
374
53
    }
_ZN5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb1EEENS_14FourParamTypesEE4openEPNS_15FunctionContextENS5_18FunctionStateScopeE
Line
Count
Source
343
103
    Status open(FunctionContext* context, FunctionContext::FunctionStateScope scope) override {
344
103
        if (scope == FunctionContext::THREAD_LOCAL) {
345
94
            if (context->is_col_constant(1)) {
346
43
                DCHECK(!context->get_function_state(scope));
347
43
                const auto pattern_col = context->get_constant_col(1)->column_ptr;
348
43
                const auto& pattern = pattern_col->get_data_at(0);
349
43
                if (pattern.size == 0) {
350
0
                    return Status::OK();
351
0
                }
352
353
43
                std::string error_str;
354
43
                std::unique_ptr<re2::RE2> scoped_re;
355
43
                StringRef options_value;
356
43
                if constexpr (std::is_same_v<FourParamTypes, ParamTypes>) {
357
43
                    DCHECK_EQ(context->get_num_args(), 4);
358
43
                    DCHECK(context->is_col_constant(3));
359
43
                    const auto options_col = context->get_constant_col(3)->column_ptr;
360
43
                    options_value = options_col->get_data_at(0);
361
43
                }
362
363
43
                bool st = StringFunctions::compile_regex(pattern, &error_str, StringRef(),
364
43
                                                         options_value, scoped_re);
365
43
                if (!st) {
366
0
                    context->set_error(error_str.c_str());
367
0
                    return Status::InvalidArgument(error_str);
368
0
                }
369
43
                std::shared_ptr<re2::RE2> re(scoped_re.release());
370
43
                context->set_function_state(scope, re);
371
43
            }
372
94
        }
373
103
        return Status::OK();
374
103
    }
375
376
    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
377
71
                        uint32_t result, size_t input_rows_count) const override {
378
71
        size_t argument_size = arguments.size();
379
380
71
        auto result_null_map = ColumnUInt8::create(input_rows_count, 0);
381
71
        auto result_data_column = ColumnString::create();
382
71
        auto& result_data = result_data_column->get_chars();
383
71
        auto& result_offset = result_data_column->get_offsets();
384
71
        result_offset.resize(input_rows_count);
385
386
71
        bool col_const[3];
387
71
        ColumnPtr argument_columns[3];
388
284
        for (int i = 0; i < 3; ++i) {
389
213
            col_const[i] = is_column_const(*block.get_by_position(arguments[i]).column);
390
213
        }
391
71
        argument_columns[0] = col_const[0] ? static_cast<const ColumnConst&>(
392
6
                                                     *block.get_by_position(arguments[0]).column)
393
6
                                                     .convert_to_full_column()
394
71
                                           : block.get_by_position(arguments[0]).column;
395
396
71
        default_preprocess_parameter_columns(argument_columns, col_const, {1, 2}, block, arguments);
397
398
71
        StringRef options_value;
399
71
        if (col_const[1] && col_const[2]) {
400
3
            Impl::execute_impl_const_args(context, argument_columns, options_value,
401
3
                                          input_rows_count, result_data, result_offset,
402
3
                                          result_null_map->get_data());
403
68
        } else {
404
            // the options have check in FE, so is always const, and get idx of 0
405
68
            if (argument_size == 4) {
406
15
                options_value = block.get_by_position(arguments[3]).column->get_data_at(0);
407
15
            }
408
68
            Impl::execute_impl(context, argument_columns, options_value, input_rows_count,
409
68
                               result_data, result_offset, result_null_map->get_data());
410
68
        }
411
412
71
        block.get_by_position(result).column =
413
71
                ColumnNullable::create(std::move(result_data_column), std::move(result_null_map));
414
71
        return Status::OK();
415
71
    }
_ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb0EEENS_15ThreeParamTypesEE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
377
30
                        uint32_t result, size_t input_rows_count) const override {
378
30
        size_t argument_size = arguments.size();
379
380
30
        auto result_null_map = ColumnUInt8::create(input_rows_count, 0);
381
30
        auto result_data_column = ColumnString::create();
382
30
        auto& result_data = result_data_column->get_chars();
383
30
        auto& result_offset = result_data_column->get_offsets();
384
30
        result_offset.resize(input_rows_count);
385
386
30
        bool col_const[3];
387
30
        ColumnPtr argument_columns[3];
388
120
        for (int i = 0; i < 3; ++i) {
389
90
            col_const[i] = is_column_const(*block.get_by_position(arguments[i]).column);
390
90
        }
391
30
        argument_columns[0] = col_const[0] ? static_cast<const ColumnConst&>(
392
0
                                                     *block.get_by_position(arguments[0]).column)
393
0
                                                     .convert_to_full_column()
394
30
                                           : block.get_by_position(arguments[0]).column;
395
396
30
        default_preprocess_parameter_columns(argument_columns, col_const, {1, 2}, block, arguments);
397
398
30
        StringRef options_value;
399
30
        if (col_const[1] && col_const[2]) {
400
1
            Impl::execute_impl_const_args(context, argument_columns, options_value,
401
1
                                          input_rows_count, result_data, result_offset,
402
1
                                          result_null_map->get_data());
403
29
        } else {
404
            // the options have check in FE, so is always const, and get idx of 0
405
29
            if (argument_size == 4) {
406
0
                options_value = block.get_by_position(arguments[3]).column->get_data_at(0);
407
0
            }
408
29
            Impl::execute_impl(context, argument_columns, options_value, input_rows_count,
409
29
                               result_data, result_offset, result_null_map->get_data());
410
29
        }
411
412
30
        block.get_by_position(result).column =
413
30
                ColumnNullable::create(std::move(result_data_column), std::move(result_null_map));
414
30
        return Status::OK();
415
30
    }
_ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb0EEENS_14FourParamTypesEE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
377
8
                        uint32_t result, size_t input_rows_count) const override {
378
8
        size_t argument_size = arguments.size();
379
380
8
        auto result_null_map = ColumnUInt8::create(input_rows_count, 0);
381
8
        auto result_data_column = ColumnString::create();
382
8
        auto& result_data = result_data_column->get_chars();
383
8
        auto& result_offset = result_data_column->get_offsets();
384
8
        result_offset.resize(input_rows_count);
385
386
8
        bool col_const[3];
387
8
        ColumnPtr argument_columns[3];
388
32
        for (int i = 0; i < 3; ++i) {
389
24
            col_const[i] = is_column_const(*block.get_by_position(arguments[i]).column);
390
24
        }
391
8
        argument_columns[0] = col_const[0] ? static_cast<const ColumnConst&>(
392
3
                                                     *block.get_by_position(arguments[0]).column)
393
3
                                                     .convert_to_full_column()
394
8
                                           : block.get_by_position(arguments[0]).column;
395
396
8
        default_preprocess_parameter_columns(argument_columns, col_const, {1, 2}, block, arguments);
397
398
8
        StringRef options_value;
399
8
        if (col_const[1] && col_const[2]) {
400
1
            Impl::execute_impl_const_args(context, argument_columns, options_value,
401
1
                                          input_rows_count, result_data, result_offset,
402
1
                                          result_null_map->get_data());
403
7
        } else {
404
            // the options have check in FE, so is always const, and get idx of 0
405
7
            if (argument_size == 4) {
406
7
                options_value = block.get_by_position(arguments[3]).column->get_data_at(0);
407
7
            }
408
7
            Impl::execute_impl(context, argument_columns, options_value, input_rows_count,
409
7
                               result_data, result_offset, result_null_map->get_data());
410
7
        }
411
412
8
        block.get_by_position(result).column =
413
8
                ColumnNullable::create(std::move(result_data_column), std::move(result_null_map));
414
8
        return Status::OK();
415
8
    }
_ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb1EEENS_15ThreeParamTypesEE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
377
24
                        uint32_t result, size_t input_rows_count) const override {
378
24
        size_t argument_size = arguments.size();
379
380
24
        auto result_null_map = ColumnUInt8::create(input_rows_count, 0);
381
24
        auto result_data_column = ColumnString::create();
382
24
        auto& result_data = result_data_column->get_chars();
383
24
        auto& result_offset = result_data_column->get_offsets();
384
24
        result_offset.resize(input_rows_count);
385
386
24
        bool col_const[3];
387
24
        ColumnPtr argument_columns[3];
388
96
        for (int i = 0; i < 3; ++i) {
389
72
            col_const[i] = is_column_const(*block.get_by_position(arguments[i]).column);
390
72
        }
391
24
        argument_columns[0] = col_const[0] ? static_cast<const ColumnConst&>(
392
0
                                                     *block.get_by_position(arguments[0]).column)
393
0
                                                     .convert_to_full_column()
394
24
                                           : block.get_by_position(arguments[0]).column;
395
396
24
        default_preprocess_parameter_columns(argument_columns, col_const, {1, 2}, block, arguments);
397
398
24
        StringRef options_value;
399
24
        if (col_const[1] && col_const[2]) {
400
0
            Impl::execute_impl_const_args(context, argument_columns, options_value,
401
0
                                          input_rows_count, result_data, result_offset,
402
0
                                          result_null_map->get_data());
403
24
        } else {
404
            // the options have check in FE, so is always const, and get idx of 0
405
24
            if (argument_size == 4) {
406
0
                options_value = block.get_by_position(arguments[3]).column->get_data_at(0);
407
0
            }
408
24
            Impl::execute_impl(context, argument_columns, options_value, input_rows_count,
409
24
                               result_data, result_offset, result_null_map->get_data());
410
24
        }
411
412
24
        block.get_by_position(result).column =
413
24
                ColumnNullable::create(std::move(result_data_column), std::move(result_null_map));
414
24
        return Status::OK();
415
24
    }
_ZNK5doris21FunctionRegexpReplaceINS_17RegexpReplaceImplILb1EEENS_14FourParamTypesEE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
377
9
                        uint32_t result, size_t input_rows_count) const override {
378
9
        size_t argument_size = arguments.size();
379
380
9
        auto result_null_map = ColumnUInt8::create(input_rows_count, 0);
381
9
        auto result_data_column = ColumnString::create();
382
9
        auto& result_data = result_data_column->get_chars();
383
9
        auto& result_offset = result_data_column->get_offsets();
384
9
        result_offset.resize(input_rows_count);
385
386
9
        bool col_const[3];
387
9
        ColumnPtr argument_columns[3];
388
36
        for (int i = 0; i < 3; ++i) {
389
27
            col_const[i] = is_column_const(*block.get_by_position(arguments[i]).column);
390
27
        }
391
9
        argument_columns[0] = col_const[0] ? static_cast<const ColumnConst&>(
392
3
                                                     *block.get_by_position(arguments[0]).column)
393
3
                                                     .convert_to_full_column()
394
9
                                           : block.get_by_position(arguments[0]).column;
395
396
9
        default_preprocess_parameter_columns(argument_columns, col_const, {1, 2}, block, arguments);
397
398
9
        StringRef options_value;
399
9
        if (col_const[1] && col_const[2]) {
400
1
            Impl::execute_impl_const_args(context, argument_columns, options_value,
401
1
                                          input_rows_count, result_data, result_offset,
402
1
                                          result_null_map->get_data());
403
8
        } else {
404
            // the options have check in FE, so is always const, and get idx of 0
405
8
            if (argument_size == 4) {
406
8
                options_value = block.get_by_position(arguments[3]).column->get_data_at(0);
407
8
            }
408
8
            Impl::execute_impl(context, argument_columns, options_value, input_rows_count,
409
8
                               result_data, result_offset, result_null_map->get_data());
410
8
        }
411
412
9
        block.get_by_position(result).column =
413
9
                ColumnNullable::create(std::move(result_data_column), std::move(result_null_map));
414
9
        return Status::OK();
415
9
    }
416
};
417
418
template <bool ReplaceOne>
419
struct RegexpReplaceImpl {
420
    static constexpr auto name = ReplaceOne ? "regexp_replace_one" : "regexp_replace";
421
422
    static void execute_impl(FunctionContext* context, ColumnPtr argument_columns[],
423
                             const StringRef& options_value, size_t input_rows_count,
424
                             ColumnString::Chars& result_data, ColumnString::Offsets& result_offset,
425
68
                             NullMap& null_map) {
426
68
        const auto* str_col = check_and_get_column<ColumnString>(argument_columns[0].get());
427
68
        const auto* pattern_col = check_and_get_column<ColumnString>(argument_columns[1].get());
428
68
        const auto* replace_col = check_and_get_column<ColumnString>(argument_columns[2].get());
429
430
248
        for (size_t i = 0; i < input_rows_count; ++i) {
431
180
            _execute_inner_loop<false>(context, str_col, pattern_col, replace_col, options_value,
432
180
                                       result_data, result_offset, null_map, i);
433
180
        }
434
68
    }
_ZN5doris17RegexpReplaceImplILb0EE12execute_implEPNS_15FunctionContextEPNS_3COWINS_7IColumnEE13immutable_ptrIS5_EERKNS_9StringRefEmRNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEERNSD_IjLm4096ESG_Lm16ELm15EEESI_
Line
Count
Source
425
36
                             NullMap& null_map) {
426
36
        const auto* str_col = check_and_get_column<ColumnString>(argument_columns[0].get());
427
36
        const auto* pattern_col = check_and_get_column<ColumnString>(argument_columns[1].get());
428
36
        const auto* replace_col = check_and_get_column<ColumnString>(argument_columns[2].get());
429
430
126
        for (size_t i = 0; i < input_rows_count; ++i) {
431
90
            _execute_inner_loop<false>(context, str_col, pattern_col, replace_col, options_value,
432
90
                                       result_data, result_offset, null_map, i);
433
90
        }
434
36
    }
_ZN5doris17RegexpReplaceImplILb1EE12execute_implEPNS_15FunctionContextEPNS_3COWINS_7IColumnEE13immutable_ptrIS5_EERKNS_9StringRefEmRNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEERNSD_IjLm4096ESG_Lm16ELm15EEESI_
Line
Count
Source
425
32
                             NullMap& null_map) {
426
32
        const auto* str_col = check_and_get_column<ColumnString>(argument_columns[0].get());
427
32
        const auto* pattern_col = check_and_get_column<ColumnString>(argument_columns[1].get());
428
32
        const auto* replace_col = check_and_get_column<ColumnString>(argument_columns[2].get());
429
430
122
        for (size_t i = 0; i < input_rows_count; ++i) {
431
90
            _execute_inner_loop<false>(context, str_col, pattern_col, replace_col, options_value,
432
90
                                       result_data, result_offset, null_map, i);
433
90
        }
434
32
    }
435
436
    static void execute_impl_const_args(FunctionContext* context, ColumnPtr argument_columns[],
437
                                        const StringRef& options_value, size_t input_rows_count,
438
                                        ColumnString::Chars& result_data,
439
3
                                        ColumnString::Offsets& result_offset, NullMap& null_map) {
440
3
        const auto* str_col = check_and_get_column<ColumnString>(argument_columns[0].get());
441
3
        const auto* pattern_col = check_and_get_column<ColumnString>(argument_columns[1].get());
442
3
        const auto* replace_col = check_and_get_column<ColumnString>(argument_columns[2].get());
443
444
18
        for (size_t i = 0; i < input_rows_count; ++i) {
445
15
            _execute_inner_loop<true>(context, str_col, pattern_col, replace_col, options_value,
446
15
                                      result_data, result_offset, null_map, i);
447
15
        }
448
3
    }
_ZN5doris17RegexpReplaceImplILb0EE23execute_impl_const_argsEPNS_15FunctionContextEPNS_3COWINS_7IColumnEE13immutable_ptrIS5_EERKNS_9StringRefEmRNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEERNSD_IjLm4096ESG_Lm16ELm15EEESI_
Line
Count
Source
439
2
                                        ColumnString::Offsets& result_offset, NullMap& null_map) {
440
2
        const auto* str_col = check_and_get_column<ColumnString>(argument_columns[0].get());
441
2
        const auto* pattern_col = check_and_get_column<ColumnString>(argument_columns[1].get());
442
2
        const auto* replace_col = check_and_get_column<ColumnString>(argument_columns[2].get());
443
444
12
        for (size_t i = 0; i < input_rows_count; ++i) {
445
10
            _execute_inner_loop<true>(context, str_col, pattern_col, replace_col, options_value,
446
10
                                      result_data, result_offset, null_map, i);
447
10
        }
448
2
    }
_ZN5doris17RegexpReplaceImplILb1EE23execute_impl_const_argsEPNS_15FunctionContextEPNS_3COWINS_7IColumnEE13immutable_ptrIS5_EERKNS_9StringRefEmRNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEERNSD_IjLm4096ESG_Lm16ELm15EEESI_
Line
Count
Source
439
1
                                        ColumnString::Offsets& result_offset, NullMap& null_map) {
440
1
        const auto* str_col = check_and_get_column<ColumnString>(argument_columns[0].get());
441
1
        const auto* pattern_col = check_and_get_column<ColumnString>(argument_columns[1].get());
442
1
        const auto* replace_col = check_and_get_column<ColumnString>(argument_columns[2].get());
443
444
6
        for (size_t i = 0; i < input_rows_count; ++i) {
445
5
            _execute_inner_loop<true>(context, str_col, pattern_col, replace_col, options_value,
446
5
                                      result_data, result_offset, null_map, i);
447
5
        }
448
1
    }
449
450
    template <bool Const>
451
    static void _execute_inner_loop(FunctionContext* context, const ColumnString* str_col,
452
                                    const ColumnString* pattern_col,
453
                                    const ColumnString* replace_col, const StringRef& options_value,
454
                                    ColumnString::Chars& result_data,
455
                                    ColumnString::Offsets& result_offset, NullMap& null_map,
456
195
                                    const size_t index_now) {
457
195
        re2::RE2* re = reinterpret_cast<re2::RE2*>(
458
195
                context->get_function_state(FunctionContext::THREAD_LOCAL));
459
195
        std::unique_ptr<re2::RE2> scoped_re; // destroys re if state->re is nullptr
460
195
        if (re == nullptr) {
461
139
            std::string error_str;
462
139
            const auto& pattern = pattern_col->get_data_at(index_check_const(index_now, Const));
463
139
            bool st = StringFunctions::compile_regex(pattern, &error_str, StringRef(),
464
139
                                                     options_value, scoped_re);
465
139
            if (!st) {
466
0
                context->add_warning(error_str.c_str());
467
0
                StringOP::push_null_string(index_now, result_data, result_offset, null_map);
468
0
                return;
469
0
            }
470
139
            re = scoped_re.get();
471
139
        }
472
473
195
        re2::StringPiece replace_str = re2::StringPiece(
474
195
                replace_col->get_data_at(index_check_const(index_now, Const)).to_string_view());
475
476
195
        std::string result_str(str_col->get_data_at(index_now).to_string());
477
195
        if constexpr (ReplaceOne) {
478
95
            re2::RE2::Replace(&result_str, *re, replace_str);
479
100
        } else {
480
100
            re2::RE2::GlobalReplace(&result_str, *re, replace_str);
481
100
        }
482
195
        StringOP::push_value_string(result_str, index_now, result_data, result_offset);
483
195
    }
_ZN5doris17RegexpReplaceImplILb0EE19_execute_inner_loopILb1EEEvPNS_15FunctionContextEPKNS_9ColumnStrIjEES8_S8_RKNS_9StringRefERNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEERNSC_IjLm4096ESF_Lm16ELm15EEESH_m
Line
Count
Source
456
10
                                    const size_t index_now) {
457
10
        re2::RE2* re = reinterpret_cast<re2::RE2*>(
458
10
                context->get_function_state(FunctionContext::THREAD_LOCAL));
459
10
        std::unique_ptr<re2::RE2> scoped_re; // destroys re if state->re is nullptr
460
10
        if (re == nullptr) {
461
0
            std::string error_str;
462
0
            const auto& pattern = pattern_col->get_data_at(index_check_const(index_now, Const));
463
0
            bool st = StringFunctions::compile_regex(pattern, &error_str, StringRef(),
464
0
                                                     options_value, scoped_re);
465
0
            if (!st) {
466
0
                context->add_warning(error_str.c_str());
467
0
                StringOP::push_null_string(index_now, result_data, result_offset, null_map);
468
0
                return;
469
0
            }
470
0
            re = scoped_re.get();
471
0
        }
472
473
10
        re2::StringPiece replace_str = re2::StringPiece(
474
10
                replace_col->get_data_at(index_check_const(index_now, Const)).to_string_view());
475
476
10
        std::string result_str(str_col->get_data_at(index_now).to_string());
477
        if constexpr (ReplaceOne) {
478
            re2::RE2::Replace(&result_str, *re, replace_str);
479
10
        } else {
480
10
            re2::RE2::GlobalReplace(&result_str, *re, replace_str);
481
10
        }
482
10
        StringOP::push_value_string(result_str, index_now, result_data, result_offset);
483
10
    }
_ZN5doris17RegexpReplaceImplILb0EE19_execute_inner_loopILb0EEEvPNS_15FunctionContextEPKNS_9ColumnStrIjEES8_S8_RKNS_9StringRefERNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEERNSC_IjLm4096ESF_Lm16ELm15EEESH_m
Line
Count
Source
456
90
                                    const size_t index_now) {
457
90
        re2::RE2* re = reinterpret_cast<re2::RE2*>(
458
90
                context->get_function_state(FunctionContext::THREAD_LOCAL));
459
90
        std::unique_ptr<re2::RE2> scoped_re; // destroys re if state->re is nullptr
460
90
        if (re == nullptr) {
461
67
            std::string error_str;
462
67
            const auto& pattern = pattern_col->get_data_at(index_check_const(index_now, Const));
463
67
            bool st = StringFunctions::compile_regex(pattern, &error_str, StringRef(),
464
67
                                                     options_value, scoped_re);
465
67
            if (!st) {
466
0
                context->add_warning(error_str.c_str());
467
0
                StringOP::push_null_string(index_now, result_data, result_offset, null_map);
468
0
                return;
469
0
            }
470
67
            re = scoped_re.get();
471
67
        }
472
473
90
        re2::StringPiece replace_str = re2::StringPiece(
474
90
                replace_col->get_data_at(index_check_const(index_now, Const)).to_string_view());
475
476
90
        std::string result_str(str_col->get_data_at(index_now).to_string());
477
        if constexpr (ReplaceOne) {
478
            re2::RE2::Replace(&result_str, *re, replace_str);
479
90
        } else {
480
90
            re2::RE2::GlobalReplace(&result_str, *re, replace_str);
481
90
        }
482
90
        StringOP::push_value_string(result_str, index_now, result_data, result_offset);
483
90
    }
_ZN5doris17RegexpReplaceImplILb1EE19_execute_inner_loopILb1EEEvPNS_15FunctionContextEPKNS_9ColumnStrIjEES8_S8_RKNS_9StringRefERNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEERNSC_IjLm4096ESF_Lm16ELm15EEESH_m
Line
Count
Source
456
5
                                    const size_t index_now) {
457
5
        re2::RE2* re = reinterpret_cast<re2::RE2*>(
458
5
                context->get_function_state(FunctionContext::THREAD_LOCAL));
459
5
        std::unique_ptr<re2::RE2> scoped_re; // destroys re if state->re is nullptr
460
5
        if (re == nullptr) {
461
0
            std::string error_str;
462
0
            const auto& pattern = pattern_col->get_data_at(index_check_const(index_now, Const));
463
0
            bool st = StringFunctions::compile_regex(pattern, &error_str, StringRef(),
464
0
                                                     options_value, scoped_re);
465
0
            if (!st) {
466
0
                context->add_warning(error_str.c_str());
467
0
                StringOP::push_null_string(index_now, result_data, result_offset, null_map);
468
0
                return;
469
0
            }
470
0
            re = scoped_re.get();
471
0
        }
472
473
5
        re2::StringPiece replace_str = re2::StringPiece(
474
5
                replace_col->get_data_at(index_check_const(index_now, Const)).to_string_view());
475
476
5
        std::string result_str(str_col->get_data_at(index_now).to_string());
477
5
        if constexpr (ReplaceOne) {
478
5
            re2::RE2::Replace(&result_str, *re, replace_str);
479
        } else {
480
            re2::RE2::GlobalReplace(&result_str, *re, replace_str);
481
        }
482
5
        StringOP::push_value_string(result_str, index_now, result_data, result_offset);
483
5
    }
_ZN5doris17RegexpReplaceImplILb1EE19_execute_inner_loopILb0EEEvPNS_15FunctionContextEPKNS_9ColumnStrIjEES8_S8_RKNS_9StringRefERNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEERNSC_IjLm4096ESF_Lm16ELm15EEESH_m
Line
Count
Source
456
90
                                    const size_t index_now) {
457
90
        re2::RE2* re = reinterpret_cast<re2::RE2*>(
458
90
                context->get_function_state(FunctionContext::THREAD_LOCAL));
459
90
        std::unique_ptr<re2::RE2> scoped_re; // destroys re if state->re is nullptr
460
90
        if (re == nullptr) {
461
72
            std::string error_str;
462
72
            const auto& pattern = pattern_col->get_data_at(index_check_const(index_now, Const));
463
72
            bool st = StringFunctions::compile_regex(pattern, &error_str, StringRef(),
464
72
                                                     options_value, scoped_re);
465
72
            if (!st) {
466
0
                context->add_warning(error_str.c_str());
467
0
                StringOP::push_null_string(index_now, result_data, result_offset, null_map);
468
0
                return;
469
0
            }
470
72
            re = scoped_re.get();
471
72
        }
472
473
90
        re2::StringPiece replace_str = re2::StringPiece(
474
90
                replace_col->get_data_at(index_check_const(index_now, Const)).to_string_view());
475
476
90
        std::string result_str(str_col->get_data_at(index_now).to_string());
477
90
        if constexpr (ReplaceOne) {
478
90
            re2::RE2::Replace(&result_str, *re, replace_str);
479
        } else {
480
            re2::RE2::GlobalReplace(&result_str, *re, replace_str);
481
        }
482
90
        StringOP::push_value_string(result_str, index_now, result_data, result_offset);
483
90
    }
484
};
485
486
template <bool ReturnNull>
487
struct RegexpExtractImpl {
488
    static constexpr auto name = ReturnNull ? "regexp_extract_or_null" : "regexp_extract";
489
    static constexpr size_t num_args = 3;
490
    static constexpr size_t PATTERN_ARG_IDX = 1;
491
492
55
    static DataTypePtr return_type() { return make_nullable(std::make_shared<DataTypeString>()); }
_ZN5doris17RegexpExtractImplILb1EE11return_typeEv
Line
Count
Source
492
21
    static DataTypePtr return_type() { return make_nullable(std::make_shared<DataTypeString>()); }
_ZN5doris17RegexpExtractImplILb0EE11return_typeEv
Line
Count
Source
492
34
    static DataTypePtr return_type() { return make_nullable(std::make_shared<DataTypeString>()); }
493
494
    static Status execute(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
495
60
                          uint32_t result, size_t input_rows_count) {
496
60
        bool col_const[3];
497
60
        ColumnPtr argument_columns[3];
498
240
        for (int i = 0; i < 3; ++i) {
499
180
            col_const[i] = is_column_const(*block.get_by_position(arguments[i]).column);
500
180
        }
501
60
        argument_columns[0] = col_const[0] ? static_cast<const ColumnConst&>(
502
3
                                                     *block.get_by_position(arguments[0]).column)
503
3
                                                     .convert_to_full_column()
504
60
                                           : block.get_by_position(arguments[0]).column;
505
506
60
        auto result_null_map = ColumnUInt8::create(input_rows_count, 0);
507
60
        auto result_data_column = ColumnString::create();
508
60
        auto& result_data = result_data_column->get_chars();
509
60
        auto& result_offset = result_data_column->get_offsets();
510
60
        result_offset.resize(input_rows_count);
511
60
        auto& null_map = result_null_map->get_data();
512
513
60
        default_preprocess_parameter_columns(argument_columns, col_const, {1, 2}, block, arguments);
514
515
60
        if (col_const[1] && col_const[2]) {
516
1
            _execute_loop<true>(context, argument_columns, input_rows_count, result_data,
517
1
                                result_offset, null_map);
518
59
        } else {
519
59
            _execute_loop<false>(context, argument_columns, input_rows_count, result_data,
520
59
                                 result_offset, null_map);
521
59
        }
522
523
60
        block.get_by_position(result).column =
524
60
                ColumnNullable::create(std::move(result_data_column), std::move(result_null_map));
525
60
        return Status::OK();
526
60
    }
_ZN5doris17RegexpExtractImplILb1EE7executeEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
495
18
                          uint32_t result, size_t input_rows_count) {
496
18
        bool col_const[3];
497
18
        ColumnPtr argument_columns[3];
498
72
        for (int i = 0; i < 3; ++i) {
499
54
            col_const[i] = is_column_const(*block.get_by_position(arguments[i]).column);
500
54
        }
501
18
        argument_columns[0] = col_const[0] ? static_cast<const ColumnConst&>(
502
0
                                                     *block.get_by_position(arguments[0]).column)
503
0
                                                     .convert_to_full_column()
504
18
                                           : block.get_by_position(arguments[0]).column;
505
506
18
        auto result_null_map = ColumnUInt8::create(input_rows_count, 0);
507
18
        auto result_data_column = ColumnString::create();
508
18
        auto& result_data = result_data_column->get_chars();
509
18
        auto& result_offset = result_data_column->get_offsets();
510
18
        result_offset.resize(input_rows_count);
511
18
        auto& null_map = result_null_map->get_data();
512
513
18
        default_preprocess_parameter_columns(argument_columns, col_const, {1, 2}, block, arguments);
514
515
18
        if (col_const[1] && col_const[2]) {
516
0
            _execute_loop<true>(context, argument_columns, input_rows_count, result_data,
517
0
                                result_offset, null_map);
518
18
        } else {
519
18
            _execute_loop<false>(context, argument_columns, input_rows_count, result_data,
520
18
                                 result_offset, null_map);
521
18
        }
522
523
18
        block.get_by_position(result).column =
524
18
                ColumnNullable::create(std::move(result_data_column), std::move(result_null_map));
525
18
        return Status::OK();
526
18
    }
_ZN5doris17RegexpExtractImplILb0EE7executeEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
495
42
                          uint32_t result, size_t input_rows_count) {
496
42
        bool col_const[3];
497
42
        ColumnPtr argument_columns[3];
498
168
        for (int i = 0; i < 3; ++i) {
499
126
            col_const[i] = is_column_const(*block.get_by_position(arguments[i]).column);
500
126
        }
501
42
        argument_columns[0] = col_const[0] ? static_cast<const ColumnConst&>(
502
3
                                                     *block.get_by_position(arguments[0]).column)
503
3
                                                     .convert_to_full_column()
504
42
                                           : block.get_by_position(arguments[0]).column;
505
506
42
        auto result_null_map = ColumnUInt8::create(input_rows_count, 0);
507
42
        auto result_data_column = ColumnString::create();
508
42
        auto& result_data = result_data_column->get_chars();
509
42
        auto& result_offset = result_data_column->get_offsets();
510
42
        result_offset.resize(input_rows_count);
511
42
        auto& null_map = result_null_map->get_data();
512
513
42
        default_preprocess_parameter_columns(argument_columns, col_const, {1, 2}, block, arguments);
514
515
42
        if (col_const[1] && col_const[2]) {
516
1
            _execute_loop<true>(context, argument_columns, input_rows_count, result_data,
517
1
                                result_offset, null_map);
518
41
        } else {
519
41
            _execute_loop<false>(context, argument_columns, input_rows_count, result_data,
520
41
                                 result_offset, null_map);
521
41
        }
522
523
42
        block.get_by_position(result).column =
524
42
                ColumnNullable::create(std::move(result_data_column), std::move(result_null_map));
525
42
        return Status::OK();
526
42
    }
527
528
private:
529
    template <bool Const>
530
    static void _execute_loop(FunctionContext* context, ColumnPtr argument_columns[],
531
                              size_t input_rows_count, ColumnString::Chars& result_data,
532
60
                              ColumnString::Offsets& result_offset, NullMap& null_map) {
533
60
        const auto* str_col = check_and_get_column<ColumnString>(argument_columns[0].get());
534
60
        const auto* pattern_col = check_and_get_column<ColumnString>(argument_columns[1].get());
535
60
        const auto* index_col = check_and_get_column<ColumnInt64>(argument_columns[2].get());
536
537
60
        if constexpr (Const) {
538
1
            const auto& index_data = index_col->get_int(0);
539
1
            if (index_data < 0) {
540
0
                for (size_t i = 0; i < input_rows_count; ++i) {
541
0
                    ReturnNull ? StringOP::push_null_string(i, result_data, result_offset, null_map)
542
0
                               : StringOP::push_empty_string(i, result_data, result_offset);
543
0
                }
544
0
                return;
545
0
            }
546
8
            for (size_t i = 0; i < input_rows_count; ++i) {
547
7
                _execute_inner_loop<true>(context, str_col, pattern_col, index_data, result_data,
548
7
                                          result_offset, null_map, i);
549
7
            }
550
59
        } else {
551
188
            for (size_t i = 0; i < input_rows_count; ++i) {
552
129
                const auto& index_data = index_col->get_int(i);
553
129
                if (index_data < 0) {
554
0
                    ReturnNull ? StringOP::push_null_string(i, result_data, result_offset, null_map)
555
0
                               : StringOP::push_empty_string(i, result_data, result_offset);
556
0
                    continue;
557
0
                }
558
129
                _execute_inner_loop<false>(context, str_col, pattern_col, index_data, result_data,
559
129
                                           result_offset, null_map, i);
560
129
            }
561
59
        }
562
60
    }
Unexecuted instantiation: _ZN5doris17RegexpExtractImplILb1EE13_execute_loopILb1EEEvPNS_15FunctionContextEPNS_3COWINS_7IColumnEE13immutable_ptrIS6_EEmRNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEERNSB_IjLm4096ESE_Lm16ELm15EEESG_
_ZN5doris17RegexpExtractImplILb1EE13_execute_loopILb0EEEvPNS_15FunctionContextEPNS_3COWINS_7IColumnEE13immutable_ptrIS6_EEmRNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEERNSB_IjLm4096ESE_Lm16ELm15EEESG_
Line
Count
Source
532
18
                              ColumnString::Offsets& result_offset, NullMap& null_map) {
533
18
        const auto* str_col = check_and_get_column<ColumnString>(argument_columns[0].get());
534
18
        const auto* pattern_col = check_and_get_column<ColumnString>(argument_columns[1].get());
535
18
        const auto* index_col = check_and_get_column<ColumnInt64>(argument_columns[2].get());
536
537
        if constexpr (Const) {
538
            const auto& index_data = index_col->get_int(0);
539
            if (index_data < 0) {
540
                for (size_t i = 0; i < input_rows_count; ++i) {
541
                    ReturnNull ? StringOP::push_null_string(i, result_data, result_offset, null_map)
542
                               : StringOP::push_empty_string(i, result_data, result_offset);
543
                }
544
                return;
545
            }
546
            for (size_t i = 0; i < input_rows_count; ++i) {
547
                _execute_inner_loop<true>(context, str_col, pattern_col, index_data, result_data,
548
                                          result_offset, null_map, i);
549
            }
550
18
        } else {
551
36
            for (size_t i = 0; i < input_rows_count; ++i) {
552
18
                const auto& index_data = index_col->get_int(i);
553
18
                if (index_data < 0) {
554
0
                    ReturnNull ? StringOP::push_null_string(i, result_data, result_offset, null_map)
555
0
                               : StringOP::push_empty_string(i, result_data, result_offset);
556
0
                    continue;
557
0
                }
558
18
                _execute_inner_loop<false>(context, str_col, pattern_col, index_data, result_data,
559
18
                                           result_offset, null_map, i);
560
18
            }
561
18
        }
562
18
    }
_ZN5doris17RegexpExtractImplILb0EE13_execute_loopILb1EEEvPNS_15FunctionContextEPNS_3COWINS_7IColumnEE13immutable_ptrIS6_EEmRNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEERNSB_IjLm4096ESE_Lm16ELm15EEESG_
Line
Count
Source
532
1
                              ColumnString::Offsets& result_offset, NullMap& null_map) {
533
1
        const auto* str_col = check_and_get_column<ColumnString>(argument_columns[0].get());
534
1
        const auto* pattern_col = check_and_get_column<ColumnString>(argument_columns[1].get());
535
1
        const auto* index_col = check_and_get_column<ColumnInt64>(argument_columns[2].get());
536
537
1
        if constexpr (Const) {
538
1
            const auto& index_data = index_col->get_int(0);
539
1
            if (index_data < 0) {
540
0
                for (size_t i = 0; i < input_rows_count; ++i) {
541
0
                    ReturnNull ? StringOP::push_null_string(i, result_data, result_offset, null_map)
542
0
                               : StringOP::push_empty_string(i, result_data, result_offset);
543
0
                }
544
0
                return;
545
0
            }
546
8
            for (size_t i = 0; i < input_rows_count; ++i) {
547
7
                _execute_inner_loop<true>(context, str_col, pattern_col, index_data, result_data,
548
7
                                          result_offset, null_map, i);
549
7
            }
550
        } else {
551
            for (size_t i = 0; i < input_rows_count; ++i) {
552
                const auto& index_data = index_col->get_int(i);
553
                if (index_data < 0) {
554
                    ReturnNull ? StringOP::push_null_string(i, result_data, result_offset, null_map)
555
                               : StringOP::push_empty_string(i, result_data, result_offset);
556
                    continue;
557
                }
558
                _execute_inner_loop<false>(context, str_col, pattern_col, index_data, result_data,
559
                                           result_offset, null_map, i);
560
            }
561
        }
562
1
    }
_ZN5doris17RegexpExtractImplILb0EE13_execute_loopILb0EEEvPNS_15FunctionContextEPNS_3COWINS_7IColumnEE13immutable_ptrIS6_EEmRNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEERNSB_IjLm4096ESE_Lm16ELm15EEESG_
Line
Count
Source
532
41
                              ColumnString::Offsets& result_offset, NullMap& null_map) {
533
41
        const auto* str_col = check_and_get_column<ColumnString>(argument_columns[0].get());
534
41
        const auto* pattern_col = check_and_get_column<ColumnString>(argument_columns[1].get());
535
41
        const auto* index_col = check_and_get_column<ColumnInt64>(argument_columns[2].get());
536
537
        if constexpr (Const) {
538
            const auto& index_data = index_col->get_int(0);
539
            if (index_data < 0) {
540
                for (size_t i = 0; i < input_rows_count; ++i) {
541
                    ReturnNull ? StringOP::push_null_string(i, result_data, result_offset, null_map)
542
                               : StringOP::push_empty_string(i, result_data, result_offset);
543
                }
544
                return;
545
            }
546
            for (size_t i = 0; i < input_rows_count; ++i) {
547
                _execute_inner_loop<true>(context, str_col, pattern_col, index_data, result_data,
548
                                          result_offset, null_map, i);
549
            }
550
41
        } else {
551
152
            for (size_t i = 0; i < input_rows_count; ++i) {
552
111
                const auto& index_data = index_col->get_int(i);
553
111
                if (index_data < 0) {
554
0
                    ReturnNull ? StringOP::push_null_string(i, result_data, result_offset, null_map)
555
0
                               : StringOP::push_empty_string(i, result_data, result_offset);
556
0
                    continue;
557
0
                }
558
111
                _execute_inner_loop<false>(context, str_col, pattern_col, index_data, result_data,
559
111
                                           result_offset, null_map, i);
560
111
            }
561
41
        }
562
41
    }
563
564
    template <bool Const>
565
    static void _execute_inner_loop(FunctionContext* context, const ColumnString* str_col,
566
                                    const ColumnString* pattern_col, const Int64 index_data,
567
                                    ColumnString::Chars& result_data,
568
                                    ColumnString::Offsets& result_offset, NullMap& null_map,
569
136
                                    const size_t index_now) {
570
136
        auto* engine = reinterpret_cast<RegexpExtractEngine*>(
571
136
                context->get_function_state(FunctionContext::THREAD_LOCAL));
572
136
        std::unique_ptr<RegexpExtractEngine> scoped_engine;
573
574
136
        if (engine == nullptr) {
575
78
            std::string error_str;
576
78
            const auto& pattern = pattern_col->get_data_at(index_check_const(index_now, Const));
577
78
            scoped_engine = std::make_unique<RegexpExtractEngine>();
578
78
            bool st = RegexpExtractEngine::compile(pattern, &error_str, *scoped_engine,
579
78
                                                   context->state()->enable_extended_regex());
580
78
            if (!st) {
581
0
                context->add_warning(error_str.c_str());
582
0
                StringOP::push_null_string(index_now, result_data, result_offset, null_map);
583
0
                return;
584
0
            }
585
78
            engine = scoped_engine.get();
586
78
        }
587
588
136
        const auto& str = str_col->get_data_at(index_now);
589
590
136
        int max_matches = 1 + engine->number_of_capturing_groups();
591
136
        if (index_data >= max_matches) {
592
84
            ReturnNull ? StringOP::push_null_string(index_now, result_data, result_offset, null_map)
593
84
                       : StringOP::push_empty_string(index_now, result_data, result_offset);
594
84
            return;
595
84
        }
596
597
52
        std::string match_result;
598
52
        bool success = engine->match_and_extract(str.data, str.size, static_cast<int>(index_data),
599
52
                                                 match_result);
600
601
52
        if (!success) {
602
13
            ReturnNull ? StringOP::push_null_string(index_now, result_data, result_offset, null_map)
603
13
                       : StringOP::push_empty_string(index_now, result_data, result_offset);
604
13
            return;
605
13
        }
606
607
39
        StringOP::push_value_string(std::string_view(match_result.data(), match_result.size()),
608
39
                                    index_now, result_data, result_offset);
609
39
    }
Unexecuted instantiation: _ZN5doris17RegexpExtractImplILb1EE19_execute_inner_loopILb1EEEvPNS_15FunctionContextEPKNS_9ColumnStrIjEES8_lRNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEERNS9_IjLm4096ESC_Lm16ELm15EEESE_m
_ZN5doris17RegexpExtractImplILb1EE19_execute_inner_loopILb0EEEvPNS_15FunctionContextEPKNS_9ColumnStrIjEES8_lRNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEERNS9_IjLm4096ESC_Lm16ELm15EEESE_m
Line
Count
Source
569
18
                                    const size_t index_now) {
570
18
        auto* engine = reinterpret_cast<RegexpExtractEngine*>(
571
18
                context->get_function_state(FunctionContext::THREAD_LOCAL));
572
18
        std::unique_ptr<RegexpExtractEngine> scoped_engine;
573
574
18
        if (engine == nullptr) {
575
0
            std::string error_str;
576
0
            const auto& pattern = pattern_col->get_data_at(index_check_const(index_now, Const));
577
0
            scoped_engine = std::make_unique<RegexpExtractEngine>();
578
0
            bool st = RegexpExtractEngine::compile(pattern, &error_str, *scoped_engine,
579
0
                                                   context->state()->enable_extended_regex());
580
0
            if (!st) {
581
0
                context->add_warning(error_str.c_str());
582
0
                StringOP::push_null_string(index_now, result_data, result_offset, null_map);
583
0
                return;
584
0
            }
585
0
            engine = scoped_engine.get();
586
0
        }
587
588
18
        const auto& str = str_col->get_data_at(index_now);
589
590
18
        int max_matches = 1 + engine->number_of_capturing_groups();
591
18
        if (index_data >= max_matches) {
592
1
            ReturnNull ? StringOP::push_null_string(index_now, result_data, result_offset, null_map)
593
1
                       : StringOP::push_empty_string(index_now, result_data, result_offset);
594
1
            return;
595
1
        }
596
597
17
        std::string match_result;
598
17
        bool success = engine->match_and_extract(str.data, str.size, static_cast<int>(index_data),
599
17
                                                 match_result);
600
601
17
        if (!success) {
602
1
            ReturnNull ? StringOP::push_null_string(index_now, result_data, result_offset, null_map)
603
1
                       : StringOP::push_empty_string(index_now, result_data, result_offset);
604
1
            return;
605
1
        }
606
607
16
        StringOP::push_value_string(std::string_view(match_result.data(), match_result.size()),
608
16
                                    index_now, result_data, result_offset);
609
16
    }
_ZN5doris17RegexpExtractImplILb0EE19_execute_inner_loopILb1EEEvPNS_15FunctionContextEPKNS_9ColumnStrIjEES8_lRNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEERNS9_IjLm4096ESC_Lm16ELm15EEESE_m
Line
Count
Source
569
7
                                    const size_t index_now) {
570
7
        auto* engine = reinterpret_cast<RegexpExtractEngine*>(
571
7
                context->get_function_state(FunctionContext::THREAD_LOCAL));
572
7
        std::unique_ptr<RegexpExtractEngine> scoped_engine;
573
574
7
        if (engine == nullptr) {
575
0
            std::string error_str;
576
0
            const auto& pattern = pattern_col->get_data_at(index_check_const(index_now, Const));
577
0
            scoped_engine = std::make_unique<RegexpExtractEngine>();
578
0
            bool st = RegexpExtractEngine::compile(pattern, &error_str, *scoped_engine,
579
0
                                                   context->state()->enable_extended_regex());
580
0
            if (!st) {
581
0
                context->add_warning(error_str.c_str());
582
0
                StringOP::push_null_string(index_now, result_data, result_offset, null_map);
583
0
                return;
584
0
            }
585
0
            engine = scoped_engine.get();
586
0
        }
587
588
7
        const auto& str = str_col->get_data_at(index_now);
589
590
7
        int max_matches = 1 + engine->number_of_capturing_groups();
591
7
        if (index_data >= max_matches) {
592
0
            ReturnNull ? StringOP::push_null_string(index_now, result_data, result_offset, null_map)
593
0
                       : StringOP::push_empty_string(index_now, result_data, result_offset);
594
0
            return;
595
0
        }
596
597
7
        std::string match_result;
598
7
        bool success = engine->match_and_extract(str.data, str.size, static_cast<int>(index_data),
599
7
                                                 match_result);
600
601
7
        if (!success) {
602
7
            ReturnNull ? StringOP::push_null_string(index_now, result_data, result_offset, null_map)
603
7
                       : StringOP::push_empty_string(index_now, result_data, result_offset);
604
7
            return;
605
7
        }
606
607
0
        StringOP::push_value_string(std::string_view(match_result.data(), match_result.size()),
608
0
                                    index_now, result_data, result_offset);
609
0
    }
_ZN5doris17RegexpExtractImplILb0EE19_execute_inner_loopILb0EEEvPNS_15FunctionContextEPKNS_9ColumnStrIjEES8_lRNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEERNS9_IjLm4096ESC_Lm16ELm15EEESE_m
Line
Count
Source
569
111
                                    const size_t index_now) {
570
111
        auto* engine = reinterpret_cast<RegexpExtractEngine*>(
571
111
                context->get_function_state(FunctionContext::THREAD_LOCAL));
572
111
        std::unique_ptr<RegexpExtractEngine> scoped_engine;
573
574
111
        if (engine == nullptr) {
575
78
            std::string error_str;
576
78
            const auto& pattern = pattern_col->get_data_at(index_check_const(index_now, Const));
577
78
            scoped_engine = std::make_unique<RegexpExtractEngine>();
578
78
            bool st = RegexpExtractEngine::compile(pattern, &error_str, *scoped_engine,
579
78
                                                   context->state()->enable_extended_regex());
580
78
            if (!st) {
581
0
                context->add_warning(error_str.c_str());
582
0
                StringOP::push_null_string(index_now, result_data, result_offset, null_map);
583
0
                return;
584
0
            }
585
78
            engine = scoped_engine.get();
586
78
        }
587
588
111
        const auto& str = str_col->get_data_at(index_now);
589
590
111
        int max_matches = 1 + engine->number_of_capturing_groups();
591
111
        if (index_data >= max_matches) {
592
83
            ReturnNull ? StringOP::push_null_string(index_now, result_data, result_offset, null_map)
593
83
                       : StringOP::push_empty_string(index_now, result_data, result_offset);
594
83
            return;
595
83
        }
596
597
28
        std::string match_result;
598
28
        bool success = engine->match_and_extract(str.data, str.size, static_cast<int>(index_data),
599
28
                                                 match_result);
600
601
28
        if (!success) {
602
5
            ReturnNull ? StringOP::push_null_string(index_now, result_data, result_offset, null_map)
603
5
                       : StringOP::push_empty_string(index_now, result_data, result_offset);
604
5
            return;
605
5
        }
606
607
23
        StringOP::push_value_string(std::string_view(match_result.data(), match_result.size()),
608
23
                                    index_now, result_data, result_offset);
609
23
    }
610
};
611
612
// Output handler for existing string-formatted result: "['a','b']"
613
struct RegexpExtractAllStringOutput {
614
    static constexpr const char* func_name = "regexp_extract_all";
615
35
    static DataTypePtr return_type() { return make_nullable(std::make_shared<DataTypeString>()); }
616
617
    ColumnString::Chars& result_data;
618
    ColumnString::Offsets& result_offset;
619
620
75
    void push_empty(size_t index) {
621
75
        StringOP::push_empty_string(index, result_data, result_offset);
622
75
    }
623
0
    void push_null(size_t index, NullMap& null_map) {
624
0
        StringOP::push_null_string(index, result_data, result_offset, null_map);
625
0
    }
626
20
    void push_matches(size_t index, const std::vector<std::string>& matches) {
627
20
        size_t total_size = 2; // '[' and ']'
628
39
        for (const auto& m : matches) {
629
39
            total_size += m.size() + 3; // "'xxx',"
630
39
        }
631
632
20
        size_t old_size = result_data.size();
633
20
        result_data.resize(old_size + total_size);
634
20
        char* pos = reinterpret_cast<char*>(&result_data[old_size]);
635
636
20
        *pos++ = '[';
637
59
        for (size_t j = 0; j < matches.size(); ++j) {
638
39
            if (j > 0) {
639
19
                *pos++ = ',';
640
19
            }
641
39
            *pos++ = '\'';
642
39
            memcpy(pos, matches[j].data(), matches[j].size());
643
39
            pos += matches[j].size();
644
39
            *pos++ = '\'';
645
39
        }
646
20
        *pos++ = ']';
647
648
20
        result_data.resize(old_size + static_cast<size_t>(pos - reinterpret_cast<char*>(
649
20
                                                                        &result_data[old_size])));
650
20
        result_offset[index] = static_cast<ColumnString::Offset>(result_data.size());
651
20
    }
652
653
    struct State {
654
        ColumnString::MutablePtr data_column;
655
43
        explicit State(size_t rows) : data_column(ColumnString::create()) {
656
43
            data_column->get_offsets().resize(rows);
657
43
        }
658
43
        RegexpExtractAllStringOutput create_handler() {
659
43
            return {.result_data = data_column->get_chars(),
660
43
                    .result_offset = data_column->get_offsets()};
661
43
        }
662
43
        ColumnPtr finalize(ColumnUInt8::MutablePtr null_map) {
663
43
            return ColumnNullable::create(std::move(data_column), std::move(null_map));
664
43
        }
665
    };
666
};
667
668
// Output handler for proper Array<Nullable<String>> result
669
struct RegexpExtractAllArrayOutput {
670
    static constexpr const char* func_name = "regexp_extract_all_array";
671
20
    static DataTypePtr return_type() {
672
20
        return make_nullable(
673
20
                std::make_shared<DataTypeArray>(make_nullable(std::make_shared<DataTypeString>())));
674
20
    }
675
676
    ColumnString& nested_col;
677
    ColumnArray::Offsets64& array_offsets;
678
    NullMap& nested_null_map;
679
    UInt64 current_offset = 0;
680
681
14
    void push_empty(size_t index) { array_offsets.push_back(current_offset); }
682
0
    void push_null(size_t index, NullMap& null_map) {
683
0
        null_map[index] = 1;
684
0
        array_offsets.push_back(current_offset);
685
0
    }
686
25
    void push_matches(size_t index, const std::vector<std::string>& matches) {
687
55
        for (const auto& m : matches) {
688
55
            nested_col.insert_data(m.data(), m.size());
689
55
            nested_null_map.push_back(0);
690
55
            current_offset++;
691
55
        }
692
25
        array_offsets.push_back(current_offset);
693
25
    }
694
695
    struct State {
696
        ColumnArray::MutablePtr array_column;
697
        ColumnNullable* nested_nullable;
698
16
        explicit State(size_t /*rows*/) {
699
16
            auto nullable_str = make_nullable(std::make_shared<DataTypeString>());
700
16
            array_column = ColumnArray::create(nullable_str->create_column(),
701
16
                                               ColumnArray::ColumnOffsets::create());
702
16
            nested_nullable = assert_cast<ColumnNullable*>(&array_column->get_data());
703
16
        }
704
16
        RegexpExtractAllArrayOutput create_handler() {
705
16
            return {.nested_col = assert_cast<ColumnString&>(nested_nullable->get_nested_column()),
706
16
                    .array_offsets = array_column->get_offsets(),
707
16
                    .nested_null_map = nested_nullable->get_null_map_data()};
708
16
        }
709
16
        ColumnPtr finalize(ColumnUInt8::MutablePtr null_map) {
710
16
            return ColumnNullable::create(std::move(array_column), std::move(null_map));
711
16
        }
712
    };
713
};
714
715
// Handler controls return type & column layout
716
template <typename Handler>
717
struct RegexpExtractAllImpl {
718
    static constexpr auto name = Handler::func_name;
719
    static constexpr size_t num_args = 2;
720
    static constexpr size_t PATTERN_ARG_IDX = 1;
721
722
55
    static DataTypePtr return_type() { return Handler::return_type(); }
_ZN5doris20RegexpExtractAllImplINS_28RegexpExtractAllStringOutputEE11return_typeEv
Line
Count
Source
722
35
    static DataTypePtr return_type() { return Handler::return_type(); }
_ZN5doris20RegexpExtractAllImplINS_27RegexpExtractAllArrayOutputEE11return_typeEv
Line
Count
Source
722
20
    static DataTypePtr return_type() { return Handler::return_type(); }
723
724
    static Status execute(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
725
56
                          uint32_t result, size_t input_rows_count) {
726
56
        bool col_const[2];
727
56
        ColumnPtr argument_columns[2];
728
172
        for (int i = 0; i < 2; ++i) {
729
116
            col_const[i] = is_column_const(*block.get_by_position(arguments[i]).column);
730
116
        }
731
56
        argument_columns[0] = col_const[0] ? static_cast<const ColumnConst&>(
732
1
                                                     *block.get_by_position(arguments[0]).column)
733
1
                                                     .convert_to_full_column()
734
56
                                           : block.get_by_position(arguments[0]).column;
735
736
56
        default_preprocess_parameter_columns(argument_columns, col_const, {1}, block, arguments);
737
738
56
        const auto* str_col = check_and_get_column<ColumnString>(argument_columns[0].get());
739
56
        const auto* pattern_col = check_and_get_column<ColumnString>(argument_columns[1].get());
740
741
56
        auto outer_null_map = ColumnUInt8::create(input_rows_count, 0);
742
56
        auto& null_map_data = outer_null_map->get_data();
743
744
56
        typename Handler::State state(input_rows_count);
745
56
        auto handler = state.create_handler();
746
747
56
        std::visit(
748
59
                [&](auto is_const) {
749
193
                    for (size_t i = 0; i < input_rows_count; ++i) {
750
134
                        if (null_map_data[i]) {
751
0
                            handler.push_null(i, null_map_data);
752
0
                            continue;
753
0
                        }
754
134
                        regexp_extract_all_inner_loop<is_const>(context, str_col, pattern_col,
755
134
                                                                handler, null_map_data, i);
756
134
                    }
757
59
                },
_ZZN5doris20RegexpExtractAllImplINS_28RegexpExtractAllStringOutputEE7executeEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlT_E_clISt17integral_constantIbLb0EEEEDaSC_
Line
Count
Source
748
35
                [&](auto is_const) {
749
116
                    for (size_t i = 0; i < input_rows_count; ++i) {
750
81
                        if (null_map_data[i]) {
751
0
                            handler.push_null(i, null_map_data);
752
0
                            continue;
753
0
                        }
754
81
                        regexp_extract_all_inner_loop<is_const>(context, str_col, pattern_col,
755
81
                                                                handler, null_map_data, i);
756
81
                    }
757
35
                },
_ZZN5doris20RegexpExtractAllImplINS_28RegexpExtractAllStringOutputEE7executeEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlT_E_clISt17integral_constantIbLb1EEEEDaSC_
Line
Count
Source
748
8
                [&](auto is_const) {
749
22
                    for (size_t i = 0; i < input_rows_count; ++i) {
750
14
                        if (null_map_data[i]) {
751
0
                            handler.push_null(i, null_map_data);
752
0
                            continue;
753
0
                        }
754
14
                        regexp_extract_all_inner_loop<is_const>(context, str_col, pattern_col,
755
14
                                                                handler, null_map_data, i);
756
14
                    }
757
8
                },
_ZZN5doris20RegexpExtractAllImplINS_27RegexpExtractAllArrayOutputEE7executeEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlT_E_clISt17integral_constantIbLb0EEEEDaSC_
Line
Count
Source
748
6
                [&](auto is_const) {
749
17
                    for (size_t i = 0; i < input_rows_count; ++i) {
750
11
                        if (null_map_data[i]) {
751
0
                            handler.push_null(i, null_map_data);
752
0
                            continue;
753
0
                        }
754
11
                        regexp_extract_all_inner_loop<is_const>(context, str_col, pattern_col,
755
11
                                                                handler, null_map_data, i);
756
11
                    }
757
6
                },
_ZZN5doris20RegexpExtractAllImplINS_27RegexpExtractAllArrayOutputEE7executeEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjmENKUlT_E_clISt17integral_constantIbLb1EEEEDaSC_
Line
Count
Source
748
10
                [&](auto is_const) {
749
38
                    for (size_t i = 0; i < input_rows_count; ++i) {
750
28
                        if (null_map_data[i]) {
751
0
                            handler.push_null(i, null_map_data);
752
0
                            continue;
753
0
                        }
754
28
                        regexp_extract_all_inner_loop<is_const>(context, str_col, pattern_col,
755
28
                                                                handler, null_map_data, i);
756
28
                    }
757
10
                },
758
56
                make_bool_variant(col_const[1]));
759
760
56
        block.get_by_position(result).column = state.finalize(std::move(outer_null_map));
761
56
        return Status::OK();
762
56
    }
_ZN5doris20RegexpExtractAllImplINS_28RegexpExtractAllStringOutputEE7executeEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
725
40
                          uint32_t result, size_t input_rows_count) {
726
40
        bool col_const[2];
727
40
        ColumnPtr argument_columns[2];
728
124
        for (int i = 0; i < 2; ++i) {
729
84
            col_const[i] = is_column_const(*block.get_by_position(arguments[i]).column);
730
84
        }
731
40
        argument_columns[0] = col_const[0] ? static_cast<const ColumnConst&>(
732
1
                                                     *block.get_by_position(arguments[0]).column)
733
1
                                                     .convert_to_full_column()
734
40
                                           : block.get_by_position(arguments[0]).column;
735
736
40
        default_preprocess_parameter_columns(argument_columns, col_const, {1}, block, arguments);
737
738
40
        const auto* str_col = check_and_get_column<ColumnString>(argument_columns[0].get());
739
40
        const auto* pattern_col = check_and_get_column<ColumnString>(argument_columns[1].get());
740
741
40
        auto outer_null_map = ColumnUInt8::create(input_rows_count, 0);
742
40
        auto& null_map_data = outer_null_map->get_data();
743
744
40
        typename Handler::State state(input_rows_count);
745
40
        auto handler = state.create_handler();
746
747
40
        std::visit(
748
40
                [&](auto is_const) {
749
40
                    for (size_t i = 0; i < input_rows_count; ++i) {
750
40
                        if (null_map_data[i]) {
751
40
                            handler.push_null(i, null_map_data);
752
40
                            continue;
753
40
                        }
754
40
                        regexp_extract_all_inner_loop<is_const>(context, str_col, pattern_col,
755
40
                                                                handler, null_map_data, i);
756
40
                    }
757
40
                },
758
40
                make_bool_variant(col_const[1]));
759
760
40
        block.get_by_position(result).column = state.finalize(std::move(outer_null_map));
761
40
        return Status::OK();
762
40
    }
_ZN5doris20RegexpExtractAllImplINS_27RegexpExtractAllArrayOutputEE7executeEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
725
16
                          uint32_t result, size_t input_rows_count) {
726
16
        bool col_const[2];
727
16
        ColumnPtr argument_columns[2];
728
48
        for (int i = 0; i < 2; ++i) {
729
32
            col_const[i] = is_column_const(*block.get_by_position(arguments[i]).column);
730
32
        }
731
16
        argument_columns[0] = col_const[0] ? static_cast<const ColumnConst&>(
732
0
                                                     *block.get_by_position(arguments[0]).column)
733
0
                                                     .convert_to_full_column()
734
16
                                           : block.get_by_position(arguments[0]).column;
735
736
16
        default_preprocess_parameter_columns(argument_columns, col_const, {1}, block, arguments);
737
738
16
        const auto* str_col = check_and_get_column<ColumnString>(argument_columns[0].get());
739
16
        const auto* pattern_col = check_and_get_column<ColumnString>(argument_columns[1].get());
740
741
16
        auto outer_null_map = ColumnUInt8::create(input_rows_count, 0);
742
16
        auto& null_map_data = outer_null_map->get_data();
743
744
16
        typename Handler::State state(input_rows_count);
745
16
        auto handler = state.create_handler();
746
747
16
        std::visit(
748
16
                [&](auto is_const) {
749
16
                    for (size_t i = 0; i < input_rows_count; ++i) {
750
16
                        if (null_map_data[i]) {
751
16
                            handler.push_null(i, null_map_data);
752
16
                            continue;
753
16
                        }
754
16
                        regexp_extract_all_inner_loop<is_const>(context, str_col, pattern_col,
755
16
                                                                handler, null_map_data, i);
756
16
                    }
757
16
                },
758
16
                make_bool_variant(col_const[1]));
759
760
16
        block.get_by_position(result).column = state.finalize(std::move(outer_null_map));
761
16
        return Status::OK();
762
16
    }
763
764
private:
765
    template <bool is_const>
766
    static void regexp_extract_all_inner_loop(FunctionContext* context, const ColumnString* str_col,
767
                                              const ColumnString* pattern_col, Handler& handler,
768
134
                                              NullMap& null_map, const size_t index_now) {
769
134
        auto* engine = reinterpret_cast<RegexpExtractEngine*>(
770
134
                context->get_function_state(FunctionContext::THREAD_LOCAL));
771
134
        std::unique_ptr<RegexpExtractEngine> scoped_engine;
772
773
134
        if (engine == nullptr) {
774
70
            std::string error_str;
775
70
            const auto& pattern = pattern_col->get_data_at(index_check_const(index_now, is_const));
776
70
            scoped_engine = std::make_unique<RegexpExtractEngine>();
777
70
            bool st = RegexpExtractEngine::compile(pattern, &error_str, *scoped_engine,
778
70
                                                   context->state()->enable_extended_regex());
779
70
            if (!st) {
780
0
                context->add_warning(error_str.c_str());
781
0
                handler.push_null(index_now, null_map);
782
0
                return;
783
0
            }
784
70
            engine = scoped_engine.get();
785
70
        }
786
787
134
        if (engine->number_of_capturing_groups() == 0) {
788
72
            handler.push_empty(index_now);
789
72
            return;
790
72
        }
791
62
        const auto& str = str_col->get_data_at(index_now);
792
62
        std::vector<std::string> res_matches;
793
62
        engine->match_all_and_extract(str.data, str.size, res_matches);
794
795
62
        if (res_matches.empty()) {
796
17
            handler.push_empty(index_now);
797
17
            return;
798
17
        }
799
45
        handler.push_matches(index_now, res_matches);
800
45
    }
_ZN5doris20RegexpExtractAllImplINS_28RegexpExtractAllStringOutputEE29regexp_extract_all_inner_loopILb0EEEvPNS_15FunctionContextEPKNS_9ColumnStrIjEES9_RS1_RNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEEm
Line
Count
Source
768
81
                                              NullMap& null_map, const size_t index_now) {
769
81
        auto* engine = reinterpret_cast<RegexpExtractEngine*>(
770
81
                context->get_function_state(FunctionContext::THREAD_LOCAL));
771
81
        std::unique_ptr<RegexpExtractEngine> scoped_engine;
772
773
81
        if (engine == nullptr) {
774
64
            std::string error_str;
775
64
            const auto& pattern = pattern_col->get_data_at(index_check_const(index_now, is_const));
776
64
            scoped_engine = std::make_unique<RegexpExtractEngine>();
777
64
            bool st = RegexpExtractEngine::compile(pattern, &error_str, *scoped_engine,
778
64
                                                   context->state()->enable_extended_regex());
779
64
            if (!st) {
780
0
                context->add_warning(error_str.c_str());
781
0
                handler.push_null(index_now, null_map);
782
0
                return;
783
0
            }
784
64
            engine = scoped_engine.get();
785
64
        }
786
787
81
        if (engine->number_of_capturing_groups() == 0) {
788
65
            handler.push_empty(index_now);
789
65
            return;
790
65
        }
791
16
        const auto& str = str_col->get_data_at(index_now);
792
16
        std::vector<std::string> res_matches;
793
16
        engine->match_all_and_extract(str.data, str.size, res_matches);
794
795
16
        if (res_matches.empty()) {
796
3
            handler.push_empty(index_now);
797
3
            return;
798
3
        }
799
13
        handler.push_matches(index_now, res_matches);
800
13
    }
_ZN5doris20RegexpExtractAllImplINS_28RegexpExtractAllStringOutputEE29regexp_extract_all_inner_loopILb1EEEvPNS_15FunctionContextEPKNS_9ColumnStrIjEES9_RS1_RNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEEm
Line
Count
Source
768
14
                                              NullMap& null_map, const size_t index_now) {
769
14
        auto* engine = reinterpret_cast<RegexpExtractEngine*>(
770
14
                context->get_function_state(FunctionContext::THREAD_LOCAL));
771
14
        std::unique_ptr<RegexpExtractEngine> scoped_engine;
772
773
14
        if (engine == nullptr) {
774
0
            std::string error_str;
775
0
            const auto& pattern = pattern_col->get_data_at(index_check_const(index_now, is_const));
776
0
            scoped_engine = std::make_unique<RegexpExtractEngine>();
777
0
            bool st = RegexpExtractEngine::compile(pattern, &error_str, *scoped_engine,
778
0
                                                   context->state()->enable_extended_regex());
779
0
            if (!st) {
780
0
                context->add_warning(error_str.c_str());
781
0
                handler.push_null(index_now, null_map);
782
0
                return;
783
0
            }
784
0
            engine = scoped_engine.get();
785
0
        }
786
787
14
        if (engine->number_of_capturing_groups() == 0) {
788
0
            handler.push_empty(index_now);
789
0
            return;
790
0
        }
791
14
        const auto& str = str_col->get_data_at(index_now);
792
14
        std::vector<std::string> res_matches;
793
14
        engine->match_all_and_extract(str.data, str.size, res_matches);
794
795
14
        if (res_matches.empty()) {
796
7
            handler.push_empty(index_now);
797
7
            return;
798
7
        }
799
7
        handler.push_matches(index_now, res_matches);
800
7
    }
_ZN5doris20RegexpExtractAllImplINS_27RegexpExtractAllArrayOutputEE29regexp_extract_all_inner_loopILb0EEEvPNS_15FunctionContextEPKNS_9ColumnStrIjEES9_RS1_RNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEEm
Line
Count
Source
768
11
                                              NullMap& null_map, const size_t index_now) {
769
11
        auto* engine = reinterpret_cast<RegexpExtractEngine*>(
770
11
                context->get_function_state(FunctionContext::THREAD_LOCAL));
771
11
        std::unique_ptr<RegexpExtractEngine> scoped_engine;
772
773
11
        if (engine == nullptr) {
774
6
            std::string error_str;
775
6
            const auto& pattern = pattern_col->get_data_at(index_check_const(index_now, is_const));
776
6
            scoped_engine = std::make_unique<RegexpExtractEngine>();
777
6
            bool st = RegexpExtractEngine::compile(pattern, &error_str, *scoped_engine,
778
6
                                                   context->state()->enable_extended_regex());
779
6
            if (!st) {
780
0
                context->add_warning(error_str.c_str());
781
0
                handler.push_null(index_now, null_map);
782
0
                return;
783
0
            }
784
6
            engine = scoped_engine.get();
785
6
        }
786
787
11
        if (engine->number_of_capturing_groups() == 0) {
788
7
            handler.push_empty(index_now);
789
7
            return;
790
7
        }
791
4
        const auto& str = str_col->get_data_at(index_now);
792
4
        std::vector<std::string> res_matches;
793
4
        engine->match_all_and_extract(str.data, str.size, res_matches);
794
795
4
        if (res_matches.empty()) {
796
0
            handler.push_empty(index_now);
797
0
            return;
798
0
        }
799
4
        handler.push_matches(index_now, res_matches);
800
4
    }
_ZN5doris20RegexpExtractAllImplINS_27RegexpExtractAllArrayOutputEE29regexp_extract_all_inner_loopILb1EEEvPNS_15FunctionContextEPKNS_9ColumnStrIjEES9_RS1_RNS_8PODArrayIhLm4096ENS_9AllocatorILb0ELb0ELb0ENS_22DefaultMemoryAllocatorELb1EEELm16ELm15EEEm
Line
Count
Source
768
28
                                              NullMap& null_map, const size_t index_now) {
769
28
        auto* engine = reinterpret_cast<RegexpExtractEngine*>(
770
28
                context->get_function_state(FunctionContext::THREAD_LOCAL));
771
28
        std::unique_ptr<RegexpExtractEngine> scoped_engine;
772
773
28
        if (engine == nullptr) {
774
0
            std::string error_str;
775
0
            const auto& pattern = pattern_col->get_data_at(index_check_const(index_now, is_const));
776
0
            scoped_engine = std::make_unique<RegexpExtractEngine>();
777
0
            bool st = RegexpExtractEngine::compile(pattern, &error_str, *scoped_engine,
778
0
                                                   context->state()->enable_extended_regex());
779
0
            if (!st) {
780
0
                context->add_warning(error_str.c_str());
781
0
                handler.push_null(index_now, null_map);
782
0
                return;
783
0
            }
784
0
            engine = scoped_engine.get();
785
0
        }
786
787
28
        if (engine->number_of_capturing_groups() == 0) {
788
0
            handler.push_empty(index_now);
789
0
            return;
790
0
        }
791
28
        const auto& str = str_col->get_data_at(index_now);
792
28
        std::vector<std::string> res_matches;
793
28
        engine->match_all_and_extract(str.data, str.size, res_matches);
794
795
28
        if (res_matches.empty()) {
796
7
            handler.push_empty(index_now);
797
7
            return;
798
7
        }
799
21
        handler.push_matches(index_now, res_matches);
800
21
    }
801
};
802
803
// template FunctionRegexpFunctionality is used for regexp_xxxx series functions, not for regexp match.
804
template <typename Impl>
805
class FunctionRegexpFunctionality : public IFunction {
806
public:
807
    static constexpr auto name = Impl::name;
808
809
146
    static FunctionPtr create() { return std::make_shared<FunctionRegexpFunctionality>(); }
_ZN5doris27FunctionRegexpFunctionalityINS_17RegexpExtractImplILb1EEEE6createEv
Line
Count
Source
809
30
    static FunctionPtr create() { return std::make_shared<FunctionRegexpFunctionality>(); }
_ZN5doris27FunctionRegexpFunctionalityINS_17RegexpExtractImplILb0EEEE6createEv
Line
Count
Source
809
43
    static FunctionPtr create() { return std::make_shared<FunctionRegexpFunctionality>(); }
_ZN5doris27FunctionRegexpFunctionalityINS_20RegexpExtractAllImplINS_28RegexpExtractAllStringOutputEEEE6createEv
Line
Count
Source
809
44
    static FunctionPtr create() { return std::make_shared<FunctionRegexpFunctionality>(); }
_ZN5doris27FunctionRegexpFunctionalityINS_20RegexpExtractAllImplINS_27RegexpExtractAllArrayOutputEEEE6createEv
Line
Count
Source
809
29
    static FunctionPtr create() { return std::make_shared<FunctionRegexpFunctionality>(); }
810
811
4
    String get_name() const override { return name; }
_ZNK5doris27FunctionRegexpFunctionalityINS_17RegexpExtractImplILb1EEEE8get_nameB5cxx11Ev
Line
Count
Source
811
1
    String get_name() const override { return name; }
_ZNK5doris27FunctionRegexpFunctionalityINS_17RegexpExtractImplILb0EEEE8get_nameB5cxx11Ev
Line
Count
Source
811
1
    String get_name() const override { return name; }
_ZNK5doris27FunctionRegexpFunctionalityINS_20RegexpExtractAllImplINS_28RegexpExtractAllStringOutputEEEE8get_nameB5cxx11Ev
Line
Count
Source
811
1
    String get_name() const override { return name; }
_ZNK5doris27FunctionRegexpFunctionalityINS_20RegexpExtractAllImplINS_27RegexpExtractAllArrayOutputEEEE8get_nameB5cxx11Ev
Line
Count
Source
811
1
    String get_name() const override { return name; }
812
813
110
    size_t get_number_of_arguments() const override { return Impl::num_args; }
_ZNK5doris27FunctionRegexpFunctionalityINS_17RegexpExtractImplILb1EEEE23get_number_of_argumentsEv
Line
Count
Source
813
21
    size_t get_number_of_arguments() const override { return Impl::num_args; }
_ZNK5doris27FunctionRegexpFunctionalityINS_17RegexpExtractImplILb0EEEE23get_number_of_argumentsEv
Line
Count
Source
813
34
    size_t get_number_of_arguments() const override { return Impl::num_args; }
_ZNK5doris27FunctionRegexpFunctionalityINS_20RegexpExtractAllImplINS_28RegexpExtractAllStringOutputEEEE23get_number_of_argumentsEv
Line
Count
Source
813
35
    size_t get_number_of_arguments() const override { return Impl::num_args; }
_ZNK5doris27FunctionRegexpFunctionalityINS_20RegexpExtractAllImplINS_27RegexpExtractAllArrayOutputEEEE23get_number_of_argumentsEv
Line
Count
Source
813
20
    size_t get_number_of_arguments() const override { return Impl::num_args; }
814
815
110
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
816
110
        return Impl::return_type();
817
110
    }
_ZNK5doris27FunctionRegexpFunctionalityINS_17RegexpExtractImplILb1EEEE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS8_EE
Line
Count
Source
815
21
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
816
21
        return Impl::return_type();
817
21
    }
_ZNK5doris27FunctionRegexpFunctionalityINS_17RegexpExtractImplILb0EEEE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS8_EE
Line
Count
Source
815
34
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
816
34
        return Impl::return_type();
817
34
    }
_ZNK5doris27FunctionRegexpFunctionalityINS_20RegexpExtractAllImplINS_28RegexpExtractAllStringOutputEEEE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS9_EE
Line
Count
Source
815
35
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
816
35
        return Impl::return_type();
817
35
    }
_ZNK5doris27FunctionRegexpFunctionalityINS_20RegexpExtractAllImplINS_27RegexpExtractAllArrayOutputEEEE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS9_EE
Line
Count
Source
815
20
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
816
20
        return Impl::return_type();
817
20
    }
818
819
334
    Status open(FunctionContext* context, FunctionContext::FunctionStateScope scope) override {
820
334
        if (scope == FunctionContext::THREAD_LOCAL) {
821
224
            if (context->is_col_constant(Impl::PATTERN_ARG_IDX)) {
822
155
                DCHECK(!context->get_function_state(scope));
823
155
                const auto pattern_col =
824
155
                        context->get_constant_col(Impl::PATTERN_ARG_IDX)->column_ptr;
825
155
                const auto& pattern = pattern_col->get_data_at(0);
826
155
                if (pattern.size == 0) {
827
4
                    return Status::OK();
828
4
                }
829
830
151
                std::string error_str;
831
151
                auto engine = std::make_shared<RegexpExtractEngine>();
832
151
                bool st = RegexpExtractEngine::compile(pattern, &error_str, *engine,
833
151
                                                       context->state()->enable_extended_regex());
834
835
151
                if (!st) {
836
5
                    context->set_error(error_str.c_str());
837
5
                    return Status::InvalidArgument(error_str);
838
5
                }
839
146
                context->set_function_state(scope, engine);
840
146
            }
841
224
        }
842
325
        return Status::OK();
843
334
    }
_ZN5doris27FunctionRegexpFunctionalityINS_17RegexpExtractImplILb1EEEE4openEPNS_15FunctionContextENS4_18FunctionStateScopeE
Line
Count
Source
819
52
    Status open(FunctionContext* context, FunctionContext::FunctionStateScope scope) override {
820
52
        if (scope == FunctionContext::THREAD_LOCAL) {
821
31
            if (context->is_col_constant(Impl::PATTERN_ARG_IDX)) {
822
31
                DCHECK(!context->get_function_state(scope));
823
31
                const auto pattern_col =
824
31
                        context->get_constant_col(Impl::PATTERN_ARG_IDX)->column_ptr;
825
31
                const auto& pattern = pattern_col->get_data_at(0);
826
31
                if (pattern.size == 0) {
827
1
                    return Status::OK();
828
1
                }
829
830
30
                std::string error_str;
831
30
                auto engine = std::make_shared<RegexpExtractEngine>();
832
30
                bool st = RegexpExtractEngine::compile(pattern, &error_str, *engine,
833
30
                                                       context->state()->enable_extended_regex());
834
835
30
                if (!st) {
836
1
                    context->set_error(error_str.c_str());
837
1
                    return Status::InvalidArgument(error_str);
838
1
                }
839
29
                context->set_function_state(scope, engine);
840
29
            }
841
31
        }
842
50
        return Status::OK();
843
52
    }
_ZN5doris27FunctionRegexpFunctionalityINS_17RegexpExtractImplILb0EEEE4openEPNS_15FunctionContextENS4_18FunctionStateScopeE
Line
Count
Source
819
114
    Status open(FunctionContext* context, FunctionContext::FunctionStateScope scope) override {
820
114
        if (scope == FunctionContext::THREAD_LOCAL) {
821
80
            if (context->is_col_constant(Impl::PATTERN_ARG_IDX)) {
822
44
                DCHECK(!context->get_function_state(scope));
823
44
                const auto pattern_col =
824
44
                        context->get_constant_col(Impl::PATTERN_ARG_IDX)->column_ptr;
825
44
                const auto& pattern = pattern_col->get_data_at(0);
826
44
                if (pattern.size == 0) {
827
1
                    return Status::OK();
828
1
                }
829
830
43
                std::string error_str;
831
43
                auto engine = std::make_shared<RegexpExtractEngine>();
832
43
                bool st = RegexpExtractEngine::compile(pattern, &error_str, *engine,
833
43
                                                       context->state()->enable_extended_regex());
834
835
43
                if (!st) {
836
1
                    context->set_error(error_str.c_str());
837
1
                    return Status::InvalidArgument(error_str);
838
1
                }
839
42
                context->set_function_state(scope, engine);
840
42
            }
841
80
        }
842
112
        return Status::OK();
843
114
    }
_ZN5doris27FunctionRegexpFunctionalityINS_20RegexpExtractAllImplINS_28RegexpExtractAllStringOutputEEEE4openEPNS_15FunctionContextENS5_18FunctionStateScopeE
Line
Count
Source
819
115
    Status open(FunctionContext* context, FunctionContext::FunctionStateScope scope) override {
820
115
        if (scope == FunctionContext::THREAD_LOCAL) {
821
80
            if (context->is_col_constant(Impl::PATTERN_ARG_IDX)) {
822
50
                DCHECK(!context->get_function_state(scope));
823
50
                const auto pattern_col =
824
50
                        context->get_constant_col(Impl::PATTERN_ARG_IDX)->column_ptr;
825
50
                const auto& pattern = pattern_col->get_data_at(0);
826
50
                if (pattern.size == 0) {
827
1
                    return Status::OK();
828
1
                }
829
830
49
                std::string error_str;
831
49
                auto engine = std::make_shared<RegexpExtractEngine>();
832
49
                bool st = RegexpExtractEngine::compile(pattern, &error_str, *engine,
833
49
                                                       context->state()->enable_extended_regex());
834
835
49
                if (!st) {
836
1
                    context->set_error(error_str.c_str());
837
1
                    return Status::InvalidArgument(error_str);
838
1
                }
839
48
                context->set_function_state(scope, engine);
840
48
            }
841
80
        }
842
113
        return Status::OK();
843
115
    }
_ZN5doris27FunctionRegexpFunctionalityINS_20RegexpExtractAllImplINS_27RegexpExtractAllArrayOutputEEEE4openEPNS_15FunctionContextENS5_18FunctionStateScopeE
Line
Count
Source
819
53
    Status open(FunctionContext* context, FunctionContext::FunctionStateScope scope) override {
820
53
        if (scope == FunctionContext::THREAD_LOCAL) {
821
33
            if (context->is_col_constant(Impl::PATTERN_ARG_IDX)) {
822
30
                DCHECK(!context->get_function_state(scope));
823
30
                const auto pattern_col =
824
30
                        context->get_constant_col(Impl::PATTERN_ARG_IDX)->column_ptr;
825
30
                const auto& pattern = pattern_col->get_data_at(0);
826
30
                if (pattern.size == 0) {
827
1
                    return Status::OK();
828
1
                }
829
830
29
                std::string error_str;
831
29
                auto engine = std::make_shared<RegexpExtractEngine>();
832
29
                bool st = RegexpExtractEngine::compile(pattern, &error_str, *engine,
833
29
                                                       context->state()->enable_extended_regex());
834
835
29
                if (!st) {
836
2
                    context->set_error(error_str.c_str());
837
2
                    return Status::InvalidArgument(error_str);
838
2
                }
839
27
                context->set_function_state(scope, engine);
840
27
            }
841
33
        }
842
50
        return Status::OK();
843
53
    }
844
845
    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
846
117
                        uint32_t result, size_t input_rows_count) const override {
847
117
        return Impl::execute(context, block, arguments, result, input_rows_count);
848
117
    }
_ZNK5doris27FunctionRegexpFunctionalityINS_17RegexpExtractImplILb1EEEE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
846
18
                        uint32_t result, size_t input_rows_count) const override {
847
18
        return Impl::execute(context, block, arguments, result, input_rows_count);
848
18
    }
_ZNK5doris27FunctionRegexpFunctionalityINS_17RegexpExtractImplILb0EEEE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
846
42
                        uint32_t result, size_t input_rows_count) const override {
847
42
        return Impl::execute(context, block, arguments, result, input_rows_count);
848
42
    }
_ZNK5doris27FunctionRegexpFunctionalityINS_20RegexpExtractAllImplINS_28RegexpExtractAllStringOutputEEEE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
846
41
                        uint32_t result, size_t input_rows_count) const override {
847
41
        return Impl::execute(context, block, arguments, result, input_rows_count);
848
41
    }
_ZNK5doris27FunctionRegexpFunctionalityINS_20RegexpExtractAllImplINS_27RegexpExtractAllArrayOutputEEEE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
846
16
                        uint32_t result, size_t input_rows_count) const override {
847
16
        return Impl::execute(context, block, arguments, result, input_rows_count);
848
16
    }
849
};
850
851
8
void register_function_regexp_extract(SimpleFunctionFactory& factory) {
852
8
    factory.register_function<FunctionRegexpReplace<RegexpReplaceImpl<false>, ThreeParamTypes>>();
853
8
    factory.register_function<FunctionRegexpReplace<RegexpReplaceImpl<false>, FourParamTypes>>();
854
8
    factory.register_function<FunctionRegexpReplace<RegexpReplaceImpl<true>, ThreeParamTypes>>();
855
8
    factory.register_function<FunctionRegexpReplace<RegexpReplaceImpl<true>, FourParamTypes>>();
856
8
    factory.register_function<FunctionRegexpFunctionality<RegexpExtractImpl<true>>>();
857
8
    factory.register_function<FunctionRegexpFunctionality<RegexpExtractImpl<false>>>();
858
8
    factory.register_function<
859
8
            FunctionRegexpFunctionality<RegexpExtractAllImpl<RegexpExtractAllStringOutput>>>();
860
8
    factory.register_function<
861
8
            FunctionRegexpFunctionality<RegexpExtractAllImpl<RegexpExtractAllArrayOutput>>>();
862
8
    factory.register_function<FunctionRegexpCount>();
863
8
}
864
865
} // namespace doris