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 "util/variant/variant_field.h" |
19 | | |
20 | | #include <algorithm> |
21 | | #include <cstring> |
22 | | #include <limits> |
23 | | #include <utility> |
24 | | #include <vector> |
25 | | |
26 | | #include "common/exception.h" |
27 | | #include "util/utf8_check.h" |
28 | | #include "util/variant/variant_encoding.h" |
29 | | |
30 | | namespace doris { |
31 | | namespace { |
32 | | |
33 | | constexpr size_t METADATA_SIZE_PREFIX = sizeof(uint32_t); |
34 | | constexpr unsigned __int128 DECIMAL4_MAX = 999'999'999; |
35 | | constexpr unsigned __int128 DECIMAL8_MAX = 999'999'999'999'999'999; |
36 | | |
37 | 0 | constexpr unsigned __int128 max_decimal38() { |
38 | 0 | unsigned __int128 value = 1; |
39 | 0 | for (uint8_t digit = 0; digit < 38; ++digit) { |
40 | 0 | value *= 10; |
41 | 0 | } |
42 | 0 | return value - 1; |
43 | 0 | } |
44 | | |
45 | | constexpr unsigned __int128 MAX_DECIMAL38 = max_decimal38(); |
46 | | |
47 | 131k | uint32_t read_u32(const char* data) noexcept { |
48 | 131k | uint32_t result = 0; |
49 | 657k | for (uint8_t byte = 0; byte < METADATA_SIZE_PREFIX; ++byte) { |
50 | 525k | result |= static_cast<uint32_t>(static_cast<uint8_t>(data[byte])) << (byte * 8); |
51 | 525k | } |
52 | 131k | return result; |
53 | 131k | } |
54 | | |
55 | 232 | void write_u32(char* destination, uint32_t value) noexcept { |
56 | 1.16k | for (uint8_t byte = 0; byte < METADATA_SIZE_PREFIX; ++byte) { |
57 | 928 | destination[byte] = static_cast<char>(value >> (byte * 8)); |
58 | 928 | } |
59 | 232 | } |
60 | | |
61 | 1.61k | void require_non_null(StringRef bytes, const char* description) { |
62 | 1.61k | if (bytes.size != 0 && bytes.data == nullptr) { |
63 | 3 | throw Exception(ErrorCode::INVALID_ARGUMENT, |
64 | 3 | "VariantField {} has a null pointer for {} bytes", description, bytes.size); |
65 | 3 | } |
66 | 1.61k | } |
67 | | |
68 | 20 | unsigned __int128 magnitude(__int128 value) { |
69 | 20 | const auto unsigned_value = static_cast<unsigned __int128>(value); |
70 | 20 | return value < 0 ? ~unsigned_value + 1 : unsigned_value; |
71 | 20 | } |
72 | | |
73 | 392 | void require_valid_utf8(StringRef value, const char* description) { |
74 | 392 | if (value.size != 0 && !validate_utf8(value.data, value.size)) { |
75 | 10 | throw Exception(ErrorCode::CORRUPTION, "VariantField {} is not valid UTF-8", description); |
76 | 10 | } |
77 | 392 | } |
78 | | |
79 | 20 | void require_decimal_in_range(const VariantDecimal& decimal) { |
80 | 20 | unsigned __int128 maximum = MAX_DECIMAL38; |
81 | 20 | if (decimal.width == 4) { |
82 | 2 | maximum = DECIMAL4_MAX; |
83 | 18 | } else if (decimal.width == 8) { |
84 | 4 | maximum = DECIMAL8_MAX; |
85 | 4 | } |
86 | 20 | if (magnitude(decimal.unscaled) > maximum) { |
87 | 8 | throw Exception(ErrorCode::CORRUPTION, |
88 | 8 | "VariantField decimal unscaled value exceeds precision for width {}", |
89 | 8 | decimal.width); |
90 | 8 | } |
91 | 20 | } |
92 | | |
93 | 789 | void require_valid_primitive(VariantValueRef value) { |
94 | 789 | switch (value.primitive_id()) { |
95 | 95 | case VariantPrimitiveId::NULL_VALUE: |
96 | 160 | case VariantPrimitiveId::TRUE_VALUE: |
97 | 160 | case VariantPrimitiveId::FALSE_VALUE: |
98 | 160 | return; |
99 | 467 | case VariantPrimitiveId::INT8: |
100 | 471 | case VariantPrimitiveId::INT16: |
101 | 474 | case VariantPrimitiveId::INT32: |
102 | 485 | case VariantPrimitiveId::INT64: |
103 | 485 | static_cast<void>(value.get_int()); |
104 | 485 | return; |
105 | 26 | case VariantPrimitiveId::DOUBLE: |
106 | 26 | static_cast<void>(value.get_double()); |
107 | 26 | return; |
108 | 4 | case VariantPrimitiveId::DECIMAL4: |
109 | 8 | case VariantPrimitiveId::DECIMAL8: |
110 | 22 | case VariantPrimitiveId::DECIMAL16: |
111 | 22 | require_decimal_in_range(value.get_decimal()); |
112 | 22 | return; |
113 | 16 | case VariantPrimitiveId::DATE: |
114 | 16 | static_cast<void>(value.get_date()); |
115 | 16 | return; |
116 | 27 | case VariantPrimitiveId::TIMESTAMP_MICROS: |
117 | 27 | static_cast<void>(value.get_timestamp_micros()); |
118 | 27 | return; |
119 | 27 | case VariantPrimitiveId::TIMESTAMP_NTZ_MICROS: |
120 | 27 | static_cast<void>(value.get_timestamp_ntz_micros()); |
121 | 27 | return; |
122 | 0 | case VariantPrimitiveId::FLOAT: |
123 | 0 | static_cast<void>(value.get_float()); |
124 | 0 | return; |
125 | 2 | case VariantPrimitiveId::BINARY: |
126 | 2 | static_cast<void>(value.get_binary()); |
127 | 2 | return; |
128 | 18 | case VariantPrimitiveId::STRING: |
129 | 18 | require_valid_utf8(value.get_string(), "string"); |
130 | 18 | return; |
131 | 0 | case VariantPrimitiveId::TIME_NTZ_MICROS: |
132 | 0 | static_cast<void>(value.get_time_ntz_micros()); |
133 | 0 | return; |
134 | 2 | case VariantPrimitiveId::TIMESTAMP_NANOS: |
135 | 2 | static_cast<void>(value.get_timestamp_nanos()); |
136 | 2 | return; |
137 | 4 | case VariantPrimitiveId::TIMESTAMP_NTZ_NANOS: |
138 | 4 | static_cast<void>(value.get_timestamp_ntz_nanos()); |
139 | 4 | return; |
140 | 0 | case VariantPrimitiveId::UUID: |
141 | 0 | static_cast<void>(value.get_uuid()); |
142 | 0 | return; |
143 | 789 | } |
144 | 0 | throw Exception(ErrorCode::CORRUPTION, "VariantField contains an unknown primitive type"); |
145 | 789 | } |
146 | | |
147 | | void require_exact_value(VariantValueRef value, uint32_t depth); |
148 | | |
149 | | struct ObjectValueSpan { |
150 | | size_t offset; |
151 | | size_t size; |
152 | | }; |
153 | | |
154 | 250 | size_t object_values_offset(VariantValueRef value, uint32_t count) { |
155 | 250 | const uint8_t value_header = static_cast<uint8_t>(value.data[0]) >> VARIANT_VALUE_HEADER_SHIFT; |
156 | 250 | const auto offset_width = |
157 | 250 | static_cast<uint8_t>(((value_header >> VARIANT_OBJECT_OFFSET_SIZE_SHIFT) & 0x03U) + 1); |
158 | 250 | const auto id_width = |
159 | 250 | static_cast<uint8_t>(((value_header >> VARIANT_OBJECT_ID_SIZE_SHIFT) & 0x03U) + 1); |
160 | 250 | const size_t count_width = |
161 | 250 | (value_header & VARIANT_OBJECT_LARGE_MASK) != 0 ? sizeof(uint32_t) : sizeof(uint8_t); |
162 | 250 | return 1 + count_width + static_cast<size_t>(count) * id_width + |
163 | 250 | (static_cast<size_t>(count) + 1) * offset_width; |
164 | 250 | } |
165 | | |
166 | 250 | void require_valid_object(VariantValueRef value, uint32_t depth) { |
167 | 250 | const uint32_t count = value.num_elements(); |
168 | 250 | const size_t values_offset = object_values_offset(value, count); |
169 | 250 | const char* values_begin = value.data + values_offset; |
170 | 250 | const size_t values_size = value.size - values_offset; |
171 | 250 | std::vector<ObjectValueSpan> spans; |
172 | 250 | spans.reserve(count); |
173 | | |
174 | 250 | StringRef previous_key; |
175 | 566 | for (uint32_t index = 0; index < count; ++index) { |
176 | 320 | uint32_t field_id = 0; |
177 | 320 | const VariantValueRef child = value.object_value_at(index, &field_id); |
178 | 320 | const StringRef key = value.metadata.key_at(field_id); |
179 | 320 | if (index != 0 && previous_key.compare(key) >= 0) { |
180 | 4 | throw Exception(ErrorCode::CORRUPTION, |
181 | 4 | "VariantField object keys are not strictly ordered at field {}", index); |
182 | 4 | } |
183 | 316 | require_exact_value(child, depth + 1); |
184 | 316 | spans.push_back( |
185 | 316 | {.offset = static_cast<size_t>(child.data - values_begin), .size = child.size}); |
186 | 316 | previous_key = key; |
187 | 316 | } |
188 | | |
189 | 246 | std::ranges::sort(spans, [](const ObjectValueSpan& left, const ObjectValueSpan& right) { |
190 | 126 | return left.offset < right.offset; |
191 | 126 | }); |
192 | 246 | size_t consumed = 0; |
193 | 309 | for (const ObjectValueSpan& span : spans) { |
194 | 309 | if (span.offset < consumed) { |
195 | 6 | throw Exception(ErrorCode::CORRUPTION, |
196 | 6 | "VariantField object value spans overlap or reuse an offset"); |
197 | 6 | } |
198 | 303 | if (span.offset > consumed) { |
199 | 3 | throw Exception(ErrorCode::CORRUPTION, |
200 | 3 | "VariantField object values contain an unreferenced gap"); |
201 | 3 | } |
202 | 300 | consumed += span.size; |
203 | 300 | } |
204 | 237 | if (consumed != values_size) { |
205 | 2 | throw Exception(ErrorCode::CORRUPTION, |
206 | 2 | "VariantField object values contain unreferenced trailing bytes"); |
207 | 2 | } |
208 | 237 | } |
209 | | |
210 | 842 | void require_valid_array(VariantValueRef value, uint32_t depth) { |
211 | 842 | const uint32_t count = value.num_elements(); |
212 | 1.70k | for (uint32_t index = 0; index < count; ++index) { |
213 | 867 | require_exact_value(value.array_at(index), depth + 1); |
214 | 867 | } |
215 | 842 | } |
216 | | |
217 | 1.93k | void require_exact_value(VariantValueRef value, uint32_t depth) { |
218 | 1.93k | if (depth > VARIANT_MAX_NESTING_DEPTH) { |
219 | 2 | throw Exception(ErrorCode::CORRUPTION, |
220 | 2 | "VariantField value exceeds maximum nesting depth {}", |
221 | 2 | VARIANT_MAX_NESTING_DEPTH); |
222 | 2 | } |
223 | 1.93k | const size_t encoded_size = value.value_size(); |
224 | 1.93k | if (encoded_size != value.size) { |
225 | 3 | throw Exception(ErrorCode::CORRUPTION, |
226 | 3 | "VariantField value has {} trailing bytes after its {} byte root", |
227 | 3 | value.size - encoded_size, encoded_size); |
228 | 3 | } |
229 | | |
230 | 1.93k | switch (value.basic_type()) { |
231 | 789 | case VariantBasicType::PRIMITIVE: |
232 | 789 | require_valid_primitive(value); |
233 | 789 | return; |
234 | 47 | case VariantBasicType::SHORT_STRING: |
235 | 47 | require_valid_utf8(value.get_string(), "short string"); |
236 | 47 | return; |
237 | 250 | case VariantBasicType::OBJECT: |
238 | 250 | require_valid_object(value, depth); |
239 | 250 | return; |
240 | 842 | case VariantBasicType::ARRAY: |
241 | 842 | require_valid_array(value, depth); |
242 | 842 | return; |
243 | 1.93k | } |
244 | 0 | throw Exception(ErrorCode::CORRUPTION, "VariantField contains an unknown value type"); |
245 | 1.93k | } |
246 | | |
247 | | struct RowSlices { |
248 | | VariantMetadataRef metadata; |
249 | | VariantValueRef value; |
250 | | }; |
251 | | |
252 | 100 | RowSlices split_untrusted(StringRef bytes) { |
253 | 100 | require_non_null(bytes, "encoded row"); |
254 | 100 | if (bytes.size < METADATA_SIZE_PREFIX) { |
255 | 4 | throw Exception(ErrorCode::CORRUPTION, |
256 | 4 | "Truncated VariantField metadata-size prefix: need {} bytes, have {}", |
257 | 4 | METADATA_SIZE_PREFIX, bytes.size); |
258 | 4 | } |
259 | 96 | const uint32_t metadata_size = read_u32(bytes.data); |
260 | 96 | const size_t payload_size = bytes.size - METADATA_SIZE_PREFIX; |
261 | 96 | if (metadata_size > payload_size) { |
262 | 1 | throw Exception(ErrorCode::CORRUPTION, |
263 | 1 | "VariantField metadata size {} exceeds {} payload bytes", metadata_size, |
264 | 1 | payload_size); |
265 | 1 | } |
266 | 95 | VariantMetadataRef metadata {.data = bytes.data + METADATA_SIZE_PREFIX, .size = metadata_size}; |
267 | 95 | VariantValueRef value {.metadata = metadata, |
268 | 95 | .data = metadata.data + metadata.size, |
269 | 95 | .size = payload_size - metadata.size}; |
270 | 95 | return {.metadata = metadata, .value = value}; |
271 | 96 | } |
272 | | |
273 | 69 | std::unique_ptr<char[]> copy_bytes(StringRef bytes) { |
274 | 69 | auto result = std::make_unique<char[]>(bytes.size); |
275 | 69 | std::memcpy(result.get(), bytes.data, bytes.size); |
276 | 69 | return result; |
277 | 69 | } |
278 | | |
279 | 6 | [[noreturn]] void throw_comparison_not_supported() { |
280 | 6 | throw Exception(ErrorCode::NOT_IMPLEMENTED_ERROR, |
281 | 6 | "Comparison between VariantField values is not supported"); |
282 | 6 | } |
283 | | |
284 | | } // namespace |
285 | | |
286 | 758 | void validate_variant_metadata(VariantMetadataRef metadata) { |
287 | 758 | require_non_null({metadata.data, metadata.size}, "metadata"); |
288 | 758 | metadata.validate(); |
289 | 758 | const uint32_t key_count = metadata.dict_size(); |
290 | 1.08k | for (uint32_t id = 0; id < key_count; ++id) { |
291 | 327 | require_valid_utf8(metadata.key_at(id), "metadata key"); |
292 | 327 | } |
293 | 758 | } |
294 | | |
295 | 761 | void validate_variant_payload(VariantValueRef value) { |
296 | 761 | require_non_null({value.data, value.size}, "value"); |
297 | 761 | require_exact_value(value, 0); |
298 | 761 | } |
299 | | |
300 | | VariantField::VariantField(std::unique_ptr<char[]> data, size_t size) noexcept |
301 | 301 | : _data(std::move(data)), _size(size) {} |
302 | | |
303 | 3 | VariantField::VariantField(const VariantField& other) : _size(other._size) { |
304 | 3 | if (_size != 0) { |
305 | 3 | _data = std::make_unique<char[]>(_size); |
306 | 3 | std::memcpy(_data.get(), other._data.get(), _size); |
307 | 3 | } |
308 | 3 | } |
309 | | |
310 | | VariantField::VariantField(VariantField&& other) noexcept |
311 | 45 | : _data(std::move(other._data)), _size(std::exchange(other._size, 0)) {} |
312 | | |
313 | 2 | VariantField& VariantField::operator=(const VariantField& other) { |
314 | 2 | VariantField copy(other); |
315 | 2 | swap(copy); |
316 | 2 | return *this; |
317 | 2 | } |
318 | | |
319 | 2 | VariantField& VariantField::operator=(VariantField&& other) noexcept { |
320 | 2 | if (this != &other) { |
321 | 2 | _data = std::move(other._data); |
322 | 2 | _size = std::exchange(other._size, 0); |
323 | 2 | } |
324 | 2 | return *this; |
325 | 2 | } |
326 | | |
327 | 251 | VariantField VariantField::encode(VariantValueRef value) { |
328 | 251 | if (value.metadata.size > std::numeric_limits<uint32_t>::max()) { |
329 | 1 | throw Exception(ErrorCode::INVALID_ARGUMENT, |
330 | 1 | "VariantField metadata size {} exceeds uint32 limit", value.metadata.size); |
331 | 1 | } |
332 | 250 | if (value.metadata.size > std::numeric_limits<size_t>::max() - METADATA_SIZE_PREFIX) { |
333 | 0 | throw Exception(ErrorCode::INVALID_ARGUMENT, |
334 | 0 | "VariantField metadata size exceeds the addressable row size"); |
335 | 0 | } |
336 | 250 | const size_t value_offset = METADATA_SIZE_PREFIX + value.metadata.size; |
337 | 250 | if (value.size > std::numeric_limits<size_t>::max() - value_offset) { |
338 | 1 | throw Exception(ErrorCode::INVALID_ARGUMENT, |
339 | 1 | "VariantField value size exceeds the addressable row size"); |
340 | 1 | } |
341 | | |
342 | 249 | validate_variant_metadata(value.metadata); |
343 | 249 | validate_variant_payload(value); |
344 | 249 | const size_t total_size = value_offset + value.size; |
345 | 249 | auto data = std::make_unique<char[]>(total_size); |
346 | 249 | write_u32(data.get(), static_cast<uint32_t>(value.metadata.size)); |
347 | 249 | std::memcpy(data.get() + METADATA_SIZE_PREFIX, value.metadata.data, value.metadata.size); |
348 | 249 | std::memcpy(data.get() + value_offset, value.data, value.size); |
349 | 249 | return {std::move(data), total_size}; |
350 | 250 | } |
351 | | |
352 | 100 | VariantField VariantField::decode(StringRef bytes) { |
353 | 100 | const RowSlices slices = split_untrusted(bytes); |
354 | 100 | validate_variant_metadata(slices.metadata); |
355 | 100 | validate_variant_payload(slices.value); |
356 | 100 | return {copy_bytes(bytes), bytes.size}; |
357 | 100 | } |
358 | | |
359 | 131k | VariantValueRef VariantField::ref() const { |
360 | 131k | if (_size == 0) { |
361 | 3 | throw Exception(ErrorCode::INVALID_ARGUMENT, |
362 | 3 | "Cannot reference an empty or moved-from VariantField"); |
363 | 3 | } |
364 | 131k | DCHECK(_data != nullptr); |
365 | 131k | DCHECK_GE(_size, METADATA_SIZE_PREFIX); |
366 | 131k | const uint32_t metadata_size = read_u32(_data.get()); |
367 | 131k | DCHECK_LE(metadata_size, _size - METADATA_SIZE_PREFIX); |
368 | 131k | VariantMetadataRef metadata {.data = _data.get() + METADATA_SIZE_PREFIX, .size = metadata_size}; |
369 | 131k | return {.metadata = metadata, |
370 | 131k | .data = metadata.data + metadata.size, |
371 | 131k | .size = _size - METADATA_SIZE_PREFIX - metadata.size}; |
372 | 131k | } |
373 | | |
374 | 71 | StringRef VariantField::bytes() const noexcept { |
375 | 71 | return {_data.get(), _size}; |
376 | 71 | } |
377 | | |
378 | 1 | bool VariantField::operator<(const VariantField&) const { |
379 | 1 | throw_comparison_not_supported(); |
380 | 1 | } |
381 | | |
382 | 1 | bool VariantField::operator<=(const VariantField&) const { |
383 | 1 | throw_comparison_not_supported(); |
384 | 1 | } |
385 | | |
386 | 1 | bool VariantField::operator==(const VariantField&) const { |
387 | 1 | throw_comparison_not_supported(); |
388 | 1 | } |
389 | | |
390 | 1 | bool VariantField::operator!=(const VariantField&) const { |
391 | 1 | throw_comparison_not_supported(); |
392 | 1 | } |
393 | | |
394 | 1 | bool VariantField::operator>=(const VariantField&) const { |
395 | 1 | throw_comparison_not_supported(); |
396 | 1 | } |
397 | | |
398 | 1 | bool VariantField::operator>(const VariantField&) const { |
399 | 1 | throw_comparison_not_supported(); |
400 | 1 | } |
401 | | |
402 | 2 | void VariantField::swap(VariantField& other) noexcept { |
403 | 2 | _data.swap(other._data); |
404 | 2 | std::swap(_size, other._size); |
405 | 2 | } |
406 | | |
407 | | } // namespace doris |