Coverage Report

Created: 2026-09-29 04:23

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
4
    static FunctionPtr create() { return std::make_shared<FunctionGenerateUUID>(); }
function_uuid_test.cpp:_ZN5doris12_GLOBAL__N_120FunctionGenerateUUIDILb0EE6createEv
Line
Count
Source
63
2
    static FunctionPtr create() { return std::make_shared<FunctionGenerateUUID>(); }
function_uuid_test.cpp:_ZN5doris12_GLOBAL__N_120FunctionGenerateUUIDILb1EE6createEv
Line
Count
Source
63
2
    static FunctionPtr create() { return std::make_shared<FunctionGenerateUUID>(); }
64
65
2
    String get_name() const override { return name; }
function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb0EE8get_nameB5cxx11Ev
Line
Count
Source
65
1
    String get_name() const override { return name; }
function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb1EE8get_nameB5cxx11Ev
Line
Count
Source
65
1
    String get_name() const override { return name; }
66
67
0
    bool use_default_implementation_for_constants() const override { return false; }
Unexecuted instantiation: function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb0EE40use_default_implementation_for_constantsEv
Unexecuted instantiation: function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb1EE40use_default_implementation_for_constantsEv
68
69
0
    size_t get_number_of_arguments() const override { return 0; }
Unexecuted instantiation: function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb0EE23get_number_of_argumentsEv
Unexecuted instantiation: function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb1EE23get_number_of_argumentsEv
70
71
0
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
72
0
        return std::make_shared<DataTypeUUID>();
73
0
    }
Unexecuted instantiation: function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb0EE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS7_EE
Unexecuted instantiation: function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb1EE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS7_EE
74
75
    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
76
2
                        uint32_t result, size_t input_rows_count) const override {
77
2
        auto column = ColumnUUID::create(input_rows_count);
78
2
        auto& data = column->get_data();
79
2
        UUIDValue::generate(data.data(), input_rows_count, Version7);
80
2
        block.replace_by_position(result, std::move(column));
81
2
        return Status::OK();
82
2
    }
function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb0EE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
76
1
                        uint32_t result, size_t input_rows_count) const override {
77
1
        auto column = ColumnUUID::create(input_rows_count);
78
1
        auto& data = column->get_data();
79
1
        UUIDValue::generate(data.data(), input_rows_count, Version7);
80
1
        block.replace_by_position(result, std::move(column));
81
1
        return Status::OK();
82
1
    }
function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_120FunctionGenerateUUIDILb1EE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
76
1
                        uint32_t result, size_t input_rows_count) const override {
77
1
        auto column = ColumnUUID::create(input_rows_count);
78
1
        auto& data = column->get_data();
79
1
        UUIDValue::generate(data.data(), input_rows_count, Version7);
80
1
        block.replace_by_position(result, std::move(column));
81
1
        return Status::OK();
82
1
    }
83
};
84
85
class FunctionUUIDVersion : public IFunction {
86
public:
87
    static constexpr auto name = "uuid_version";
88
89
2
    static FunctionPtr create() { return std::make_shared<FunctionUUIDVersion>(); }
90
91
1
    String get_name() const override { return name; }
92
93
0
    size_t get_number_of_arguments() const override { return 1; }
94
95
0
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
96
0
        return std::make_shared<DataTypeInt8>();
97
0
    }
98
99
    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
100
1
                        uint32_t result, size_t input_rows_count) const override {
101
1
        const auto& input =
102
1
                assert_cast<const ColumnUUID&>(*block.get_by_position(arguments[0]).column);
103
1
        auto output = ColumnInt8::create(input_rows_count);
104
1
        auto& output_data = output->get_data();
105
3
        for (size_t i = 0; i < input_rows_count; ++i) {
106
2
            output_data[i] = static_cast<Int8>(UUIDValue::version(input.get_element(i)));
107
2
        }
108
1
        block.replace_by_position(result, std::move(output));
109
1
        return Status::OK();
110
1
    }
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
6
    static FunctionPtr create() { return std::make_shared<FunctionToUUID>(); }
function_uuid_test.cpp:_ZN5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE0EE6createEv
Line
Count
Source
122
2
    static FunctionPtr create() { return std::make_shared<FunctionToUUID>(); }
function_uuid_test.cpp:_ZN5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE1EE6createEv
Line
Count
Source
122
2
    static FunctionPtr create() { return std::make_shared<FunctionToUUID>(); }
function_uuid_test.cpp:_ZN5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE2EE6createEv
Line
Count
Source
122
2
    static FunctionPtr create() { return std::make_shared<FunctionToUUID>(); }
123
2
    String get_name() const override { return name; }
function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE0EE8get_nameB5cxx11Ev
Line
Count
Source
123
1
    String get_name() const override { return name; }
function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE1EE8get_nameB5cxx11Ev
Line
Count
Source
123
1
    String get_name() const override { return name; }
Unexecuted instantiation: function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE2EE8get_nameB5cxx11Ev
124
0
    size_t get_number_of_arguments() const override {
125
0
        return Mode == UUIDParseMode::Default ? 0 : 1;
126
0
    }
Unexecuted instantiation: function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE0EE23get_number_of_argumentsEv
Unexecuted instantiation: function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE1EE23get_number_of_argumentsEv
Unexecuted instantiation: function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE2EE23get_number_of_argumentsEv
127
3
    bool is_variadic() const override { return Mode == UUIDParseMode::Default; }
function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE0EE11is_variadicEv
Line
Count
Source
127
1
    bool is_variadic() const override { return Mode == UUIDParseMode::Default; }
function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE1EE11is_variadicEv
Line
Count
Source
127
1
    bool is_variadic() const override { return Mode == UUIDParseMode::Default; }
function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE2EE11is_variadicEv
Line
Count
Source
127
1
    bool is_variadic() const override { return Mode == UUIDParseMode::Default; }
128
0
    bool use_default_implementation_for_nulls() const override { return false; }
Unexecuted instantiation: function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE0EE36use_default_implementation_for_nullsEv
Unexecuted instantiation: function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE1EE36use_default_implementation_for_nullsEv
Unexecuted instantiation: function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE2EE36use_default_implementation_for_nullsEv
129
0
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
130
0
        bool nullable = Mode == UUIDParseMode::Null ||
131
0
                        (Mode == UUIDParseMode::Zero && arguments[0]->is_nullable()) ||
132
0
                        (Mode == UUIDParseMode::Default && arguments.size() == 2 &&
133
0
                         arguments[1]->is_nullable());
134
0
        DataTypePtr type = std::make_shared<DataTypeUUID>();
135
0
        return nullable ? make_nullable(type) : type;
136
0
    }
Unexecuted instantiation: function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE0EE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS8_EE
Unexecuted instantiation: function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE1EE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS8_EE
Unexecuted instantiation: function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE2EE20get_return_type_implERKSt6vectorISt10shared_ptrIKNS_9IDataTypeEESaIS8_EE
137
    Status execute_impl(FunctionContext*, Block& block, const ColumnNumbers& arguments,
138
6
                        uint32_t result, size_t rows) const override {
139
6
        auto input = block.get_by_position(arguments[0]).column->convert_to_full_column_if_const();
140
6
        const auto* nullable_input = check_and_get_column<ColumnNullable>(*input);
141
6
        const auto& strings = assert_cast<const ColumnString&>(
142
6
                nullable_input ? nullable_input->get_nested_column() : *input);
143
6
        ColumnPtr fallback;
144
6
        const ColumnNullable* nullable_fallback = nullptr;
145
6
        const ColumnUUID* fallback_values = nullptr;
146
6
        if constexpr (Mode == UUIDParseMode::Default) {
147
2
            if (arguments.size() == 2) {
148
2
                fallback = block.get_by_position(arguments[1])
149
2
                                   .column->convert_to_full_column_if_const();
150
2
                nullable_fallback = check_and_get_column<ColumnNullable>(*fallback);
151
2
                fallback_values = &assert_cast<const ColumnUUID&>(
152
2
                        nullable_fallback ? nullable_fallback->get_nested_column() : *fallback);
153
2
            }
154
2
        }
155
6
        auto output = ColumnUUID::create(rows, 0);
156
6
        auto nulls = ColumnUInt8::create(rows, 0);
157
24
        for (size_t i = 0; i < rows; ++i) {
158
18
            bool source_null = nullable_input && nullable_input->is_null_at(i);
159
18
            UUIDValueType value = 0;
160
18
            auto text = strings.get_data_at(i);
161
18
            bool parsed = !source_null && UUIDValue::from_string(value, text.data, text.size);
162
18
            if (parsed) {
163
3
                output->get_data()[i] = value;
164
5
            } else if constexpr (Mode == UUIDParseMode::Default) {
165
5
                if (fallback_values) {
166
5
                    output->get_data()[i] = fallback_values->get_element(i);
167
5
                    nulls->get_data()[i] = nullable_fallback && nullable_fallback->is_null_at(i);
168
5
                }
169
10
            } else {
170
10
                nulls->get_data()[i] = Mode == UUIDParseMode::Null || source_null;
171
10
            }
172
18
        }
173
6
        if (block.get_by_position(result).type->is_nullable()) {
174
6
            block.replace_by_position(result,
175
6
                                      ColumnNullable::create(std::move(output), std::move(nulls)));
176
6
        } else {
177
0
            block.replace_by_position(result, std::move(output));
178
0
        }
179
6
        return Status::OK();
180
6
    }
function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE0EE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
138
2
                        uint32_t result, size_t rows) const override {
139
2
        auto input = block.get_by_position(arguments[0]).column->convert_to_full_column_if_const();
140
2
        const auto* nullable_input = check_and_get_column<ColumnNullable>(*input);
141
2
        const auto& strings = assert_cast<const ColumnString&>(
142
2
                nullable_input ? nullable_input->get_nested_column() : *input);
143
2
        ColumnPtr fallback;
144
2
        const ColumnNullable* nullable_fallback = nullptr;
145
2
        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
2
        auto output = ColumnUUID::create(rows, 0);
156
2
        auto nulls = ColumnUInt8::create(rows, 0);
157
8
        for (size_t i = 0; i < rows; ++i) {
158
6
            bool source_null = nullable_input && nullable_input->is_null_at(i);
159
6
            UUIDValueType value = 0;
160
6
            auto text = strings.get_data_at(i);
161
6
            bool parsed = !source_null && UUIDValue::from_string(value, text.data, text.size);
162
6
            if (parsed) {
163
1
                output->get_data()[i] = value;
164
1
            } 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
5
            } else {
170
5
                nulls->get_data()[i] = Mode == UUIDParseMode::Null || source_null;
171
5
            }
172
6
        }
173
2
        if (block.get_by_position(result).type->is_nullable()) {
174
2
            block.replace_by_position(result,
175
2
                                      ColumnNullable::create(std::move(output), std::move(nulls)));
176
2
        } else {
177
0
            block.replace_by_position(result, std::move(output));
178
0
        }
179
2
        return Status::OK();
180
2
    }
function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE1EE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
138
2
                        uint32_t result, size_t rows) const override {
139
2
        auto input = block.get_by_position(arguments[0]).column->convert_to_full_column_if_const();
140
2
        const auto* nullable_input = check_and_get_column<ColumnNullable>(*input);
141
2
        const auto& strings = assert_cast<const ColumnString&>(
142
2
                nullable_input ? nullable_input->get_nested_column() : *input);
143
2
        ColumnPtr fallback;
144
2
        const ColumnNullable* nullable_fallback = nullptr;
145
2
        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
2
        auto output = ColumnUUID::create(rows, 0);
156
2
        auto nulls = ColumnUInt8::create(rows, 0);
157
8
        for (size_t i = 0; i < rows; ++i) {
158
6
            bool source_null = nullable_input && nullable_input->is_null_at(i);
159
6
            UUIDValueType value = 0;
160
6
            auto text = strings.get_data_at(i);
161
6
            bool parsed = !source_null && UUIDValue::from_string(value, text.data, text.size);
162
6
            if (parsed) {
163
1
                output->get_data()[i] = value;
164
1
            } 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
5
            } else {
170
5
                nulls->get_data()[i] = Mode == UUIDParseMode::Null || source_null;
171
5
            }
172
6
        }
173
2
        if (block.get_by_position(result).type->is_nullable()) {
174
2
            block.replace_by_position(result,
175
2
                                      ColumnNullable::create(std::move(output), std::move(nulls)));
176
2
        } else {
177
0
            block.replace_by_position(result, std::move(output));
178
0
        }
179
2
        return Status::OK();
180
2
    }
function_uuid_test.cpp:_ZNK5doris12_GLOBAL__N_114FunctionToUUIDILNS0_13UUIDParseModeE2EE12execute_implEPNS_15FunctionContextERNS_5BlockERKSt6vectorIjSaIjEEjm
Line
Count
Source
138
2
                        uint32_t result, size_t rows) const override {
139
2
        auto input = block.get_by_position(arguments[0]).column->convert_to_full_column_if_const();
140
2
        const auto* nullable_input = check_and_get_column<ColumnNullable>(*input);
141
2
        const auto& strings = assert_cast<const ColumnString&>(
142
2
                nullable_input ? nullable_input->get_nested_column() : *input);
143
2
        ColumnPtr fallback;
144
2
        const ColumnNullable* nullable_fallback = nullptr;
145
2
        const ColumnUUID* fallback_values = nullptr;
146
2
        if constexpr (Mode == UUIDParseMode::Default) {
147
2
            if (arguments.size() == 2) {
148
2
                fallback = block.get_by_position(arguments[1])
149
2
                                   .column->convert_to_full_column_if_const();
150
2
                nullable_fallback = check_and_get_column<ColumnNullable>(*fallback);
151
2
                fallback_values = &assert_cast<const ColumnUUID&>(
152
2
                        nullable_fallback ? nullable_fallback->get_nested_column() : *fallback);
153
2
            }
154
2
        }
155
2
        auto output = ColumnUUID::create(rows, 0);
156
2
        auto nulls = ColumnUInt8::create(rows, 0);
157
8
        for (size_t i = 0; i < rows; ++i) {
158
6
            bool source_null = nullable_input && nullable_input->is_null_at(i);
159
6
            UUIDValueType value = 0;
160
6
            auto text = strings.get_data_at(i);
161
6
            bool parsed = !source_null && UUIDValue::from_string(value, text.data, text.size);
162
6
            if (parsed) {
163
1
                output->get_data()[i] = value;
164
5
            } else if constexpr (Mode == UUIDParseMode::Default) {
165
5
                if (fallback_values) {
166
5
                    output->get_data()[i] = fallback_values->get_element(i);
167
5
                    nulls->get_data()[i] = nullable_fallback && nullable_fallback->is_null_at(i);
168
5
                }
169
            } else {
170
                nulls->get_data()[i] = Mode == UUIDParseMode::Null || source_null;
171
            }
172
6
        }
173
2
        if (block.get_by_position(result).type->is_nullable()) {
174
2
            block.replace_by_position(result,
175
2
                                      ColumnNullable::create(std::move(output), std::move(nulls)));
176
2
        } else {
177
0
            block.replace_by_position(result, std::move(output));
178
0
        }
179
2
        return Status::OK();
180
2
    }
181
};
182
183
class FunctionUUIDv7ToDateTime : public IFunction {
184
public:
185
    static constexpr auto name = "uuid_v7_to_datetime";
186
2
    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
1
    bool is_variadic() const override { return true; }
190
0
    DataTypePtr get_return_type_impl(const DataTypes&) const override {
191
0
        return make_nullable(std::make_shared<DataTypeDateTimeV2>(3));
192
0
    }
193
    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
194
2
                        uint32_t result, size_t rows) const override {
195
2
        cctz::time_zone timezone = context->state()->timezone_obj();
196
2
        if (arguments.size() == 2) {
197
0
            auto zone_column =
198
0
                    block.get_by_position(arguments[1]).column->convert_to_full_column_if_const();
199
0
            if (rows > 0) {
200
0
                auto zone = assert_cast<const ColumnString&>(*zone_column).get_data_at(0);
201
0
                if (!TimezoneUtils::find_cctz_time_zone(zone.to_string(), timezone)) {
202
0
                    return Status::InvalidArgument("Invalid timezone: {}", zone.to_string());
203
0
                }
204
0
            }
205
0
        }
206
2
        const auto& input =
207
2
                assert_cast<const ColumnUUID&>(*block.get_by_position(arguments[0]).column);
208
2
        auto output = ColumnDateTimeV2::create(rows);
209
2
        auto nulls = ColumnUInt8::create(rows, 0);
210
67
        for (size_t i = 0; i < rows; ++i) {
211
65
            auto uuid = input.get_element(i);
212
65
            uint64_t millis = UUIDValue::version(uuid) == 7 ? static_cast<uint64_t>(uuid >> 80) : 0;
213
65
            DateV2Value<DateTimeV2ValueType> datetime;
214
65
            datetime.from_unixtime(millis / 1000, (millis % 1000) * 1000000, timezone, 3);
215
            // The UUID timestamp domain extends beyond Doris DATETIME's year 9999.
216
65
            if (!datetime.is_valid_date()) {
217
1
                nulls->get_data()[i] = 1;
218
64
            } else {
219
64
                output->get_data()[i] = datetime;
220
64
            }
221
65
        }
222
2
        block.replace_by_position(result,
223
2
                                  ColumnNullable::create(std::move(output), std::move(nulls)));
224
2
        return Status::OK();
225
2
    }
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
71
    UUIDValueType next(UUIDValueType random, uint64_t millis) {
235
71
        constexpr uint64_t counter_limit = uint64_t {1} << 42;
236
71
        if (input_timestamp == millis && counter != 0) {
237
66
            ++counter;
238
66
        } else {
239
5
            input_timestamp = millis;
240
5
            timestamp = millis;
241
5
            counter = (static_cast<uint64_t>(random >> 32) & ((uint64_t {1} << 41) - 1)) + 1;
242
5
        }
243
71
        if (counter == counter_limit) {
244
1
            ++timestamp;
245
1
            counter = 1;
246
1
        }
247
71
        return (static_cast<UUIDValueType>(timestamp) << 80) | (UUIDValueType {7} << 76) |
248
71
               (static_cast<UUIDValueType>(counter >> 30) << 64) | (UUIDValueType {2} << 62) |
249
71
               (static_cast<UUIDValueType>(counter & ((uint64_t {1} << 30) - 1)) << 32) |
250
71
               (random & 0xffffffff);
251
71
    }
252
};
253
254
class FunctionDateTimeToUUIDv7 : public IFunction {
255
public:
256
    static constexpr auto name = "datetime_to_uuid_v7";
257
2
    static FunctionPtr create() { return std::make_shared<FunctionDateTimeToUUIDv7>(); }
258
1
    String get_name() const override { return name; }
259
0
    size_t get_number_of_arguments() const override { return 1; }
260
0
    bool use_default_implementation_for_constants() const override { return false; }
261
0
    DataTypePtr get_return_type_impl(const DataTypes&) const override {
262
0
        return make_nullable(std::make_shared<DataTypeUUID>());
263
0
    }
264
    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
265
1
                        uint32_t result, size_t rows) const override {
266
1
        auto input = block.get_by_position(arguments[0]).column->convert_to_full_column_if_const();
267
1
        const auto& dates = assert_cast<const ColumnDateTimeV2&>(*input).get_data();
268
1
        auto output = ColumnUUID::create(rows, 0);
269
1
        auto nulls = ColumnUInt8::create(rows, 0);
270
1
        std::vector<uint64_t> timestamps(rows);
271
1
        UUIDValue::generate(output->get_data().data(), rows, false);
272
65
        for (size_t i = 0; i < rows; ++i) {
273
64
            auto datetime = dates[i];
274
64
            int64_t seconds = -1;
275
64
            if (datetime.is_valid_date()) {
276
64
                datetime.unix_timestamp(&seconds, context->state()->timezone_obj());
277
64
            }
278
64
            if (seconds < 0) {
279
0
                nulls->get_data()[i] = 1;
280
0
                output->get_data()[i] = 0;
281
64
            } else {
282
64
                timestamps[i] = seconds * 1000 + datetime.microsecond() / 1000;
283
64
            }
284
64
        }
285
1
        static std::mutex mutex;
286
1
        static UUIDTimestampCounter counter;
287
        // Only counter and UUID bit assembly run under the lock, once per batch.
288
1
        {
289
1
            std::lock_guard lock(mutex);
290
65
            for (size_t i = 0; i < rows; ++i) {
291
64
                if (!nulls->get_data()[i]) {
292
64
                    output->get_data()[i] = counter.next(output->get_data()[i], timestamps[i]);
293
64
                }
294
64
            }
295
1
        }
296
1
        block.replace_by_position(result,
297
1
                                  ColumnNullable::create(std::move(output), std::move(nulls)));
298
1
        return Status::OK();
299
1
    }
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
2
    static FunctionPtr create() { return std::make_shared<Uuid>(); }
310
311
1
    String get_name() const override { return name; }
312
313
0
    bool use_default_implementation_for_constants() const override { return false; }
314
315
0
    size_t get_number_of_arguments() const override { return 0; }
316
317
1
    bool is_variadic() const override { return false; }
318
319
0
    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
320
0
        return std::make_shared<DataTypeString>();
321
0
    }
322
323
    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
324
0
                        uint32_t result, size_t input_rows_count) const override {
325
0
        auto col_res = ColumnString::create();
326
0
        col_res->get_offsets().reserve(input_rows_count);
327
0
        col_res->get_chars().reserve(input_rows_count * uuid_length);
328
329
0
        boost::uuids::random_generator generator;
330
0
        for (int i = 0; i < input_rows_count; i++) {
331
0
            std::string uuid = boost::uuids::to_string(generator());
332
0
            DCHECK(uuid.length() == uuid_length);
333
0
            col_res->insert_data_without_reserve(uuid.c_str(), uuid.length());
334
0
        }
335
336
0
        block.replace_by_position(result, std::move(col_res));
337
0
        return Status::OK();
338
0
    }
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
24
    static bool is_uuid_with_dash(const char* src, const char* end) {
355
24
        size_t str_size = end - src;
356
444
        for (size_t i = 0; i < str_size; ++i) {
357
440
            if (i == dash_positions[0] || i == dash_positions[1] || i == dash_positions[2] ||
358
440
                i == dash_positions[3]) {
359
                // The four separators must be dashes at the fixed positions of the
360
                // 8-4-4-4-12 layout, hex digits are not accepted here.
361
50
                if (src[i] != '-') {
362
12
                    return false;
363
12
                }
364
390
            } else if (!is_hex_ascii(src[i])) {
365
8
                return false;
366
8
            }
367
440
        }
368
4
        return true;
369
24
    }
370
371
    static Status vector(const ColumnString::Chars& data, const ColumnString::Offsets& offsets,
372
22
                         PaddedPODArray<UInt8>& res) {
373
22
        size_t rows_count = offsets.size();
374
22
        res.resize(rows_count);
375
65
        for (size_t i = 0; i < rows_count; ++i) {
376
43
            const char* source = reinterpret_cast<const char*>(&data[offsets[i - 1]]);
377
43
            int str_size = offsets[i] - offsets[i - 1];
378
43
            if (str_size == uuid_without_dash_length) {
379
6
                bool is_valid = true;
380
196
                for (int j = 0; j < str_size; ++j) {
381
192
                    if (!is_hex_ascii(source[j])) {
382
2
                        is_valid = false;
383
2
                        break;
384
2
                    }
385
192
                }
386
6
                res[i] = is_valid;
387
37
            } else if (str_size == uuid_with_dash_length) {
388
18
                res[i] = is_uuid_with_dash(source, source + str_size);
389
19
            } 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
13
            } else {
396
13
                res[i] = 0;
397
13
            }
398
43
        }
399
22
        return Status::OK();
400
22
    }
401
};
402
403
using FunctionIsUuid = FunctionUnaryToType<IsUuidImpl, NameIsUuid>;
404
405
1
void register_function_uuid(SimpleFunctionFactory& factory) {
406
1
    factory.register_function<Uuid>();
407
1
    factory.register_function<FunctionIsUuid>();
408
1
    factory.register_function<FunctionGenerateUUID<false>>();
409
1
    factory.register_function<FunctionGenerateUUID<true>>();
410
1
    factory.register_function<FunctionUUIDVersion>();
411
1
    factory.register_function<FunctionToUUID<UUIDParseMode::Zero>>();
412
1
    factory.register_function<FunctionToUUID<UUIDParseMode::Null>>();
413
1
    factory.register_function<FunctionToUUID<UUIDParseMode::Default>>();
414
1
    factory.register_function<FunctionUUIDv7ToDateTime>();
415
1
    factory.register_function<FunctionDateTimeToUUIDv7>();
416
1
    factory.register_alias("to_uuid_or_zero", "touuidorzero");
417
1
    factory.register_alias("to_uuid_or_null", "touuidornull");
418
1
    factory.register_alias("to_uuid_or_default", "touuidordefault");
419
1
    factory.register_alias("uuid_v7_to_datetime", "uuidv7todatetime");
420
1
    factory.register_alias("datetime_to_uuid_v7", "datetimetouuidv7");
421
1
    factory.register_alias(FunctionGenerateUUID<false>::name, "generate_uuid_v4");
422
1
    factory.register_alias(FunctionGenerateUUID<false>::name, "generateuuidv4");
423
1
    factory.register_alias(FunctionGenerateUUID<true>::name, "generate_uuid_v7");
424
1
    factory.register_alias(FunctionGenerateUUID<true>::name, "generateuuidv7");
425
1
}
426
427
} // namespace doris