Coverage Report

Created: 2026-09-12 19:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exprs/function/uuid.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 <stddef.h>
20
21
#include <boost/uuid/random_generator.hpp>
22
#include <boost/uuid/uuid_io.hpp>
23
#include <cstdint>
24
#include <memory>
25
#include <mutex>
26
#include <string>
27
#include <utility>
28
#include <vector>
29
30
#include "common/status.h"
31
#include "core/block/block.h"
32
#include "core/block/column_numbers.h"
33
#include "core/column/column_const.h"
34
#include "core/column/column_nullable.h"
35
#include "core/column/column_string.h"
36
#include "core/column/column_vector.h"
37
#include "core/data_type/data_type_date_time.h"
38
#include "core/data_type/data_type_nullable.h"
39
#include "core/data_type/data_type_number.h"
40
#include "core/data_type/data_type_string.h"
41
#include "core/data_type/data_type_uuid.h"
42
#include "core/types.h"
43
#include "core/value/vdatetime_value.h"
44
#include "exec/common/string_utils/string_utils.h"
45
#include "exprs/aggregate/aggregate_function.h"
46
#include "exprs/function/function.h"
47
#include "exprs/function/function_totype.h"
48
#include "exprs/function/simple_function_factory.h"
49
#include "runtime/runtime_state.h"
50
51
namespace doris {
52
class FunctionContext;
53
} // namespace doris
54
55
namespace doris {
56
namespace {
57
58
template <bool Version7>
59
class FunctionGenerateUUID : public IFunction {
60
public:
61
    static constexpr auto name = Version7 ? "uuid_v7" : "uuid_v4";
62
63
56
    static FunctionPtr create() { return std::make_shared<FunctionGenerateUUID>(); }
uuid.cpp:_ZN5doris12_GLOBAL__N_120FunctionGenerateUUIDILb0EE6createEv
Line
Count
Source
63
28
    static FunctionPtr create() { return std::make_shared<FunctionGenerateUUID>(); }
uuid.cpp:_ZN5doris12_GLOBAL__N_120FunctionGenerateUUIDILb1EE6createEv
Line
Count
Source
63
28
    static FunctionPtr create() { return std::make_shared<FunctionGenerateUUID>(); }
64
65
0
    String get_name() const override { return name; }
Unexecuted instantiation: uuid.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb0EE8get_nameB5cxx11Ev
Unexecuted instantiation: uuid.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb1EE8get_nameB5cxx11Ev
66
67
120
    bool use_default_implementation_for_constants() const override { return false; }
uuid.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb0EE40use_default_implementation_for_constantsEv
Line
Count
Source
67
60
    bool use_default_implementation_for_constants() const override { return false; }
uuid.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb1EE40use_default_implementation_for_constantsEv
Line
Count
Source
67
60
    bool use_default_implementation_for_constants() const override { return false; }
68
69
42
    size_t get_number_of_arguments() const override { return 0; }
uuid.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb0EE23get_number_of_argumentsEv
Line
Count
Source
69
21
    size_t get_number_of_arguments() const override { return 0; }
uuid.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb1EE23get_number_of_argumentsEv
Line
Count
Source
69
21
    size_t get_number_of_arguments() const override { return 0; }
70
71
42
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
72
42
        return std::make_shared<DataTypeUUID>();
73
42
    }
uuid.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb0EE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS7_EE
Line
Count
Source
71
21
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
72
21
        return std::make_shared<DataTypeUUID>();
73
21
    }
uuid.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb1EE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS7_EE
Line
Count
Source
71
21
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
72
21
        return std::make_shared<DataTypeUUID>();
73
21
    }
74
75
    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
76
42
                        uint32_t result, size_t input_rows_count) const override {
77
42
        auto column = ColumnUUID::create(input_rows_count);
78
42
        auto& data = column->get_data();
79
42
        UUIDValue::generate(data.data(), input_rows_count, Version7);
80
42
        block.replace_by_position(result, std::move(column));
81
42
        return Status::OK();
82
42
    }
uuid.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb0EE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
76
21
                        uint32_t result, size_t input_rows_count) const override {
77
21
        auto column = ColumnUUID::create(input_rows_count);
78
21
        auto& data = column->get_data();
79
21
        UUIDValue::generate(data.data(), input_rows_count, Version7);
80
21
        block.replace_by_position(result, std::move(column));
81
21
        return Status::OK();
82
21
    }
uuid.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb1EE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
76
21
                        uint32_t result, size_t input_rows_count) const override {
77
21
        auto column = ColumnUUID::create(input_rows_count);
78
21
        auto& data = column->get_data();
79
21
        UUIDValue::generate(data.data(), input_rows_count, Version7);
80
21
        block.replace_by_position(result, std::move(column));
81
21
        return Status::OK();
82
21
    }
83
};
84
85
class FunctionUUIDVersion : public IFunction {
86
public:
87
    static constexpr auto name = "uuid_version";
88
89
283
    static FunctionPtr create() { return std::make_shared<FunctionUUIDVersion>(); }
90
91
0
    String get_name() const override { return name; }
92
93
276
    size_t get_number_of_arguments() const override { return 1; }
94
95
276
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
96
276
        return std::make_shared<DataTypeInt8>();
97
276
    }
98
99
    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
100
238
                        uint32_t result, size_t input_rows_count) const override {
101
238
        const auto& input =
102
238
                assert_cast<const ColumnUUID&>(*block.get_by_position(arguments[0]).column);
103
238
        auto output = ColumnInt8::create(input_rows_count);
104
238
        auto& output_data = output->get_data();
105
100k
        for (size_t i = 0; i < input_rows_count; ++i) {
106
99.8k
            output_data[i] = static_cast<Int8>(UUIDValue::version(input.get_element(i)));
107
99.8k
        }
108
238
        block.replace_by_position(result, std::move(output));
109
238
        return Status::OK();
110
238
    }
111
};
112
113
// NULL input is propagated by OrZero/OrNull, but selects the fallback in OrDefault.
114
enum class UUIDParseMode { Zero, Null, Default };
115
116
template <UUIDParseMode Mode>
117
class FunctionToUUID : public IFunction {
118
public:
119
    static constexpr auto name = Mode == UUIDParseMode::Zero   ? "to_uuid_or_zero"
120
                                 : Mode == UUIDParseMode::Null ? "to_uuid_or_null"
121
                                                               : "to_uuid_or_default";
122
413
    static FunctionPtr create() { return std::make_shared<FunctionToUUID>(); }
uuid.cpp:_ZN5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE0EE6createEv
Line
Count
Source
122
51
    static FunctionPtr create() { return std::make_shared<FunctionToUUID>(); }
uuid.cpp:_ZN5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE1EE6createEv
Line
Count
Source
122
51
    static FunctionPtr create() { return std::make_shared<FunctionToUUID>(); }
uuid.cpp:_ZN5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE2EE6createEv
Line
Count
Source
122
311
    static FunctionPtr create() { return std::make_shared<FunctionToUUID>(); }
123
0
    String get_name() const override { return name; }
Unexecuted instantiation: uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE0EE8get_nameB5cxx11Ev
Unexecuted instantiation: uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE1EE8get_nameB5cxx11Ev
Unexecuted instantiation: uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE2EE8get_nameB5cxx11Ev
124
88
    size_t get_number_of_arguments() const override {
125
88
        return Mode == UUIDParseMode::Default ? 0 : 1;
126
88
    }
uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE0EE23get_number_of_argumentsEv
Line
Count
Source
124
44
    size_t get_number_of_arguments() const override {
125
44
        return Mode == UUIDParseMode::Default ? 0 : 1;
126
44
    }
uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE1EE23get_number_of_argumentsEv
Line
Count
Source
124
44
    size_t get_number_of_arguments() const override {
125
44
        return Mode == UUIDParseMode::Default ? 0 : 1;
126
44
    }
Unexecuted instantiation: uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE2EE23get_number_of_argumentsEv
127
392
    bool is_variadic() const override { return Mode == UUIDParseMode::Default; }
uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE0EE11is_variadicEv
Line
Count
Source
127
44
    bool is_variadic() const override { return Mode == UUIDParseMode::Default; }
uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE1EE11is_variadicEv
Line
Count
Source
127
44
    bool is_variadic() const override { return Mode == UUIDParseMode::Default; }
uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE2EE11is_variadicEv
Line
Count
Source
127
304
    bool is_variadic() const override { return Mode == UUIDParseMode::Default; }
128
784
    bool use_default_implementation_for_nulls() const override { return false; }
uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE0EE36use_default_implementation_for_nullsEv
Line
Count
Source
128
88
    bool use_default_implementation_for_nulls() const override { return false; }
uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE1EE36use_default_implementation_for_nullsEv
Line
Count
Source
128
88
    bool use_default_implementation_for_nulls() const override { return false; }
uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE2EE36use_default_implementation_for_nullsEv
Line
Count
Source
128
608
    bool use_default_implementation_for_nulls() const override { return false; }
129
392
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
130
392
        bool nullable = Mode == UUIDParseMode::Null ||
131
392
                        (Mode == UUIDParseMode::Zero && arguments[0]->is_nullable()) ||
132
392
                        (Mode == UUIDParseMode::Default && arguments.size() == 2 &&
133
340
                         arguments[1]->is_nullable());
134
392
        DataTypePtr type = std::make_shared<DataTypeUUID>();
135
392
        return nullable ? make_nullable(type) : type;
136
392
    }
uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE0EE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS8_EE
Line
Count
Source
129
44
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
130
44
        bool nullable = Mode == UUIDParseMode::Null ||
131
44
                        (Mode == UUIDParseMode::Zero && arguments[0]->is_nullable()) ||
132
44
                        (Mode == UUIDParseMode::Default && arguments.size() == 2 &&
133
36
                         arguments[1]->is_nullable());
134
44
        DataTypePtr type = std::make_shared<DataTypeUUID>();
135
44
        return nullable ? make_nullable(type) : type;
136
44
    }
uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE1EE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS8_EE
Line
Count
Source
129
44
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
130
44
        bool nullable = Mode == UUIDParseMode::Null ||
131
44
                        (Mode == UUIDParseMode::Zero && arguments[0]->is_nullable()) ||
132
44
                        (Mode == UUIDParseMode::Default && arguments.size() == 2 &&
133
0
                         arguments[1]->is_nullable());
134
44
        DataTypePtr type = std::make_shared<DataTypeUUID>();
135
44
        return nullable ? make_nullable(type) : type;
136
44
    }
uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE2EE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS8_EE
Line
Count
Source
129
304
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
130
304
        bool nullable = Mode == UUIDParseMode::Null ||
131
304
                        (Mode == UUIDParseMode::Zero && arguments[0]->is_nullable()) ||
132
304
                        (Mode == UUIDParseMode::Default && arguments.size() == 2 &&
133
304
                         arguments[1]->is_nullable());
134
304
        DataTypePtr type = std::make_shared<DataTypeUUID>();
135
304
        return nullable ? make_nullable(type) : type;
136
304
    }
137
    Status execute_impl(FunctionContext*, Block& block, const ColumnNumbers& arguments,
138
392
                        uint32_t result, size_t rows) const override {
139
392
        auto input = block.get_by_position(arguments[0]).column->convert_to_full_column_if_const();
140
392
        const auto* nullable_input = check_and_get_column<ColumnNullable>(*input);
141
392
        const auto& strings = assert_cast<const ColumnString&>(
142
392
                nullable_input ? nullable_input->get_nested_column() : *input);
143
392
        ColumnPtr fallback;
144
392
        const ColumnNullable* nullable_fallback = nullptr;
145
392
        const ColumnUUID* fallback_values = nullptr;
146
392
        if constexpr (Mode == UUIDParseMode::Default) {
147
304
            if (arguments.size() == 2) {
148
262
                fallback = block.get_by_position(arguments[1])
149
262
                                   .column->convert_to_full_column_if_const();
150
262
                nullable_fallback = check_and_get_column<ColumnNullable>(*fallback);
151
262
                fallback_values = &assert_cast<const ColumnUUID&>(
152
262
                        nullable_fallback ? nullable_fallback->get_nested_column() : *fallback);
153
262
            }
154
304
        }
155
392
        auto output = ColumnUUID::create(rows, 0);
156
392
        auto nulls = ColumnUInt8::create(rows, 0);
157
4.91k
        for (size_t i = 0; i < rows; ++i) {
158
4.52k
            bool source_null = nullable_input && nullable_input->is_null_at(i);
159
4.52k
            UUIDValueType value = 0;
160
4.52k
            auto text = strings.get_data_at(i);
161
4.52k
            bool parsed = !source_null && UUIDValue::from_string(value, text.data, text.size);
162
4.52k
            if (parsed) {
163
1.98k
                output->get_data()[i] = value;
164
2.37k
            } else if constexpr (Mode == UUIDParseMode::Default) {
165
2.37k
                if (fallback_values) {
166
2.29k
                    output->get_data()[i] = fallback_values->get_element(i);
167
2.29k
                    nulls->get_data()[i] = nullable_fallback && nullable_fallback->is_null_at(i);
168
2.29k
                }
169
2.37k
            } else {
170
163
                nulls->get_data()[i] = Mode == UUIDParseMode::Null || source_null;
171
163
            }
172
4.52k
        }
173
392
        if (block.get_by_position(result).type->is_nullable()) {
174
250
            block.replace_by_position(result,
175
250
                                      ColumnNullable::create(std::move(output), std::move(nulls)));
176
250
        } else {
177
142
            block.replace_by_position(result, std::move(output));
178
142
        }
179
392
        return Status::OK();
180
392
    }
uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE0EE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
138
44
                        uint32_t result, size_t rows) const override {
139
44
        auto input = block.get_by_position(arguments[0]).column->convert_to_full_column_if_const();
140
44
        const auto* nullable_input = check_and_get_column<ColumnNullable>(*input);
141
44
        const auto& strings = assert_cast<const ColumnString&>(
142
44
                nullable_input ? nullable_input->get_nested_column() : *input);
143
44
        ColumnPtr fallback;
144
44
        const ColumnNullable* nullable_fallback = nullptr;
145
44
        const ColumnUUID* fallback_values = nullptr;
146
        if constexpr (Mode == UUIDParseMode::Default) {
147
            if (arguments.size() == 2) {
148
                fallback = block.get_by_position(arguments[1])
149
                                   .column->convert_to_full_column_if_const();
150
                nullable_fallback = check_and_get_column<ColumnNullable>(*fallback);
151
                fallback_values = &assert_cast<const ColumnUUID&>(
152
                        nullable_fallback ? nullable_fallback->get_nested_column() : *fallback);
153
            }
154
        }
155
44
        auto output = ColumnUUID::create(rows, 0);
156
44
        auto nulls = ColumnUInt8::create(rows, 0);
157
190
        for (size_t i = 0; i < rows; ++i) {
158
146
            bool source_null = nullable_input && nullable_input->is_null_at(i);
159
146
            UUIDValueType value = 0;
160
146
            auto text = strings.get_data_at(i);
161
146
            bool parsed = !source_null && UUIDValue::from_string(value, text.data, text.size);
162
146
            if (parsed) {
163
65
                output->get_data()[i] = value;
164
65
            } else if constexpr (Mode == UUIDParseMode::Default) {
165
                if (fallback_values) {
166
                    output->get_data()[i] = fallback_values->get_element(i);
167
                    nulls->get_data()[i] = nullable_fallback && nullable_fallback->is_null_at(i);
168
                }
169
81
            } else {
170
81
                nulls->get_data()[i] = Mode == UUIDParseMode::Null || source_null;
171
81
            }
172
146
        }
173
44
        if (block.get_by_position(result).type->is_nullable()) {
174
8
            block.replace_by_position(result,
175
8
                                      ColumnNullable::create(std::move(output), std::move(nulls)));
176
36
        } else {
177
36
            block.replace_by_position(result, std::move(output));
178
36
        }
179
44
        return Status::OK();
180
44
    }
uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE1EE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
138
44
                        uint32_t result, size_t rows) const override {
139
44
        auto input = block.get_by_position(arguments[0]).column->convert_to_full_column_if_const();
140
44
        const auto* nullable_input = check_and_get_column<ColumnNullable>(*input);
141
44
        const auto& strings = assert_cast<const ColumnString&>(
142
44
                nullable_input ? nullable_input->get_nested_column() : *input);
143
44
        ColumnPtr fallback;
144
44
        const ColumnNullable* nullable_fallback = nullptr;
145
44
        const ColumnUUID* fallback_values = nullptr;
146
        if constexpr (Mode == UUIDParseMode::Default) {
147
            if (arguments.size() == 2) {
148
                fallback = block.get_by_position(arguments[1])
149
                                   .column->convert_to_full_column_if_const();
150
                nullable_fallback = check_and_get_column<ColumnNullable>(*fallback);
151
                fallback_values = &assert_cast<const ColumnUUID&>(
152
                        nullable_fallback ? nullable_fallback->get_nested_column() : *fallback);
153
            }
154
        }
155
44
        auto output = ColumnUUID::create(rows, 0);
156
44
        auto nulls = ColumnUInt8::create(rows, 0);
157
190
        for (size_t i = 0; i < rows; ++i) {
158
146
            bool source_null = nullable_input && nullable_input->is_null_at(i);
159
146
            UUIDValueType value = 0;
160
146
            auto text = strings.get_data_at(i);
161
146
            bool parsed = !source_null && UUIDValue::from_string(value, text.data, text.size);
162
146
            if (parsed) {
163
64
                output->get_data()[i] = value;
164
64
            } else if constexpr (Mode == UUIDParseMode::Default) {
165
                if (fallback_values) {
166
                    output->get_data()[i] = fallback_values->get_element(i);
167
                    nulls->get_data()[i] = nullable_fallback && nullable_fallback->is_null_at(i);
168
                }
169
82
            } else {
170
82
                nulls->get_data()[i] = Mode == UUIDParseMode::Null || source_null;
171
82
            }
172
146
        }
173
44
        if (block.get_by_position(result).type->is_nullable()) {
174
44
            block.replace_by_position(result,
175
44
                                      ColumnNullable::create(std::move(output), std::move(nulls)));
176
44
        } else {
177
0
            block.replace_by_position(result, std::move(output));
178
0
        }
179
44
        return Status::OK();
180
44
    }
uuid.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE2EE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
138
304
                        uint32_t result, size_t rows) const override {
139
304
        auto input = block.get_by_position(arguments[0]).column->convert_to_full_column_if_const();
140
304
        const auto* nullable_input = check_and_get_column<ColumnNullable>(*input);
141
304
        const auto& strings = assert_cast<const ColumnString&>(
142
304
                nullable_input ? nullable_input->get_nested_column() : *input);
143
304
        ColumnPtr fallback;
144
304
        const ColumnNullable* nullable_fallback = nullptr;
145
304
        const ColumnUUID* fallback_values = nullptr;
146
304
        if constexpr (Mode == UUIDParseMode::Default) {
147
304
            if (arguments.size() == 2) {
148
262
                fallback = block.get_by_position(arguments[1])
149
262
                                   .column->convert_to_full_column_if_const();
150
262
                nullable_fallback = check_and_get_column<ColumnNullable>(*fallback);
151
262
                fallback_values = &assert_cast<const ColumnUUID&>(
152
262
                        nullable_fallback ? nullable_fallback->get_nested_column() : *fallback);
153
262
            }
154
304
        }
155
304
        auto output = ColumnUUID::create(rows, 0);
156
304
        auto nulls = ColumnUInt8::create(rows, 0);
157
4.53k
        for (size_t i = 0; i < rows; ++i) {
158
4.23k
            bool source_null = nullable_input && nullable_input->is_null_at(i);
159
4.23k
            UUIDValueType value = 0;
160
4.23k
            auto text = strings.get_data_at(i);
161
4.23k
            bool parsed = !source_null && UUIDValue::from_string(value, text.data, text.size);
162
4.23k
            if (parsed) {
163
1.85k
                output->get_data()[i] = value;
164
2.37k
            } else if constexpr (Mode == UUIDParseMode::Default) {
165
2.37k
                if (fallback_values) {
166
2.29k
                    output->get_data()[i] = fallback_values->get_element(i);
167
2.29k
                    nulls->get_data()[i] = nullable_fallback && nullable_fallback->is_null_at(i);
168
2.29k
                }
169
            } else {
170
                nulls->get_data()[i] = Mode == UUIDParseMode::Null || source_null;
171
            }
172
4.23k
        }
173
304
        if (block.get_by_position(result).type->is_nullable()) {
174
198
            block.replace_by_position(result,
175
198
                                      ColumnNullable::create(std::move(output), std::move(nulls)));
176
198
        } else {
177
106
            block.replace_by_position(result, std::move(output));
178
106
        }
179
304
        return Status::OK();
180
304
    }
181
};
182
183
class FunctionUUIDv7ToDateTime : public IFunction {
184
public:
185
    static constexpr auto name = "uuid_v7_to_datetime";
186
262
    static FunctionPtr create() { return std::make_shared<FunctionUUIDv7ToDateTime>(); }
187
0
    String get_name() const override { return name; }
188
0
    size_t get_number_of_arguments() const override { return 0; }
189
255
    bool is_variadic() const override { return true; }
190
255
    DataTypePtr get_return_type_impl(const DataTypes&) const override {
191
255
        return make_nullable(std::make_shared<DataTypeDateTimeV2>(3));
192
255
    }
193
    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
194
199
                        uint32_t result, size_t rows) const override {
195
199
        cctz::time_zone timezone = context->state()->timezone_obj();
196
199
        if (arguments.size() == 2) {
197
137
            auto zone_column =
198
137
                    block.get_by_position(arguments[1]).column->convert_to_full_column_if_const();
199
137
            if (rows > 0) {
200
137
                auto zone = assert_cast<const ColumnString&>(*zone_column).get_data_at(0);
201
137
                if (!TimezoneUtils::find_cctz_time_zone(zone.to_string(), timezone)) {
202
3
                    return Status::InvalidArgument("Invalid timezone: {}", zone.to_string());
203
3
                }
204
137
            }
205
137
        }
206
196
        const auto& input =
207
196
                assert_cast<const ColumnUUID&>(*block.get_by_position(arguments[0]).column);
208
196
        auto output = ColumnDateTimeV2::create(rows);
209
196
        auto nulls = ColumnUInt8::create(rows, 0);
210
25.7k
        for (size_t i = 0; i < rows; ++i) {
211
25.5k
            auto uuid = input.get_element(i);
212
25.5k
            uint64_t millis = UUIDValue::version(uuid) == 7 ? static_cast<uint64_t>(uuid >> 80) : 0;
213
25.5k
            DateV2Value<DateTimeV2ValueType> datetime;
214
25.5k
            datetime.from_unixtime(millis / 1000, (millis % 1000) * 1000000, timezone, 3);
215
            // The UUID timestamp domain extends beyond Doris DATETIME's year 9999.
216
25.5k
            if (!datetime.is_valid_date()) {
217
56
                nulls->get_data()[i] = 1;
218
25.5k
            } else {
219
25.5k
                output->get_data()[i] = datetime;
220
25.5k
            }
221
25.5k
        }
222
196
        block.replace_by_position(result,
223
196
                                  ColumnNullable::create(std::move(output), std::move(nulls)));
224
196
        return Status::OK();
225
199
    }
226
};
227
228
// The caller supplies a timestamp, so a previous wall-clock UUID must not replace it.
229
// Keep a separate counter for this generator; a change of input timestamp resets the counter.
230
struct UUIDTimestampCounter {
231
    uint64_t input_timestamp = 0;
232
    uint64_t timestamp = 0;
233
    uint64_t counter = 0;
234
25.8k
    UUIDValueType next(UUIDValueType random, uint64_t millis) {
235
25.8k
        constexpr uint64_t counter_limit = uint64_t {1} << 42;
236
25.8k
        if (input_timestamp == millis && counter != 0) {
237
25.6k
            ++counter;
238
25.6k
        } else {
239
220
            input_timestamp = millis;
240
220
            timestamp = millis;
241
220
            counter = (static_cast<uint64_t>(random >> 32) & ((uint64_t {1} << 41) - 1)) + 1;
242
220
        }
243
25.8k
        if (counter == counter_limit) {
244
0
            ++timestamp;
245
0
            counter = 1;
246
0
        }
247
25.8k
        return (static_cast<UUIDValueType>(timestamp) << 80) | (UUIDValueType {7} << 76) |
248
25.8k
               (static_cast<UUIDValueType>(counter >> 30) << 64) | (UUIDValueType {2} << 62) |
249
25.8k
               (static_cast<UUIDValueType>(counter & ((uint64_t {1} << 30) - 1)) << 32) |
250
25.8k
               (random & 0xffffffff);
251
25.8k
    }
252
};
253
254
class FunctionDateTimeToUUIDv7 : public IFunction {
255
public:
256
    static constexpr auto name = "datetime_to_uuid_v7";
257
283
    static FunctionPtr create() { return std::make_shared<FunctionDateTimeToUUIDv7>(); }
258
0
    String get_name() const override { return name; }
259
276
    size_t get_number_of_arguments() const override { return 1; }
260
1.81k
    bool use_default_implementation_for_constants() const override { return false; }
261
276
    DataTypePtr get_return_type_impl(const DataTypes&) const override {
262
276
        return make_nullable(std::make_shared<DataTypeUUID>());
263
276
    }
264
    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
265
246
                        uint32_t result, size_t rows) const override {
266
246
        auto input = block.get_by_position(arguments[0]).column->convert_to_full_column_if_const();
267
246
        const auto& dates = assert_cast<const ColumnDateTimeV2&>(*input).get_data();
268
246
        auto output = ColumnUUID::create(rows, 0);
269
246
        auto nulls = ColumnUInt8::create(rows, 0);
270
246
        std::vector<uint64_t> timestamps(rows);
271
246
        UUIDValue::generate(output->get_data().data(), rows, false);
272
26.7k
        for (size_t i = 0; i < rows; ++i) {
273
26.5k
            auto datetime = dates[i];
274
26.5k
            int64_t seconds = -1;
275
26.5k
            if (datetime.is_valid_date()) {
276
26.5k
                datetime.unix_timestamp(&seconds, context->state()->timezone_obj());
277
26.5k
            }
278
26.5k
            if (seconds < 0) {
279
660
                nulls->get_data()[i] = 1;
280
660
                output->get_data()[i] = 0;
281
25.8k
            } else {
282
25.8k
                timestamps[i] = seconds * 1000 + datetime.microsecond() / 1000;
283
25.8k
            }
284
26.5k
        }
285
246
        static std::mutex mutex;
286
246
        static UUIDTimestampCounter counter;
287
        // Only counter and UUID bit assembly run under the lock, once per batch.
288
246
        {
289
246
            std::lock_guard lock(mutex);
290
26.7k
            for (size_t i = 0; i < rows; ++i) {
291
26.5k
                if (!nulls->get_data()[i]) {
292
25.8k
                    output->get_data()[i] = counter.next(output->get_data()[i], timestamps[i]);
293
25.8k
                }
294
26.5k
            }
295
246
        }
296
246
        block.replace_by_position(result,
297
246
                                  ColumnNullable::create(std::move(output), std::move(nulls)));
298
246
        return Status::OK();
299
246
    }
300
};
301
302
} // namespace
303
304
class Uuid : public IFunction {
305
public:
306
    static constexpr auto name = "uuid";
307
    static constexpr size_t uuid_length = 36; //uuid fixed length
308
309
23
    static FunctionPtr create() { return std::make_shared<Uuid>(); }
310
311
1
    String get_name() const override { return name; }
312
313
40
    bool use_default_implementation_for_constants() const override { return false; }
314
315
14
    size_t get_number_of_arguments() const override { return 0; }
316
317
15
    bool is_variadic() const override { return false; }
318
319
14
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
320
14
        return std::make_shared<DataTypeString>();
321
14
    }
322
323
    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
324
14
                        uint32_t result, size_t input_rows_count) const override {
325
14
        auto col_res = ColumnString::create();
326
14
        col_res->get_offsets().reserve(input_rows_count);
327
14
        col_res->get_chars().reserve(input_rows_count * uuid_length);
328
329
14
        boost::uuids::random_generator generator;
330
182
        for (int i = 0; i < input_rows_count; i++) {
331
168
            std::string uuid = boost::uuids::to_string(generator());
332
168
            DCHECK(uuid.length() == uuid_length);
333
168
            col_res->insert_data_without_reserve(uuid.c_str(), uuid.length());
334
168
        }
335
336
14
        block.replace_by_position(result, std::move(col_res));
337
14
        return Status::OK();
338
14
    }
339
};
340
341
struct NameIsUuid {
342
    static constexpr auto name = "is_uuid";
343
};
344
345
struct IsUuidImpl {
346
    using ReturnType = DataTypeBool;
347
    using ReturnColumnType = ColumnUInt8;
348
    static constexpr auto PrimitiveTypeImpl = PrimitiveType::TYPE_STRING;
349
    static constexpr size_t uuid_without_dash_length = 32;
350
    static constexpr size_t uuid_with_dash_length = 36;
351
    static constexpr size_t uuid_with_braces_and_dash_length = 38;
352
    static constexpr size_t dash_positions[4] = {8, 13, 18, 23};
353
354
57
    static bool is_uuid_with_dash(const char* src, const char* end) {
355
57
        size_t str_size = end - src;
356
1.89k
        for (int i = 0; i < str_size; ++i) {
357
1.84k
            if (!is_hex_ascii(src[i])) {
358
213
                if (i == dash_positions[0] || i == dash_positions[1] || i == dash_positions[2] ||
359
213
                    i == dash_positions[3]) {
360
201
                    if (src[i] != '-') {
361
0
                        return false;
362
0
                    }
363
201
                } else {
364
12
                    return false;
365
12
                }
366
213
            }
367
1.84k
        }
368
45
        return true;
369
57
    }
370
371
    static Status vector(const ColumnString::Chars& data, const ColumnString::Offsets& offsets,
372
56
                         PaddedPODArray<UInt8>& res) {
373
56
        size_t rows_count = offsets.size();
374
56
        res.resize(rows_count);
375
187
        for (size_t i = 0; i < rows_count; ++i) {
376
131
            const char* source = reinterpret_cast<const char*>(&data[offsets[i - 1]]);
377
131
            int str_size = offsets[i] - offsets[i - 1];
378
131
            if (str_size == uuid_without_dash_length) {
379
6
                bool is_valid = true;
380
195
                for (int j = 0; j < str_size; ++j) {
381
192
                    if (!is_hex_ascii(source[j])) {
382
3
                        is_valid = false;
383
3
                        break;
384
3
                    }
385
192
                }
386
6
                res[i] = is_valid;
387
125
            } else if (str_size == uuid_with_dash_length) {
388
51
                res[i] = is_uuid_with_dash(source, source + str_size);
389
74
            } else if (str_size == uuid_with_braces_and_dash_length) {
390
6
                if (source[0] != '{' || source[str_size - 1] != '}') {
391
0
                    res[i] = 0;
392
0
                    continue;
393
0
                }
394
6
                res[i] = is_uuid_with_dash(source + 1, source + str_size - 1);
395
68
            } else {
396
68
                res[i] = 0;
397
68
            }
398
131
        }
399
56
        return Status::OK();
400
56
    }
401
};
402
403
using FunctionIsUuid = FunctionUnaryToType<IsUuidImpl, NameIsUuid>;
404
405
8
void register_function_uuid(SimpleFunctionFactory& factory) {
406
8
    factory.register_function<Uuid>();
407
8
    factory.register_function<FunctionIsUuid>();
408
8
    factory.register_function<FunctionGenerateUUID<false>>();
409
8
    factory.register_function<FunctionGenerateUUID<true>>();
410
8
    factory.register_function<FunctionUUIDVersion>();
411
8
    factory.register_function<FunctionToUUID<UUIDParseMode::Zero>>();
412
8
    factory.register_function<FunctionToUUID<UUIDParseMode::Null>>();
413
8
    factory.register_function<FunctionToUUID<UUIDParseMode::Default>>();
414
8
    factory.register_function<FunctionUUIDv7ToDateTime>();
415
8
    factory.register_function<FunctionDateTimeToUUIDv7>();
416
8
    factory.register_alias("to_uuid_or_zero", "touuidorzero");
417
8
    factory.register_alias("to_uuid_or_null", "touuidornull");
418
8
    factory.register_alias("to_uuid_or_default", "touuidordefault");
419
8
    factory.register_alias("uuid_v7_to_datetime", "uuidv7todatetime");
420
8
    factory.register_alias("datetime_to_uuid_v7", "datetimetouuidv7");
421
8
    factory.register_alias(FunctionGenerateUUID<false>::name, "generate_uuid_v4");
422
8
    factory.register_alias(FunctionGenerateUUID<false>::name, "generateuuidv4");
423
8
    factory.register_alias(FunctionGenerateUUID<true>::name, "generate_uuid_v7");
424
8
    factory.register_alias(FunctionGenerateUUID<true>::name, "generateuuidv7");
425
8
}
426
427
} // namespace doris