/root/doris/be/src/util/jsonb_document.h
Line | Count | Source (jump to first uncovered line) |
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 <cctype> |
71 | | #include <charconv> |
72 | | #include <limits> |
73 | | #include <string> |
74 | | #include <type_traits> |
75 | | |
76 | | #include "common/compiler_util.h" // IWYU pragma: keep |
77 | | #include "common/status.h" |
78 | | |
79 | | // #include "util/string_parser.hpp" |
80 | | |
81 | | namespace doris { |
82 | | #if defined(__clang__) |
83 | | #pragma clang diagnostic push |
84 | | #pragma clang diagnostic ignored "-Wzero-length-array" |
85 | | #endif |
86 | | #pragma pack(push, 1) |
87 | | |
88 | 389k | #define JSONB_VER 1 |
89 | | |
90 | | using int128_t = __int128; |
91 | | |
92 | | // forward declaration |
93 | | class JsonbValue; |
94 | | class ObjectVal; |
95 | | |
96 | | const int MaxNestingLevel = 100; |
97 | | |
98 | | /* |
99 | | * JsonbType defines 10 primitive types and 2 container types, as described |
100 | | * below. |
101 | | * |
102 | | * primitive_value ::= |
103 | | * 0x00 //null value (0 byte) |
104 | | * | 0x01 //boolean true (0 byte) |
105 | | * | 0x02 //boolean false (0 byte) |
106 | | * | 0x03 int8 //char/int8 (1 byte) |
107 | | * | 0x04 int16 //int16 (2 bytes) |
108 | | * | 0x05 int32 //int32 (4 bytes) |
109 | | * | 0x06 int64 //int64 (8 bytes) |
110 | | * | 0x07 double //floating point (8 bytes) |
111 | | * | 0x08 string //variable length string |
112 | | * | 0x09 binary //variable length binary |
113 | | * |
114 | | * container ::= |
115 | | * 0x0A int32 key_value_list //object, int32 is the total bytes of the object |
116 | | * | 0x0B int32 value_list //array, int32 is the total bytes of the array |
117 | | */ |
118 | | enum class JsonbType : char { |
119 | | T_Null = 0x00, |
120 | | T_True = 0x01, |
121 | | T_False = 0x02, |
122 | | T_Int8 = 0x03, |
123 | | T_Int16 = 0x04, |
124 | | T_Int32 = 0x05, |
125 | | T_Int64 = 0x06, |
126 | | T_Double = 0x07, |
127 | | T_String = 0x08, |
128 | | T_Binary = 0x09, |
129 | | T_Object = 0x0A, |
130 | | T_Array = 0x0B, |
131 | | T_Int128 = 0x0C, |
132 | | T_Float = 0x0D, |
133 | | NUM_TYPES, |
134 | | }; |
135 | | |
136 | | //for parse json path |
137 | | constexpr char SCOPE = '$'; |
138 | | constexpr char BEGIN_MEMBER = '.'; |
139 | | constexpr char BEGIN_ARRAY = '['; |
140 | | constexpr char END_ARRAY = ']'; |
141 | | constexpr char DOUBLE_QUOTE = '"'; |
142 | | constexpr char WILDCARD = '*'; |
143 | | constexpr char MINUS = '-'; |
144 | | constexpr char LAST[] = "last"; |
145 | | constexpr char ESCAPE = '\\'; |
146 | | constexpr unsigned int MEMBER_CODE = 0; |
147 | | constexpr unsigned int ARRAY_CODE = 1; |
148 | | |
149 | | /* |
150 | | * JsonbDocument is the main object that accesses and queries JSONB packed |
151 | | * bytes. NOTE: JsonbDocument only allows object container as the top level |
152 | | * JSONB value. However, you can use the static method "createValue" to get any |
153 | | * JsonbValue object from the packed bytes. |
154 | | * |
155 | | * JsonbDocument object also dereferences to an object container value |
156 | | * (ObjectVal) once JSONB is loaded. |
157 | | * |
158 | | * ** Load ** |
159 | | * JsonbDocument is usable after loading packed bytes (memory location) into |
160 | | * the object. We only need the header and first few bytes of the payload after |
161 | | * header to verify the JSONB. |
162 | | * |
163 | | * Note: creating an JsonbDocument (through createDocument) does not allocate |
164 | | * any memory. The document object is an efficient wrapper on the packed bytes |
165 | | * which is accessed directly. |
166 | | * |
167 | | * ** Query ** |
168 | | * Query is through dereferencing into ObjectVal. |
169 | | */ |
170 | | class JsonbDocument { |
171 | | public: |
172 | | // create an JsonbDocument object from JSONB packed bytes |
173 | | [[nodiscard]] static Status checkAndCreateDocument(const char* pb, size_t size, |
174 | | JsonbDocument** doc); |
175 | | |
176 | | // create an JsonbValue from JSONB packed bytes |
177 | | static JsonbValue* createValue(const char* pb, uint32_t size); |
178 | | |
179 | 0 | uint8_t version() const { return header_.ver_; } |
180 | | |
181 | 24.6k | JsonbValue* getValue() { return ((JsonbValue*)payload_); } |
182 | | |
183 | | void setValue(const JsonbValue* value); |
184 | | |
185 | | unsigned int numPackedBytes() const; |
186 | | |
187 | 17.7k | ObjectVal* operator->() { return ((ObjectVal*)payload_); } |
188 | | |
189 | 0 | const ObjectVal* operator->() const { return ((const ObjectVal*)payload_); } |
190 | | |
191 | 0 | bool operator==(const JsonbDocument& other) const { |
192 | 0 | assert(false); |
193 | 0 | return false; |
194 | 0 | } |
195 | | |
196 | 0 | bool operator!=(const JsonbDocument& other) const { |
197 | 0 | assert(false); |
198 | 0 | return false; |
199 | 0 | } |
200 | | |
201 | 0 | bool operator<=(const JsonbDocument& other) const { |
202 | 0 | assert(false); |
203 | 0 | return false; |
204 | 0 | } |
205 | | |
206 | 0 | bool operator>=(const JsonbDocument& other) const { |
207 | 0 | assert(false); |
208 | 0 | return false; |
209 | 0 | } |
210 | | |
211 | 0 | bool operator<(const JsonbDocument& other) const { |
212 | 0 | assert(false); |
213 | 0 | return false; |
214 | 0 | } |
215 | | |
216 | 0 | bool operator>(const JsonbDocument& other) const { |
217 | 0 | assert(false); |
218 | 0 | return false; |
219 | 0 | } |
220 | | |
221 | | private: |
222 | | /* |
223 | | * JsonbHeader class defines JSONB header (internal to JsonbDocument). |
224 | | * |
225 | | * Currently it only contains version information (1-byte). We may expand the |
226 | | * header to include checksum of the JSONB binary for more security. |
227 | | */ |
228 | | struct JsonbHeader { |
229 | | uint8_t ver_; |
230 | | } header_; |
231 | | |
232 | | char payload_[0]; |
233 | | }; |
234 | | |
235 | | /// A simple input stream class for the JSON path parser. |
236 | | class Stream { |
237 | | public: |
238 | | /// Creates an input stream reading from a character string. |
239 | | /// @param string the input string |
240 | | /// @param length the length of the input string |
241 | 846 | Stream(const char* string, size_t length) : m_position(string), m_end(string + length) {} |
242 | | |
243 | | /// Returns a pointer to the current position in the stream. |
244 | 850 | const char* position() const { return m_position; } |
245 | | |
246 | | /// Returns a pointer to the position just after the end of the stream. |
247 | 0 | const char* end() const { return m_end; } |
248 | | |
249 | | /// Returns the number of bytes remaining in the stream. |
250 | 16.5k | size_t remaining() const { |
251 | 16.5k | assert(m_position <= m_end); |
252 | 0 | return m_end - m_position; |
253 | 16.5k | } |
254 | | |
255 | | /// Tells if the stream has been exhausted. |
256 | 14.0k | bool exhausted() const { return remaining() == 0; } |
257 | | |
258 | | /// Reads the next byte from the stream and moves the position forward. |
259 | 846 | char read() { |
260 | 846 | assert(!exhausted()); |
261 | 0 | return *m_position++; |
262 | 846 | } |
263 | | |
264 | | /// Reads the next byte from the stream without moving the position forward. |
265 | 6.94k | char peek() const { |
266 | 6.94k | assert(!exhausted()); |
267 | 0 | return *m_position; |
268 | 6.94k | } |
269 | | |
270 | | /// Moves the position to the next non-whitespace character. |
271 | 4.24k | void skip_whitespace() { |
272 | 4.24k | m_position = std::find_if_not(m_position, m_end, [](char c) { return std::isspace(c); }); |
273 | 4.24k | } |
274 | | |
275 | | /// Moves the position n bytes forward. |
276 | 2.55k | void skip(size_t n) { |
277 | 2.55k | assert(remaining() >= n); |
278 | 0 | m_position += n; |
279 | 2.55k | skip_whitespace(); |
280 | 2.55k | } |
281 | | |
282 | 1.70k | void clear_leg_ptr() { leg_ptr = nullptr; } |
283 | | |
284 | 850 | void set_leg_ptr(char* ptr) { |
285 | 850 | clear_leg_ptr(); |
286 | 850 | leg_ptr = ptr; |
287 | 850 | } |
288 | | |
289 | 1.15k | char* get_leg_ptr() { return leg_ptr; } |
290 | | |
291 | 850 | void clear_leg_len() { leg_len = 0; } |
292 | | |
293 | 1.15k | void add_leg_len() { leg_len++; } |
294 | | |
295 | 1.70k | unsigned int get_leg_len() const { return leg_len; } |
296 | | |
297 | 0 | void remove_escapes() { |
298 | 0 | int new_len = 0; |
299 | 0 | for (int i = 0; i < leg_len; i++) { Branch (299:25): [True: 0, False: 0]
|
300 | 0 | if (leg_ptr[i] != '\\') { Branch (300:17): [True: 0, False: 0]
|
301 | 0 | leg_ptr[new_len++] = leg_ptr[i]; |
302 | 0 | } |
303 | 0 | } |
304 | 0 | leg_ptr[new_len] = '\0'; |
305 | 0 | leg_len = new_len; |
306 | 0 | } |
307 | | |
308 | 0 | void set_has_escapes(bool has) { has_escapes = has; } |
309 | | |
310 | 308 | bool get_has_escapes() const { return has_escapes; } |
311 | | |
312 | | private: |
313 | | /// The current position in the stream. |
314 | | const char* m_position = nullptr; |
315 | | |
316 | | /// The end of the stream. |
317 | | const char* const m_end; |
318 | | |
319 | | ///path leg ptr |
320 | | char* leg_ptr = nullptr; |
321 | | |
322 | | ///path leg len |
323 | | unsigned int leg_len; |
324 | | |
325 | | ///Whether to contain escape characters |
326 | | bool has_escapes = false; |
327 | | }; |
328 | | |
329 | | struct leg_info { |
330 | | ///path leg ptr |
331 | | char* leg_ptr = nullptr; |
332 | | |
333 | | ///path leg len |
334 | | unsigned int leg_len; |
335 | | |
336 | | ///array_index |
337 | | int array_index; |
338 | | |
339 | | ///type: 0 is member 1 is array |
340 | | unsigned int type; |
341 | | |
342 | 0 | bool to_string(std::string* str) const { |
343 | 0 | if (type == MEMBER_CODE) { Branch (343:13): [True: 0, False: 0]
|
344 | 0 | str->push_back(BEGIN_MEMBER); |
345 | 0 | str->append(leg_ptr, leg_len); |
346 | 0 | return true; |
347 | 0 | } else if (type == ARRAY_CODE) { Branch (347:20): [True: 0, False: 0]
|
348 | 0 | str->push_back(BEGIN_ARRAY); |
349 | 0 | std::string int_str = std::to_string(array_index); |
350 | 0 | str->append(int_str); |
351 | 0 | str->push_back(END_ARRAY); |
352 | 0 | return true; |
353 | 0 | } else { |
354 | 0 | return false; |
355 | 0 | } |
356 | 0 | } |
357 | | }; |
358 | | |
359 | | class JsonbPath { |
360 | | public: |
361 | | // parse json path |
362 | | static bool parsePath(Stream* stream, JsonbPath* path); |
363 | | |
364 | | static bool parse_array(Stream* stream, JsonbPath* path); |
365 | | static bool parse_member(Stream* stream, JsonbPath* path); |
366 | | |
367 | | //return true if json path valid else return false |
368 | | bool seek(const char* string, size_t length); |
369 | | |
370 | 850 | void add_leg_to_leg_vector(std::unique_ptr<leg_info> leg) { |
371 | 850 | leg_vector.emplace_back(leg.release()); |
372 | 850 | } |
373 | | |
374 | 0 | void pop_leg_from_leg_vector() { leg_vector.pop_back(); } |
375 | | |
376 | 0 | bool to_string(std::string* res) const { |
377 | 0 | res->push_back(SCOPE); |
378 | 0 | for (const auto& leg : leg_vector) { Branch (378:30): [True: 0, False: 0]
|
379 | 0 | auto valid = leg->to_string(res); |
380 | 0 | if (!valid) { Branch (380:17): [True: 0, False: 0]
|
381 | 0 | return false; |
382 | 0 | } |
383 | 0 | } |
384 | 0 | return true; |
385 | 0 | } |
386 | | |
387 | 1.05k | size_t get_leg_vector_size() { return leg_vector.size(); } |
388 | | |
389 | 2.39k | leg_info* get_leg_from_leg_vector(size_t i) { return leg_vector[i].get(); } |
390 | | |
391 | 0 | void clean() { leg_vector.clear(); } |
392 | | |
393 | | private: |
394 | | std::vector<std::unique_ptr<leg_info>> leg_vector; |
395 | | }; |
396 | | |
397 | | /* |
398 | | * JsonbFwdIteratorT implements JSONB's iterator template. |
399 | | * |
400 | | * Note: it is an FORWARD iterator only due to the design of JSONB format. |
401 | | */ |
402 | | template <class Iter_Type, class Cont_Type> |
403 | | class JsonbFwdIteratorT { |
404 | | public: |
405 | | using iterator = Iter_Type; |
406 | | using pointer = typename std::iterator_traits<Iter_Type>::pointer; |
407 | | using reference = typename std::iterator_traits<Iter_Type>::reference; |
408 | | |
409 | | explicit JsonbFwdIteratorT() : current_(nullptr) {} |
410 | 1.13M | explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {} _ZN5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEC2ERKS3_ Line | Count | Source | 410 | 499k | explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {} |
_ZN5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEC2ERKS3_ Line | Count | Source | 410 | 621k | explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {} |
_ZN5doris17JsonbFwdIteratorTIPNS_13JsonbKeyValueENS_9ObjectValEEC2ERKS2_ Line | Count | Source | 410 | 17.8k | explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {} |
Unexecuted instantiation: _ZN5doris17JsonbFwdIteratorTIPNS_10JsonbValueENS_8ArrayValEEC2ERKS2_ |
411 | | |
412 | | // allow non-const to const iterator conversion (same container type) |
413 | | template <class Iter_Ty> |
414 | | JsonbFwdIteratorT(const JsonbFwdIteratorT<Iter_Ty, Cont_Type>& rhs) : current_(rhs.base()) {} |
415 | | |
416 | 8.57M | bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); } _ZNK5doris17JsonbFwdIteratorTIPNS_13JsonbKeyValueENS_9ObjectValEEeqERKS4_ Line | Count | Source | 416 | 14.6k | bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); } |
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEeqERKS5_ Line | Count | Source | 416 | 998k | bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); } |
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEeqERKS5_ Line | Count | Source | 416 | 7.56M | bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); } |
Unexecuted instantiation: _ZNK5doris17JsonbFwdIteratorTIPNS_10JsonbValueENS_8ArrayValEEeqERKS4_ |
417 | | |
418 | 8.01M | bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); } _ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEneERKS5_ Line | Count | Source | 418 | 749k | bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); } |
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEneERKS5_ Line | Count | Source | 418 | 7.25M | bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); } |
_ZNK5doris17JsonbFwdIteratorTIPNS_13JsonbKeyValueENS_9ObjectValEEneERKS4_ Line | Count | Source | 418 | 14.6k | bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); } |
Unexecuted instantiation: _ZNK5doris17JsonbFwdIteratorTIPNS_10JsonbValueENS_8ArrayValEEneERKS4_ |
419 | | |
420 | 998k | bool operator<(const JsonbFwdIteratorT& rhs) const { return (current_ < rhs.current_); } |
421 | | |
422 | | bool operator>(const JsonbFwdIteratorT& rhs) const { return !operator<(rhs); } |
423 | | |
424 | 4.23M | JsonbFwdIteratorT& operator++() { |
425 | 4.23M | current_ = (iterator)(((char*)current_) + current_->numPackedBytes()); |
426 | 4.23M | return *this; |
427 | 4.23M | } _ZN5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEppEv Line | Count | Source | 424 | 749k | JsonbFwdIteratorT& operator++() { | 425 | 749k | current_ = (iterator)(((char*)current_) + current_->numPackedBytes()); | 426 | 749k | return *this; | 427 | 749k | } |
_ZN5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEppEv Line | Count | Source | 424 | 3.47M | JsonbFwdIteratorT& operator++() { | 425 | 3.47M | current_ = (iterator)(((char*)current_) + current_->numPackedBytes()); | 426 | 3.47M | return *this; | 427 | 3.47M | } |
_ZN5doris17JsonbFwdIteratorTIPNS_13JsonbKeyValueENS_9ObjectValEEppEv Line | Count | Source | 424 | 11.4k | JsonbFwdIteratorT& operator++() { | 425 | 11.4k | current_ = (iterator)(((char*)current_) + current_->numPackedBytes()); | 426 | 11.4k | return *this; | 427 | 11.4k | } |
Unexecuted instantiation: _ZN5doris17JsonbFwdIteratorTIPNS_10JsonbValueENS_8ArrayValEEppEv |
428 | | |
429 | | JsonbFwdIteratorT operator++(int) { |
430 | | auto tmp = *this; |
431 | | current_ = (iterator)(((char*)current_) + current_->numPackedBytes()); |
432 | | return tmp; |
433 | | } |
434 | | |
435 | 3.47M | explicit operator pointer() { return current_; } |
436 | | |
437 | 0 | reference operator*() const { return *current_; } |
438 | | |
439 | 2.98M | pointer operator->() const { return current_; } _ZNK5doris17JsonbFwdIteratorTIPNS_13JsonbKeyValueENS_9ObjectValEEptEv Line | Count | Source | 439 | 20.6k | pointer operator->() const { return current_; } |
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEptEv Line | Count | Source | 439 | 2.96M | pointer operator->() const { return current_; } |
|
440 | | |
441 | 0 | iterator base() const { return current_; } |
442 | | |
443 | | private: |
444 | | iterator current_; |
445 | | }; |
446 | | |
447 | | using hDictInsert = int (*)(const char*, unsigned int); |
448 | | using hDictFind = int (*)(const char*, unsigned int); |
449 | | |
450 | | using JsonbTypeUnder = std::underlying_type_t<JsonbType>; |
451 | | |
452 | | /* |
453 | | * JsonbKeyValue class defines JSONB key type, as described below. |
454 | | * |
455 | | * key ::= |
456 | | * 0x00 int8 //1-byte dictionary id |
457 | | * | int8 (byte*) //int8 (>0) is the size of the key string |
458 | | * |
459 | | * value ::= primitive_value | container |
460 | | * |
461 | | * JsonbKeyValue can be either an id mapping to the key string in an external |
462 | | * dictionary, or it is the original key string. Whether to read an id or a |
463 | | * string is decided by the first byte (size_). |
464 | | * |
465 | | * Note: a key object must be followed by a value object. Therefore, a key |
466 | | * object implicitly refers to a key-value pair, and you can get the value |
467 | | * object right after the key object. The function numPackedBytes hence |
468 | | * indicates the total size of the key-value pair, so that we will be able go |
469 | | * to next pair from the key. |
470 | | * |
471 | | * ** Dictionary size ** |
472 | | * By default, the dictionary size is 255 (1-byte). Users can define |
473 | | * "USE_LARGE_DICT" to increase the dictionary size to 655535 (2-byte). |
474 | | */ |
475 | | class JsonbKeyValue { |
476 | | public: |
477 | | // now we use sMaxKeyId to represent an empty key |
478 | | static const int sMaxKeyId = 65535; |
479 | | using keyid_type = uint16_t; |
480 | | |
481 | | JsonbKeyValue() = delete; |
482 | | |
483 | | static const uint8_t sMaxKeyLen = 64; |
484 | | |
485 | | // size of the key. 0 indicates it is stored as id |
486 | 1.46M | uint8_t klen() const { return size_; } |
487 | | |
488 | | // get the key string. Note the string may not be null terminated. |
489 | 717k | const char* getKeyStr() const { return key_.str_; } |
490 | | |
491 | 40.4k | keyid_type getKeyId() const { return key_.id_; } |
492 | | |
493 | 1.52M | unsigned int keyPackedBytes() const { |
494 | 1.52M | return size_ ? (sizeof(size_) + size_) : (sizeof(size_) + sizeof(keyid_type)); Branch (494:16): [True: 1.43M, False: 85.2k]
|
495 | 1.52M | } |
496 | | |
497 | 760k | JsonbValue* value() const { return (JsonbValue*)(((char*)this) + keyPackedBytes()); } |
498 | | |
499 | | // size of the total packed bytes (key+value) |
500 | | unsigned int numPackedBytes() const; |
501 | | |
502 | | private: |
503 | | uint8_t size_; |
504 | | |
505 | | union key_ { |
506 | | keyid_type id_; |
507 | | char str_[1]; |
508 | | } key_; |
509 | | }; |
510 | | |
511 | | /* |
512 | | * JsonbValue is the base class of all JSONB types. It contains only one member |
513 | | * variable - type info, which can be retrieved by member functions is[Type]() |
514 | | * or type(). |
515 | | */ |
516 | | class JsonbValue { |
517 | | public: |
518 | | static const uint32_t sMaxValueLen = 1 << 24; // 16M |
519 | | |
520 | 3.12k | bool isNull() const { return (type_ == JsonbType::T_Null); } |
521 | 119 | bool isTrue() const { return (type_ == JsonbType::T_True); } |
522 | 109 | bool isFalse() const { return (type_ == JsonbType::T_False); } |
523 | 85 | bool isInt() const { return isInt8() || isInt16() || isInt32() || isInt64() || isInt128(); } Branch (523:33): [True: 6, False: 79]
Branch (523:45): [True: 6, False: 73]
Branch (523:58): [True: 6, False: 67]
Branch (523:71): [True: 6, False: 61]
Branch (523:84): [True: 0, False: 61]
|
524 | 337 | bool isInt8() const { return (type_ == JsonbType::T_Int8); } |
525 | 299 | bool isInt16() const { return (type_ == JsonbType::T_Int16); } |
526 | 271 | bool isInt32() const { return (type_ == JsonbType::T_Int32); } |
527 | 201 | bool isInt64() const { return (type_ == JsonbType::T_Int64); } |
528 | 140 | bool isDouble() const { return (type_ == JsonbType::T_Double); } |
529 | 14 | bool isFloat() const { return (type_ == JsonbType::T_Float); } |
530 | 965 | bool isString() const { return (type_ == JsonbType::T_String); } |
531 | 3.14k | bool isBinary() const { return (type_ == JsonbType::T_Binary); } |
532 | 0 | bool isObject() const { return (type_ == JsonbType::T_Object); } |
533 | 0 | bool isArray() const { return (type_ == JsonbType::T_Array); } |
534 | 61 | bool isInt128() const { return (type_ == JsonbType::T_Int128); } |
535 | | |
536 | 4.29M | JsonbType type() const { return type_; } |
537 | | |
538 | 0 | const char* typeName() const { |
539 | 0 | switch (type_) { |
540 | 0 | case JsonbType::T_Null: Branch (540:9): [True: 0, False: 0]
|
541 | 0 | return "null"; |
542 | 0 | case JsonbType::T_True: Branch (542:9): [True: 0, False: 0]
|
543 | 0 | case JsonbType::T_False: Branch (543:9): [True: 0, False: 0]
|
544 | 0 | return "bool"; |
545 | 0 | case JsonbType::T_Int8: Branch (545:9): [True: 0, False: 0]
|
546 | 0 | case JsonbType::T_Int16: Branch (546:9): [True: 0, False: 0]
|
547 | 0 | case JsonbType::T_Int32: Branch (547:9): [True: 0, False: 0]
|
548 | 0 | return "int"; |
549 | 0 | case JsonbType::T_Int64: Branch (549:9): [True: 0, False: 0]
|
550 | 0 | return "bigint"; |
551 | 0 | case JsonbType::T_Int128: Branch (551:9): [True: 0, False: 0]
|
552 | 0 | return "largeint"; |
553 | 0 | case JsonbType::T_Double: Branch (553:9): [True: 0, False: 0]
|
554 | 0 | return "double"; |
555 | 0 | case JsonbType::T_Float: Branch (555:9): [True: 0, False: 0]
|
556 | 0 | return "float"; |
557 | 0 | case JsonbType::T_String: Branch (557:9): [True: 0, False: 0]
|
558 | 0 | return "string"; |
559 | 0 | case JsonbType::T_Binary: Branch (559:9): [True: 0, False: 0]
|
560 | 0 | return "binary"; |
561 | 0 | case JsonbType::T_Object: Branch (561:9): [True: 0, False: 0]
|
562 | 0 | return "object"; |
563 | 0 | case JsonbType::T_Array: Branch (563:9): [True: 0, False: 0]
|
564 | 0 | return "array"; |
565 | 0 | default: Branch (565:9): [True: 0, False: 0]
|
566 | 0 | return "unknown"; |
567 | 0 | } |
568 | 0 | } |
569 | | |
570 | | // size of the total packed bytes |
571 | | unsigned int numPackedBytes() const; |
572 | | |
573 | | // size of the value in bytes |
574 | | unsigned int size() const; |
575 | | |
576 | | //Get the number of jsonbvalue elements |
577 | | int length() const; |
578 | | |
579 | | //Whether to include the jsonbvalue rhs |
580 | | bool contains(JsonbValue* rhs) const; |
581 | | |
582 | | // get the raw byte array of the value |
583 | | const char* getValuePtr() const; |
584 | | |
585 | | // find the JSONB value by JsonbPath |
586 | | JsonbValue* findValue(JsonbPath& path, hDictFind handler); |
587 | | friend class JsonbDocument; |
588 | | |
589 | | protected: |
590 | | JsonbType type_; // type info |
591 | | |
592 | | JsonbValue(); |
593 | | }; |
594 | | |
595 | | /* |
596 | | * NumerValT is the template class (derived from JsonbValue) of all number |
597 | | * types (integers and double). |
598 | | */ |
599 | | template <class T> |
600 | | class NumberValT : public JsonbValue { |
601 | | public: |
602 | 1.61M | T val() const { return num_; } _ZNK5doris10NumberValTIaE3valEv Line | Count | Source | 602 | 518 | T val() const { return num_; } |
_ZNK5doris10NumberValTIsE3valEv Line | Count | Source | 602 | 446 | T val() const { return num_; } |
_ZNK5doris10NumberValTIiE3valEv Line | Count | Source | 602 | 3.49k | T val() const { return num_; } |
_ZNK5doris10NumberValTIlE3valEv Line | Count | Source | 602 | 846k | T val() const { return num_; } |
_ZNK5doris10NumberValTInE3valEv Line | Count | Source | 602 | 1.02k | T val() const { return num_; } |
_ZNK5doris10NumberValTIdE3valEv Line | Count | Source | 602 | 765k | T val() const { return num_; } |
Unexecuted instantiation: _ZNK5doris10NumberValTIfE3valEv |
603 | | |
604 | | unsigned int numPackedBytes() const { return sizeof(JsonbValue) + sizeof(T); } |
605 | | |
606 | | // catch all unknow specialization of the template class |
607 | | bool setVal(T value) { return false; } |
608 | | |
609 | | private: |
610 | | T num_; |
611 | | |
612 | | NumberValT(); |
613 | | }; |
614 | | |
615 | | using JsonbInt8Val = NumberValT<int8_t>; |
616 | | |
617 | | // override setVal for Int8Val |
618 | | template <> |
619 | 0 | inline bool JsonbInt8Val::setVal(int8_t value) { |
620 | 0 | if (!isInt8()) { |
621 | 0 | return false; |
622 | 0 | } |
623 | 0 |
|
624 | 0 | num_ = value; |
625 | 0 | return true; |
626 | 0 | } |
627 | | |
628 | | using JsonbInt16Val = NumberValT<int16_t>; |
629 | | |
630 | | // override setVal for Int16Val |
631 | | template <> |
632 | 0 | inline bool JsonbInt16Val::setVal(int16_t value) { |
633 | 0 | if (!isInt16()) { |
634 | 0 | return false; |
635 | 0 | } |
636 | 0 |
|
637 | 0 | num_ = value; |
638 | 0 | return true; |
639 | 0 | } |
640 | | using JsonbInt32Val = NumberValT<int32_t>; |
641 | | |
642 | | // override setVal for Int32Val |
643 | | template <> |
644 | 0 | inline bool JsonbInt32Val::setVal(int32_t value) { |
645 | 0 | if (!isInt32()) { |
646 | 0 | return false; |
647 | 0 | } |
648 | 0 |
|
649 | 0 | num_ = value; |
650 | 0 | return true; |
651 | 0 | } |
652 | | |
653 | | using JsonbInt64Val = NumberValT<int64_t>; |
654 | | |
655 | | // override setVal for Int64Val |
656 | | template <> |
657 | 0 | inline bool JsonbInt64Val::setVal(int64_t value) { |
658 | 0 | if (!isInt64()) { |
659 | 0 | return false; |
660 | 0 | } |
661 | 0 |
|
662 | 0 | num_ = value; |
663 | 0 | return true; |
664 | 0 | } |
665 | | |
666 | | using JsonbInt128Val = NumberValT<int128_t>; |
667 | | |
668 | | // override setVal for Int128Val |
669 | | template <> |
670 | 0 | inline bool JsonbInt128Val::setVal(int128_t value) { |
671 | 0 | if (!isInt128()) { |
672 | 0 | return false; |
673 | 0 | } |
674 | 0 |
|
675 | 0 | num_ = value; |
676 | 0 | return true; |
677 | 0 | } |
678 | | |
679 | | using JsonbDoubleVal = NumberValT<double>; |
680 | | |
681 | | // override setVal for DoubleVal |
682 | | template <> |
683 | 0 | inline bool JsonbDoubleVal::setVal(double value) { |
684 | 0 | if (!isDouble()) { |
685 | 0 | return false; |
686 | 0 | } |
687 | 0 |
|
688 | 0 | num_ = value; |
689 | 0 | return true; |
690 | 0 | } |
691 | | |
692 | | using JsonbFloatVal = NumberValT<float>; |
693 | | |
694 | | // override setVal for DoubleVal |
695 | | template <> |
696 | 0 | inline bool JsonbFloatVal::setVal(float value) { |
697 | 0 | if (!isFloat()) { |
698 | 0 | return false; |
699 | 0 | } |
700 | 0 |
|
701 | 0 | num_ = value; |
702 | 0 | return true; |
703 | 0 | } |
704 | | |
705 | | // A class to get an integer |
706 | | class JsonbIntVal : public JsonbValue { |
707 | | public: |
708 | 76 | int128_t val() const { |
709 | 76 | switch (type_) { |
710 | 30 | case JsonbType::T_Int8: Branch (710:9): [True: 30, False: 46]
|
711 | 30 | return ((JsonbInt8Val*)this)->val(); |
712 | 24 | case JsonbType::T_Int16: Branch (712:9): [True: 24, False: 52]
|
713 | 24 | return ((JsonbInt16Val*)this)->val(); |
714 | 12 | case JsonbType::T_Int32: Branch (714:9): [True: 12, False: 64]
|
715 | 12 | return ((JsonbInt32Val*)this)->val(); |
716 | 10 | case JsonbType::T_Int64: Branch (716:9): [True: 10, False: 66]
|
717 | 10 | return ((JsonbInt64Val*)this)->val(); |
718 | 0 | case JsonbType::T_Int128: Branch (718:9): [True: 0, False: 76]
|
719 | 0 | return ((JsonbInt128Val*)this)->val(); |
720 | 0 | default: Branch (720:9): [True: 0, False: 76]
|
721 | 0 | return 0; |
722 | 76 | } |
723 | 76 | } |
724 | 0 | bool setVal(int128_t val) { |
725 | 0 | switch (type_) { |
726 | 0 | case JsonbType::T_Int8: |
727 | 0 | if (val < std::numeric_limits<int8_t>::min() || |
728 | 0 | val > std::numeric_limits<int8_t>::max()) { |
729 | 0 | return false; |
730 | 0 | } |
731 | 0 | return ((JsonbInt8Val*)this)->setVal((int8_t)val); |
732 | 0 | case JsonbType::T_Int16: |
733 | 0 | if (val < std::numeric_limits<int16_t>::min() || |
734 | 0 | val > std::numeric_limits<int16_t>::max()) { |
735 | 0 | return false; |
736 | 0 | } |
737 | 0 | return ((JsonbInt16Val*)this)->setVal((int16_t)val); |
738 | 0 | case JsonbType::T_Int32: |
739 | 0 | if (val < std::numeric_limits<int32_t>::min() || |
740 | 0 | val > std::numeric_limits<int32_t>::max()) { |
741 | 0 | return false; |
742 | 0 | } |
743 | 0 | return ((JsonbInt32Val*)this)->setVal((int32_t)val); |
744 | 0 | case JsonbType::T_Int64: |
745 | 0 | return ((JsonbInt64Val*)this)->setVal((int64_t)val); |
746 | 0 | case JsonbType::T_Int128: |
747 | 0 | return ((JsonbInt128Val*)this)->setVal(val); |
748 | 0 | default: |
749 | 0 | return false; |
750 | 0 | } |
751 | 0 | } |
752 | | }; |
753 | | |
754 | | /* |
755 | | * BlobVal is the base class (derived from JsonbValue) for string and binary |
756 | | * types. The size_ indicates the total bytes of the payload_. |
757 | | */ |
758 | | class JsonbBlobVal : public JsonbValue { |
759 | | public: |
760 | | // size of the blob payload only |
761 | 3.17k | unsigned int getBlobLen() const { return size_; } |
762 | | |
763 | | // return the blob as byte array |
764 | 1.96M | const char* getBlob() const { return payload_; } |
765 | | |
766 | | // size of the total packed bytes |
767 | 1.96M | unsigned int numPackedBytes() const { return sizeof(JsonbValue) + sizeof(size_) + size_; } |
768 | | friend class JsonbDocument; |
769 | | |
770 | | protected: |
771 | | uint32_t size_; |
772 | | char payload_[0]; |
773 | | |
774 | | // set new blob bytes |
775 | 0 | bool internalSetVal(const char* blob, uint32_t blobSize) { |
776 | 0 | // if we cannot fit the new blob, fail the operation |
777 | 0 | if (blobSize > size_) { |
778 | 0 | return false; |
779 | 0 | } |
780 | 0 |
|
781 | 0 | memcpy(payload_, blob, blobSize); |
782 | 0 |
|
783 | 0 | // Set the reset of the bytes to 0. Note we cannot change the size_ of the |
784 | 0 | // current payload, as all values are packed. |
785 | 0 | memset(payload_ + blobSize, 0, size_ - blobSize); |
786 | 0 |
|
787 | 0 | return true; |
788 | 0 | } |
789 | | |
790 | | JsonbBlobVal(); |
791 | | }; |
792 | | |
793 | | /* |
794 | | * Binary type |
795 | | */ |
796 | | class JsonbBinaryVal : public JsonbBlobVal { |
797 | | public: |
798 | 0 | bool setVal(const char* blob, uint32_t blobSize) { |
799 | 0 | if (!isBinary()) { |
800 | 0 | return false; |
801 | 0 | } |
802 | 0 |
|
803 | 0 | return internalSetVal(blob, blobSize); |
804 | 0 | } |
805 | | |
806 | | private: |
807 | | JsonbBinaryVal(); |
808 | | }; |
809 | | |
810 | | /* |
811 | | * String type |
812 | | * Note: JSONB string may not be a c-string (NULL-terminated) |
813 | | */ |
814 | | class JsonbStringVal : public JsonbBlobVal { |
815 | | public: |
816 | 0 | bool setVal(const char* str, uint32_t blobSize) { |
817 | 0 | if (!isString()) { |
818 | 0 | return false; |
819 | 0 | } |
820 | 0 |
|
821 | 0 | return internalSetVal(str, blobSize); |
822 | 0 | } |
823 | | /* |
824 | | This function return the actual size of a string. Since for |
825 | | a string, it can be null-terminated with null paddings or it |
826 | | can take all the space in the payload_ without null in the end. |
827 | | So we need to check it to get the true actual length of a string. |
828 | | */ |
829 | 1.95M | size_t length() { |
830 | | // It's an empty string |
831 | 1.95M | if (0 == size_) { Branch (831:13): [True: 143k, False: 1.81M]
|
832 | 143k | return size_; |
833 | 143k | } |
834 | | // The string stored takes all the spaces in payload_ |
835 | 1.81M | if (payload_[size_ - 1] != 0) { Branch (835:13): [True: 1.81M, False: 0]
|
836 | 1.81M | return size_; |
837 | 1.81M | } |
838 | | // It's shorter than the size of payload_ |
839 | 0 | return strnlen(payload_, size_); |
840 | 1.81M | } |
841 | | // convert the string (case insensitive) to a boolean value |
842 | | // "false": 0 |
843 | | // "true": 1 |
844 | | // all other strings: -1 |
845 | 0 | int getBoolVal() { |
846 | 0 | if (size_ == 4 && tolower(payload_[0]) == 't' && tolower(payload_[1]) == 'r' && |
847 | 0 | tolower(payload_[2]) == 'u' && tolower(payload_[3]) == 'e') { |
848 | 0 | return 1; |
849 | 0 | } else if (size_ == 5 && tolower(payload_[0]) == 'f' && tolower(payload_[1]) == 'a' && |
850 | 0 | tolower(payload_[2]) == 'l' && tolower(payload_[3]) == 's' && |
851 | 0 | tolower(payload_[4]) == 'e') { |
852 | 0 | return 0; |
853 | 0 | } else { |
854 | 0 | return -1; |
855 | 0 | } |
856 | 0 | } |
857 | | |
858 | | private: |
859 | | JsonbStringVal(); |
860 | | }; |
861 | | |
862 | | /* |
863 | | * ContainerVal is the base class (derived from JsonbValue) for object and |
864 | | * array types. The size_ indicates the total bytes of the payload_. |
865 | | */ |
866 | | class ContainerVal : public JsonbValue { |
867 | | public: |
868 | | // size of the container payload only |
869 | 10 | unsigned int getContainerSize() const { return size_; } |
870 | | |
871 | | // return the container payload as byte array |
872 | 0 | const char* getPayload() const { return payload_; } |
873 | | |
874 | | // size of the total packed bytes |
875 | 564k | unsigned int numPackedBytes() const { return sizeof(JsonbValue) + sizeof(size_) + size_; } |
876 | | friend class JsonbDocument; |
877 | | |
878 | | protected: |
879 | | uint32_t size_; |
880 | | char payload_[0]; |
881 | | |
882 | | ContainerVal(); |
883 | | }; |
884 | | |
885 | | /* |
886 | | * Object type |
887 | | */ |
888 | | class ObjectVal : public ContainerVal { |
889 | | public: |
890 | | using value_type = JsonbKeyValue; |
891 | | using pointer = value_type*; |
892 | | using const_pointer = const value_type*; |
893 | | using iterator = JsonbFwdIteratorT<pointer, ObjectVal>; |
894 | | using const_iterator = JsonbFwdIteratorT<const_pointer, ObjectVal>; |
895 | | |
896 | 0 | const_iterator search(const char* key, hDictFind handler = nullptr) const { |
897 | 0 | return const_cast<ObjectVal*>(this)->search(key, handler); |
898 | 0 | } |
899 | | |
900 | 0 | const_iterator search(const char* key, unsigned int klen, hDictFind handler = nullptr) const { |
901 | 0 | return const_cast<ObjectVal*>(this)->search(key, klen, handler); |
902 | 0 | } |
903 | | |
904 | 0 | const_iterator search(int key_id) const { return const_cast<ObjectVal*>(this)->search(key_id); } |
905 | 0 | iterator search(const char* key, hDictFind handler = nullptr) { |
906 | 0 | if (!key) { |
907 | 0 | return end(); |
908 | 0 | } |
909 | 0 | return search(key, (unsigned int)strlen(key), handler); |
910 | 0 | } |
911 | | |
912 | 51 | iterator search(const char* key, unsigned int klen, hDictFind handler = nullptr) { |
913 | 51 | if (!key || !klen) { Branch (913:13): [True: 0, False: 51]
Branch (913:21): [True: 0, False: 51]
|
914 | 0 | return end(); |
915 | 0 | } |
916 | | |
917 | 51 | int key_id = -1; |
918 | 51 | if (handler && (key_id = handler(key, klen)) >= 0) { Branch (918:13): [True: 0, False: 51]
Branch (918:24): [True: 0, False: 0]
|
919 | 0 | return search(key_id); |
920 | 0 | } |
921 | 51 | return internalSearch(key, klen); |
922 | 51 | } |
923 | | |
924 | 0 | iterator search(int key_id) { |
925 | 0 | if (key_id < 0 || key_id > JsonbKeyValue::sMaxKeyId) { Branch (925:13): [True: 0, False: 0]
Branch (925:27): [True: 0, False: 0]
|
926 | 0 | return end(); |
927 | 0 | } |
928 | | |
929 | 0 | const char* pch = payload_; |
930 | 0 | const char* fence = payload_ + size_; |
931 | |
|
932 | 0 | while (pch < fence) { Branch (932:16): [True: 0, False: 0]
|
933 | 0 | auto* pkey = (JsonbKeyValue*)(pch); |
934 | 0 | if (!pkey->klen() && key_id == pkey->getKeyId()) { Branch (934:17): [True: 0, False: 0]
Branch (934:34): [True: 0, False: 0]
|
935 | 0 | return iterator(pkey); |
936 | 0 | } |
937 | 0 | pch += pkey->numPackedBytes(); |
938 | 0 | } |
939 | | |
940 | 0 | assert(pch == fence); |
941 | 0 | return end(); |
942 | 0 | } |
943 | | |
944 | | // Get number of elements in object |
945 | 0 | int numElem() const { |
946 | 0 | const char* pch = payload_; |
947 | 0 | const char* fence = payload_ + size_; |
948 | |
|
949 | 0 | unsigned int num = 0; |
950 | 0 | while (pch < fence) { Branch (950:16): [True: 0, False: 0]
|
951 | 0 | auto* pkey = (JsonbKeyValue*)(pch); |
952 | 0 | ++num; |
953 | 0 | pch += pkey->numPackedBytes(); |
954 | 0 | } |
955 | |
|
956 | 0 | assert(pch == fence); |
957 | | |
958 | 0 | return num; |
959 | 0 | } |
960 | | |
961 | 0 | JsonbKeyValue* getJsonbKeyValue(unsigned int i) const { |
962 | 0 | const char* pch = payload_; |
963 | 0 | const char* fence = payload_ + size_; |
964 | |
|
965 | 0 | unsigned int num = 0; |
966 | 0 | while (pch < fence) { Branch (966:16): [True: 0, False: 0]
|
967 | 0 | auto* pkey = (JsonbKeyValue*)(pch); |
968 | 0 | if (num == i) { Branch (968:17): [True: 0, False: 0]
|
969 | 0 | return pkey; |
970 | 0 | } |
971 | 0 | ++num; |
972 | 0 | pch += pkey->numPackedBytes(); |
973 | 0 | } |
974 | | |
975 | 0 | assert(pch == fence); |
976 | | |
977 | 0 | return nullptr; |
978 | 0 | } |
979 | | |
980 | 0 | JsonbValue* find(const char* key, hDictFind handler = nullptr) const { |
981 | 0 | return const_cast<ObjectVal*>(this)->find(key, handler); |
982 | 0 | } |
983 | | |
984 | 0 | JsonbValue* find(const char* key, unsigned int klen, hDictFind handler = nullptr) const { |
985 | 0 | return const_cast<ObjectVal*>(this)->find(key, klen, handler); |
986 | 0 | } |
987 | 0 | JsonbValue* find(int key_id) const { return const_cast<ObjectVal*>(this)->find(key_id); } |
988 | | |
989 | | // find the JSONB value by a key string (null terminated) |
990 | 0 | JsonbValue* find(const char* key, hDictFind handler = nullptr) { |
991 | 0 | if (!key) { |
992 | 0 | return nullptr; |
993 | 0 | } |
994 | 0 | return find(key, (unsigned int)strlen(key), handler); |
995 | 0 | } |
996 | | |
997 | | // find the JSONB value by a key string (with length) |
998 | 51 | JsonbValue* find(const char* key, unsigned int klen, hDictFind handler = nullptr) { |
999 | 51 | iterator kv = search(key, klen, handler); |
1000 | 51 | if (end() == kv) { Branch (1000:13): [True: 18, False: 33]
|
1001 | 18 | return nullptr; |
1002 | 18 | } |
1003 | 33 | return kv->value(); |
1004 | 51 | } |
1005 | | |
1006 | | // find the JSONB value by a key dictionary ID |
1007 | 0 | JsonbValue* find(int key_id) { |
1008 | 0 | iterator kv = search(key_id); |
1009 | 0 | if (end() == kv) { |
1010 | 0 | return nullptr; |
1011 | 0 | } |
1012 | 0 | return kv->value(); |
1013 | 0 | } |
1014 | | |
1015 | 3.18k | iterator begin() { return iterator((pointer)payload_); } |
1016 | | |
1017 | 249k | const_iterator begin() const { return const_iterator((pointer)payload_); } |
1018 | | |
1019 | 14.6k | iterator end() { return iterator((pointer)(payload_ + size_)); } |
1020 | | |
1021 | 249k | const_iterator end() const { return const_iterator((pointer)(payload_ + size_)); } |
1022 | | |
1023 | | private: |
1024 | 51 | iterator internalSearch(const char* key, unsigned int klen) { |
1025 | 51 | const char* pch = payload_; |
1026 | 51 | const char* fence = payload_ + size_; |
1027 | | |
1028 | 57 | while (pch < fence) { Branch (1028:16): [True: 39, False: 18]
|
1029 | 39 | auto* pkey = (JsonbKeyValue*)(pch); |
1030 | 39 | if (klen == pkey->klen() && strncmp(key, pkey->getKeyStr(), klen) == 0) { Branch (1030:17): [True: 39, False: 0]
Branch (1030:41): [True: 33, False: 6]
|
1031 | 33 | return iterator(pkey); |
1032 | 33 | } |
1033 | 6 | pch += pkey->numPackedBytes(); |
1034 | 6 | } |
1035 | | |
1036 | 18 | assert(pch == fence); |
1037 | | |
1038 | 0 | return end(); |
1039 | 51 | } |
1040 | | |
1041 | | private: |
1042 | | ObjectVal(); |
1043 | | }; |
1044 | | |
1045 | | /* |
1046 | | * Array type |
1047 | | */ |
1048 | | class ArrayVal : public ContainerVal { |
1049 | | public: |
1050 | | using value_type = JsonbValue; |
1051 | | using pointer = value_type*; |
1052 | | using const_pointer = const value_type*; |
1053 | | using iterator = JsonbFwdIteratorT<pointer, ArrayVal>; |
1054 | | using const_iterator = JsonbFwdIteratorT<const_pointer, ArrayVal>; |
1055 | | |
1056 | | // get the JSONB value at index |
1057 | 231 | JsonbValue* get(int idx) const { |
1058 | 231 | if (idx < 0) { Branch (1058:13): [True: 0, False: 231]
|
1059 | 0 | return nullptr; |
1060 | 0 | } |
1061 | | |
1062 | 231 | const char* pch = payload_; |
1063 | 231 | const char* fence = payload_ + size_; |
1064 | | |
1065 | 564 | while (pch < fence && idx-- > 0) { Branch (1065:16): [True: 501, False: 63]
Branch (1065:31): [True: 333, False: 168]
|
1066 | 333 | pch += ((JsonbValue*)pch)->numPackedBytes(); |
1067 | 333 | } |
1068 | 231 | if (idx > 0 || pch == fence) { Branch (1068:13): [True: 9, False: 222]
Branch (1068:24): [True: 54, False: 168]
|
1069 | 63 | return nullptr; |
1070 | 63 | } |
1071 | | |
1072 | 168 | return (JsonbValue*)pch; |
1073 | 231 | } |
1074 | | |
1075 | | // Get number of elements in array |
1076 | 0 | int numElem() const { |
1077 | 0 | const char* pch = payload_; |
1078 | 0 | const char* fence = payload_ + size_; |
1079 | |
|
1080 | 0 | unsigned int num = 0; |
1081 | 0 | while (pch < fence) { Branch (1081:16): [True: 0, False: 0]
|
1082 | 0 | ++num; |
1083 | 0 | pch += ((JsonbValue*)pch)->numPackedBytes(); |
1084 | 0 | } |
1085 | |
|
1086 | 0 | assert(pch == fence); |
1087 | | |
1088 | 0 | return num; |
1089 | 0 | } |
1090 | | |
1091 | 0 | iterator begin() { return iterator((pointer)payload_); } |
1092 | | |
1093 | 310k | const_iterator begin() const { return const_iterator((pointer)payload_); } |
1094 | | |
1095 | 0 | iterator end() { return iterator((pointer)(payload_ + size_)); } |
1096 | | |
1097 | 310k | const_iterator end() const { return const_iterator((pointer)(payload_ + size_)); } |
1098 | | |
1099 | | private: |
1100 | | ArrayVal(); |
1101 | | }; |
1102 | | |
1103 | | inline Status JsonbDocument::checkAndCreateDocument(const char* pb, size_t size, |
1104 | 26.9k | JsonbDocument** doc) { |
1105 | 26.9k | *doc = nullptr; |
1106 | 26.9k | if (!pb || size < sizeof(JsonbHeader) + sizeof(JsonbValue)) { Branch (1106:9): [True: 0, False: 26.9k]
Branch (1106:16): [True: 30, False: 26.9k]
|
1107 | 30 | return Status::InvalidArgument("Invalid JSONB document: too small size({}) or null pointer", |
1108 | 30 | size); |
1109 | 30 | } |
1110 | | |
1111 | 26.9k | auto* doc_ptr = (JsonbDocument*)pb; |
1112 | 26.9k | if (doc_ptr->header_.ver_ != JSONB_VER) { Line | Count | Source | 88 | 26.9k | #define JSONB_VER 1 |
Branch (1112:9): [True: 2, False: 26.9k]
|
1113 | 2 | return Status::InvalidArgument("Invalid JSONB document: invalid version({})", |
1114 | 2 | doc_ptr->header_.ver_); |
1115 | 2 | } |
1116 | | |
1117 | 26.9k | auto* val = (JsonbValue*)doc_ptr->payload_; |
1118 | 26.9k | if (val->type() < JsonbType::T_Null || val->type() >= JsonbType::NUM_TYPES || Branch (1118:9): [True: 0, False: 26.9k]
Branch (1118:44): [True: 0, False: 26.9k]
|
1119 | 26.9k | size != sizeof(JsonbHeader) + val->numPackedBytes()) { Branch (1119:9): [True: 0, False: 26.9k]
|
1120 | 0 | return Status::InvalidArgument("Invalid JSONB document: invalid type({}) or size({})", |
1121 | 0 | static_cast<JsonbTypeUnder>(val->type()), size); |
1122 | 0 | } |
1123 | | |
1124 | 26.9k | *doc = doc_ptr; |
1125 | 26.9k | return Status::OK(); |
1126 | 26.9k | } |
1127 | 0 | inline void JsonbDocument::setValue(const JsonbValue* value) { |
1128 | 0 | memcpy(payload_, value, value->numPackedBytes()); |
1129 | 0 | } |
1130 | | |
1131 | 21 | inline JsonbValue* JsonbDocument::createValue(const char* pb, uint32_t size) { |
1132 | 21 | if (!pb || size < sizeof(JsonbHeader) + sizeof(JsonbValue)) { Branch (1132:9): [True: 0, False: 21]
Branch (1132:16): [True: 0, False: 21]
|
1133 | 0 | return nullptr; |
1134 | 0 | } |
1135 | | |
1136 | 21 | auto* doc = (JsonbDocument*)pb; |
1137 | 21 | if (doc->header_.ver_ != JSONB_VER) { Line | Count | Source | 88 | 21 | #define JSONB_VER 1 |
Branch (1137:9): [True: 0, False: 21]
|
1138 | 0 | return nullptr; |
1139 | 0 | } |
1140 | | |
1141 | 21 | auto* val = (JsonbValue*)doc->payload_; |
1142 | 21 | if (size != sizeof(JsonbHeader) + val->numPackedBytes()) { Branch (1142:9): [True: 0, False: 21]
|
1143 | 0 | return nullptr; |
1144 | 0 | } |
1145 | | |
1146 | 21 | return val; |
1147 | 21 | } |
1148 | | |
1149 | 0 | inline unsigned int JsonbDocument::numPackedBytes() const { |
1150 | 0 | return ((const JsonbValue*)payload_)->numPackedBytes() + sizeof(header_); |
1151 | 0 | } |
1152 | | |
1153 | 760k | inline unsigned int JsonbKeyValue::numPackedBytes() const { |
1154 | 760k | unsigned int ks = keyPackedBytes(); |
1155 | 760k | auto* val = (JsonbValue*)(((char*)this) + ks); |
1156 | 760k | return ks + val->numPackedBytes(); |
1157 | 760k | } |
1158 | | |
1159 | | // Poor man's "virtual" function JsonbValue::numPackedBytes |
1160 | 4.25M | inline unsigned int JsonbValue::numPackedBytes() const { |
1161 | 4.25M | switch (type_) { |
1162 | 91.3k | case JsonbType::T_Null: Branch (1162:5): [True: 91.3k, False: 4.16M]
|
1163 | 102k | case JsonbType::T_True: Branch (1163:5): [True: 10.8k, False: 4.24M]
|
1164 | 112k | case JsonbType::T_False: { Branch (1164:5): [True: 10.8k, False: 4.24M]
|
1165 | 112k | return sizeof(type_); |
1166 | 102k | } |
1167 | | |
1168 | 628 | case JsonbType::T_Int8: { Branch (1168:5): [True: 628, False: 4.25M]
|
1169 | 628 | return sizeof(type_) + sizeof(int8_t); |
1170 | 102k | } |
1171 | 480 | case JsonbType::T_Int16: { Branch (1171:5): [True: 480, False: 4.25M]
|
1172 | 480 | return sizeof(type_) + sizeof(int16_t); |
1173 | 102k | } |
1174 | 3.53k | case JsonbType::T_Int32: { Branch (1174:5): [True: 3.53k, False: 4.25M]
|
1175 | 3.53k | return sizeof(type_) + sizeof(int32_t); |
1176 | 102k | } |
1177 | 846k | case JsonbType::T_Int64: { Branch (1177:5): [True: 846k, False: 3.41M]
|
1178 | 846k | return sizeof(type_) + sizeof(int64_t); |
1179 | 102k | } |
1180 | 765k | case JsonbType::T_Double: { Branch (1180:5): [True: 765k, False: 3.49M]
|
1181 | 765k | return sizeof(type_) + sizeof(double); |
1182 | 102k | } |
1183 | 0 | case JsonbType::T_Float: { Branch (1183:5): [True: 0, False: 4.25M]
|
1184 | 0 | return sizeof(type_) + sizeof(float); |
1185 | 102k | } |
1186 | 1.02k | case JsonbType::T_Int128: { Branch (1186:5): [True: 1.02k, False: 4.25M]
|
1187 | 1.02k | return sizeof(type_) + sizeof(int128_t); |
1188 | 102k | } |
1189 | 1.96M | case JsonbType::T_String: Branch (1189:5): [True: 1.96M, False: 2.29M]
|
1190 | 1.96M | case JsonbType::T_Binary: { Branch (1190:5): [True: 4.44k, False: 4.25M]
|
1191 | 1.96M | return ((JsonbBlobVal*)(this))->numPackedBytes(); |
1192 | 1.96M | } |
1193 | | |
1194 | 253k | case JsonbType::T_Object: Branch (1194:5): [True: 253k, False: 4.00M]
|
1195 | 564k | case JsonbType::T_Array: { Branch (1195:5): [True: 311k, False: 3.94M]
|
1196 | 564k | return ((ContainerVal*)(this))->numPackedBytes(); |
1197 | 253k | } |
1198 | 0 | default: Branch (1198:5): [True: 0, False: 4.25M]
|
1199 | 0 | return 0; |
1200 | 4.25M | } |
1201 | 4.25M | } |
1202 | | |
1203 | 55 | inline unsigned int JsonbValue::size() const { |
1204 | 55 | switch (type_) { |
1205 | 14 | case JsonbType::T_Int8: { Branch (1205:5): [True: 14, False: 41]
|
1206 | 14 | return sizeof(int8_t); |
1207 | 0 | } |
1208 | 2 | case JsonbType::T_Int16: { Branch (1208:5): [True: 2, False: 53]
|
1209 | 2 | return sizeof(int16_t); |
1210 | 0 | } |
1211 | 1 | case JsonbType::T_Int32: { Branch (1211:5): [True: 1, False: 54]
|
1212 | 1 | return sizeof(int32_t); |
1213 | 0 | } |
1214 | 1 | case JsonbType::T_Int64: { Branch (1214:5): [True: 1, False: 54]
|
1215 | 1 | return sizeof(int64_t); |
1216 | 0 | } |
1217 | 3 | case JsonbType::T_Double: { Branch (1217:5): [True: 3, False: 52]
|
1218 | 3 | return sizeof(double); |
1219 | 0 | } |
1220 | 0 | case JsonbType::T_Float: { Branch (1220:5): [True: 0, False: 55]
|
1221 | 0 | return sizeof(float); |
1222 | 0 | } |
1223 | 0 | case JsonbType::T_Int128: { Branch (1223:5): [True: 0, False: 55]
|
1224 | 0 | return sizeof(int128_t); |
1225 | 0 | } |
1226 | 18 | case JsonbType::T_String: Branch (1226:5): [True: 18, False: 37]
|
1227 | 18 | case JsonbType::T_Binary: { Branch (1227:5): [True: 0, False: 55]
|
1228 | 18 | return ((JsonbBlobVal*)(this))->getBlobLen(); |
1229 | 18 | } |
1230 | | |
1231 | 5 | case JsonbType::T_Object: Branch (1231:5): [True: 5, False: 50]
|
1232 | 10 | case JsonbType::T_Array: { Branch (1232:5): [True: 5, False: 50]
|
1233 | 10 | return ((ContainerVal*)(this))->getContainerSize(); |
1234 | 5 | } |
1235 | 2 | case JsonbType::T_Null: Branch (1235:5): [True: 2, False: 53]
|
1236 | 4 | case JsonbType::T_True: Branch (1236:5): [True: 2, False: 53]
|
1237 | 6 | case JsonbType::T_False: Branch (1237:5): [True: 2, False: 53]
|
1238 | 6 | default: Branch (1238:5): [True: 0, False: 55]
|
1239 | 6 | return 0; |
1240 | 55 | } |
1241 | 55 | } |
1242 | | |
1243 | 0 | inline int JsonbValue::length() const { |
1244 | 0 | switch (type_) { |
1245 | 0 | case JsonbType::T_Int8: Branch (1245:5): [True: 0, False: 0]
|
1246 | 0 | case JsonbType::T_Int16: Branch (1246:5): [True: 0, False: 0]
|
1247 | 0 | case JsonbType::T_Int32: Branch (1247:5): [True: 0, False: 0]
|
1248 | 0 | case JsonbType::T_Int64: Branch (1248:5): [True: 0, False: 0]
|
1249 | 0 | case JsonbType::T_Double: Branch (1249:5): [True: 0, False: 0]
|
1250 | 0 | case JsonbType::T_Float: Branch (1250:5): [True: 0, False: 0]
|
1251 | 0 | case JsonbType::T_Int128: Branch (1251:5): [True: 0, False: 0]
|
1252 | 0 | case JsonbType::T_String: Branch (1252:5): [True: 0, False: 0]
|
1253 | 0 | case JsonbType::T_Binary: Branch (1253:5): [True: 0, False: 0]
|
1254 | 0 | case JsonbType::T_Null: Branch (1254:5): [True: 0, False: 0]
|
1255 | 0 | case JsonbType::T_True: Branch (1255:5): [True: 0, False: 0]
|
1256 | 0 | case JsonbType::T_False: { Branch (1256:5): [True: 0, False: 0]
|
1257 | 0 | return 1; |
1258 | 0 | } |
1259 | 0 | case JsonbType::T_Object: { Branch (1259:5): [True: 0, False: 0]
|
1260 | 0 | return ((ObjectVal*)this)->numElem(); |
1261 | 0 | } |
1262 | 0 | case JsonbType::T_Array: { Branch (1262:5): [True: 0, False: 0]
|
1263 | 0 | return ((ArrayVal*)this)->numElem(); |
1264 | 0 | } |
1265 | 0 | default: Branch (1265:5): [True: 0, False: 0]
|
1266 | 0 | return 0; |
1267 | 0 | } |
1268 | 0 | } |
1269 | | |
1270 | 0 | inline bool JsonbValue::contains(JsonbValue* rhs) const { |
1271 | 0 | switch (type_) { |
1272 | 0 | case JsonbType::T_Int8: Branch (1272:5): [True: 0, False: 0]
|
1273 | 0 | case JsonbType::T_Int16: Branch (1273:5): [True: 0, False: 0]
|
1274 | 0 | case JsonbType::T_Int32: Branch (1274:5): [True: 0, False: 0]
|
1275 | 0 | case JsonbType::T_Int64: Branch (1275:5): [True: 0, False: 0]
|
1276 | 0 | case JsonbType::T_Int128: { Branch (1276:5): [True: 0, False: 0]
|
1277 | 0 | return ((JsonbIntVal*)(this))->val() == ((JsonbIntVal*)(rhs))->val(); |
1278 | 0 | } |
1279 | 0 | case JsonbType::T_Double: { Branch (1279:5): [True: 0, False: 0]
|
1280 | 0 | if (rhs->isDouble()) { Branch (1280:13): [True: 0, False: 0]
|
1281 | 0 | return ((JsonbDoubleVal*)(this))->val() == ((JsonbDoubleVal*)(rhs))->val(); |
1282 | 0 | } |
1283 | 0 | return false; |
1284 | 0 | } |
1285 | 0 | case JsonbType::T_Float: { Branch (1285:5): [True: 0, False: 0]
|
1286 | 0 | if (rhs->isDouble()) { Branch (1286:13): [True: 0, False: 0]
|
1287 | 0 | return ((JsonbFloatVal*)(this))->val() == ((JsonbFloatVal*)(rhs))->val(); |
1288 | 0 | } |
1289 | 0 | return false; |
1290 | 0 | } |
1291 | 0 | case JsonbType::T_String: Branch (1291:5): [True: 0, False: 0]
|
1292 | 0 | case JsonbType::T_Binary: { Branch (1292:5): [True: 0, False: 0]
|
1293 | 0 | if (rhs->isString()) { Branch (1293:13): [True: 0, False: 0]
|
1294 | 0 | auto* str_value1 = (JsonbStringVal*)this; |
1295 | 0 | auto* str_value2 = (JsonbStringVal*)rhs; |
1296 | 0 | return str_value1->length() == str_value2->length() && Branch (1296:20): [True: 0, False: 0]
|
1297 | 0 | std::memcmp(str_value1->getBlob(), str_value2->getBlob(), Branch (1297:20): [True: 0, False: 0]
|
1298 | 0 | str_value1->length()) == 0; |
1299 | 0 | } |
1300 | 0 | return false; |
1301 | 0 | } |
1302 | 0 | case JsonbType::T_Array: { Branch (1302:5): [True: 0, False: 0]
|
1303 | 0 | int lhs_num = ((ArrayVal*)this)->numElem(); |
1304 | 0 | if (rhs->isArray()) { Branch (1304:13): [True: 0, False: 0]
|
1305 | 0 | int rhs_num = ((ArrayVal*)rhs)->numElem(); |
1306 | 0 | if (rhs_num > lhs_num) { Branch (1306:17): [True: 0, False: 0]
|
1307 | 0 | return false; |
1308 | 0 | } |
1309 | 0 | int contains_num = 0; |
1310 | 0 | for (int i = 0; i < lhs_num; ++i) { Branch (1310:29): [True: 0, False: 0]
|
1311 | 0 | for (int j = 0; j < rhs_num; ++j) { Branch (1311:33): [True: 0, False: 0]
|
1312 | 0 | if (((ArrayVal*)this)->get(i)->contains(((ArrayVal*)rhs)->get(j))) { Branch (1312:25): [True: 0, False: 0]
|
1313 | 0 | contains_num++; |
1314 | 0 | break; |
1315 | 0 | } |
1316 | 0 | } |
1317 | 0 | } |
1318 | 0 | return contains_num == rhs_num; |
1319 | 0 | } |
1320 | 0 | for (int i = 0; i < lhs_num; ++i) { Branch (1320:25): [True: 0, False: 0]
|
1321 | 0 | if (((ArrayVal*)this)->get(i)->contains(rhs)) { Branch (1321:17): [True: 0, False: 0]
|
1322 | 0 | return true; |
1323 | 0 | } |
1324 | 0 | } |
1325 | 0 | return false; |
1326 | 0 | } |
1327 | 0 | case JsonbType::T_Object: { Branch (1327:5): [True: 0, False: 0]
|
1328 | 0 | if (rhs->isObject()) { Branch (1328:13): [True: 0, False: 0]
|
1329 | 0 | const auto* obj_value1 = (ObjectVal*)this; |
1330 | 0 | const auto* obj_value2 = (ObjectVal*)rhs; |
1331 | 0 | for (int i = 0; i < obj_value2->numElem(); ++i) { Branch (1331:29): [True: 0, False: 0]
|
1332 | 0 | JsonbKeyValue* key = obj_value2->getJsonbKeyValue(i); |
1333 | 0 | JsonbValue* value = obj_value1->find(key->getKeyStr(), key->klen()); |
1334 | 0 | if (value == nullptr || !value->contains(key->value())) { Branch (1334:21): [True: 0, False: 0]
Branch (1334:41): [True: 0, False: 0]
|
1335 | 0 | return false; |
1336 | 0 | } |
1337 | 0 | } |
1338 | 0 | return true; |
1339 | 0 | } |
1340 | 0 | return false; |
1341 | 0 | } |
1342 | 0 | case JsonbType::T_Null: { Branch (1342:5): [True: 0, False: 0]
|
1343 | 0 | return rhs->isNull(); |
1344 | 0 | } |
1345 | 0 | case JsonbType::T_True: { Branch (1345:5): [True: 0, False: 0]
|
1346 | 0 | return rhs->isTrue(); |
1347 | 0 | } |
1348 | 0 | case JsonbType::T_False: { Branch (1348:5): [True: 0, False: 0]
|
1349 | 0 | return rhs->isFalse(); |
1350 | 0 | } |
1351 | 0 | default: Branch (1351:5): [True: 0, False: 0]
|
1352 | 0 | return false; |
1353 | 0 | } |
1354 | 0 | } |
1355 | | |
1356 | 0 | inline const char* JsonbValue::getValuePtr() const { |
1357 | 0 | switch (type_) { |
1358 | 0 | case JsonbType::T_Int8: |
1359 | 0 | case JsonbType::T_Int16: |
1360 | 0 | case JsonbType::T_Int32: |
1361 | 0 | case JsonbType::T_Int64: |
1362 | 0 | case JsonbType::T_Double: |
1363 | 0 | case JsonbType::T_Float: |
1364 | 0 | case JsonbType::T_Int128: |
1365 | 0 | return ((char*)this) + sizeof(JsonbType); |
1366 | 0 |
|
1367 | 0 | case JsonbType::T_String: |
1368 | 0 | case JsonbType::T_Binary: |
1369 | 0 | return ((JsonbBlobVal*)(this))->getBlob(); |
1370 | 0 |
|
1371 | 0 | case JsonbType::T_Object: |
1372 | 0 | case JsonbType::T_Array: |
1373 | 0 | return ((ContainerVal*)(this))->getPayload(); |
1374 | 0 |
|
1375 | 0 | case JsonbType::T_Null: |
1376 | 0 | case JsonbType::T_True: |
1377 | 0 | case JsonbType::T_False: |
1378 | 0 | default: |
1379 | 0 | return nullptr; |
1380 | 0 | } |
1381 | 0 | } |
1382 | | |
1383 | 846 | inline bool JsonbPath::seek(const char* key_path, size_t kp_len) { |
1384 | | //path invalid |
1385 | 846 | if (!key_path || kp_len == 0) { Branch (1385:9): [True: 0, False: 846]
Branch (1385:22): [True: 0, False: 846]
|
1386 | 0 | return false; |
1387 | 0 | } |
1388 | 846 | Stream stream(key_path, kp_len); |
1389 | 846 | stream.skip_whitespace(); |
1390 | 846 | if (stream.exhausted() || stream.read() != SCOPE) { Branch (1390:9): [True: 0, False: 846]
Branch (1390:31): [True: 0, False: 846]
|
1391 | | //path invalid |
1392 | 0 | return false; |
1393 | 0 | } |
1394 | | |
1395 | 1.69k | while (!stream.exhausted()) { Branch (1395:12): [True: 850, False: 846]
|
1396 | 850 | stream.skip_whitespace(); |
1397 | 850 | stream.clear_leg_ptr(); |
1398 | 850 | stream.clear_leg_len(); |
1399 | | |
1400 | 850 | if (!JsonbPath::parsePath(&stream, this)) { Branch (1400:13): [True: 0, False: 850]
|
1401 | | //path invalid |
1402 | 0 | return false; |
1403 | 0 | } |
1404 | 850 | } |
1405 | 846 | return true; |
1406 | 846 | } |
1407 | | |
1408 | 816 | inline JsonbValue* JsonbValue::findValue(JsonbPath& path, hDictFind handler) { |
1409 | 816 | JsonbValue* pval = this; |
1410 | 1.05k | for (size_t i = 0; i < path.get_leg_vector_size(); ++i) { Branch (1410:24): [True: 732, False: 321]
|
1411 | 732 | switch (path.get_leg_from_leg_vector(i)->type) { Branch (1411:17): [True: 0, False: 732]
|
1412 | 204 | case MEMBER_CODE: { Branch (1412:9): [True: 204, False: 528]
|
1413 | 204 | if (LIKELY(pval->type_ == JsonbType::T_Object)) { |
1414 | 51 | if (path.get_leg_from_leg_vector(i)->leg_len == 1 && Branch (1414:21): [True: 0, False: 51]
|
1415 | 51 | *path.get_leg_from_leg_vector(i)->leg_ptr == WILDCARD) { Branch (1415:21): [True: 0, False: 0]
|
1416 | 0 | continue; |
1417 | 0 | } |
1418 | | |
1419 | 51 | pval = ((ObjectVal*)pval) |
1420 | 51 | ->find(path.get_leg_from_leg_vector(i)->leg_ptr, |
1421 | 51 | path.get_leg_from_leg_vector(i)->leg_len, handler); |
1422 | | |
1423 | 51 | if (!pval) { Branch (1423:21): [True: 18, False: 33]
|
1424 | 18 | return nullptr; |
1425 | 18 | } |
1426 | 33 | continue; |
1427 | 153 | } else { |
1428 | 153 | return nullptr; |
1429 | 153 | } |
1430 | 204 | } |
1431 | 528 | case ARRAY_CODE: { Branch (1431:9): [True: 528, False: 204]
|
1432 | 528 | if (path.get_leg_from_leg_vector(i)->leg_len == 1 && Branch (1432:17): [True: 0, False: 528]
|
1433 | 528 | *path.get_leg_from_leg_vector(i)->leg_ptr == WILDCARD) { Branch (1433:17): [True: 0, False: 0]
|
1434 | 0 | if (LIKELY(pval->type_ == JsonbType::T_Array)) { |
1435 | 0 | continue; |
1436 | 0 | } else { |
1437 | 0 | return nullptr; |
1438 | 0 | } |
1439 | 0 | } |
1440 | | |
1441 | 528 | if (pval->type_ == JsonbType::T_Object && Branch (1441:17): [True: 54, False: 474]
|
1442 | 528 | path.get_leg_from_leg_vector(i)->array_index == 0) { Branch (1442:17): [True: 36, False: 18]
|
1443 | 36 | continue; |
1444 | 36 | } |
1445 | | |
1446 | 492 | if (pval->type_ != JsonbType::T_Array || Branch (1446:17): [True: 261, False: 231]
|
1447 | 492 | path.get_leg_from_leg_vector(i)->leg_ptr != nullptr || Branch (1447:17): [True: 0, False: 231]
|
1448 | 492 | path.get_leg_from_leg_vector(i)->leg_len != 0) { Branch (1448:17): [True: 0, False: 231]
|
1449 | 261 | return nullptr; |
1450 | 261 | } |
1451 | | |
1452 | 231 | if (path.get_leg_from_leg_vector(i)->array_index >= 0) { Branch (1452:17): [True: 231, False: 0]
|
1453 | 231 | pval = ((ArrayVal*)pval)->get(path.get_leg_from_leg_vector(i)->array_index); |
1454 | 231 | } else { |
1455 | 0 | pval = ((ArrayVal*)pval) |
1456 | 0 | ->get(((ArrayVal*)pval)->numElem() + |
1457 | 0 | path.get_leg_from_leg_vector(i)->array_index); |
1458 | 0 | } |
1459 | | |
1460 | 231 | if (!pval) { Branch (1460:17): [True: 63, False: 168]
|
1461 | 63 | return nullptr; |
1462 | 63 | } |
1463 | 168 | continue; |
1464 | 231 | } |
1465 | 732 | } |
1466 | 732 | } |
1467 | 321 | return pval; |
1468 | 816 | } |
1469 | | |
1470 | 850 | inline bool JsonbPath::parsePath(Stream* stream, JsonbPath* path) { |
1471 | | // $[0] |
1472 | 850 | if (stream->peek() == BEGIN_ARRAY) { Branch (1472:9): [True: 542, False: 308]
|
1473 | 542 | return parse_array(stream, path); |
1474 | 542 | } |
1475 | | // $.a or $.[0] |
1476 | 308 | else if (stream->peek() == BEGIN_MEMBER) { Branch (1476:14): [True: 308, False: 0]
|
1477 | | // advance past the . |
1478 | 308 | stream->skip(1); |
1479 | | |
1480 | 308 | if (stream->exhausted()) { Branch (1480:13): [True: 0, False: 308]
|
1481 | 0 | return false; |
1482 | 0 | } |
1483 | | |
1484 | | // $.[0] |
1485 | 308 | if (stream->peek() == BEGIN_ARRAY) { Branch (1485:13): [True: 0, False: 308]
|
1486 | 0 | return parse_array(stream, path); |
1487 | 0 | } |
1488 | | // $.a |
1489 | 308 | else { |
1490 | 308 | return parse_member(stream, path); |
1491 | 308 | } |
1492 | 308 | } else { |
1493 | 0 | return false; //invalid json path |
1494 | 0 | } |
1495 | 850 | } |
1496 | | |
1497 | 542 | inline bool JsonbPath::parse_array(Stream* stream, JsonbPath* path) { |
1498 | 542 | assert(stream->peek() == BEGIN_ARRAY); |
1499 | 0 | stream->skip(1); |
1500 | 542 | if (stream->exhausted()) { Branch (1500:9): [True: 0, False: 542]
|
1501 | 0 | return false; |
1502 | 0 | } |
1503 | | |
1504 | 542 | if (stream->peek() == WILDCARD) { Branch (1504:9): [True: 0, False: 542]
|
1505 | 0 | stream->set_leg_ptr(const_cast<char*>(stream->position())); |
1506 | 0 | stream->add_leg_len(); |
1507 | 0 | stream->skip(1); |
1508 | 0 | if (stream->exhausted()) { Branch (1508:13): [True: 0, False: 0]
|
1509 | 0 | return false; |
1510 | 0 | } |
1511 | | |
1512 | 0 | if (stream->peek() == END_ARRAY) { Branch (1512:13): [True: 0, False: 0]
|
1513 | 0 | std::unique_ptr<leg_info> leg( |
1514 | 0 | new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, ARRAY_CODE)); |
1515 | 0 | path->add_leg_to_leg_vector(std::move(leg)); |
1516 | 0 | stream->skip(1); |
1517 | 0 | return true; |
1518 | 0 | } else { |
1519 | 0 | return false; |
1520 | 0 | } |
1521 | 0 | } |
1522 | | |
1523 | 542 | stream->set_leg_ptr(const_cast<char*>(stream->position())); |
1524 | | |
1525 | 1.08k | for (; !stream->exhausted() && stream->peek() != END_ARRAY; stream->skip(1)) { Branch (1525:12): [True: 1.08k, False: 0]
Branch (1525:36): [True: 542, False: 542]
|
1526 | 542 | stream->add_leg_len(); |
1527 | 542 | } |
1528 | | |
1529 | 542 | if (stream->exhausted() || stream->peek() != END_ARRAY) { Branch (1529:9): [True: 0, False: 542]
Branch (1529:32): [True: 0, False: 542]
|
1530 | 0 | return false; |
1531 | 542 | } else { |
1532 | 542 | stream->skip(1); |
1533 | 542 | } |
1534 | | |
1535 | | //parse array index to int |
1536 | | |
1537 | 542 | std::string_view idx_string(stream->get_leg_ptr(), stream->get_leg_len()); |
1538 | 542 | int index = 0; |
1539 | | |
1540 | 542 | if (stream->get_leg_len() >= 4 && Branch (1540:9): [True: 0, False: 542]
|
1541 | 542 | std::equal(LAST, LAST + 4, stream->get_leg_ptr(), Branch (1541:9): [True: 0, False: 0]
|
1542 | 0 | [](char c1, char c2) { return std::tolower(c1) == std::tolower(c2); })) { |
1543 | 0 | auto pos = idx_string.find(MINUS); |
1544 | |
|
1545 | 0 | if (pos != std::string::npos) { Branch (1545:13): [True: 0, False: 0]
|
1546 | 0 | idx_string = idx_string.substr(pos + 1); |
1547 | |
|
1548 | 0 | auto result = std::from_chars(idx_string.data(), idx_string.data() + idx_string.size(), |
1549 | 0 | index); |
1550 | 0 | if (result.ec != std::errc()) { Branch (1550:17): [True: 0, False: 0]
|
1551 | 0 | return false; |
1552 | 0 | } |
1553 | |
|
1554 | 0 | } else if (stream->get_leg_len() > 4) { Branch (1554:20): [True: 0, False: 0]
|
1555 | 0 | return false; |
1556 | 0 | } |
1557 | | |
1558 | 0 | std::unique_ptr<leg_info> leg(new leg_info(nullptr, 0, -index - 1, ARRAY_CODE)); |
1559 | 0 | path->add_leg_to_leg_vector(std::move(leg)); |
1560 | |
|
1561 | 0 | return true; |
1562 | 0 | } |
1563 | | |
1564 | 542 | auto result = std::from_chars(idx_string.data(), idx_string.data() + idx_string.size(), index); |
1565 | | |
1566 | 542 | if (result.ec != std::errc()) { Branch (1566:9): [True: 0, False: 542]
|
1567 | 0 | return false; |
1568 | 0 | } |
1569 | | |
1570 | 542 | std::unique_ptr<leg_info> leg(new leg_info(nullptr, 0, index, ARRAY_CODE)); |
1571 | 542 | path->add_leg_to_leg_vector(std::move(leg)); |
1572 | | |
1573 | 542 | return true; |
1574 | 542 | } |
1575 | | |
1576 | 308 | inline bool JsonbPath::parse_member(Stream* stream, JsonbPath* path) { |
1577 | 308 | if (stream->exhausted()) { Branch (1577:9): [True: 0, False: 308]
|
1578 | 0 | return false; |
1579 | 0 | } |
1580 | | |
1581 | 308 | if (stream->peek() == WILDCARD) { Branch (1581:9): [True: 0, False: 308]
|
1582 | 0 | stream->set_leg_ptr(const_cast<char*>(stream->position())); |
1583 | 0 | stream->add_leg_len(); |
1584 | 0 | stream->skip(1); |
1585 | 0 | std::unique_ptr<leg_info> leg( |
1586 | 0 | new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, MEMBER_CODE)); |
1587 | 0 | path->add_leg_to_leg_vector(std::move(leg)); |
1588 | 0 | return true; |
1589 | 0 | } |
1590 | | |
1591 | 308 | stream->set_leg_ptr(const_cast<char*>(stream->position())); |
1592 | | |
1593 | 308 | const char* left_quotation_marks = nullptr; |
1594 | 308 | const char* right_quotation_marks = nullptr; |
1595 | | |
1596 | 924 | for (; !stream->exhausted(); stream->skip(1)) { Branch (1596:12): [True: 616, False: 308]
|
1597 | 616 | if (stream->peek() == ESCAPE) { Branch (1597:13): [True: 0, False: 616]
|
1598 | 0 | stream->add_leg_len(); |
1599 | 0 | stream->skip(1); |
1600 | 0 | stream->add_leg_len(); |
1601 | 0 | stream->set_has_escapes(true); |
1602 | 0 | if (stream->exhausted()) { Branch (1602:17): [True: 0, False: 0]
|
1603 | 0 | return false; |
1604 | 0 | } |
1605 | 0 | continue; |
1606 | 616 | } else if (stream->peek() == DOUBLE_QUOTE) { Branch (1606:20): [True: 0, False: 616]
|
1607 | 0 | if (left_quotation_marks == nullptr) { Branch (1607:17): [True: 0, False: 0]
|
1608 | 0 | left_quotation_marks = stream->position(); |
1609 | 0 | stream->set_leg_ptr(const_cast<char*>(++left_quotation_marks)); |
1610 | 0 | continue; |
1611 | 0 | } else { |
1612 | 0 | right_quotation_marks = stream->position(); |
1613 | 0 | stream->skip(1); |
1614 | 0 | break; |
1615 | 0 | } |
1616 | 616 | } else if (stream->peek() == BEGIN_MEMBER || stream->peek() == BEGIN_ARRAY) { Branch (1616:20): [True: 0, False: 616]
Branch (1616:54): [True: 0, False: 616]
|
1617 | 0 | if (left_quotation_marks == nullptr) { Branch (1617:17): [True: 0, False: 0]
|
1618 | 0 | break; |
1619 | 0 | } |
1620 | 0 | } |
1621 | | |
1622 | 616 | stream->add_leg_len(); |
1623 | 616 | } |
1624 | | |
1625 | 308 | if ((left_quotation_marks != nullptr && right_quotation_marks == nullptr) || Branch (1625:10): [True: 0, False: 308]
Branch (1625:45): [True: 0, False: 0]
|
1626 | 308 | stream->get_leg_ptr() == nullptr || stream->get_leg_len() == 0) { Branch (1626:9): [True: 0, False: 308]
Branch (1626:45): [True: 0, False: 308]
|
1627 | 0 | return false; //invalid json path |
1628 | 0 | } |
1629 | | |
1630 | 308 | if (stream->get_has_escapes()) { Branch (1630:9): [True: 0, False: 308]
|
1631 | 0 | stream->remove_escapes(); |
1632 | 0 | } |
1633 | | |
1634 | 308 | std::unique_ptr<leg_info> leg( |
1635 | 308 | new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, MEMBER_CODE)); |
1636 | 308 | path->add_leg_to_leg_vector(std::move(leg)); |
1637 | | |
1638 | 308 | return true; |
1639 | 308 | } |
1640 | | |
1641 | | #pragma pack(pop) |
1642 | | #if defined(__clang__) |
1643 | | #pragma clang diagnostic pop |
1644 | | #endif |
1645 | | } // namespace doris |
1646 | | |
1647 | | #endif // JSONB_JSONBDOCUMENT_H |