be/src/util/jsonb_document.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2014, Facebook, Inc. |
3 | | * All rights reserved. |
4 | | * |
5 | | * This source code is licensed under the BSD-style license found in the |
6 | | * LICENSE file in the root directory of this source tree. An additional grant |
7 | | * of patent rights can be found in the PATENTS file in the same directory. |
8 | | * |
9 | | */ |
10 | | |
11 | | /* |
12 | | * This header defines JsonbDocument, JsonbKeyValue, and various value classes |
13 | | * which are derived from JsonbValue, and a forward iterator for container |
14 | | * values - essentially everything that is related to JSONB binary data |
15 | | * structures. |
16 | | * |
17 | | * Implementation notes: |
18 | | * |
19 | | * None of the classes in this header file can be instantiated directly (i.e. |
20 | | * you cannot create a JsonbKeyValue or JsonbValue object - all constructors |
21 | | * are declared non-public). We use the classes as wrappers on the packed JSONB |
22 | | * bytes (serialized), and cast the classes (types) to the underlying packed |
23 | | * byte array. |
24 | | * |
25 | | * For the same reason, we cannot define any JSONB value class to be virtual, |
26 | | * since we never call constructors, and will not instantiate vtbl and vptrs. |
27 | | * |
28 | | * Therefore, the classes are defined as packed structures (i.e. no data |
29 | | * alignment and padding), and the private member variables of the classes are |
30 | | * defined precisely in the same order as the JSONB spec. This ensures we |
31 | | * access the packed JSONB bytes correctly. |
32 | | * |
33 | | * The packed structures are highly optimized for in-place operations with low |
34 | | * overhead. The reads (and in-place writes) are performed directly on packed |
35 | | * bytes. There is no memory allocation at all at runtime. |
36 | | * |
37 | | * For updates/writes of values that will expand the original JSONB size, the |
38 | | * write will fail, and the caller needs to handle buffer increase. |
39 | | * |
40 | | * ** Iterator ** |
41 | | * Both ObjectVal class and ArrayVal class have iterator type that you can use |
42 | | * to declare an iterator on a container object to go through the key-value |
43 | | * pairs or value list. The iterator has both non-const and const types. |
44 | | * |
45 | | * Note: iterators are forward direction only. |
46 | | * |
47 | | * ** Query ** |
48 | | * Querying into containers is through the member functions find (for key/value |
49 | | * pairs) and get (for array elements), and is in streaming style. We don't |
50 | | * need to read/scan the whole JSONB packed bytes in order to return results. |
51 | | * Once the key/index is found, we will stop search. You can use text to query |
52 | | * both objects and array (for array, text will be converted to integer index), |
53 | | * and use index to retrieve from array. Array index is 0-based. |
54 | | * |
55 | | * ** External dictionary ** |
56 | | * During query processing, you can also pass a call-back function, so the |
57 | | * search will first try to check if the key string exists in the dictionary. |
58 | | * If so, search will be based on the id instead of the key string. |
59 | | * @author Tian Xia <tianx@fb.com> |
60 | | * |
61 | | * this file is copied from |
62 | | * https://github.com/facebook/mysql-5.6/blob/fb-mysql-5.6.35/fbson/FbsonDocument.h |
63 | | * and modified by Doris |
64 | | */ |
65 | | |
66 | | #ifndef JSONB_JSONBDOCUMENT_H |
67 | | #define JSONB_JSONBDOCUMENT_H |
68 | | |
69 | | #include <algorithm> |
70 | | #include <array> |
71 | | #include <cctype> |
72 | | #include <charconv> |
73 | | #include <cmath> |
74 | | #include <cstddef> |
75 | | #include <cstdint> |
76 | | #include <limits> |
77 | | #include <string> |
78 | | #include <string_view> |
79 | | #include <type_traits> |
80 | | |
81 | | #include "common/compiler_util.h" // IWYU pragma: keep |
82 | | #include "common/status.h" |
83 | | #include "core/data_type/define_primitive_type.h" |
84 | | #include "core/string_ref.h" |
85 | | #include "core/types.h" |
86 | | #include "util/string_util.h" |
87 | | |
88 | | // #include "util/string_parser.hpp" |
89 | | |
90 | | // Concept to check for supported decimal types |
91 | | template <typename T> |
92 | | concept JsonbDecimalType = |
93 | | std::same_as<T, doris::Decimal256> || std::same_as<T, doris::Decimal64> || |
94 | | std::same_as<T, doris::Decimal128V3> || std::same_as<T, doris::Decimal32>; |
95 | | |
96 | | namespace doris { |
97 | | |
98 | | template <typename T> |
99 | | constexpr bool is_pod_v = std::is_trivial_v<T> && std::is_standard_layout_v<T>; |
100 | | |
101 | | struct JsonbStringVal; |
102 | | struct ObjectVal; |
103 | | struct ArrayVal; |
104 | | struct JsonbBinaryVal; |
105 | | struct ContainerVal; |
106 | | |
107 | | template <JsonbDecimalType T> |
108 | | struct JsonbDecimalVal; |
109 | | |
110 | | using JsonbDecimal256 = JsonbDecimalVal<Decimal256>; |
111 | | using JsonbDecimal128 = JsonbDecimalVal<Decimal128V3>; |
112 | | using JsonbDecimal64 = JsonbDecimalVal<Decimal64>; |
113 | | using JsonbDecimal32 = JsonbDecimalVal<Decimal32>; |
114 | | |
115 | | template <typename T> |
116 | | requires std::is_integral_v<T> || std::is_floating_point_v<T> |
117 | | struct NumberValT; |
118 | | |
119 | | using JsonbInt8Val = NumberValT<int8_t>; |
120 | | using JsonbInt16Val = NumberValT<int16_t>; |
121 | | using JsonbInt32Val = NumberValT<int32_t>; |
122 | | using JsonbInt64Val = NumberValT<int64_t>; |
123 | | using JsonbInt128Val = NumberValT<int128_t>; |
124 | | using JsonbDoubleVal = NumberValT<double>; |
125 | | using JsonbFloatVal = NumberValT<float>; |
126 | | |
127 | | template <typename T> |
128 | | concept JsonbPodType = (std::same_as<T, JsonbStringVal> || std::same_as<T, ObjectVal> || |
129 | | std::same_as<T, ContainerVal> || std::same_as<T, ArrayVal> || |
130 | | std::same_as<T, JsonbBinaryVal> || std::same_as<T, JsonbDecimal32> || |
131 | | std::same_as<T, JsonbDecimal64> || std::same_as<T, JsonbDecimal128> || |
132 | | std::same_as<T, JsonbDecimal256> || std::same_as<T, JsonbDecimal32> || |
133 | | std::same_as<T, JsonbInt8Val> || std::same_as<T, JsonbInt16Val> || |
134 | | std::same_as<T, JsonbInt32Val> || std::same_as<T, JsonbInt64Val> || |
135 | | std::same_as<T, JsonbInt128Val> || std::same_as<T, JsonbFloatVal> || |
136 | | std::same_as<T, JsonbFloatVal> || std::same_as<T, JsonbDoubleVal>); |
137 | | |
138 | 5.77M | #define JSONB_VER 1 |
139 | | |
140 | | using int128_t = __int128; |
141 | | |
142 | | // forward declaration |
143 | | struct JsonbValue; |
144 | | |
145 | | class JsonbOutStream; |
146 | | |
147 | | template <class OS_TYPE> |
148 | | class JsonbWriterT; |
149 | | |
150 | | using JsonbWriter = JsonbWriterT<JsonbOutStream>; |
151 | | |
152 | | const int MaxNestingLevel = 100; |
153 | | |
154 | | /* |
155 | | * JsonbType defines 10 primitive types and 2 container types, as described |
156 | | * below. |
157 | | * NOTE: Do NOT modify the existing values or their order in this enum. |
158 | | * You may only append new entries at the end before `NUM_TYPES`. |
159 | | * This enum will be used in serialized data and/or persisted data. |
160 | | * Changing existing values may break backward compatibility |
161 | | * with previously stored or transmitted data. |
162 | | * |
163 | | * primitive_value ::= |
164 | | * 0x00 //null value (0 byte) |
165 | | * | 0x01 //boolean true (0 byte) |
166 | | * | 0x02 //boolean false (0 byte) |
167 | | * | 0x03 int8 //char/int8 (1 byte) |
168 | | * | 0x04 int16 //int16 (2 bytes) |
169 | | * | 0x05 int32 //int32 (4 bytes) |
170 | | * | 0x06 int64 //int64 (8 bytes) |
171 | | * | 0x07 double //floating point (8 bytes) |
172 | | * | 0x08 string //variable length string |
173 | | * | 0x09 binary //variable length binary |
174 | | * |
175 | | * container ::= |
176 | | * 0x0A int32 key_value_list //object, int32 is the total bytes of the object |
177 | | * | 0x0B int32 value_list //array, int32 is the total bytes of the array |
178 | | */ |
179 | | enum class JsonbType : char { |
180 | | T_Null = 0x00, |
181 | | T_True = 0x01, |
182 | | T_False = 0x02, |
183 | | T_Int8 = 0x03, |
184 | | T_Int16 = 0x04, |
185 | | T_Int32 = 0x05, |
186 | | T_Int64 = 0x06, |
187 | | T_Double = 0x07, |
188 | | T_String = 0x08, |
189 | | T_Binary = 0x09, |
190 | | T_Object = 0x0A, |
191 | | T_Array = 0x0B, |
192 | | T_Int128 = 0x0C, |
193 | | T_Float = 0x0D, |
194 | | T_Decimal32 = 0x0E, // DecimalV3 only |
195 | | T_Decimal64 = 0x0F, // DecimalV3 only |
196 | | T_Decimal128 = 0x10, // DecimalV3 only |
197 | | T_Decimal256 = 0x11, // DecimalV3 only |
198 | | NUM_TYPES, |
199 | | }; |
200 | | |
201 | | inline PrimitiveType get_primitive_type_from_json_type(JsonbType json_type) { |
202 | | switch (json_type) { |
203 | | case JsonbType::T_Null: |
204 | | return TYPE_NULL; |
205 | | case JsonbType::T_True: |
206 | | case JsonbType::T_False: |
207 | | return TYPE_BOOLEAN; |
208 | | case JsonbType::T_Int8: |
209 | | return TYPE_TINYINT; |
210 | | case JsonbType::T_Int16: |
211 | | return TYPE_SMALLINT; |
212 | | case JsonbType::T_Int32: |
213 | | return TYPE_INT; |
214 | | case JsonbType::T_Int64: |
215 | | return TYPE_BIGINT; |
216 | | case JsonbType::T_Double: |
217 | | return TYPE_DOUBLE; |
218 | | case JsonbType::T_String: |
219 | | return TYPE_STRING; |
220 | | case JsonbType::T_Binary: |
221 | | return TYPE_BINARY; |
222 | | case JsonbType::T_Object: |
223 | | return TYPE_STRUCT; |
224 | | case JsonbType::T_Array: |
225 | | return TYPE_ARRAY; |
226 | | case JsonbType::T_Int128: |
227 | | return TYPE_LARGEINT; |
228 | | case JsonbType::T_Float: |
229 | | return TYPE_FLOAT; |
230 | | case JsonbType::T_Decimal32: |
231 | | return TYPE_DECIMAL32; |
232 | | case JsonbType::T_Decimal64: |
233 | | return TYPE_DECIMAL64; |
234 | | case JsonbType::T_Decimal128: |
235 | | return TYPE_DECIMAL128I; |
236 | | case JsonbType::T_Decimal256: |
237 | | return TYPE_DECIMAL256; |
238 | | default: |
239 | | throw Exception(ErrorCode::INTERNAL_ERROR, "Unsupported JsonbType: {}", |
240 | | static_cast<int>(json_type)); |
241 | | } |
242 | | } |
243 | | |
244 | | //for parse json path |
245 | | constexpr char SCOPE = '$'; |
246 | | constexpr char BEGIN_MEMBER = '.'; |
247 | | constexpr char BEGIN_ARRAY = '['; |
248 | | constexpr char END_ARRAY = ']'; |
249 | | constexpr char DOUBLE_QUOTE = '"'; |
250 | | constexpr char WILDCARD = '*'; |
251 | | constexpr char MINUS = '-'; |
252 | | constexpr char LAST[] = "last"; |
253 | | constexpr char ESCAPE = '\\'; |
254 | | constexpr unsigned int MEMBER_CODE = 0; |
255 | | constexpr unsigned int ARRAY_CODE = 1; |
256 | | |
257 | | /// A simple input stream class for the JSON path parser. |
258 | | class Stream { |
259 | | public: |
260 | | /// Creates an input stream reading from a character string. |
261 | | /// @param string the input string |
262 | | /// @param length the length of the input string |
263 | 15.3k | Stream(const char* string, size_t length) : m_position(string), m_end(string + length) {} |
264 | | |
265 | | /// Returns a pointer to the current position in the stream. |
266 | 21.8k | const char* position() const { return m_position; } |
267 | | |
268 | | /// Returns a pointer to the position just after the end of the stream. |
269 | 0 | const char* end() const { return m_end; } |
270 | | |
271 | | /// Returns the number of bytes remaining in the stream. |
272 | 480k | size_t remaining() const { |
273 | 480k | assert(m_position <= m_end); |
274 | 480k | return m_end - m_position; |
275 | 480k | } |
276 | | |
277 | | /// Tells if the stream has been exhausted. |
278 | 447k | bool exhausted() const { return remaining() == 0; } |
279 | | |
280 | | /// Reads the next byte from the stream and moves the position forward. |
281 | 15.2k | char read() { |
282 | 15.2k | assert(!exhausted()); |
283 | 15.2k | return *m_position++; |
284 | 15.2k | } |
285 | | |
286 | | /// Reads the next byte from the stream without moving the position forward. |
287 | 270k | char peek() const { |
288 | 270k | assert(!exhausted()); |
289 | 270k | return *m_position; |
290 | 270k | } |
291 | | |
292 | | /// Moves the position to the next non-whitespace character. |
293 | 70.1k | void skip_whitespace() { |
294 | 70.1k | m_position = std::find_if_not(m_position, m_end, [](char c) { return std::isspace(c); }); |
295 | 70.1k | } |
296 | | |
297 | | /// Moves the position n bytes forward. |
298 | 33.4k | void skip(size_t n) { |
299 | 33.4k | assert(remaining() >= n); |
300 | 33.4k | m_position += n; |
301 | 33.4k | skip_whitespace(); |
302 | 33.4k | } |
303 | | |
304 | 45.3k | void advance() { m_position++; } |
305 | | |
306 | 43.0k | void clear_leg_ptr() { leg_ptr = nullptr; } |
307 | | |
308 | 21.6k | void set_leg_ptr(char* ptr) { |
309 | 21.6k | clear_leg_ptr(); |
310 | 21.6k | leg_ptr = ptr; |
311 | 21.6k | } |
312 | | |
313 | 32.9k | char* get_leg_ptr() { return leg_ptr; } |
314 | | |
315 | 21.4k | void clear_leg_len() { leg_len = 0; } |
316 | | |
317 | 45.3k | void add_leg_len() { leg_len++; } |
318 | | |
319 | 42.7k | unsigned int get_leg_len() const { return leg_len; } |
320 | | |
321 | 16 | void remove_escapes() { |
322 | 16 | unsigned int new_len = 0; |
323 | 114 | for (unsigned int i = 0; i < leg_len; ++i) { |
324 | 99 | if (leg_ptr[i] != ESCAPE) { |
325 | 65 | leg_ptr[new_len++] = leg_ptr[i]; |
326 | 65 | continue; |
327 | 65 | } |
328 | | |
329 | 34 | ++i; |
330 | 34 | if (i >= leg_len) { |
331 | 1 | break; |
332 | 1 | } |
333 | | |
334 | 33 | switch (leg_ptr[i]) { |
335 | 2 | case 'b': |
336 | 2 | leg_ptr[new_len++] = '\b'; |
337 | 2 | break; |
338 | 2 | case 'f': |
339 | 2 | leg_ptr[new_len++] = '\f'; |
340 | 2 | break; |
341 | 4 | case 'n': |
342 | 4 | leg_ptr[new_len++] = '\n'; |
343 | 4 | break; |
344 | 2 | case 'r': |
345 | 2 | leg_ptr[new_len++] = '\r'; |
346 | 2 | break; |
347 | 2 | case 't': |
348 | 2 | leg_ptr[new_len++] = '\t'; |
349 | 2 | break; |
350 | 11 | case 'u': { |
351 | 11 | if (i + 4 >= leg_len || leg_ptr[i + 1] != '0' || leg_ptr[i + 2] != '0') { |
352 | 2 | leg_ptr[new_len++] = leg_ptr[i]; |
353 | 2 | break; |
354 | 2 | } |
355 | | |
356 | 18 | auto hex_to_int = [](char c) -> int { |
357 | 18 | if (c >= '0' && c <= '9') { |
358 | 12 | return c - '0'; |
359 | 12 | } |
360 | 6 | if (c >= 'a' && c <= 'f') { |
361 | 2 | return c - 'a' + 10; |
362 | 2 | } |
363 | 4 | if (c >= 'A' && c <= 'F') { |
364 | 1 | return c - 'A' + 10; |
365 | 1 | } |
366 | 3 | return -1; |
367 | 4 | }; |
368 | 9 | int high = hex_to_int(leg_ptr[i + 3]); |
369 | 9 | int low = hex_to_int(leg_ptr[i + 4]); |
370 | 9 | if (high < 0 || low < 0) { |
371 | 3 | leg_ptr[new_len++] = leg_ptr[i]; |
372 | 3 | break; |
373 | 3 | } |
374 | 6 | leg_ptr[new_len++] = static_cast<char>((high << 4) | low); |
375 | 6 | i += 4; |
376 | 6 | break; |
377 | 9 | } |
378 | 10 | default: |
379 | 10 | leg_ptr[new_len++] = leg_ptr[i]; |
380 | 10 | break; |
381 | 33 | } |
382 | 33 | } |
383 | 16 | leg_ptr[new_len] = '\0'; |
384 | 16 | leg_len = new_len; |
385 | 16 | } |
386 | | |
387 | 21.4k | void set_has_escapes(bool has) { has_escapes = has; } |
388 | | |
389 | 9.92k | bool get_has_escapes() const { return has_escapes; } |
390 | | |
391 | | private: |
392 | | /// The current position in the stream. |
393 | | const char* m_position = nullptr; |
394 | | |
395 | | /// The end of the stream. |
396 | | const char* const m_end; |
397 | | |
398 | | ///path leg ptr |
399 | | char* leg_ptr = nullptr; |
400 | | |
401 | | ///path leg len |
402 | | unsigned int leg_len; |
403 | | |
404 | | ///Whether to contain escape characters |
405 | | bool has_escapes = false; |
406 | | }; |
407 | | |
408 | | struct leg_info { |
409 | | ///path leg ptr |
410 | | char* leg_ptr = nullptr; |
411 | | |
412 | | ///path leg len |
413 | | unsigned int leg_len; |
414 | | |
415 | | ///array_index |
416 | | int array_index; |
417 | | |
418 | | ///type: 0 is member 1 is array |
419 | | unsigned int type; |
420 | | |
421 | | ///true only for an unquoted `*` member leg or a `[*]` array leg; a quoted "*" member leg |
422 | | ///is the literal key `*` |
423 | | bool is_wildcard = false; |
424 | | |
425 | | // NOLINTNEXTLINE(readability-non-const-parameter): str is an output parameter. |
426 | 419 | bool to_string(std::string* str) const { |
427 | 419 | if (type == MEMBER_CODE) { |
428 | 158 | str->push_back(BEGIN_MEMBER); |
429 | | // JsonbPath::parse_member reads an unquoted member leg until the next '.' or '[', |
430 | | // rejects unquoted whitespace, treats a leading '*' as a wildcard and rejects an |
431 | | // unquoted empty leg. A key that would not read back as this same single leg must be |
432 | | // double-quoted so the emitted path can be parsed again (for example by |
433 | | // JSON_EXTRACT on the result of JSON_SEARCH). A parsed wildcard leg stays `*`. |
434 | 158 | bool needs_quotes = leg_len == 0 || (!is_wildcard && *leg_ptr == WILDCARD); |
435 | 158 | std::string tmp; |
436 | 435 | for (auto* it = leg_ptr; it != (leg_ptr + leg_len); ++it) { |
437 | 277 | auto c = static_cast<unsigned char>(*it); |
438 | 277 | if (std::isspace(c) || *it == BEGIN_MEMBER || *it == BEGIN_ARRAY) { |
439 | 27 | needs_quotes = true; |
440 | 27 | } |
441 | | |
442 | 277 | switch (*it) { |
443 | 6 | case '"': |
444 | 6 | tmp.append("\\\""); |
445 | 6 | break; |
446 | 2 | case ESCAPE: |
447 | 2 | tmp.append("\\\\"); |
448 | 2 | break; |
449 | 2 | case '\b': |
450 | 2 | tmp.append("\\b"); |
451 | 2 | break; |
452 | 2 | case '\f': |
453 | 2 | tmp.append("\\f"); |
454 | 2 | break; |
455 | 5 | case '\n': |
456 | 5 | tmp.append("\\n"); |
457 | 5 | break; |
458 | 3 | case '\r': |
459 | 3 | tmp.append("\\r"); |
460 | 3 | break; |
461 | 3 | case '\t': |
462 | 3 | tmp.append("\\t"); |
463 | 3 | break; |
464 | 254 | default: |
465 | 254 | if (c < 0x20) { |
466 | 7 | constexpr char hex[] = "0123456789abcdef"; |
467 | 7 | tmp.append("\\u00"); |
468 | 7 | tmp.push_back(hex[c >> 4]); |
469 | 7 | tmp.push_back(hex[c & 0x0F]); |
470 | 247 | } else { |
471 | 247 | tmp.push_back(*it); |
472 | 247 | } |
473 | 254 | break; |
474 | 277 | } |
475 | 277 | } |
476 | 158 | if (needs_quotes) { |
477 | 37 | str->push_back(DOUBLE_QUOTE); |
478 | 37 | } |
479 | 158 | str->append(tmp); |
480 | 158 | if (needs_quotes) { |
481 | 37 | str->push_back(DOUBLE_QUOTE); |
482 | 37 | } |
483 | 158 | return true; |
484 | 261 | } else if (type == ARRAY_CODE) { |
485 | 261 | str->push_back(BEGIN_ARRAY); |
486 | 261 | if (is_wildcard) { |
487 | 2 | str->push_back(WILDCARD); |
488 | 259 | } else { |
489 | 259 | str->append(std::to_string(array_index)); |
490 | 259 | } |
491 | 261 | str->push_back(END_ARRAY); |
492 | 261 | return true; |
493 | 261 | } else { |
494 | 0 | return false; |
495 | 0 | } |
496 | 419 | } |
497 | | }; |
498 | | |
499 | | class JsonbPath { |
500 | | public: |
501 | | // parse json path |
502 | | static bool parsePath(Stream* stream, JsonbPath* path); |
503 | | |
504 | | static bool parse_array(Stream* stream, JsonbPath* path); |
505 | | static bool parse_member(Stream* stream, JsonbPath* path); |
506 | | |
507 | | //return true if json path valid else return false |
508 | | bool seek(const char* string, size_t length); |
509 | | |
510 | 22.3k | void add_leg_to_leg_vector(std::unique_ptr<leg_info> leg) { |
511 | 22.3k | leg_vector.emplace_back(leg.release()); |
512 | 22.3k | } |
513 | | |
514 | 660 | void pop_leg_from_leg_vector() { leg_vector.pop_back(); } |
515 | | |
516 | | // NOLINTNEXTLINE(readability-non-const-parameter): res is an output parameter. |
517 | 265 | bool to_string(std::string* res) const { |
518 | 265 | res->push_back(SCOPE); |
519 | 408 | for (const auto& leg : leg_vector) { |
520 | 408 | auto valid = leg->to_string(res); |
521 | 408 | if (!valid) { |
522 | 0 | return false; |
523 | 0 | } |
524 | 408 | } |
525 | 265 | return true; |
526 | 265 | } |
527 | | |
528 | 1.97M | size_t get_leg_vector_size() const { return leg_vector.size(); } |
529 | | |
530 | 4.42M | leg_info* get_leg_from_leg_vector(size_t i) const { return leg_vector[i].get(); } |
531 | | |
532 | 317 | bool is_wildcard() const { return _is_wildcard; } |
533 | 932k | bool is_supper_wildcard() const { return _is_supper_wildcard; } |
534 | | |
535 | 118 | void clean() { leg_vector.clear(); } |
536 | | |
537 | | private: |
538 | | std::vector<std::unique_ptr<leg_info>> leg_vector; |
539 | | bool _is_wildcard = false; // whether the path is a wildcard path |
540 | | bool _is_supper_wildcard = false; // supper wildcard likes '$**.a' or '$**[1]' |
541 | | }; |
542 | | |
543 | | /* |
544 | | * JsonbFwdIteratorT implements JSONB's iterator template. |
545 | | * |
546 | | * Note: it is an FORWARD iterator only due to the design of JSONB format. |
547 | | */ |
548 | | template <class Iter_Type, class Cont_Type> |
549 | | class JsonbFwdIteratorT { |
550 | | public: |
551 | | using iterator = Iter_Type; |
552 | | using pointer = typename std::iterator_traits<Iter_Type>::pointer; |
553 | | using reference = typename std::iterator_traits<Iter_Type>::reference; |
554 | | |
555 | | explicit JsonbFwdIteratorT() : current_(nullptr) {} |
556 | 1.81M | explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {}_ZN5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEC2ERKS3_ Line | Count | Source | 556 | 1.78M | explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {} |
_ZN5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEC2ERKS3_ Line | Count | Source | 556 | 27.8k | explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {} |
|
557 | | |
558 | | // allow non-const to const iterator conversion (same container type) |
559 | | template <class Iter_Ty> |
560 | | JsonbFwdIteratorT(const JsonbFwdIteratorT<Iter_Ty, Cont_Type>& rhs) : current_(rhs.base()) {} |
561 | | |
562 | 1.08M | bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); }_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEeqERKS5_ Line | Count | Source | 562 | 993k | bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); } |
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEeqERKS5_ Line | Count | Source | 562 | 92.8k | bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); } |
|
563 | | |
564 | 248k | bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); }_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEneERKS5_ Line | Count | Source | 564 | 166k | bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); } |
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEneERKS5_ Line | Count | Source | 564 | 81.1k | bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); } |
|
565 | | |
566 | 58.1k | bool operator<(const JsonbFwdIteratorT& rhs) const { return (current_ < rhs.current_); }_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEltERKS5_ Line | Count | Source | 566 | 839 | bool operator<(const JsonbFwdIteratorT& rhs) const { return (current_ < rhs.current_); } |
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEltERKS5_ Line | Count | Source | 566 | 57.3k | bool operator<(const JsonbFwdIteratorT& rhs) const { return (current_ < rhs.current_); } |
|
567 | | |
568 | | bool operator>(const JsonbFwdIteratorT& rhs) const { return !operator<(rhs); } |
569 | | |
570 | 193k | JsonbFwdIteratorT& operator++() { |
571 | 193k | current_ = (iterator)(((char*)current_) + current_->numPackedBytes()); |
572 | 193k | return *this; |
573 | 193k | } _ZN5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEppEv Line | Count | Source | 570 | 157k | JsonbFwdIteratorT& operator++() { | 571 | 157k | current_ = (iterator)(((char*)current_) + current_->numPackedBytes()); | 572 | 157k | return *this; | 573 | 157k | } |
_ZN5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEppEv Line | Count | Source | 570 | 35.9k | JsonbFwdIteratorT& operator++() { | 571 | 35.9k | current_ = (iterator)(((char*)current_) + current_->numPackedBytes()); | 572 | 35.9k | return *this; | 573 | 35.9k | } |
|
574 | | |
575 | | JsonbFwdIteratorT operator++(int) { |
576 | | auto tmp = *this; |
577 | | current_ = (iterator)(((char*)current_) + current_->numPackedBytes()); |
578 | | return tmp; |
579 | | } |
580 | | |
581 | 33.3k | explicit operator pointer() { return current_; } |
582 | | |
583 | 3.66k | reference operator*() const { return *current_; }_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEdeEv Line | Count | Source | 583 | 2.50k | reference operator*() const { return *current_; } |
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEdeEv Line | Count | Source | 583 | 1.15k | reference operator*() const { return *current_; } |
|
584 | | |
585 | 377k | pointer operator->() const { return current_; }_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEptEv Line | Count | Source | 585 | 377k | pointer operator->() const { return current_; } |
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEptEv Line | Count | Source | 585 | 136 | pointer operator->() const { return current_; } |
|
586 | | |
587 | | iterator base() const { return current_; } |
588 | | |
589 | | private: |
590 | | iterator current_; |
591 | | }; |
592 | | using JsonbTypeUnder = std::underlying_type_t<JsonbType>; |
593 | | |
594 | | #if defined(__clang__) |
595 | | #pragma clang diagnostic push |
596 | | #pragma clang diagnostic ignored "-Wzero-length-array" |
597 | | #endif |
598 | | #pragma pack(push, 1) |
599 | | |
600 | | /* |
601 | | * JsonbDocument is the main object that accesses and queries JSONB packed |
602 | | * bytes. NOTE: JsonbDocument only allows object container as the top level |
603 | | * JSONB value. However, you can use the static method "createValue" to get any |
604 | | * JsonbValue object from the packed bytes. |
605 | | * |
606 | | * JsonbDocument object also dereferences to an object container value |
607 | | * (ObjectVal) once JSONB is loaded. |
608 | | * |
609 | | * ** Load ** |
610 | | * JsonbDocument is usable after loading packed bytes (memory location) into |
611 | | * the object. We only need the header and first few bytes of the payload after |
612 | | * header to verify the JSONB. |
613 | | * |
614 | | * Note: creating an JsonbDocument (through createDocument) does not allocate |
615 | | * any memory. The document object is an efficient wrapper on the packed bytes |
616 | | * which is accessed directly. |
617 | | * |
618 | | * ** Query ** |
619 | | * Query is through dereferencing into ObjectVal. |
620 | | */ |
621 | | class JsonbDocument { |
622 | | public: |
623 | | // create an JsonbDocument object from JSONB packed bytes |
624 | | [[nodiscard]] static Status checkAndCreateDocument(const char* pb, size_t size, |
625 | | const JsonbDocument** doc); |
626 | | |
627 | | // create an JsonbValue from JSONB packed bytes |
628 | | static const JsonbValue* createValue(const char* pb, size_t size); |
629 | | |
630 | 0 | uint8_t version() const { return header_.ver_; } |
631 | | |
632 | 2.10M | const JsonbValue* getValue() const { return ((const JsonbValue*)payload_); } |
633 | | |
634 | | unsigned int numPackedBytes() const; |
635 | | |
636 | | const ObjectVal* operator->() const; |
637 | | |
638 | | private: |
639 | | /* |
640 | | * JsonbHeader class defines JSONB header (internal to JsonbDocument). |
641 | | * |
642 | | * Currently it only contains version information (1-byte). We may expand the |
643 | | * header to include checksum of the JSONB binary for more security. |
644 | | */ |
645 | | struct JsonbHeader { |
646 | | uint8_t ver_; |
647 | | } header_; |
648 | | |
649 | | char payload_[0]; |
650 | | }; |
651 | | |
652 | | /* |
653 | | * JsonbKeyValue class defines JSONB key type, as described below. |
654 | | * |
655 | | * key ::= |
656 | | * 0x00 int8 //1-byte dictionary id |
657 | | * | int8 (byte*) //int8 (>0) is the size of the key string |
658 | | * |
659 | | * value ::= primitive_value | container |
660 | | * |
661 | | * JsonbKeyValue can be either an id mapping to the key string in an external |
662 | | * dictionary, or it is the original key string. Whether to read an id or a |
663 | | * string is decided by the first byte (size). |
664 | | * |
665 | | * Note: a key object must be followed by a value object. Therefore, a key |
666 | | * object implicitly refers to a key-value pair, and you can get the value |
667 | | * object right after the key object. The function numPackedBytes hence |
668 | | * indicates the total size of the key-value pair, so that we will be able go |
669 | | * to next pair from the key. |
670 | | * |
671 | | * ** Dictionary size ** |
672 | | * By default, the dictionary size is 255 (1-byte). Users can define |
673 | | * "USE_LARGE_DICT" to increase the dictionary size to 655535 (2-byte). |
674 | | */ |
675 | | class JsonbKeyValue { |
676 | | public: |
677 | | // now we use sMaxKeyId to represent an empty key |
678 | | static const int sMaxKeyId = 65535; |
679 | | using keyid_type = uint16_t; |
680 | | |
681 | | static const uint8_t sMaxKeyLen = 64; |
682 | | |
683 | | // size of the key. 0 indicates it is stored as id |
684 | 889k | uint8_t klen() const { return size; } |
685 | | |
686 | | // get the key string. Note the string may not be null terminated. |
687 | 55.3k | const char* getKeyStr() const { return key.str_; } |
688 | | |
689 | 111k | keyid_type getKeyId() const { return key.id_; } |
690 | | |
691 | 1.11M | unsigned int keyPackedBytes() const { |
692 | 1.11M | return size ? (sizeof(size) + size) : (sizeof(size) + sizeof(keyid_type)); |
693 | 1.11M | } |
694 | | |
695 | 154k | const JsonbValue* value() const { |
696 | 154k | return (const JsonbValue*)(((char*)this) + keyPackedBytes()); |
697 | 154k | } |
698 | | |
699 | | // size of the total packed bytes (key+value) |
700 | | unsigned int numPackedBytes() const; |
701 | | |
702 | | uint8_t size; |
703 | | |
704 | | union key_ { |
705 | | keyid_type id_; |
706 | | char str_[1]; |
707 | | } key; |
708 | | }; |
709 | | |
710 | | struct JsonbFindResult { |
711 | | const JsonbValue* value = nullptr; // found value |
712 | | std::unique_ptr<JsonbWriter> writer; // writer to write the value |
713 | | bool is_wildcard = false; // whether the path is a wildcard path |
714 | | }; |
715 | | |
716 | | /* |
717 | | * JsonbValue is the base class of all JSONB types. It contains only one member |
718 | | * variable - type info, which can be retrieved by member functions is[Type]() |
719 | | * or type(). |
720 | | */ |
721 | | struct JsonbValue { |
722 | | static const uint32_t sMaxValueLen = 1 << 24; // 16M |
723 | | |
724 | 195k | bool isNull() const { return (type == JsonbType::T_Null); } |
725 | 8.30k | bool isTrue() const { return (type == JsonbType::T_True); } |
726 | 12 | bool isFalse() const { return (type == JsonbType::T_False); } |
727 | 64.5k | bool isInt() const { return isInt8() || isInt16() || isInt32() || isInt64() || isInt128(); } |
728 | 64.5k | bool isInt8() const { return (type == JsonbType::T_Int8); } |
729 | 54.2k | bool isInt16() const { return (type == JsonbType::T_Int16); } |
730 | 49.4k | bool isInt32() const { return (type == JsonbType::T_Int32); } |
731 | 34.9k | bool isInt64() const { return (type == JsonbType::T_Int64); } |
732 | 819 | bool isDouble() const { return (type == JsonbType::T_Double); } |
733 | 738 | bool isFloat() const { return (type == JsonbType::T_Float); } |
734 | 2.60k | bool isString() const { return (type == JsonbType::T_String); } |
735 | 15.3k | bool isBinary() const { return (type == JsonbType::T_Binary); } |
736 | 5.54k | bool isObject() const { return (type == JsonbType::T_Object); } |
737 | 4.31k | bool isArray() const { return (type == JsonbType::T_Array); } |
738 | 16.6k | bool isInt128() const { return (type == JsonbType::T_Int128); } |
739 | 434 | bool isDecimal() const { |
740 | 434 | return (type == JsonbType::T_Decimal32 || type == JsonbType::T_Decimal64 || |
741 | 434 | type == JsonbType::T_Decimal128 || type == JsonbType::T_Decimal256); |
742 | 434 | } |
743 | | bool isDecimal32() const { return (type == JsonbType::T_Decimal32); } |
744 | | bool isDecimal64() const { return (type == JsonbType::T_Decimal64); } |
745 | | bool isDecimal128() const { return (type == JsonbType::T_Decimal128); } |
746 | | bool isDecimal256() const { return (type == JsonbType::T_Decimal256); } |
747 | | |
748 | | PrimitiveType get_primitive_type() const { return get_primitive_type_from_json_type(type); } |
749 | | |
750 | 444 | const char* typeName() const { |
751 | 444 | switch (type) { |
752 | 24 | case JsonbType::T_Null: |
753 | 24 | return "null"; |
754 | 18 | case JsonbType::T_True: |
755 | 36 | case JsonbType::T_False: |
756 | 36 | return "bool"; |
757 | 43 | case JsonbType::T_Int8: |
758 | 79 | case JsonbType::T_Int16: |
759 | 93 | case JsonbType::T_Int32: |
760 | 93 | return "int"; |
761 | 20 | case JsonbType::T_Int64: |
762 | 20 | return "bigint"; |
763 | 16 | case JsonbType::T_Int128: |
764 | 16 | return "largeint"; |
765 | 43 | case JsonbType::T_Double: |
766 | 43 | return "double"; |
767 | 0 | case JsonbType::T_Float: |
768 | 0 | return "float"; |
769 | 69 | case JsonbType::T_String: |
770 | 69 | return "string"; |
771 | 0 | case JsonbType::T_Binary: |
772 | 0 | return "binary"; |
773 | 103 | case JsonbType::T_Object: |
774 | 103 | return "object"; |
775 | 39 | case JsonbType::T_Array: |
776 | 39 | return "array"; |
777 | 1 | case JsonbType::T_Decimal32: |
778 | 1 | return "Decimal32"; |
779 | 0 | case JsonbType::T_Decimal64: |
780 | 0 | return "Decimal64"; |
781 | 0 | case JsonbType::T_Decimal128: |
782 | 0 | return "Decimal128"; |
783 | 0 | case JsonbType::T_Decimal256: |
784 | 0 | return "Decimal256"; |
785 | 0 | default: |
786 | 0 | return "unknown"; |
787 | 444 | } |
788 | 444 | } |
789 | | |
790 | | // size of the total packed bytes |
791 | | unsigned int numPackedBytes() const; |
792 | | |
793 | | // size of the value in bytes |
794 | | unsigned int size() const; |
795 | | |
796 | | //Get the number of jsonbvalue elements |
797 | | int numElements() const; |
798 | | |
799 | | //Whether to include the jsonbvalue rhs |
800 | | bool contains(const JsonbValue* rhs) const; |
801 | | |
802 | | // find the JSONB value by JsonbPath |
803 | | JsonbFindResult findValue(JsonbPath& path) const; |
804 | | friend class JsonbDocument; |
805 | | |
806 | | JsonbType type; // type info |
807 | | |
808 | | char payload[0]; // payload, which is the packed bytes of the value |
809 | | |
810 | | /** |
811 | | * @brief Unpacks the underlying Jsonb binary content as a pointer to type `T`. |
812 | | * |
813 | | * @tparam T A POD (Plain Old Data) type that must satisfy the `JsonbPodType` concept. |
814 | | * This ensures that `T` is trivially copyable, standard-layout, and safe to |
815 | | * reinterpret from raw bytes without invoking undefined behavior. |
816 | | * |
817 | | * @return A pointer to a `const T` object, interpreted from the internal buffer. |
818 | | * |
819 | | * @note The caller must ensure that the current JsonbValue actually contains data |
820 | | * compatible with type `T`, otherwise the result is undefined. |
821 | | */ |
822 | | template <JsonbPodType T> |
823 | 3.35M | const T* unpack() const { |
824 | 3.35M | static_assert(is_pod_v<T>, "T must be a POD type"); |
825 | 3.35M | return reinterpret_cast<const T*>(payload); |
826 | 3.35M | } _ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_9ObjectValEEEPKT_v Line | Count | Source | 823 | 959k | const T* unpack() const { | 824 | 959k | static_assert(is_pod_v<T>, "T must be a POD type"); | 825 | 959k | return reinterpret_cast<const T*>(payload); | 826 | 959k | } |
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIaEEEEPKT_v Line | Count | Source | 823 | 121k | const T* unpack() const { | 824 | 121k | static_assert(is_pod_v<T>, "T must be a POD type"); | 825 | 121k | return reinterpret_cast<const T*>(payload); | 826 | 121k | } |
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIsEEEEPKT_v Line | Count | Source | 823 | 18.0k | const T* unpack() const { | 824 | 18.0k | static_assert(is_pod_v<T>, "T must be a POD type"); | 825 | 18.0k | return reinterpret_cast<const T*>(payload); | 826 | 18.0k | } |
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIiEEEEPKT_v Line | Count | Source | 823 | 16.6k | const T* unpack() const { | 824 | 16.6k | static_assert(is_pod_v<T>, "T must be a POD type"); | 825 | 16.6k | return reinterpret_cast<const T*>(payload); | 826 | 16.6k | } |
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIlEEEEPKT_v Line | Count | Source | 823 | 21.1k | const T* unpack() const { | 824 | 21.1k | static_assert(is_pod_v<T>, "T must be a POD type"); | 825 | 21.1k | return reinterpret_cast<const T*>(payload); | 826 | 21.1k | } |
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTInEEEEPKT_v Line | Count | Source | 823 | 18.6k | const T* unpack() const { | 824 | 18.6k | static_assert(is_pod_v<T>, "T must be a POD type"); | 825 | 18.6k | return reinterpret_cast<const T*>(payload); | 826 | 18.6k | } |
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIdEEEEPKT_v Line | Count | Source | 823 | 11.8k | const T* unpack() const { | 824 | 11.8k | static_assert(is_pod_v<T>, "T must be a POD type"); | 825 | 11.8k | return reinterpret_cast<const T*>(payload); | 826 | 11.8k | } |
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIfEEEEPKT_v Line | Count | Source | 823 | 4.58k | const T* unpack() const { | 824 | 4.58k | static_assert(is_pod_v<T>, "T must be a POD type"); | 825 | 4.58k | return reinterpret_cast<const T*>(payload); | 826 | 4.58k | } |
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_7DecimalIiEEEEEEPKT_v Line | Count | Source | 823 | 57 | const T* unpack() const { | 824 | 57 | static_assert(is_pod_v<T>, "T must be a POD type"); | 825 | 57 | return reinterpret_cast<const T*>(payload); | 826 | 57 | } |
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_7DecimalIlEEEEEEPKT_v Line | Count | Source | 823 | 46 | const T* unpack() const { | 824 | 46 | static_assert(is_pod_v<T>, "T must be a POD type"); | 825 | 46 | return reinterpret_cast<const T*>(payload); | 826 | 46 | } |
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_12Decimal128V3EEEEEPKT_v Line | Count | Source | 823 | 65 | const T* unpack() const { | 824 | 65 | static_assert(is_pod_v<T>, "T must be a POD type"); | 825 | 65 | return reinterpret_cast<const T*>(payload); | 826 | 65 | } |
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_7DecimalIN4wide7integerILm256EiEEEEEEEEPKT_v Line | Count | Source | 823 | 13 | const T* unpack() const { | 824 | 13 | static_assert(is_pod_v<T>, "T must be a POD type"); | 825 | 13 | return reinterpret_cast<const T*>(payload); | 826 | 13 | } |
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_14JsonbBinaryValEEEPKT_v Line | Count | Source | 823 | 114k | const T* unpack() const { | 824 | 114k | static_assert(is_pod_v<T>, "T must be a POD type"); | 825 | 114k | return reinterpret_cast<const T*>(payload); | 826 | 114k | } |
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_12ContainerValEEEPKT_v Line | Count | Source | 823 | 1.79M | const T* unpack() const { | 824 | 1.79M | static_assert(is_pod_v<T>, "T must be a POD type"); | 825 | 1.79M | return reinterpret_cast<const T*>(payload); | 826 | 1.79M | } |
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_8ArrayValEEEPKT_v Line | Count | Source | 823 | 208k | const T* unpack() const { | 824 | 208k | static_assert(is_pod_v<T>, "T must be a POD type"); | 825 | 208k | return reinterpret_cast<const T*>(payload); | 826 | 208k | } |
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_14JsonbStringValEEEPKT_v Line | Count | Source | 823 | 62.7k | const T* unpack() const { | 824 | 62.7k | static_assert(is_pod_v<T>, "T must be a POD type"); | 825 | 62.7k | return reinterpret_cast<const T*>(payload); | 826 | 62.7k | } |
|
827 | | |
828 | | // /** |
829 | | // * @brief Unpacks the underlying Jsonb binary content as a pointer to type `T`. |
830 | | // * |
831 | | // * @tparam T A POD (Plain Old Data) type that must satisfy the `JsonbPodType` concept. |
832 | | // * This ensures that `T` is trivially copyable, standard-layout, and safe to |
833 | | // * reinterpret from raw bytes without invoking undefined behavior. |
834 | | // * |
835 | | // * @return A pointer to a `T` object, interpreted from the internal buffer. |
836 | | // * |
837 | | // * @note The caller must ensure that the current JsonbValue actually contains data |
838 | | // * compatible with type `T`, otherwise the result is undefined. |
839 | | // */ |
840 | | // template <JsonbPodType T> |
841 | | // T* unpack() { |
842 | | // static_assert(is_pod_v<T>, "T must be a POD type"); |
843 | | // return reinterpret_cast<T*>(payload); |
844 | | // } |
845 | | |
846 | | int128_t int_val() const; |
847 | | }; |
848 | | |
849 | | // inline ObjectVal* JsonbDocument::operator->() { |
850 | | // return (((JsonbValue*)payload_)->unpack<ObjectVal>()); |
851 | | // } |
852 | | |
853 | 131k | inline const ObjectVal* JsonbDocument::operator->() const { |
854 | 131k | return (((const JsonbValue*)payload_)->unpack<ObjectVal>()); |
855 | 131k | } |
856 | | |
857 | | /* |
858 | | * NumerValT is the template class (derived from JsonbValue) of all number |
859 | | * types (integers and double). |
860 | | */ |
861 | | template <typename T> |
862 | | requires std::is_integral_v<T> || std::is_floating_point_v<T> |
863 | | struct NumberValT { |
864 | | public: |
865 | 212k | T val() const { return num; }_ZNK5doris10NumberValTIaE3valEv Line | Count | Source | 865 | 121k | T val() const { return num; } |
_ZNK5doris10NumberValTIsE3valEv Line | Count | Source | 865 | 18.0k | T val() const { return num; } |
_ZNK5doris10NumberValTIiE3valEv Line | Count | Source | 865 | 16.6k | T val() const { return num; } |
_ZNK5doris10NumberValTIlE3valEv Line | Count | Source | 865 | 21.1k | T val() const { return num; } |
_ZNK5doris10NumberValTInE3valEv Line | Count | Source | 865 | 18.6k | T val() const { return num; } |
_ZNK5doris10NumberValTIdE3valEv Line | Count | Source | 865 | 11.8k | T val() const { return num; } |
_ZNK5doris10NumberValTIfE3valEv Line | Count | Source | 865 | 4.58k | T val() const { return num; } |
|
866 | | |
867 | | static unsigned int numPackedBytes() { return sizeof(JsonbValue) + sizeof(T); } |
868 | | |
869 | | T num; |
870 | | }; |
871 | | |
872 | 64.2k | inline int128_t JsonbValue::int_val() const { |
873 | 64.2k | switch (type) { |
874 | 10.2k | case JsonbType::T_Int8: |
875 | 10.2k | return unpack<JsonbInt8Val>()->val(); |
876 | 4.71k | case JsonbType::T_Int16: |
877 | 4.71k | return unpack<JsonbInt16Val>()->val(); |
878 | 14.5k | case JsonbType::T_Int32: |
879 | 14.5k | return unpack<JsonbInt32Val>()->val(); |
880 | 18.2k | case JsonbType::T_Int64: |
881 | 18.2k | return unpack<JsonbInt64Val>()->val(); |
882 | 16.4k | case JsonbType::T_Int128: |
883 | 16.4k | return unpack<JsonbInt128Val>()->val(); |
884 | 0 | default: |
885 | 0 | throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}", |
886 | 0 | static_cast<int32_t>(type)); |
887 | 64.2k | } |
888 | 64.2k | } |
889 | | |
890 | | template <JsonbDecimalType T> |
891 | | struct JsonbDecimalVal { |
892 | | public: |
893 | | using NativeType = typename T::NativeType; |
894 | | |
895 | | // get the decimal value |
896 | 148 | NativeType val() const { |
897 | | // to avoid memory alignment issues, we use memcpy to copy the value |
898 | 148 | NativeType tmp; |
899 | 148 | memcpy(&tmp, &value, sizeof(NativeType)); |
900 | 148 | return tmp; |
901 | 148 | } _ZNK5doris15JsonbDecimalValINS_7DecimalIiEEE3valEv Line | Count | Source | 896 | 48 | NativeType val() const { | 897 | | // to avoid memory alignment issues, we use memcpy to copy the value | 898 | 48 | NativeType tmp; | 899 | 48 | memcpy(&tmp, &value, sizeof(NativeType)); | 900 | 48 | return tmp; | 901 | 48 | } |
_ZNK5doris15JsonbDecimalValINS_7DecimalIlEEE3valEv Line | Count | Source | 896 | 39 | NativeType val() const { | 897 | | // to avoid memory alignment issues, we use memcpy to copy the value | 898 | 39 | NativeType tmp; | 899 | 39 | memcpy(&tmp, &value, sizeof(NativeType)); | 900 | 39 | return tmp; | 901 | 39 | } |
_ZNK5doris15JsonbDecimalValINS_12Decimal128V3EE3valEv Line | Count | Source | 896 | 55 | NativeType val() const { | 897 | | // to avoid memory alignment issues, we use memcpy to copy the value | 898 | 55 | NativeType tmp; | 899 | 55 | memcpy(&tmp, &value, sizeof(NativeType)); | 900 | 55 | return tmp; | 901 | 55 | } |
_ZNK5doris15JsonbDecimalValINS_7DecimalIN4wide7integerILm256EiEEEEE3valEv Line | Count | Source | 896 | 6 | NativeType val() const { | 897 | | // to avoid memory alignment issues, we use memcpy to copy the value | 898 | 6 | NativeType tmp; | 899 | 6 | memcpy(&tmp, &value, sizeof(NativeType)); | 900 | 6 | return tmp; | 901 | 6 | } |
|
902 | | |
903 | 271 | static constexpr int numPackedBytes() { |
904 | 271 | return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value); |
905 | 271 | } _ZN5doris15JsonbDecimalValINS_7DecimalIiEEE14numPackedBytesEv Line | Count | Source | 903 | 79 | static constexpr int numPackedBytes() { | 904 | 79 | return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value); | 905 | 79 | } |
_ZN5doris15JsonbDecimalValINS_7DecimalIlEEE14numPackedBytesEv Line | Count | Source | 903 | 87 | static constexpr int numPackedBytes() { | 904 | 87 | return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value); | 905 | 87 | } |
_ZN5doris15JsonbDecimalValINS_12Decimal128V3EE14numPackedBytesEv Line | Count | Source | 903 | 99 | static constexpr int numPackedBytes() { | 904 | 99 | return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value); | 905 | 99 | } |
_ZN5doris15JsonbDecimalValINS_7DecimalIN4wide7integerILm256EiEEEEE14numPackedBytesEv Line | Count | Source | 903 | 6 | static constexpr int numPackedBytes() { | 904 | 6 | return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value); | 905 | 6 | } |
|
906 | | |
907 | | uint32_t precision; |
908 | | uint32_t scale; |
909 | | NativeType value; |
910 | | }; |
911 | | |
912 | | /* |
913 | | * BlobVal is the base class (derived from JsonbValue) for string and binary |
914 | | * types. The size indicates the total bytes of the payload. |
915 | | */ |
916 | | struct JsonbBinaryVal { |
917 | | public: |
918 | | // size of the blob payload only |
919 | 48.0k | unsigned int getBlobLen() const { return size; } |
920 | | |
921 | | // return the blob as byte array |
922 | 55.5k | const char* getBlob() const { return payload; } |
923 | | |
924 | | // size of the total packed bytes |
925 | 90.8k | unsigned int numPackedBytes() const { return sizeof(JsonbValue) + sizeof(size) + size; } |
926 | | friend class JsonbDocument; |
927 | | |
928 | | uint32_t size; |
929 | | char payload[0]; |
930 | | }; |
931 | | |
932 | | /* |
933 | | * String type |
934 | | * Note: JSONB string may not be a c-string (NULL-terminated) |
935 | | */ |
936 | | struct JsonbStringVal : public JsonbBinaryVal { |
937 | | public: |
938 | | /* |
939 | | This function return the actual size of a string. Since for |
940 | | a string, it can be null-terminated with null paddings or it |
941 | | can take all the space in the payload without null in the end. |
942 | | So we need to check it to get the true actual length of a string. |
943 | | */ |
944 | 434 | size_t length() const { |
945 | | // It's an empty string |
946 | 434 | if (0 == size) { |
947 | 0 | return size; |
948 | 0 | } |
949 | | // The string stored takes all the spaces in payload |
950 | 434 | if (payload[size - 1] != 0) { |
951 | 434 | return size; |
952 | 434 | } |
953 | | // It's shorter than the size of payload |
954 | 0 | return strnlen(payload, size); |
955 | 434 | } |
956 | | }; |
957 | | |
958 | | /* |
959 | | * ContainerVal is the base class (derived from JsonbValue) for object and |
960 | | * array types. The size indicates the total bytes of the payload. |
961 | | */ |
962 | | struct ContainerVal { |
963 | | // size of the container payload only |
964 | 0 | unsigned int getContainerSize() const { return size; } |
965 | | |
966 | | // return the container payload as byte array |
967 | 0 | const char* getPayload() const { return payload; } |
968 | | |
969 | | // size of the total packed bytes |
970 | 1.79M | unsigned int numPackedBytes() const { return sizeof(JsonbValue) + sizeof(size) + size; } |
971 | | friend class JsonbDocument; |
972 | | |
973 | | uint32_t size; |
974 | | char payload[0]; |
975 | | }; |
976 | | |
977 | | /* |
978 | | * Object type |
979 | | */ |
980 | | struct ObjectVal : public ContainerVal { |
981 | | using value_type = JsonbKeyValue; |
982 | | using pointer = value_type*; |
983 | | using const_pointer = const value_type*; |
984 | | using const_iterator = JsonbFwdIteratorT<const_pointer, ObjectVal>; |
985 | | |
986 | | const_iterator search(const char* key) const { |
987 | | if (!key) { |
988 | | return end(); |
989 | | } |
990 | | return search(key, (unsigned int)strlen(key)); |
991 | | } |
992 | | |
993 | 807k | const_iterator search(const char* key, unsigned int klen) const { |
994 | | // An empty key is a valid object key, so klen == 0 is still searched. |
995 | 807k | if (!key) { |
996 | 0 | return end(); |
997 | 0 | } |
998 | 807k | return internalSearch(key, klen); |
999 | 807k | } |
1000 | | |
1001 | | // Get number of elements in object |
1002 | 176 | int numElem() const { |
1003 | 176 | const char* pch = payload; |
1004 | 176 | const char* fence = payload + size; |
1005 | | |
1006 | 176 | unsigned int num = 0; |
1007 | 452 | while (pch < fence) { |
1008 | 276 | auto* pkey = (JsonbKeyValue*)(pch); |
1009 | 276 | ++num; |
1010 | 276 | pch += pkey->numPackedBytes(); |
1011 | 276 | } |
1012 | | |
1013 | 176 | assert(pch == fence); |
1014 | | |
1015 | 176 | return num; |
1016 | 176 | } |
1017 | | |
1018 | | // find the JSONB value by a key string (null terminated) |
1019 | | const JsonbValue* find(const char* key) const { |
1020 | | if (!key) { |
1021 | | return nullptr; |
1022 | | } |
1023 | | return find(key, (unsigned int)strlen(key)); |
1024 | | } |
1025 | | |
1026 | | // find the JSONB value by a key string (with length) |
1027 | 807k | const JsonbValue* find(const char* key, unsigned int klen) const { |
1028 | 807k | const_iterator kv = search(key, klen); |
1029 | 807k | if (end() == kv) { |
1030 | 796k | return nullptr; |
1031 | 796k | } |
1032 | 10.6k | return kv->value(); |
1033 | 807k | } |
1034 | | |
1035 | | // find the JSONB value by a key id, as stored when klen() == 0 (sMaxKeyId is the empty key) |
1036 | 4 | const JsonbValue* find_by_key_id(JsonbKeyValue::keyid_type key_id) const { |
1037 | 6 | for (auto it = begin(); it != end(); ++it) { |
1038 | 4 | if (it->klen() == 0 && it->getKeyId() == key_id) { |
1039 | 2 | return it->value(); |
1040 | 2 | } |
1041 | 4 | } |
1042 | 2 | return nullptr; |
1043 | 4 | } |
1044 | | |
1045 | 28.3k | const_iterator begin() const { return const_iterator((pointer)payload); } |
1046 | | |
1047 | 1.75M | const_iterator end() const { return const_iterator((pointer)(payload + size)); } |
1048 | | |
1049 | | std::vector<std::pair<StringRef, const JsonbValue*>> get_ordered_key_value_pairs() const; |
1050 | | |
1051 | | private: |
1052 | 807k | const_iterator internalSearch(const char* key, unsigned int klen) const { |
1053 | 807k | const char* pch = payload; |
1054 | 807k | const char* fence = payload + size; |
1055 | | |
1056 | 1.60M | while (pch < fence) { |
1057 | 813k | const auto* pkey = (const JsonbKeyValue*)(pch); |
1058 | | // A key id entry is also stored with klen() == 0, so an empty name only matches |
1059 | | // the sMaxKeyId sentinel that JsonbWriter writes for an empty key. |
1060 | 813k | if (klen == 0 ? pkey->klen() == 0 && pkey->getKeyId() == JsonbKeyValue::sMaxKeyId |
1061 | 813k | : klen == pkey->klen() && strncmp(key, pkey->getKeyStr(), klen) == 0) { |
1062 | 10.6k | return const_iterator(pkey); |
1063 | 10.6k | } |
1064 | 802k | pch += pkey->numPackedBytes(); |
1065 | 802k | } |
1066 | | |
1067 | 807k | assert(pch == fence); |
1068 | | |
1069 | 796k | return end(); |
1070 | 796k | } |
1071 | | }; |
1072 | | |
1073 | | /* |
1074 | | * Array type |
1075 | | */ |
1076 | | struct ArrayVal : public ContainerVal { |
1077 | | using value_type = JsonbValue; |
1078 | | using pointer = value_type*; |
1079 | | using const_pointer = const value_type*; |
1080 | | using const_iterator = JsonbFwdIteratorT<const_pointer, ArrayVal>; |
1081 | | |
1082 | | // get the JSONB value at index |
1083 | 194k | const JsonbValue* get(int idx) const { |
1084 | 194k | if (idx < 0) { |
1085 | 65 | return nullptr; |
1086 | 65 | } |
1087 | | |
1088 | 194k | const char* pch = payload; |
1089 | 194k | const char* fence = payload + size; |
1090 | | |
1091 | 200k | while (pch < fence && idx-- > 0) { |
1092 | 6.42k | pch += ((const JsonbValue*)pch)->numPackedBytes(); |
1093 | 6.42k | } |
1094 | 194k | if (idx > 0 || pch == fence) { |
1095 | 1.66k | return nullptr; |
1096 | 1.66k | } |
1097 | | |
1098 | 192k | return (const JsonbValue*)pch; |
1099 | 194k | } |
1100 | | |
1101 | | // Get number of elements in array |
1102 | 390 | int numElem() const { |
1103 | 390 | const char* pch = payload; |
1104 | 390 | const char* fence = payload + size; |
1105 | | |
1106 | 390 | unsigned int num = 0; |
1107 | 1.79k | while (pch < fence) { |
1108 | 1.40k | ++num; |
1109 | 1.40k | pch += ((const JsonbValue*)pch)->numPackedBytes(); |
1110 | 1.40k | } |
1111 | | |
1112 | 390 | assert(pch == fence); |
1113 | | |
1114 | 390 | return num; |
1115 | 390 | } |
1116 | | |
1117 | 12.7k | const_iterator begin() const { return const_iterator((pointer)payload); } |
1118 | | |
1119 | 15.0k | const_iterator end() const { return const_iterator((pointer)(payload + size)); } |
1120 | | }; |
1121 | | |
1122 | | namespace jsonb_detail { |
1123 | | |
1124 | | struct JsonbScaledDecimal { |
1125 | | wide::Int256 value; |
1126 | | uint32_t scale; |
1127 | | }; |
1128 | | |
1129 | 26 | inline void validate_decimal_scale(uint32_t scale) { |
1130 | 26 | if (scale > static_cast<uint32_t>(BeConsts::MAX_DECIMALV3_SCALE)) { |
1131 | 2 | throw Exception(ErrorCode::INTERNAL_ERROR, |
1132 | 2 | "Invalid JSONB decimal scale: {}, max allowed scale: {}", scale, |
1133 | 2 | BeConsts::MAX_DECIMALV3_SCALE); |
1134 | 2 | } |
1135 | 26 | } |
1136 | | |
1137 | 192 | inline bool is_numeric(const JsonbValue* value) { |
1138 | 192 | return value->isInt() || value->isDouble() || value->isFloat() || value->isDecimal(); |
1139 | 192 | } |
1140 | | |
1141 | 25 | inline double floating_value(const JsonbValue* value) { |
1142 | 25 | if (value->isDouble()) { |
1143 | 25 | return value->unpack<JsonbDoubleVal>()->val(); |
1144 | 25 | } |
1145 | 0 | return value->unpack<JsonbFloatVal>()->val(); |
1146 | 25 | } |
1147 | | |
1148 | 20 | inline JsonbScaledDecimal get_scaled_decimal(const JsonbValue* value) { |
1149 | 20 | switch (value->type) { |
1150 | 12 | case JsonbType::T_Decimal32: { |
1151 | 12 | const auto* decimal = value->unpack<JsonbDecimal32>(); |
1152 | 12 | validate_decimal_scale(decimal->scale); |
1153 | 12 | return {wide::Int256(decimal->val()), decimal->scale}; |
1154 | 0 | } |
1155 | 2 | case JsonbType::T_Decimal64: { |
1156 | 2 | const auto* decimal = value->unpack<JsonbDecimal64>(); |
1157 | 2 | validate_decimal_scale(decimal->scale); |
1158 | 2 | return {wide::Int256(decimal->val()), decimal->scale}; |
1159 | 0 | } |
1160 | 6 | case JsonbType::T_Decimal128: { |
1161 | 6 | const auto* decimal = value->unpack<JsonbDecimal128>(); |
1162 | 6 | validate_decimal_scale(decimal->scale); |
1163 | 6 | return {wide::Int256(decimal->val()), decimal->scale}; |
1164 | 0 | } |
1165 | 0 | case JsonbType::T_Decimal256: { |
1166 | 0 | const auto* decimal = value->unpack<JsonbDecimal256>(); |
1167 | 0 | validate_decimal_scale(decimal->scale); |
1168 | 0 | return {decimal->val(), decimal->scale}; |
1169 | 0 | } |
1170 | 0 | default: |
1171 | 0 | throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB decimal value type: {}", |
1172 | 0 | static_cast<int32_t>(value->type)); |
1173 | 20 | } |
1174 | 20 | } |
1175 | | |
1176 | | inline bool scaled_decimal_equal_decimal(const JsonbScaledDecimal& lhs, |
1177 | 4 | const JsonbScaledDecimal& rhs) { |
1178 | 4 | if (lhs.scale == rhs.scale) { |
1179 | 0 | return lhs.value == rhs.value; |
1180 | 0 | } |
1181 | | |
1182 | 4 | if (lhs.scale < rhs.scale) { |
1183 | 2 | const auto scale_multiplier = decimal_scale_multiplier<wide::Int256>(rhs.scale - lhs.scale); |
1184 | 2 | return rhs.value % scale_multiplier == 0 && lhs.value == rhs.value / scale_multiplier; |
1185 | 2 | } |
1186 | | |
1187 | 2 | const auto scale_multiplier = decimal_scale_multiplier<wide::Int256>(lhs.scale - rhs.scale); |
1188 | 2 | return lhs.value % scale_multiplier == 0 && lhs.value / scale_multiplier == rhs.value; |
1189 | 4 | } |
1190 | | |
1191 | 4 | inline bool scaled_decimal_equal_integer(const JsonbScaledDecimal& decimal, int128_t integer) { |
1192 | 4 | const auto integer_value = wide::Int256(integer); |
1193 | 4 | if (decimal.scale == 0) { |
1194 | 0 | return decimal.value == integer_value; |
1195 | 0 | } |
1196 | | |
1197 | 4 | const auto scale_multiplier = decimal_scale_multiplier<wide::Int256>(decimal.scale); |
1198 | 4 | return decimal.value % scale_multiplier == 0 && |
1199 | 4 | decimal.value / scale_multiplier == integer_value; |
1200 | 4 | } |
1201 | | |
1202 | | inline constexpr auto kPowersOfFive = [] { |
1203 | | std::array<wide::Int256, BeConsts::MAX_DECIMALV3_SCALE + 1> powers {}; |
1204 | | powers[0] = 1; |
1205 | | for (size_t i = 1; i < powers.size(); ++i) { |
1206 | | powers[i] = powers[i - 1] * 5; |
1207 | | } |
1208 | | return powers; |
1209 | | }(); |
1210 | | |
1211 | 6 | inline wide::Int256 power_of_five(uint32_t exponent) { |
1212 | 6 | validate_decimal_scale(exponent); |
1213 | 6 | return kPowersOfFive[exponent]; |
1214 | 6 | } |
1215 | | |
1216 | 6 | inline bool scaled_binary_equal(wide::Int256 value, int exponent, wide::Int256 significand) { |
1217 | 6 | if (exponent < 0) { |
1218 | 4 | const int divisor_exponent = -exponent; |
1219 | 4 | if (divisor_exponent >= std::numeric_limits<int64_t>::digits) { |
1220 | 0 | return false; |
1221 | 0 | } |
1222 | 4 | const auto divisor = wide::Int256(1) << divisor_exponent; |
1223 | 4 | return significand % divisor == 0 && value == significand / divisor; |
1224 | 4 | } |
1225 | 2 | constexpr int max_positive_int256_shift = std::numeric_limits<wide::Int256>::digits; |
1226 | | // wide::Int256 is signed, so shifting 1 by 255 reaches the sign bit. |
1227 | 2 | if (exponent >= max_positive_int256_shift) { |
1228 | 0 | return false; |
1229 | 0 | } |
1230 | 2 | const auto multiplier = wide::Int256(1) << exponent; |
1231 | 2 | return value % multiplier == 0 && value / multiplier == significand; |
1232 | 2 | } |
1233 | | |
1234 | 15 | inline bool floating_equal_integer(const JsonbValue* floating, int128_t integer) { |
1235 | 15 | const double value = floating_value(floating); |
1236 | 15 | int exponent = 0; |
1237 | 15 | std::frexp(value, &exponent); |
1238 | 15 | if (!std::isfinite(value) || std::trunc(value) != value) { |
1239 | 6 | return false; |
1240 | 6 | } |
1241 | 9 | if (exponent >= 128) { |
1242 | 0 | return value == -std::ldexp(1.0, 127) && integer == std::numeric_limits<int128_t>::min(); |
1243 | 0 | } |
1244 | 9 | if (exponent <= -1) { |
1245 | 0 | return false; |
1246 | 0 | } |
1247 | 9 | return static_cast<int128_t>(value) == integer; |
1248 | 9 | } |
1249 | | |
1250 | 6 | inline bool floating_equal_decimal(const JsonbValue* floating, const JsonbScaledDecimal& decimal) { |
1251 | 6 | const double value = floating_value(floating); |
1252 | 6 | if (!std::isfinite(value)) { |
1253 | 0 | return false; |
1254 | 0 | } |
1255 | 6 | if (value == 0) { |
1256 | 0 | return decimal.value == 0; |
1257 | 0 | } |
1258 | | |
1259 | 6 | int exponent = 0; |
1260 | 6 | const double significand_fraction = std::frexp(value, &exponent); |
1261 | 6 | const double significand_double = |
1262 | 6 | std::ldexp(significand_fraction, std::numeric_limits<double>::digits); |
1263 | 6 | auto significand = wide::Int256(static_cast<int64_t>(significand_double)); |
1264 | 6 | exponent -= std::numeric_limits<double>::digits; |
1265 | | |
1266 | 6 | const auto five_multiplier = power_of_five(decimal.scale); |
1267 | 6 | if (decimal.value % five_multiplier != 0) { |
1268 | 0 | return false; |
1269 | 0 | } |
1270 | 6 | const auto binary_scaled_decimal = decimal.value / five_multiplier; |
1271 | 6 | return scaled_binary_equal(binary_scaled_decimal, exponent + decimal.scale, significand); |
1272 | 6 | } |
1273 | | |
1274 | 192 | inline bool numeric_equal(const JsonbValue* lhs, const JsonbValue* rhs) { |
1275 | 192 | if (!is_numeric(rhs)) { |
1276 | 68 | return false; |
1277 | 68 | } |
1278 | | |
1279 | 124 | if ((lhs->isDouble() || lhs->isFloat()) && rhs->isInt()) { |
1280 | 8 | return floating_equal_integer(lhs, rhs->int_val()); |
1281 | 8 | } |
1282 | | |
1283 | 116 | if ((rhs->isDouble() || rhs->isFloat()) && lhs->isInt()) { |
1284 | 7 | return floating_equal_integer(rhs, lhs->int_val()); |
1285 | 7 | } |
1286 | | |
1287 | 109 | if ((lhs->isDouble() || lhs->isFloat()) && rhs->isDecimal()) { |
1288 | 4 | return floating_equal_decimal(lhs, get_scaled_decimal(rhs)); |
1289 | 4 | } |
1290 | | |
1291 | 105 | if ((rhs->isDouble() || rhs->isFloat()) && lhs->isDecimal()) { |
1292 | 4 | return floating_equal_decimal(rhs, get_scaled_decimal(lhs)); |
1293 | 4 | } |
1294 | | |
1295 | 101 | if (lhs->isDouble() || lhs->isFloat()) { |
1296 | 2 | return (rhs->isDouble() || rhs->isFloat()) && floating_value(lhs) == floating_value(rhs); |
1297 | 2 | } |
1298 | | |
1299 | 99 | if (lhs->isDecimal()) { |
1300 | 6 | const auto lhs_decimal = get_scaled_decimal(lhs); |
1301 | 6 | if (rhs->isDecimal()) { |
1302 | 4 | return scaled_decimal_equal_decimal(lhs_decimal, get_scaled_decimal(rhs)); |
1303 | 4 | } |
1304 | 2 | return scaled_decimal_equal_integer(lhs_decimal, rhs->int_val()); |
1305 | 6 | } |
1306 | | |
1307 | 93 | if (rhs->isDecimal()) { |
1308 | 2 | return scaled_decimal_equal_integer(get_scaled_decimal(rhs), lhs->int_val()); |
1309 | 2 | } |
1310 | | |
1311 | 91 | return lhs->int_val() == rhs->int_val(); |
1312 | 93 | } |
1313 | | |
1314 | 67 | inline bool array_contains_value(const ArrayVal* target_array, const JsonbValue* candidate) { |
1315 | 170 | for (auto it = target_array->begin(); it < target_array->end(); ++it) { |
1316 | 133 | if (it->contains(candidate)) { |
1317 | 30 | return true; |
1318 | 30 | } |
1319 | 133 | } |
1320 | 37 | return false; |
1321 | 67 | } |
1322 | | |
1323 | 24 | inline bool array_contains_array(const ArrayVal* target_array, const ArrayVal* candidate_array) { |
1324 | 41 | for (auto it = candidate_array->begin(); it < candidate_array->end(); ++it) { |
1325 | 31 | if (!array_contains_value(target_array, &*it)) { |
1326 | 14 | return false; |
1327 | 14 | } |
1328 | 31 | } |
1329 | 10 | return true; |
1330 | 24 | } |
1331 | | |
1332 | | } // namespace jsonb_detail |
1333 | | |
1334 | 131k | inline const JsonbValue* JsonbDocument::createValue(const char* pb, size_t size) { |
1335 | 131k | if (!pb || size < sizeof(JsonbHeader) + sizeof(JsonbValue)) { |
1336 | 0 | return nullptr; |
1337 | 0 | } |
1338 | | |
1339 | 131k | auto* doc = (JsonbDocument*)pb; |
1340 | 131k | if (doc->header_.ver_ != JSONB_VER) { |
1341 | 0 | return nullptr; |
1342 | 0 | } |
1343 | | |
1344 | 131k | const auto* val = (const JsonbValue*)doc->payload_; |
1345 | | // Same as checkAndCreateDocument(), this is intentionally a lightweight structural check for |
1346 | | // hot paths. Do not recursively validate container bodies here unless the caller is a clearly |
1347 | | // untrusted raw binary boundary and accepts the O(document size) cost. |
1348 | 131k | if (size != sizeof(JsonbHeader) + val->numPackedBytes()) { |
1349 | 0 | return nullptr; |
1350 | 0 | } |
1351 | | |
1352 | 131k | return val; |
1353 | 131k | } |
1354 | | |
1355 | 200 | inline unsigned int JsonbDocument::numPackedBytes() const { |
1356 | 200 | return ((const JsonbValue*)payload_)->numPackedBytes() + sizeof(header_); |
1357 | 200 | } |
1358 | | |
1359 | 960k | inline unsigned int JsonbKeyValue::numPackedBytes() const { |
1360 | 960k | unsigned int ks = keyPackedBytes(); |
1361 | 960k | const auto* val = (const JsonbValue*)(((char*)this) + ks); |
1362 | 960k | return ks + val->numPackedBytes(); |
1363 | 960k | } |
1364 | | |
1365 | | // Poor man's "virtual" function JsonbValue::numPackedBytes |
1366 | 3.07M | inline unsigned int JsonbValue::numPackedBytes() const { |
1367 | 3.07M | switch (type) { |
1368 | 12.2k | case JsonbType::T_Null: |
1369 | 33.9k | case JsonbType::T_True: |
1370 | 39.2k | case JsonbType::T_False: { |
1371 | 39.2k | return sizeof(type); |
1372 | 33.9k | } |
1373 | | |
1374 | 226k | case JsonbType::T_Int8: { |
1375 | 226k | return sizeof(type) + sizeof(int8_t); |
1376 | 33.9k | } |
1377 | 281k | case JsonbType::T_Int16: { |
1378 | 281k | return sizeof(type) + sizeof(int16_t); |
1379 | 33.9k | } |
1380 | 553k | case JsonbType::T_Int32: { |
1381 | 553k | return sizeof(type) + sizeof(int32_t); |
1382 | 33.9k | } |
1383 | 52.3k | case JsonbType::T_Int64: { |
1384 | 52.3k | return sizeof(type) + sizeof(int64_t); |
1385 | 33.9k | } |
1386 | 15.3k | case JsonbType::T_Double: { |
1387 | 15.3k | return sizeof(type) + sizeof(double); |
1388 | 33.9k | } |
1389 | 4.75k | case JsonbType::T_Float: { |
1390 | 4.75k | return sizeof(type) + sizeof(float); |
1391 | 33.9k | } |
1392 | 21.7k | case JsonbType::T_Int128: { |
1393 | 21.7k | return sizeof(type) + sizeof(int128_t); |
1394 | 33.9k | } |
1395 | 66.6k | case JsonbType::T_String: |
1396 | 90.8k | case JsonbType::T_Binary: { |
1397 | 90.8k | return unpack<JsonbBinaryVal>()->numPackedBytes(); |
1398 | 66.6k | } |
1399 | | |
1400 | 1.11M | case JsonbType::T_Object: |
1401 | 1.79M | case JsonbType::T_Array: { |
1402 | 1.79M | return unpack<ContainerVal>()->numPackedBytes(); |
1403 | 1.11M | } |
1404 | 79 | case JsonbType::T_Decimal32: { |
1405 | 79 | return JsonbDecimal32::numPackedBytes(); |
1406 | 1.11M | } |
1407 | 87 | case JsonbType::T_Decimal64: { |
1408 | 87 | return JsonbDecimal64::numPackedBytes(); |
1409 | 1.11M | } |
1410 | 99 | case JsonbType::T_Decimal128: { |
1411 | 99 | return JsonbDecimal128::numPackedBytes(); |
1412 | 1.11M | } |
1413 | 6 | case JsonbType::T_Decimal256: { |
1414 | 6 | return JsonbDecimal256::numPackedBytes(); |
1415 | 1.11M | } |
1416 | 0 | case JsonbType::NUM_TYPES: |
1417 | 0 | break; |
1418 | 3.07M | } |
1419 | | |
1420 | 0 | throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}", |
1421 | 0 | static_cast<int32_t>(type)); |
1422 | 3.07M | } |
1423 | | |
1424 | 143 | inline int JsonbValue::numElements() const { |
1425 | 143 | switch (type) { |
1426 | 8 | case JsonbType::T_Int8: |
1427 | 18 | case JsonbType::T_Int16: |
1428 | 20 | case JsonbType::T_Int32: |
1429 | 23 | case JsonbType::T_Int64: |
1430 | 25 | case JsonbType::T_Double: |
1431 | 25 | case JsonbType::T_Float: |
1432 | 27 | case JsonbType::T_Int128: |
1433 | 35 | case JsonbType::T_String: |
1434 | 35 | case JsonbType::T_Binary: |
1435 | 40 | case JsonbType::T_Null: |
1436 | 46 | case JsonbType::T_True: |
1437 | 48 | case JsonbType::T_False: |
1438 | 48 | case JsonbType::T_Decimal32: |
1439 | 48 | case JsonbType::T_Decimal64: |
1440 | 48 | case JsonbType::T_Decimal128: |
1441 | 48 | case JsonbType::T_Decimal256: { |
1442 | 48 | return 1; |
1443 | 48 | } |
1444 | 29 | case JsonbType::T_Object: { |
1445 | 29 | return unpack<ObjectVal>()->numElem(); |
1446 | 48 | } |
1447 | 66 | case JsonbType::T_Array: { |
1448 | 66 | return unpack<ArrayVal>()->numElem(); |
1449 | 48 | } |
1450 | 0 | case JsonbType::NUM_TYPES: |
1451 | 0 | break; |
1452 | 143 | } |
1453 | 0 | throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}", |
1454 | 0 | static_cast<int32_t>(type)); |
1455 | 143 | } |
1456 | | |
1457 | 421 | inline bool JsonbValue::contains(const JsonbValue* rhs) const { |
1458 | 421 | switch (type) { |
1459 | 104 | case JsonbType::T_Int8: |
1460 | 134 | case JsonbType::T_Int16: |
1461 | 140 | case JsonbType::T_Int32: |
1462 | 149 | case JsonbType::T_Int64: |
1463 | 156 | case JsonbType::T_Int128: |
1464 | 182 | case JsonbType::T_Double: |
1465 | 182 | case JsonbType::T_Float: |
1466 | 188 | case JsonbType::T_Decimal32: |
1467 | 189 | case JsonbType::T_Decimal64: |
1468 | 192 | case JsonbType::T_Decimal128: |
1469 | 192 | case JsonbType::T_Decimal256: { |
1470 | 192 | return jsonb_detail::numeric_equal(this, rhs); |
1471 | 192 | } |
1472 | 47 | case JsonbType::T_String: |
1473 | 47 | case JsonbType::T_Binary: { |
1474 | 47 | if (rhs->isString() || rhs->isBinary()) { |
1475 | 19 | const auto* str_value1 = unpack<JsonbStringVal>(); |
1476 | 19 | const auto* str_value2 = rhs->unpack<JsonbStringVal>(); |
1477 | 19 | return str_value1->length() == str_value2->length() && |
1478 | 19 | std::memcmp(str_value1->getBlob(), str_value2->getBlob(), |
1479 | 18 | str_value1->length()) == 0; |
1480 | 19 | } |
1481 | 28 | return false; |
1482 | 47 | } |
1483 | 60 | case JsonbType::T_Array: { |
1484 | 60 | const auto* lhs_array = unpack<ArrayVal>(); |
1485 | 60 | if (rhs->isArray()) { |
1486 | 24 | return jsonb_detail::array_contains_array(lhs_array, rhs->unpack<ArrayVal>()); |
1487 | 24 | } |
1488 | 36 | return jsonb_detail::array_contains_value(lhs_array, rhs); |
1489 | 60 | } |
1490 | 88 | case JsonbType::T_Object: { |
1491 | 88 | if (rhs->isObject()) { |
1492 | 55 | const auto* obj_value1 = unpack<ObjectVal>(); |
1493 | 55 | const auto* obj_value2 = rhs->unpack<ObjectVal>(); |
1494 | 104 | for (auto it = obj_value2->begin(); it != obj_value2->end(); ++it) { |
1495 | | // A key stored as an id (including the empty key sentinel) has klen() == 0 and |
1496 | | // must be matched by id, not looked up as an empty key name. |
1497 | 73 | const JsonbValue* value = it->klen() == 0 |
1498 | 73 | ? obj_value1->find_by_key_id(it->getKeyId()) |
1499 | 73 | : obj_value1->find(it->getKeyStr(), it->klen()); |
1500 | 73 | if (value == nullptr || !value->contains(it->value())) { |
1501 | 24 | return false; |
1502 | 24 | } |
1503 | 73 | } |
1504 | 31 | return true; |
1505 | 55 | } |
1506 | 33 | return false; |
1507 | 88 | } |
1508 | 12 | case JsonbType::T_Null: { |
1509 | 12 | return rhs->isNull(); |
1510 | 88 | } |
1511 | 12 | case JsonbType::T_True: { |
1512 | 12 | return rhs->isTrue(); |
1513 | 88 | } |
1514 | 10 | case JsonbType::T_False: { |
1515 | 10 | return rhs->isFalse(); |
1516 | 88 | } |
1517 | 0 | case JsonbType::NUM_TYPES: |
1518 | 0 | break; |
1519 | 421 | } |
1520 | | |
1521 | 0 | throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}", |
1522 | 0 | static_cast<int32_t>(type)); |
1523 | 421 | } |
1524 | | |
1525 | 15.2k | inline bool JsonbPath::seek(const char* key_path, size_t kp_len) { |
1526 | 15.3k | while (kp_len > 0 && std::isspace(key_path[kp_len - 1])) { |
1527 | 7 | --kp_len; |
1528 | 7 | } |
1529 | | |
1530 | | //path invalid |
1531 | 15.2k | if (!key_path || kp_len == 0) { |
1532 | 2 | return false; |
1533 | 2 | } |
1534 | 15.2k | Stream stream(key_path, kp_len); |
1535 | 15.2k | stream.skip_whitespace(); |
1536 | 15.2k | if (stream.exhausted() || stream.read() != SCOPE) { |
1537 | | //path invalid |
1538 | 2 | return false; |
1539 | 2 | } |
1540 | | |
1541 | 36.6k | while (!stream.exhausted()) { |
1542 | 21.4k | stream.skip_whitespace(); |
1543 | 21.4k | stream.clear_leg_ptr(); |
1544 | 21.4k | stream.clear_leg_len(); |
1545 | 21.4k | stream.set_has_escapes(false); |
1546 | | |
1547 | 21.4k | if (!JsonbPath::parsePath(&stream, this)) { |
1548 | | //path invalid |
1549 | 25 | return false; |
1550 | 25 | } |
1551 | 21.4k | } |
1552 | 15.2k | return true; |
1553 | 15.2k | } |
1554 | | |
1555 | 21.4k | inline bool JsonbPath::parsePath(Stream* stream, JsonbPath* path) { |
1556 | | // $[0] |
1557 | 21.4k | if (stream->peek() == BEGIN_ARRAY) { |
1558 | 11.0k | return parse_array(stream, path); |
1559 | 11.0k | } |
1560 | | // $.a or $.[0] |
1561 | | // Keep $.[0] for backward compatibility: although the dot before an array |
1562 | | // leg is non-standard, existing JSONB users may rely on it. |
1563 | 10.3k | else if (stream->peek() == BEGIN_MEMBER) { |
1564 | | // advance past the . |
1565 | 10.3k | stream->skip(1); |
1566 | | |
1567 | 10.3k | if (stream->exhausted()) { |
1568 | 20 | return false; |
1569 | 20 | } |
1570 | | |
1571 | | // $.[0] |
1572 | 10.2k | if (stream->peek() == BEGIN_ARRAY) { |
1573 | 248 | return parse_array(stream, path); |
1574 | 248 | } |
1575 | | // $.a |
1576 | 10.0k | else { |
1577 | 10.0k | return parse_member(stream, path); |
1578 | 10.0k | } |
1579 | 10.2k | } else if (stream->peek() == WILDCARD) { |
1580 | 16 | stream->skip(1); |
1581 | 16 | if (stream->exhausted()) { |
1582 | 0 | return false; |
1583 | 0 | } |
1584 | | |
1585 | | // $** |
1586 | 16 | if (stream->peek() == WILDCARD) { |
1587 | 16 | path->_is_supper_wildcard = true; |
1588 | 16 | } |
1589 | | |
1590 | 16 | stream->skip(1); |
1591 | 16 | if (stream->exhausted()) { |
1592 | 2 | return false; |
1593 | 2 | } |
1594 | | |
1595 | 14 | if (stream->peek() == BEGIN_ARRAY) { |
1596 | 2 | return parse_array(stream, path); |
1597 | 12 | } else if (stream->peek() == BEGIN_MEMBER) { |
1598 | | // advance past the . |
1599 | 12 | stream->skip(1); |
1600 | | |
1601 | 12 | if (stream->exhausted()) { |
1602 | 0 | return false; |
1603 | 0 | } |
1604 | | |
1605 | | // $**.[0] |
1606 | | // Keep the dot-array form compatible with the root path behavior. |
1607 | 12 | if (stream->peek() == BEGIN_ARRAY) { |
1608 | 0 | return parse_array(stream, path); |
1609 | 0 | } |
1610 | | // $.a |
1611 | 12 | else { |
1612 | 12 | return parse_member(stream, path); |
1613 | 12 | } |
1614 | 12 | } |
1615 | 0 | return false; |
1616 | 14 | } else { |
1617 | 0 | return false; //invalid json path |
1618 | 0 | } |
1619 | 21.4k | } |
1620 | | |
1621 | 11.3k | inline bool JsonbPath::parse_array(Stream* stream, JsonbPath* path) { |
1622 | 11.3k | assert(stream->peek() == BEGIN_ARRAY); |
1623 | 11.3k | stream->skip(1); |
1624 | 11.3k | if (stream->exhausted()) { |
1625 | 0 | return false; |
1626 | 0 | } |
1627 | | |
1628 | 11.3k | if (stream->peek() == WILDCARD) { |
1629 | | // Called by function_jsonb.cpp, the variables passed in originate from a mutable block; |
1630 | | // using const_cast is acceptable. |
1631 | 25 | stream->set_leg_ptr(const_cast<char*>(stream->position())); |
1632 | 25 | stream->add_leg_len(); |
1633 | 25 | stream->skip(1); |
1634 | 25 | if (stream->exhausted()) { |
1635 | 0 | return false; |
1636 | 0 | } |
1637 | | |
1638 | 25 | if (stream->peek() == END_ARRAY) { |
1639 | 25 | std::unique_ptr<leg_info> leg( |
1640 | 25 | new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, ARRAY_CODE)); |
1641 | 25 | leg->is_wildcard = true; |
1642 | 25 | path->add_leg_to_leg_vector(std::move(leg)); |
1643 | 25 | stream->skip(1); |
1644 | 25 | path->_is_wildcard = true; |
1645 | 25 | return true; |
1646 | 25 | } else { |
1647 | 0 | return false; |
1648 | 0 | } |
1649 | 25 | } |
1650 | | |
1651 | | // Called by function_jsonb.cpp, the variables passed in originate from a mutable block; |
1652 | | // using const_cast is acceptable. |
1653 | 11.3k | stream->set_leg_ptr(const_cast<char*>(stream->position())); |
1654 | | |
1655 | 33.0k | for (; !stream->exhausted() && stream->peek() != END_ARRAY; stream->advance()) { |
1656 | 21.7k | stream->add_leg_len(); |
1657 | 21.7k | } |
1658 | | |
1659 | 11.3k | if (stream->exhausted() || stream->peek() != END_ARRAY) { |
1660 | 0 | return false; |
1661 | 11.3k | } else { |
1662 | 11.3k | stream->skip(1); |
1663 | 11.3k | } |
1664 | | |
1665 | | //parse array index to int |
1666 | | |
1667 | 11.3k | std::string_view idx_string(stream->get_leg_ptr(), stream->get_leg_len()); |
1668 | 11.3k | int index = 0; |
1669 | | |
1670 | | // Match "last" case-insensitively for compatibility with existing JSONB |
1671 | | // paths such as [Last] and [LAST]. |
1672 | 11.3k | if (stream->get_leg_len() >= 4 && |
1673 | 11.3k | std::equal(LAST, LAST + 4, stream->get_leg_ptr(), |
1674 | 6.71k | [](char c1, char c2) { return std::tolower(c1) == std::tolower(c2); })) { |
1675 | 1.67k | auto pos = idx_string.find(MINUS); |
1676 | | |
1677 | 1.67k | if (pos != std::string::npos) { |
1678 | 1.34k | for (size_t i = 4; i < pos; ++i) { |
1679 | 6 | if (std::isspace(idx_string[i])) { |
1680 | 4 | continue; |
1681 | 4 | } else { |
1682 | | // leading zeroes are not allowed |
1683 | 2 | LOG(WARNING) << "Non-space char in idx_string: '" << idx_string << "'"; |
1684 | 2 | return false; |
1685 | 2 | } |
1686 | 6 | } |
1687 | 1.33k | idx_string = idx_string.substr(pos + 1); |
1688 | 1.33k | idx_string = trim(idx_string); |
1689 | | |
1690 | | // Keep numeric-prefix parsing for last-N offsets as existing JSONB |
1691 | | // path behavior. |
1692 | 1.33k | auto result = std::from_chars(idx_string.data(), idx_string.data() + idx_string.size(), |
1693 | 1.33k | index); |
1694 | 1.33k | if (result.ec != std::errc()) { |
1695 | 0 | LOG(WARNING) << "Invalid index in JSON path: '" << idx_string << "'"; |
1696 | 0 | return false; |
1697 | 0 | } |
1698 | | |
1699 | 1.33k | } else if (stream->get_leg_len() > 4) { |
1700 | 0 | return false; |
1701 | 0 | } |
1702 | | |
1703 | 1.67k | std::unique_ptr<leg_info> leg(new leg_info(nullptr, 0, -index - 1, ARRAY_CODE)); |
1704 | 1.67k | path->add_leg_to_leg_vector(std::move(leg)); |
1705 | | |
1706 | 1.67k | return true; |
1707 | 1.67k | } |
1708 | | |
1709 | | // Preserve legacy numeric-prefix parsing for array indexes. std::from_chars |
1710 | | // may stop before the end (for example [1.5] is parsed as index 1), and |
1711 | | // current JSONB path semantics treat that as supported behavior. |
1712 | 9.63k | auto result = std::from_chars(idx_string.data(), idx_string.data() + idx_string.size(), index); |
1713 | | |
1714 | 9.63k | if (result.ec != std::errc()) { |
1715 | 0 | return false; |
1716 | 0 | } |
1717 | | |
1718 | 9.63k | std::unique_ptr<leg_info> leg(new leg_info(nullptr, 0, index, ARRAY_CODE)); |
1719 | 9.63k | path->add_leg_to_leg_vector(std::move(leg)); |
1720 | | |
1721 | 9.63k | return true; |
1722 | 9.63k | } |
1723 | | |
1724 | 10.0k | inline bool JsonbPath::parse_member(Stream* stream, JsonbPath* path) { |
1725 | 10.0k | if (stream->exhausted()) { |
1726 | 0 | return false; |
1727 | 0 | } |
1728 | | |
1729 | 10.0k | if (stream->peek() == WILDCARD) { |
1730 | | // Called by function_jsonb.cpp, the variables passed in originate from a mutable block; |
1731 | | // using const_cast is acceptable. |
1732 | 127 | stream->set_leg_ptr(const_cast<char*>(stream->position())); |
1733 | 127 | stream->add_leg_len(); |
1734 | 127 | stream->skip(1); |
1735 | 127 | std::unique_ptr<leg_info> leg( |
1736 | 127 | new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, MEMBER_CODE)); |
1737 | 127 | leg->is_wildcard = true; |
1738 | 127 | path->add_leg_to_leg_vector(std::move(leg)); |
1739 | 127 | path->_is_wildcard = true; |
1740 | 127 | return true; |
1741 | 127 | } |
1742 | | |
1743 | | // Called by function_jsonb.cpp, the variables passed in originate from a mutable block; |
1744 | | // using const_cast is acceptable. |
1745 | 9.92k | stream->set_leg_ptr(const_cast<char*>(stream->position())); |
1746 | | |
1747 | 9.92k | const char* left_quotation_marks = nullptr; |
1748 | 9.92k | const char* right_quotation_marks = nullptr; |
1749 | | |
1750 | 33.5k | for (; !stream->exhausted(); stream->advance()) { |
1751 | | // Only accept space characters quoted by double quotes. |
1752 | 30.6k | if (std::isspace(stream->peek()) && left_quotation_marks == nullptr) { |
1753 | 0 | return false; |
1754 | 30.6k | } else if (stream->peek() == ESCAPE) { |
1755 | 16 | stream->add_leg_len(); |
1756 | 16 | stream->skip(1); |
1757 | 16 | stream->add_leg_len(); |
1758 | 16 | stream->set_has_escapes(true); |
1759 | 16 | if (stream->exhausted()) { |
1760 | 0 | return false; |
1761 | 0 | } |
1762 | 16 | continue; |
1763 | 30.6k | } else if (stream->peek() == DOUBLE_QUOTE) { |
1764 | 476 | if (left_quotation_marks == nullptr) { |
1765 | 238 | left_quotation_marks = stream->position(); |
1766 | | // Called by function_jsonb.cpp, the variables passed in originate from a mutable block; |
1767 | | // using const_cast is acceptable. |
1768 | 238 | stream->set_leg_ptr(const_cast<char*>(++left_quotation_marks)); |
1769 | 238 | continue; |
1770 | 238 | } else { |
1771 | 238 | right_quotation_marks = stream->position(); |
1772 | 238 | stream->skip(1); |
1773 | 238 | break; |
1774 | 238 | } |
1775 | 30.1k | } else if (stream->peek() == BEGIN_MEMBER || stream->peek() == BEGIN_ARRAY) { |
1776 | 7.11k | if (left_quotation_marks == nullptr) { |
1777 | 6.79k | break; |
1778 | 6.79k | } |
1779 | 7.11k | } |
1780 | | |
1781 | 23.3k | stream->add_leg_len(); |
1782 | 23.3k | } |
1783 | | |
1784 | | // An empty member name is only valid when it is written explicitly as `""`. |
1785 | 9.92k | if ((left_quotation_marks != nullptr && right_quotation_marks == nullptr) || |
1786 | 9.92k | stream->get_leg_ptr() == nullptr || |
1787 | 9.92k | (left_quotation_marks == nullptr && stream->get_leg_len() == 0)) { |
1788 | 1 | return false; //invalid json path |
1789 | 1 | } |
1790 | | |
1791 | 9.92k | if (stream->get_has_escapes()) { |
1792 | 8 | stream->remove_escapes(); |
1793 | 8 | } |
1794 | | |
1795 | 9.92k | std::unique_ptr<leg_info> leg( |
1796 | 9.92k | new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, MEMBER_CODE)); |
1797 | 9.92k | path->add_leg_to_leg_vector(std::move(leg)); |
1798 | | |
1799 | 9.92k | return true; |
1800 | 9.92k | } |
1801 | | |
1802 | | static_assert(is_pod_v<JsonbDocument>, "JsonbDocument must be standard layout and trivial"); |
1803 | | static_assert(is_pod_v<JsonbValue>, "JsonbValue must be standard layout and trivial"); |
1804 | | static_assert(is_pod_v<JsonbDecimal32>, "JsonbDecimal32 must be standard layout and trivial"); |
1805 | | static_assert(is_pod_v<JsonbDecimal64>, "JsonbDecimal64 must be standard layout and trivial"); |
1806 | | static_assert(is_pod_v<JsonbDecimal128>, "JsonbDecimal128 must be standard layout and trivial"); |
1807 | | static_assert(is_pod_v<JsonbDecimal256>, "JsonbDecimal256 must be standard layout and trivial"); |
1808 | | static_assert(is_pod_v<JsonbInt8Val>, "JsonbInt8Val must be standard layout and trivial"); |
1809 | | static_assert(is_pod_v<JsonbInt32Val>, "JsonbInt32Val must be standard layout and trivial"); |
1810 | | static_assert(is_pod_v<JsonbInt64Val>, "JsonbInt64Val must be standard layout and trivial"); |
1811 | | static_assert(is_pod_v<JsonbInt128Val>, "JsonbInt128Val must be standard layout and trivial"); |
1812 | | static_assert(is_pod_v<JsonbDoubleVal>, "JsonbDoubleVal must be standard layout and trivial"); |
1813 | | static_assert(is_pod_v<JsonbFloatVal>, "JsonbFloatVal must be standard layout and trivial"); |
1814 | | static_assert(is_pod_v<JsonbBinaryVal>, "JsonbBinaryVal must be standard layout and trivial"); |
1815 | | static_assert(is_pod_v<ContainerVal>, "ContainerVal must be standard layout and trivial"); |
1816 | | |
1817 | | #define ASSERT_DECIMAL_LAYOUT(type) \ |
1818 | | static_assert(offsetof(type, precision) == 0); \ |
1819 | | static_assert(offsetof(type, scale) == 4); \ |
1820 | | static_assert(offsetof(type, value) == 8); |
1821 | | |
1822 | | ASSERT_DECIMAL_LAYOUT(JsonbDecimal32) |
1823 | | ASSERT_DECIMAL_LAYOUT(JsonbDecimal64) |
1824 | | ASSERT_DECIMAL_LAYOUT(JsonbDecimal128) |
1825 | | ASSERT_DECIMAL_LAYOUT(JsonbDecimal256) |
1826 | | |
1827 | | #define ASSERT_NUMERIC_LAYOUT(type) static_assert(offsetof(type, num) == 0); |
1828 | | |
1829 | | ASSERT_NUMERIC_LAYOUT(JsonbInt8Val) |
1830 | | ASSERT_NUMERIC_LAYOUT(JsonbInt32Val) |
1831 | | ASSERT_NUMERIC_LAYOUT(JsonbInt64Val) |
1832 | | ASSERT_NUMERIC_LAYOUT(JsonbInt128Val) |
1833 | | ASSERT_NUMERIC_LAYOUT(JsonbDoubleVal) |
1834 | | |
1835 | | static_assert(offsetof(JsonbBinaryVal, size) == 0); |
1836 | | static_assert(offsetof(JsonbBinaryVal, payload) == 4); |
1837 | | |
1838 | | static_assert(offsetof(ContainerVal, size) == 0); |
1839 | | static_assert(offsetof(ContainerVal, payload) == 4); |
1840 | | |
1841 | | #pragma pack(pop) |
1842 | | #if defined(__clang__) |
1843 | | #pragma clang diagnostic pop |
1844 | | #endif |
1845 | | } // namespace doris |
1846 | | |
1847 | | #endif // JSONB_JSONBDOCUMENT_H |