Coverage Report

Created: 2026-11-05 14:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
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
6.16M
#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.6k
    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
22.4k
    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
492k
    size_t remaining() const {
273
492k
        assert(m_position <= m_end);
274
492k
        return m_end - m_position;
275
492k
    }
276
277
    /// Tells if the stream has been exhausted.
278
458k
    bool exhausted() const { return remaining() == 0; }
279
280
    /// Reads the next byte from the stream and moves the position forward.
281
15.6k
    char read() {
282
15.6k
        assert(!exhausted());
283
15.6k
        return *m_position++;
284
15.6k
    }
285
286
    /// Reads the next byte from the stream without moving the position forward.
287
278k
    char peek() const {
288
278k
        assert(!exhausted());
289
278k
        return *m_position;
290
278k
    }
291
292
    /// Moves the position to the next non-whitespace character.
293
71.3k
    void skip_whitespace() {
294
71.3k
        m_position = std::find_if_not(m_position, m_end, [](char c) { return std::isspace(c); });
295
71.3k
    }
296
297
    /// Moves the position n bytes forward.
298
33.8k
    void skip(size_t n) {
299
33.8k
        assert(remaining() >= n);
300
33.8k
        m_position += n;
301
33.8k
        skip_whitespace();
302
33.8k
    }
303
304
46.4k
    void advance() { m_position++; }
305
306
43.9k
    void clear_leg_ptr() { leg_ptr = nullptr; }
307
308
22.1k
    void set_leg_ptr(char* ptr) {
309
22.1k
        clear_leg_ptr();
310
22.1k
        leg_ptr = ptr;
311
22.1k
    }
312
313
33.8k
    char* get_leg_ptr() { return leg_ptr; }
314
315
21.8k
    void clear_leg_len() { leg_len = 0; }
316
317
46.5k
    void add_leg_len() { leg_len++; }
318
319
43.5k
    unsigned int get_leg_len() const { return leg_len; }
320
321
28
    void remove_escapes() {
322
28
        unsigned int new_len = 0;
323
200
        for (unsigned int i = 0; i < leg_len; ++i) {
324
174
            if (leg_ptr[i] != ESCAPE) {
325
110
                leg_ptr[new_len++] = leg_ptr[i];
326
110
                continue;
327
110
            }
328
329
64
            ++i;
330
64
            if (i >= leg_len) {
331
2
                break;
332
2
            }
333
334
62
            switch (leg_ptr[i]) {
335
4
            case 'b':
336
4
                leg_ptr[new_len++] = '\b';
337
4
                break;
338
4
            case 'f':
339
4
                leg_ptr[new_len++] = '\f';
340
4
                break;
341
7
            case 'n':
342
7
                leg_ptr[new_len++] = '\n';
343
7
                break;
344
4
            case 'r':
345
4
                leg_ptr[new_len++] = '\r';
346
4
                break;
347
4
            case 't':
348
4
                leg_ptr[new_len++] = '\t';
349
4
                break;
350
22
            case 'u': {
351
22
                if (i + 4 >= leg_len || leg_ptr[i + 1] != '0' || leg_ptr[i + 2] != '0') {
352
4
                    leg_ptr[new_len++] = leg_ptr[i];
353
4
                    break;
354
4
                }
355
356
36
                auto hex_to_int = [](char c) -> int {
357
36
                    if (c >= '0' && c <= '9') {
358
24
                        return c - '0';
359
24
                    }
360
12
                    if (c >= 'a' && c <= 'f') {
361
4
                        return c - 'a' + 10;
362
4
                    }
363
8
                    if (c >= 'A' && c <= 'F') {
364
2
                        return c - 'A' + 10;
365
2
                    }
366
6
                    return -1;
367
8
                };
368
18
                int high = hex_to_int(leg_ptr[i + 3]);
369
18
                int low = hex_to_int(leg_ptr[i + 4]);
370
18
                if (high < 0 || low < 0) {
371
6
                    leg_ptr[new_len++] = leg_ptr[i];
372
6
                    break;
373
6
                }
374
12
                leg_ptr[new_len++] = static_cast<char>((high << 4) | low);
375
12
                i += 4;
376
12
                break;
377
18
            }
378
17
            default:
379
17
                leg_ptr[new_len++] = leg_ptr[i];
380
17
                break;
381
62
            }
382
62
        }
383
28
        leg_ptr[new_len] = '\0';
384
28
        leg_len = new_len;
385
28
    }
386
387
21.8k
    void set_has_escapes(bool has) { has_escapes = has; }
388
389
10.3k
    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
451
    bool to_string(std::string* str) const {
427
451
        if (type == MEMBER_CODE) {
428
187
            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
187
            bool needs_quotes = leg_len == 0 || (!is_wildcard && *leg_ptr == WILDCARD);
435
187
            std::string tmp;
436
557
            for (auto* it = leg_ptr; it != (leg_ptr + leg_len); ++it) {
437
370
                auto c = static_cast<unsigned char>(*it);
438
370
                if (std::isspace(c) || *it == BEGIN_MEMBER || *it == BEGIN_ARRAY) {
439
40
                    needs_quotes = true;
440
40
                }
441
442
370
                switch (*it) {
443
10
                case '"':
444
10
                    tmp.append("\\\"");
445
10
                    break;
446
4
                case ESCAPE:
447
4
                    tmp.append("\\\\");
448
4
                    break;
449
4
                case '\b':
450
4
                    tmp.append("\\b");
451
4
                    break;
452
4
                case '\f':
453
4
                    tmp.append("\\f");
454
4
                    break;
455
8
                case '\n':
456
8
                    tmp.append("\\n");
457
8
                    break;
458
5
                case '\r':
459
5
                    tmp.append("\\r");
460
5
                    break;
461
5
                case '\t':
462
5
                    tmp.append("\\t");
463
5
                    break;
464
330
                default:
465
330
                    if (c < 0x20) {
466
13
                        constexpr char hex[] = "0123456789abcdef";
467
13
                        tmp.append("\\u00");
468
13
                        tmp.push_back(hex[c >> 4]);
469
13
                        tmp.push_back(hex[c & 0x0F]);
470
317
                    } else {
471
317
                        tmp.push_back(*it);
472
317
                    }
473
330
                    break;
474
370
                }
475
370
            }
476
187
            if (needs_quotes) {
477
53
                str->push_back(DOUBLE_QUOTE);
478
53
            }
479
187
            str->append(tmp);
480
187
            if (needs_quotes) {
481
53
                str->push_back(DOUBLE_QUOTE);
482
53
            }
483
187
            return true;
484
264
        } else if (type == ARRAY_CODE) {
485
264
            str->push_back(BEGIN_ARRAY);
486
264
            if (is_wildcard) {
487
4
                str->push_back(WILDCARD);
488
260
            } else {
489
260
                str->append(std::to_string(array_index));
490
260
            }
491
264
            str->push_back(END_ARRAY);
492
264
            return true;
493
264
        } else {
494
0
            return false;
495
0
        }
496
451
    }
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.9k
    void add_leg_to_leg_vector(std::unique_ptr<leg_info> leg) {
511
22.9k
        leg_vector.emplace_back(leg.release());
512
22.9k
    }
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
282
    bool to_string(std::string* res) const {
518
282
        res->push_back(SCOPE);
519
429
        for (const auto& leg : leg_vector) {
520
429
            auto valid = leg->to_string(res);
521
429
            if (!valid) {
522
0
                return false;
523
0
            }
524
429
        }
525
282
        return true;
526
282
    }
527
528
1.96M
    size_t get_leg_vector_size() const { return leg_vector.size(); }
529
530
4.39M
    leg_info* get_leg_from_leg_vector(size_t i) const { return leg_vector[i].get(); }
531
532
429
    bool is_wildcard() const { return _is_wildcard; }
533
931k
    bool is_supper_wildcard() const { return _is_supper_wildcard; }
534
535
127
    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.83M
    explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {}
_ZN5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEC2ERKS3_
Line
Count
Source
556
1.80M
    explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {}
_ZN5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEC2ERKS3_
Line
Count
Source
556
29.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.11M
    bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEeqERKS5_
Line
Count
Source
562
1.01M
    bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEeqERKS5_
Line
Count
Source
562
99.6k
    bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); }
563
564
276k
    bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEneERKS5_
Line
Count
Source
564
189k
    bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEneERKS5_
Line
Count
Source
564
87.0k
    bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); }
565
566
62.5k
    bool operator<(const JsonbFwdIteratorT& rhs) const { return (current_ < rhs.current_); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEltERKS5_
Line
Count
Source
566
914
    bool operator<(const JsonbFwdIteratorT& rhs) const { return (current_ < rhs.current_); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEltERKS5_
Line
Count
Source
566
61.6k
    bool operator<(const JsonbFwdIteratorT& rhs) const { return (current_ < rhs.current_); }
567
568
    bool operator>(const JsonbFwdIteratorT& rhs) const { return !operator<(rhs); }
569
570
217k
    JsonbFwdIteratorT& operator++() {
571
217k
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
572
217k
        return *this;
573
217k
    }
_ZN5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEppEv
Line
Count
Source
570
179k
    JsonbFwdIteratorT& operator++() {
571
179k
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
572
179k
        return *this;
573
179k
    }
_ZN5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEppEv
Line
Count
Source
570
38.3k
    JsonbFwdIteratorT& operator++() {
571
38.3k
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
572
38.3k
        return *this;
573
38.3k
    }
574
575
    JsonbFwdIteratorT operator++(int) {
576
        auto tmp = *this;
577
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
578
        return tmp;
579
    }
580
581
35.8k
    explicit operator pointer() { return current_; }
582
583
3.94k
    reference operator*() const { return *current_; }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEdeEv
Line
Count
Source
583
2.53k
    reference operator*() const { return *current_; }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEdeEv
Line
Count
Source
583
1.40k
    reference operator*() const { return *current_; }
584
585
417k
    pointer operator->() const { return current_; }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEptEv
Line
Count
Source
585
417k
    pointer operator->() const { return current_; }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEptEv
Line
Count
Source
585
164
    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.11M
    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
891k
    uint8_t klen() const { return size; }
685
686
    // get the key string. Note the string may not be null terminated.
687
58.6k
    const char* getKeyStr() const { return key.str_; }
688
689
122k
    keyid_type getKeyId() const { return key.id_; }
690
691
1.15M
    unsigned int keyPackedBytes() const {
692
1.15M
        return size ? (sizeof(size) + size) : (sizeof(size) + sizeof(keyid_type));
693
1.15M
    }
694
695
175k
    const JsonbValue* value() const {
696
175k
        return (const JsonbValue*)(((char*)this) + keyPackedBytes());
697
175k
    }
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
201k
    bool isNull() const { return (type == JsonbType::T_Null); }
725
8.36k
    bool isTrue() const { return (type == JsonbType::T_True); }
726
14
    bool isFalse() const { return (type == JsonbType::T_False); }
727
74.8k
    bool isInt() const { return isInt8() || isInt16() || isInt32() || isInt64() || isInt128(); }
728
74.8k
    bool isInt8() const { return (type == JsonbType::T_Int8); }
729
64.2k
    bool isInt16() const { return (type == JsonbType::T_Int16); }
730
59.4k
    bool isInt32() const { return (type == JsonbType::T_Int32); }
731
41.2k
    bool isInt64() const { return (type == JsonbType::T_Int64); }
732
1.03k
    bool isDouble() const { return (type == JsonbType::T_Double); }
733
916
    bool isFloat() const { return (type == JsonbType::T_Float); }
734
3.06k
    bool isString() const { return (type == JsonbType::T_String); }
735
16.5k
    bool isBinary() const { return (type == JsonbType::T_Binary); }
736
5.85k
    bool isObject() const { return (type == JsonbType::T_Object); }
737
4.76k
    bool isArray() const { return (type == JsonbType::T_Array); }
738
20.9k
    bool isInt128() const { return (type == JsonbType::T_Int128); }
739
518
    bool isDecimal() const {
740
518
        return (type == JsonbType::T_Decimal32 || type == JsonbType::T_Decimal64 ||
741
518
                type == JsonbType::T_Decimal128 || type == JsonbType::T_Decimal256);
742
518
    }
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
460
    const char* typeName() const {
751
460
        switch (type) {
752
24
        case JsonbType::T_Null:
753
24
            return "null";
754
20
        case JsonbType::T_True:
755
40
        case JsonbType::T_False:
756
40
            return "bool";
757
45
        case JsonbType::T_Int8:
758
83
        case JsonbType::T_Int16:
759
99
        case JsonbType::T_Int32:
760
99
            return "int";
761
22
        case JsonbType::T_Int64:
762
22
            return "bigint";
763
18
        case JsonbType::T_Int128:
764
18
            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
105
        case JsonbType::T_Object:
774
105
            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
460
        }
788
460
    }
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.46M
    const T* unpack() const {
824
3.46M
        static_assert(is_pod_v<T>, "T must be a POD type");
825
3.46M
        return reinterpret_cast<const T*>(payload);
826
3.46M
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_9ObjectValEEEPKT_v
Line
Count
Source
823
979k
    const T* unpack() const {
824
979k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
979k
        return reinterpret_cast<const T*>(payload);
826
979k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIaEEEEPKT_v
Line
Count
Source
823
122k
    const T* unpack() const {
824
122k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
122k
        return reinterpret_cast<const T*>(payload);
826
122k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIsEEEEPKT_v
Line
Count
Source
823
18.4k
    const T* unpack() const {
824
18.4k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
18.4k
        return reinterpret_cast<const T*>(payload);
826
18.4k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIiEEEEPKT_v
Line
Count
Source
823
20.4k
    const T* unpack() const {
824
20.4k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
20.4k
        return reinterpret_cast<const T*>(payload);
826
20.4k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIlEEEEPKT_v
Line
Count
Source
823
31.1k
    const T* unpack() const {
824
31.1k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
31.1k
        return reinterpret_cast<const T*>(payload);
826
31.1k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTInEEEEPKT_v
Line
Count
Source
823
22.9k
    const T* unpack() const {
824
22.9k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
22.9k
        return reinterpret_cast<const T*>(payload);
826
22.9k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIdEEEEPKT_v
Line
Count
Source
823
12.1k
    const T* unpack() const {
824
12.1k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
12.1k
        return reinterpret_cast<const T*>(payload);
826
12.1k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIfEEEEPKT_v
Line
Count
Source
823
4.63k
    const T* unpack() const {
824
4.63k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
4.63k
        return reinterpret_cast<const T*>(payload);
826
4.63k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_7DecimalIiEEEEEEPKT_v
Line
Count
Source
823
94
    const T* unpack() const {
824
94
        static_assert(is_pod_v<T>, "T must be a POD type");
825
94
        return reinterpret_cast<const T*>(payload);
826
94
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_7DecimalIlEEEEEEPKT_v
Line
Count
Source
823
62
    const T* unpack() const {
824
62
        static_assert(is_pod_v<T>, "T must be a POD type");
825
62
        return reinterpret_cast<const T*>(payload);
826
62
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_12Decimal128V3EEEEEPKT_v
Line
Count
Source
823
160
    const T* unpack() const {
824
160
        static_assert(is_pod_v<T>, "T must be a POD type");
825
160
        return reinterpret_cast<const T*>(payload);
826
160
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_7DecimalIN4wide7integerILm256EiEEEEEEEEPKT_v
Line
Count
Source
823
26
    const T* unpack() const {
824
26
        static_assert(is_pod_v<T>, "T must be a POD type");
825
26
        return reinterpret_cast<const T*>(payload);
826
26
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_14JsonbBinaryValEEEPKT_v
Line
Count
Source
823
151k
    const T* unpack() const {
824
151k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
151k
        return reinterpret_cast<const T*>(payload);
826
151k
    }
_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
207k
    const T* unpack() const {
824
207k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
207k
        return reinterpret_cast<const T*>(payload);
826
207k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_14JsonbStringValEEEPKT_v
Line
Count
Source
823
100k
    const T* unpack() const {
824
100k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
100k
        return reinterpret_cast<const T*>(payload);
826
100k
    }
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
152k
inline const ObjectVal* JsonbDocument::operator->() const {
854
152k
    return (((const JsonbValue*)payload_)->unpack<ObjectVal>());
855
152k
}
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
232k
    T val() const { return num; }
_ZNK5doris10NumberValTIaE3valEv
Line
Count
Source
865
123k
    T val() const { return num; }
_ZNK5doris10NumberValTIsE3valEv
Line
Count
Source
865
18.4k
    T val() const { return num; }
_ZNK5doris10NumberValTIiE3valEv
Line
Count
Source
865
20.4k
    T val() const { return num; }
_ZNK5doris10NumberValTIlE3valEv
Line
Count
Source
865
31.1k
    T val() const { return num; }
_ZNK5doris10NumberValTInE3valEv
Line
Count
Source
865
22.9k
    T val() const { return num; }
_ZNK5doris10NumberValTIdE3valEv
Line
Count
Source
865
12.1k
    T val() const { return num; }
_ZNK5doris10NumberValTIfE3valEv
Line
Count
Source
865
4.63k
    T val() const { return num; }
866
867
    static unsigned int numPackedBytes() { return sizeof(JsonbValue) + sizeof(T); }
868
869
    T num;
870
};
871
872
74.5k
inline int128_t JsonbValue::int_val() const {
873
74.5k
    switch (type) {
874
10.6k
    case JsonbType::T_Int8:
875
10.6k
        return unpack<JsonbInt8Val>()->val();
876
4.82k
    case JsonbType::T_Int16:
877
4.82k
        return unpack<JsonbInt16Val>()->val();
878
18.2k
    case JsonbType::T_Int32:
879
18.2k
        return unpack<JsonbInt32Val>()->val();
880
20.2k
    case JsonbType::T_Int64:
881
20.2k
        return unpack<JsonbInt64Val>()->val();
882
20.6k
    case JsonbType::T_Int128:
883
20.6k
        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
74.5k
    }
888
74.5k
}
889
890
template <JsonbDecimalType T>
891
struct JsonbDecimalVal {
892
public:
893
    using NativeType = typename T::NativeType;
894
895
    // get the decimal value
896
272
    NativeType val() const {
897
        // to avoid memory alignment issues, we use memcpy to copy the value
898
272
        NativeType tmp;
899
272
        memcpy(&tmp, &value, sizeof(NativeType));
900
272
        return tmp;
901
272
    }
_ZNK5doris15JsonbDecimalValINS_7DecimalIiEEE3valEv
Line
Count
Source
896
71
    NativeType val() const {
897
        // to avoid memory alignment issues, we use memcpy to copy the value
898
71
        NativeType tmp;
899
71
        memcpy(&tmp, &value, sizeof(NativeType));
900
71
        return tmp;
901
71
    }
_ZNK5doris15JsonbDecimalValINS_7DecimalIlEEE3valEv
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_12Decimal128V3EE3valEv
Line
Count
Source
896
141
    NativeType val() const {
897
        // to avoid memory alignment issues, we use memcpy to copy the value
898
141
        NativeType tmp;
899
141
        memcpy(&tmp, &value, sizeof(NativeType));
900
141
        return tmp;
901
141
    }
_ZNK5doris15JsonbDecimalValINS_7DecimalIN4wide7integerILm256EiEEEEE3valEv
Line
Count
Source
896
12
    NativeType val() const {
897
        // to avoid memory alignment issues, we use memcpy to copy the value
898
12
        NativeType tmp;
899
12
        memcpy(&tmp, &value, sizeof(NativeType));
900
12
        return tmp;
901
12
    }
902
903
501
    static constexpr int numPackedBytes() {
904
501
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
905
501
    }
_ZN5doris15JsonbDecimalValINS_7DecimalIiEEE14numPackedBytesEv
Line
Count
Source
903
130
    static constexpr int numPackedBytes() {
904
130
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
905
130
    }
_ZN5doris15JsonbDecimalValINS_7DecimalIlEEE14numPackedBytesEv
Line
Count
Source
903
120
    static constexpr int numPackedBytes() {
904
120
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
905
120
    }
_ZN5doris15JsonbDecimalValINS_12Decimal128V3EE14numPackedBytesEv
Line
Count
Source
903
239
    static constexpr int numPackedBytes() {
904
239
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
905
239
    }
_ZN5doris15JsonbDecimalValINS_7DecimalIN4wide7integerILm256EiEEEEE14numPackedBytesEv
Line
Count
Source
903
12
    static constexpr int numPackedBytes() {
904
12
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
905
12
    }
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
69.3k
    unsigned int getBlobLen() const { return size; }
920
921
    // return the blob as byte array
922
79.2k
    const char* getBlob() const { return payload; }
923
924
    // size of the total packed bytes
925
123k
    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
441
    size_t length() const {
945
        // It's an empty string
946
441
        if (0 == size) {
947
0
            return size;
948
0
        }
949
        // The string stored takes all the spaces in payload
950
441
        if (payload[size - 1] != 0) {
951
441
            return size;
952
441
        }
953
        // It's shorter than the size of payload
954
0
        return strnlen(payload, size);
955
441
    }
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
803k
    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
803k
        if (!key) {
996
0
            return end();
997
0
        }
998
803k
        return internalSearch(key, klen);
999
803k
    }
1000
1001
    // Get number of elements in object
1002
245
    int numElem() const {
1003
245
        const char* pch = payload;
1004
245
        const char* fence = payload + size;
1005
1006
245
        unsigned int num = 0;
1007
629
        while (pch < fence) {
1008
384
            auto* pkey = (JsonbKeyValue*)(pch);
1009
384
            ++num;
1010
384
            pch += pkey->numPackedBytes();
1011
384
        }
1012
1013
245
        assert(pch == fence);
1014
1015
245
        return num;
1016
245
    }
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
803k
    const JsonbValue* find(const char* key, unsigned int klen) const {
1028
803k
        const_iterator kv = search(key, klen);
1029
803k
        if (end() == kv) {
1030
791k
            return nullptr;
1031
791k
        }
1032
12.1k
        return kv->value();
1033
803k
    }
1034
1035
    // find the JSONB value by a key id, as stored when klen() == 0 (sMaxKeyId is the empty key)
1036
8
    const JsonbValue* find_by_key_id(JsonbKeyValue::keyid_type key_id) const {
1037
12
        for (auto it = begin(); it != end(); ++it) {
1038
8
            if (it->klen() == 0 && it->getKeyId() == key_id) {
1039
4
                return it->value();
1040
4
            }
1041
8
        }
1042
4
        return nullptr;
1043
8
    }
1044
1045
31.6k
    const_iterator begin() const { return const_iterator((pointer)payload); }
1046
1047
1.76M
    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
803k
    const_iterator internalSearch(const char* key, unsigned int klen) const {
1053
803k
        const char* pch = payload;
1054
803k
        const char* fence = payload + size;
1055
1056
1.60M
        while (pch < fence) {
1057
809k
            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
809k
            if (klen == 0 ? pkey->klen() == 0 && pkey->getKeyId() == JsonbKeyValue::sMaxKeyId
1061
809k
                          : klen == pkey->klen() && strncmp(key, pkey->getKeyStr(), klen) == 0) {
1062
10.9k
                return const_iterator(pkey);
1063
10.9k
            }
1064
798k
            pch += pkey->numPackedBytes();
1065
798k
        }
1066
1067
803k
        assert(pch == fence);
1068
1069
791k
        return end();
1070
792k
    }
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
192k
    const JsonbValue* get(int idx) const {
1084
192k
        if (idx < 0) {
1085
65
            return nullptr;
1086
65
        }
1087
1088
192k
        const char* pch = payload;
1089
192k
        const char* fence = payload + size;
1090
1091
199k
        while (pch < fence && idx-- > 0) {
1092
7.02k
            pch += ((const JsonbValue*)pch)->numPackedBytes();
1093
7.02k
        }
1094
192k
        if (idx > 0 || pch == fence) {
1095
1.67k
            return nullptr;
1096
1.67k
        }
1097
1098
190k
        return (const JsonbValue*)pch;
1099
192k
    }
1100
1101
    // Get number of elements in array
1102
527
    int numElem() const {
1103
527
        const char* pch = payload;
1104
527
        const char* fence = payload + size;
1105
1106
527
        unsigned int num = 0;
1107
2.21k
        while (pch < fence) {
1108
1.68k
            ++num;
1109
1.68k
            pch += ((const JsonbValue*)pch)->numPackedBytes();
1110
1.68k
        }
1111
1112
527
        assert(pch == fence);
1113
1114
527
        return num;
1115
527
    }
1116
1117
13.7k
    const_iterator begin() const { return const_iterator((pointer)payload); }
1118
1119
16.1k
    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
52
inline void validate_decimal_scale(uint32_t scale) {
1130
52
    if (scale > static_cast<uint32_t>(BeConsts::MAX_DECIMALV3_SCALE)) {
1131
4
        throw Exception(ErrorCode::INTERNAL_ERROR,
1132
4
                        "Invalid JSONB decimal scale: {}, max allowed scale: {}", scale,
1133
4
                        BeConsts::MAX_DECIMALV3_SCALE);
1134
4
    }
1135
52
}
1136
1137
236
inline bool is_numeric(const JsonbValue* value) {
1138
236
    return value->isInt() || value->isDouble() || value->isFloat() || value->isDecimal();
1139
236
}
1140
1141
35
inline double floating_value(const JsonbValue* value) {
1142
35
    if (value->isDouble()) {
1143
35
        return value->unpack<JsonbDoubleVal>()->val();
1144
35
    }
1145
0
    return value->unpack<JsonbFloatVal>()->val();
1146
35
}
1147
1148
40
inline JsonbScaledDecimal get_scaled_decimal(const JsonbValue* value) {
1149
40
    switch (value->type) {
1150
24
    case JsonbType::T_Decimal32: {
1151
24
        const auto* decimal = value->unpack<JsonbDecimal32>();
1152
24
        validate_decimal_scale(decimal->scale);
1153
24
        return {wide::Int256(decimal->val()), decimal->scale};
1154
0
    }
1155
4
    case JsonbType::T_Decimal64: {
1156
4
        const auto* decimal = value->unpack<JsonbDecimal64>();
1157
4
        validate_decimal_scale(decimal->scale);
1158
4
        return {wide::Int256(decimal->val()), decimal->scale};
1159
0
    }
1160
12
    case JsonbType::T_Decimal128: {
1161
12
        const auto* decimal = value->unpack<JsonbDecimal128>();
1162
12
        validate_decimal_scale(decimal->scale);
1163
12
        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
40
    }
1174
40
}
1175
1176
inline bool scaled_decimal_equal_decimal(const JsonbScaledDecimal& lhs,
1177
8
                                         const JsonbScaledDecimal& rhs) {
1178
8
    if (lhs.scale == rhs.scale) {
1179
0
        return lhs.value == rhs.value;
1180
0
    }
1181
1182
8
    if (lhs.scale < rhs.scale) {
1183
4
        const auto scale_multiplier = decimal_scale_multiplier<wide::Int256>(rhs.scale - lhs.scale);
1184
4
        return rhs.value % scale_multiplier == 0 && lhs.value == rhs.value / scale_multiplier;
1185
4
    }
1186
1187
4
    const auto scale_multiplier = decimal_scale_multiplier<wide::Int256>(lhs.scale - rhs.scale);
1188
4
    return lhs.value % scale_multiplier == 0 && lhs.value / scale_multiplier == rhs.value;
1189
8
}
1190
1191
8
inline bool scaled_decimal_equal_integer(const JsonbScaledDecimal& decimal, int128_t integer) {
1192
8
    const auto integer_value = wide::Int256(integer);
1193
8
    if (decimal.scale == 0) {
1194
0
        return decimal.value == integer_value;
1195
0
    }
1196
1197
8
    const auto scale_multiplier = decimal_scale_multiplier<wide::Int256>(decimal.scale);
1198
8
    return decimal.value % scale_multiplier == 0 &&
1199
8
           decimal.value / scale_multiplier == integer_value;
1200
8
}
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
12
inline wide::Int256 power_of_five(uint32_t exponent) {
1212
12
    validate_decimal_scale(exponent);
1213
12
    return kPowersOfFive[exponent];
1214
12
}
1215
1216
12
inline bool scaled_binary_equal(wide::Int256 value, int exponent, wide::Int256 significand) {
1217
12
    if (exponent < 0) {
1218
8
        const int divisor_exponent = -exponent;
1219
8
        if (divisor_exponent >= std::numeric_limits<int64_t>::digits) {
1220
0
            return false;
1221
0
        }
1222
8
        const auto divisor = wide::Int256(1) << divisor_exponent;
1223
8
        return significand % divisor == 0 && value == significand / divisor;
1224
8
    }
1225
4
    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
4
    if (exponent >= max_positive_int256_shift) {
1228
0
        return false;
1229
0
    }
1230
4
    const auto multiplier = wide::Int256(1) << exponent;
1231
4
    return value % multiplier == 0 && value / multiplier == significand;
1232
4
}
1233
1234
19
inline bool floating_equal_integer(const JsonbValue* floating, int128_t integer) {
1235
19
    const double value = floating_value(floating);
1236
19
    int exponent = 0;
1237
19
    std::frexp(value, &exponent);
1238
19
    if (!std::isfinite(value) || std::trunc(value) != value) {
1239
7
        return false;
1240
7
    }
1241
12
    if (exponent >= 128) {
1242
0
        return value == -std::ldexp(1.0, 127) && integer == std::numeric_limits<int128_t>::min();
1243
0
    }
1244
12
    if (exponent <= -1) {
1245
0
        return false;
1246
0
    }
1247
12
    return static_cast<int128_t>(value) == integer;
1248
12
}
1249
1250
12
inline bool floating_equal_decimal(const JsonbValue* floating, const JsonbScaledDecimal& decimal) {
1251
12
    const double value = floating_value(floating);
1252
12
    if (!std::isfinite(value)) {
1253
0
        return false;
1254
0
    }
1255
12
    if (value == 0) {
1256
0
        return decimal.value == 0;
1257
0
    }
1258
1259
12
    int exponent = 0;
1260
12
    const double significand_fraction = std::frexp(value, &exponent);
1261
12
    const double significand_double =
1262
12
            std::ldexp(significand_fraction, std::numeric_limits<double>::digits);
1263
12
    auto significand = wide::Int256(static_cast<int64_t>(significand_double));
1264
12
    exponent -= std::numeric_limits<double>::digits;
1265
1266
12
    const auto five_multiplier = power_of_five(decimal.scale);
1267
12
    if (decimal.value % five_multiplier != 0) {
1268
0
        return false;
1269
0
    }
1270
12
    const auto binary_scaled_decimal = decimal.value / five_multiplier;
1271
12
    return scaled_binary_equal(binary_scaled_decimal, exponent + decimal.scale, significand);
1272
12
}
1273
1274
236
inline bool numeric_equal(const JsonbValue* lhs, const JsonbValue* rhs) {
1275
236
    if (!is_numeric(rhs)) {
1276
70
        return false;
1277
70
    }
1278
1279
166
    if ((lhs->isDouble() || lhs->isFloat()) && rhs->isInt()) {
1280
9
        return floating_equal_integer(lhs, rhs->int_val());
1281
9
    }
1282
1283
157
    if ((rhs->isDouble() || rhs->isFloat()) && lhs->isInt()) {
1284
10
        return floating_equal_integer(rhs, lhs->int_val());
1285
10
    }
1286
1287
147
    if ((lhs->isDouble() || lhs->isFloat()) && rhs->isDecimal()) {
1288
8
        return floating_equal_decimal(lhs, get_scaled_decimal(rhs));
1289
8
    }
1290
1291
139
    if ((rhs->isDouble() || rhs->isFloat()) && lhs->isDecimal()) {
1292
8
        return floating_equal_decimal(rhs, get_scaled_decimal(lhs));
1293
8
    }
1294
1295
131
    if (lhs->isDouble() || lhs->isFloat()) {
1296
2
        return (rhs->isDouble() || rhs->isFloat()) && floating_value(lhs) == floating_value(rhs);
1297
2
    }
1298
1299
129
    if (lhs->isDecimal()) {
1300
12
        const auto lhs_decimal = get_scaled_decimal(lhs);
1301
12
        if (rhs->isDecimal()) {
1302
8
            return scaled_decimal_equal_decimal(lhs_decimal, get_scaled_decimal(rhs));
1303
8
        }
1304
4
        return scaled_decimal_equal_integer(lhs_decimal, rhs->int_val());
1305
12
    }
1306
1307
117
    if (rhs->isDecimal()) {
1308
4
        return scaled_decimal_equal_integer(get_scaled_decimal(rhs), lhs->int_val());
1309
4
    }
1310
1311
113
    return lhs->int_val() == rhs->int_val();
1312
117
}
1313
1314
84
inline bool array_contains_value(const ArrayVal* target_array, const JsonbValue* candidate) {
1315
200
    for (auto it = target_array->begin(); it < target_array->end(); ++it) {
1316
158
        if (it->contains(candidate)) {
1317
42
            return true;
1318
42
        }
1319
158
    }
1320
42
    return false;
1321
84
}
1322
1323
34
inline bool array_contains_array(const ArrayVal* target_array, const ArrayVal* candidate_array) {
1324
62
    for (auto it = candidate_array->begin(); it < candidate_array->end(); ++it) {
1325
46
        if (!array_contains_value(target_array, &*it)) {
1326
18
            return false;
1327
18
        }
1328
46
    }
1329
16
    return true;
1330
34
}
1331
1332
} // namespace jsonb_detail
1333
1334
134k
inline const JsonbValue* JsonbDocument::createValue(const char* pb, size_t size) {
1335
134k
    if (!pb || size < sizeof(JsonbHeader) + sizeof(JsonbValue)) {
1336
0
        return nullptr;
1337
0
    }
1338
1339
134k
    auto* doc = (JsonbDocument*)pb;
1340
134k
    if (doc->header_.ver_ != JSONB_VER) {
1341
0
        return nullptr;
1342
0
    }
1343
1344
134k
    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
134k
    if (size != sizeof(JsonbHeader) + val->numPackedBytes()) {
1349
0
        return nullptr;
1350
0
    }
1351
1352
134k
    return val;
1353
134k
}
1354
1355
306
inline unsigned int JsonbDocument::numPackedBytes() const {
1356
306
    return ((const JsonbValue*)payload_)->numPackedBytes() + sizeof(header_);
1357
306
}
1358
1359
977k
inline unsigned int JsonbKeyValue::numPackedBytes() const {
1360
977k
    unsigned int ks = keyPackedBytes();
1361
977k
    const auto* val = (const JsonbValue*)(((char*)this) + ks);
1362
977k
    return ks + val->numPackedBytes();
1363
977k
}
1364
1365
// Poor man's "virtual" function JsonbValue::numPackedBytes
1366
3.13M
inline unsigned int JsonbValue::numPackedBytes() const {
1367
3.13M
    switch (type) {
1368
15.3k
    case JsonbType::T_Null:
1369
37.2k
    case JsonbType::T_True:
1370
42.7k
    case JsonbType::T_False: {
1371
42.7k
        return sizeof(type);
1372
37.2k
    }
1373
1374
231k
    case JsonbType::T_Int8: {
1375
231k
        return sizeof(type) + sizeof(int8_t);
1376
37.2k
    }
1377
281k
    case JsonbType::T_Int16: {
1378
281k
        return sizeof(type) + sizeof(int16_t);
1379
37.2k
    }
1380
553k
    case JsonbType::T_Int32: {
1381
553k
        return sizeof(type) + sizeof(int32_t);
1382
37.2k
    }
1383
70.5k
    case JsonbType::T_Int64: {
1384
70.5k
        return sizeof(type) + sizeof(int64_t);
1385
37.2k
    }
1386
15.7k
    case JsonbType::T_Double: {
1387
15.7k
        return sizeof(type) + sizeof(double);
1388
37.2k
    }
1389
4.81k
    case JsonbType::T_Float: {
1390
4.81k
        return sizeof(type) + sizeof(float);
1391
37.2k
    }
1392
26.0k
    case JsonbType::T_Int128: {
1393
26.0k
        return sizeof(type) + sizeof(int128_t);
1394
37.2k
    }
1395
94.2k
    case JsonbType::T_String:
1396
123k
    case JsonbType::T_Binary: {
1397
123k
        return unpack<JsonbBinaryVal>()->numPackedBytes();
1398
94.2k
    }
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
130
    case JsonbType::T_Decimal32: {
1405
130
        return JsonbDecimal32::numPackedBytes();
1406
1.11M
    }
1407
120
    case JsonbType::T_Decimal64: {
1408
120
        return JsonbDecimal64::numPackedBytes();
1409
1.11M
    }
1410
239
    case JsonbType::T_Decimal128: {
1411
239
        return JsonbDecimal128::numPackedBytes();
1412
1.11M
    }
1413
12
    case JsonbType::T_Decimal256: {
1414
12
        return JsonbDecimal256::numPackedBytes();
1415
1.11M
    }
1416
0
    case JsonbType::NUM_TYPES:
1417
0
        break;
1418
3.13M
    }
1419
1420
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1421
0
                    static_cast<int32_t>(type));
1422
3.13M
}
1423
1424
154
inline int JsonbValue::numElements() const {
1425
154
    switch (type) {
1426
9
    case JsonbType::T_Int8:
1427
19
    case JsonbType::T_Int16:
1428
21
    case JsonbType::T_Int32:
1429
24
    case JsonbType::T_Int64:
1430
26
    case JsonbType::T_Double:
1431
26
    case JsonbType::T_Float:
1432
28
    case JsonbType::T_Int128:
1433
37
    case JsonbType::T_String:
1434
37
    case JsonbType::T_Binary:
1435
43
    case JsonbType::T_Null:
1436
49
    case JsonbType::T_True:
1437
51
    case JsonbType::T_False:
1438
51
    case JsonbType::T_Decimal32:
1439
51
    case JsonbType::T_Decimal64:
1440
51
    case JsonbType::T_Decimal128:
1441
51
    case JsonbType::T_Decimal256: {
1442
51
        return 1;
1443
51
    }
1444
29
    case JsonbType::T_Object: {
1445
29
        return unpack<ObjectVal>()->numElem();
1446
51
    }
1447
74
    case JsonbType::T_Array: {
1448
74
        return unpack<ArrayVal>()->numElem();
1449
51
    }
1450
0
    case JsonbType::NUM_TYPES:
1451
0
        break;
1452
154
    }
1453
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1454
0
                    static_cast<int32_t>(type));
1455
154
}
1456
1457
485
inline bool JsonbValue::contains(const JsonbValue* rhs) const {
1458
485
    switch (type) {
1459
132
    case JsonbType::T_Int8:
1460
162
    case JsonbType::T_Int16:
1461
168
    case JsonbType::T_Int32:
1462
177
    case JsonbType::T_Int64:
1463
185
    case JsonbType::T_Int128:
1464
216
    case JsonbType::T_Double:
1465
216
    case JsonbType::T_Float:
1466
228
    case JsonbType::T_Decimal32:
1467
230
    case JsonbType::T_Decimal64:
1468
236
    case JsonbType::T_Decimal128:
1469
236
    case JsonbType::T_Decimal256: {
1470
236
        return jsonb_detail::numeric_equal(this, rhs);
1471
236
    }
1472
48
    case JsonbType::T_String:
1473
48
    case JsonbType::T_Binary: {
1474
48
        if (rhs->isString() || rhs->isBinary()) {
1475
20
            const auto* str_value1 = unpack<JsonbStringVal>();
1476
20
            const auto* str_value2 = rhs->unpack<JsonbStringVal>();
1477
20
            return str_value1->length() == str_value2->length() &&
1478
20
                   std::memcmp(str_value1->getBlob(), str_value2->getBlob(),
1479
19
                               str_value1->length()) == 0;
1480
20
        }
1481
28
        return false;
1482
48
    }
1483
72
    case JsonbType::T_Array: {
1484
72
        const auto* lhs_array = unpack<ArrayVal>();
1485
72
        if (rhs->isArray()) {
1486
34
            return jsonb_detail::array_contains_array(lhs_array, rhs->unpack<ArrayVal>());
1487
34
        }
1488
38
        return jsonb_detail::array_contains_value(lhs_array, rhs);
1489
72
    }
1490
95
    case JsonbType::T_Object: {
1491
95
        if (rhs->isObject()) {
1492
61
            const auto* obj_value1 = unpack<ObjectVal>();
1493
61
            const auto* obj_value2 = rhs->unpack<ObjectVal>();
1494
113
            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
79
                const JsonbValue* value = it->klen() == 0
1498
79
                                                  ? obj_value1->find_by_key_id(it->getKeyId())
1499
79
                                                  : obj_value1->find(it->getKeyStr(), it->klen());
1500
79
                if (value == nullptr || !value->contains(it->value())) {
1501
27
                    return false;
1502
27
                }
1503
79
            }
1504
34
            return true;
1505
61
        }
1506
34
        return false;
1507
95
    }
1508
12
    case JsonbType::T_Null: {
1509
12
        return rhs->isNull();
1510
95
    }
1511
12
    case JsonbType::T_True: {
1512
12
        return rhs->isTrue();
1513
95
    }
1514
10
    case JsonbType::T_False: {
1515
10
        return rhs->isFalse();
1516
95
    }
1517
0
    case JsonbType::NUM_TYPES:
1518
0
        break;
1519
485
    }
1520
1521
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1522
0
                    static_cast<int32_t>(type));
1523
485
}
1524
1525
15.6k
inline bool JsonbPath::seek(const char* key_path, size_t kp_len) {
1526
15.6k
    while (kp_len > 0 && std::isspace(key_path[kp_len - 1])) {
1527
7
        --kp_len;
1528
7
    }
1529
1530
    //path invalid
1531
15.6k
    if (!key_path || kp_len == 0) {
1532
2
        return false;
1533
2
    }
1534
15.6k
    Stream stream(key_path, kp_len);
1535
15.6k
    stream.skip_whitespace();
1536
15.6k
    if (stream.exhausted() || stream.read() != SCOPE) {
1537
        //path invalid
1538
2
        return false;
1539
2
    }
1540
1541
37.4k
    while (!stream.exhausted()) {
1542
21.8k
        stream.skip_whitespace();
1543
21.8k
        stream.clear_leg_ptr();
1544
21.8k
        stream.clear_leg_len();
1545
21.8k
        stream.set_has_escapes(false);
1546
1547
21.8k
        if (!JsonbPath::parsePath(&stream, this)) {
1548
            //path invalid
1549
27
            return false;
1550
27
        }
1551
21.8k
    }
1552
15.6k
    return true;
1553
15.6k
}
1554
1555
21.8k
inline bool JsonbPath::parsePath(Stream* stream, JsonbPath* path) {
1556
    // $[0]
1557
21.8k
    if (stream->peek() == BEGIN_ARRAY) {
1558
11.1k
        return parse_array(stream, path);
1559
11.1k
    }
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.6k
    else if (stream->peek() == BEGIN_MEMBER) {
1564
        // advance past the .
1565
10.6k
        stream->skip(1);
1566
1567
10.6k
        if (stream->exhausted()) {
1568
21
            return false;
1569
21
        }
1570
1571
        // $.[0]
1572
10.6k
        if (stream->peek() == BEGIN_ARRAY) {
1573
150
            return parse_array(stream, path);
1574
150
        }
1575
        // $.a
1576
10.4k
        else {
1577
10.4k
            return parse_member(stream, path);
1578
10.4k
        }
1579
10.6k
    } else if (stream->peek() == WILDCARD) {
1580
18
        stream->skip(1);
1581
18
        if (stream->exhausted()) {
1582
0
            return false;
1583
0
        }
1584
1585
        // $**
1586
18
        if (stream->peek() == WILDCARD) {
1587
18
            path->_is_supper_wildcard = true;
1588
18
        }
1589
1590
18
        stream->skip(1);
1591
18
        if (stream->exhausted()) {
1592
2
            return false;
1593
2
        }
1594
1595
16
        if (stream->peek() == BEGIN_ARRAY) {
1596
2
            return parse_array(stream, path);
1597
14
        } else if (stream->peek() == BEGIN_MEMBER) {
1598
            // advance past the .
1599
14
            stream->skip(1);
1600
1601
14
            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
14
            if (stream->peek() == BEGIN_ARRAY) {
1608
0
                return parse_array(stream, path);
1609
0
            }
1610
            // $.a
1611
14
            else {
1612
14
                return parse_member(stream, path);
1613
14
            }
1614
14
        }
1615
0
        return false;
1616
16
    } else {
1617
0
        return false; //invalid json path
1618
0
    }
1619
21.8k
}
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
27
        stream->set_leg_ptr(const_cast<char*>(stream->position()));
1632
27
        stream->add_leg_len();
1633
27
        stream->skip(1);
1634
27
        if (stream->exhausted()) {
1635
0
            return false;
1636
0
        }
1637
1638
27
        if (stream->peek() == END_ARRAY) {
1639
27
            std::unique_ptr<leg_info> leg(
1640
27
                    new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, ARRAY_CODE));
1641
27
            leg->is_wildcard = true;
1642
27
            path->add_leg_to_leg_vector(std::move(leg));
1643
27
            stream->skip(1);
1644
27
            path->_is_wildcard = true;
1645
27
            return true;
1646
27
        } else {
1647
0
            return false;
1648
0
        }
1649
27
    }
1650
1651
    // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1652
    // using const_cast is acceptable.
1653
11.2k
    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.2k
    if (stream->exhausted() || stream->peek() != END_ARRAY) {
1660
0
        return false;
1661
11.2k
    } else {
1662
11.2k
        stream->skip(1);
1663
11.2k
    }
1664
1665
    //parse array index to int
1666
1667
11.2k
    std::string_view idx_string(stream->get_leg_ptr(), stream->get_leg_len());
1668
11.2k
    int index = 0;
1669
1670
    // Match "last" case-insensitively for compatibility with existing JSONB
1671
    // paths such as [Last] and [LAST].
1672
11.2k
    if (stream->get_leg_len() >= 4 &&
1673
11.2k
        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.61k
    auto result = std::from_chars(idx_string.data(), idx_string.data() + idx_string.size(), index);
1713
1714
9.61k
    if (result.ec != std::errc()) {
1715
0
        return false;
1716
0
    }
1717
1718
9.61k
    std::unique_ptr<leg_info> leg(new leg_info(nullptr, 0, index, ARRAY_CODE));
1719
9.61k
    path->add_leg_to_leg_vector(std::move(leg));
1720
1721
9.61k
    return true;
1722
9.61k
}
1723
1724
10.5k
inline bool JsonbPath::parse_member(Stream* stream, JsonbPath* path) {
1725
10.5k
    if (stream->exhausted()) {
1726
0
        return false;
1727
0
    }
1728
1729
10.5k
    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
135
        stream->set_leg_ptr(const_cast<char*>(stream->position()));
1733
135
        stream->add_leg_len();
1734
135
        stream->skip(1);
1735
135
        std::unique_ptr<leg_info> leg(
1736
135
                new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, MEMBER_CODE));
1737
135
        leg->is_wildcard = true;
1738
135
        path->add_leg_to_leg_vector(std::move(leg));
1739
135
        path->_is_wildcard = true;
1740
135
        return true;
1741
135
    }
1742
1743
    // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1744
    // using const_cast is acceptable.
1745
10.3k
    stream->set_leg_ptr(const_cast<char*>(stream->position()));
1746
1747
10.3k
    const char* left_quotation_marks = nullptr;
1748
10.3k
    const char* right_quotation_marks = nullptr;
1749
1750
35.0k
    for (; !stream->exhausted(); stream->advance()) {
1751
        // Only accept space characters quoted by double quotes.
1752
31.9k
        if (std::isspace(stream->peek()) && left_quotation_marks == nullptr) {
1753
0
            return false;
1754
31.9k
        } else if (stream->peek() == ESCAPE) {
1755
28
            stream->add_leg_len();
1756
28
            stream->skip(1);
1757
28
            stream->add_leg_len();
1758
28
            stream->set_has_escapes(true);
1759
28
            if (stream->exhausted()) {
1760
0
                return false;
1761
0
            }
1762
28
            continue;
1763
31.8k
        } else if (stream->peek() == DOUBLE_QUOTE) {
1764
582
            if (left_quotation_marks == nullptr) {
1765
291
                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
291
                stream->set_leg_ptr(const_cast<char*>(++left_quotation_marks));
1769
291
                continue;
1770
291
            } else {
1771
291
                right_quotation_marks = stream->position();
1772
291
                stream->skip(1);
1773
291
                break;
1774
291
            }
1775
31.2k
        } else if (stream->peek() == BEGIN_MEMBER || stream->peek() == BEGIN_ARRAY) {
1776
7.21k
            if (left_quotation_marks == nullptr) {
1777
6.89k
                break;
1778
6.89k
            }
1779
7.21k
        }
1780
1781
24.4k
        stream->add_leg_len();
1782
24.4k
    }
1783
1784
    // An empty member name is only valid when it is written explicitly as `""`.
1785
10.3k
    if ((left_quotation_marks != nullptr && right_quotation_marks == nullptr) ||
1786
10.3k
        stream->get_leg_ptr() == nullptr ||
1787
10.3k
        (left_quotation_marks == nullptr && stream->get_leg_len() == 0)) {
1788
2
        return false; //invalid json path
1789
2
    }
1790
1791
10.3k
    if (stream->get_has_escapes()) {
1792
12
        stream->remove_escapes();
1793
12
    }
1794
1795
10.3k
    std::unique_ptr<leg_info> leg(
1796
10.3k
            new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, MEMBER_CODE));
1797
10.3k
    path->add_leg_to_leg_vector(std::move(leg));
1798
1799
10.3k
    return true;
1800
10.3k
}
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