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 |