Coverage Report

Created: 2026-10-20 19:14

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
31.7k
#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
11
inline PrimitiveType get_primitive_type_from_json_type(JsonbType json_type) {
202
11
    switch (json_type) {
203
1
    case JsonbType::T_Null:
204
1
        return TYPE_NULL;
205
1
    case JsonbType::T_True:
206
2
    case JsonbType::T_False:
207
2
        return TYPE_BOOLEAN;
208
0
    case JsonbType::T_Int8:
209
0
        return TYPE_TINYINT;
210
0
    case JsonbType::T_Int16:
211
0
        return TYPE_SMALLINT;
212
0
    case JsonbType::T_Int32:
213
0
        return TYPE_INT;
214
0
    case JsonbType::T_Int64:
215
0
        return TYPE_BIGINT;
216
0
    case JsonbType::T_Double:
217
0
        return TYPE_DOUBLE;
218
1
    case JsonbType::T_String:
219
1
        return TYPE_STRING;
220
0
    case JsonbType::T_Binary:
221
0
        return TYPE_BINARY;
222
0
    case JsonbType::T_Object:
223
0
        return TYPE_STRUCT;
224
1
    case JsonbType::T_Array:
225
1
        return TYPE_ARRAY;
226
1
    case JsonbType::T_Int128:
227
1
        return TYPE_LARGEINT;
228
1
    case JsonbType::T_Float:
229
1
        return TYPE_FLOAT;
230
1
    case JsonbType::T_Decimal32:
231
1
        return TYPE_DECIMAL32;
232
1
    case JsonbType::T_Decimal64:
233
1
        return TYPE_DECIMAL64;
234
1
    case JsonbType::T_Decimal128:
235
1
        return TYPE_DECIMAL128I;
236
1
    case JsonbType::T_Decimal256:
237
1
        return TYPE_DECIMAL256;
238
0
    default:
239
0
        throw Exception(ErrorCode::INTERNAL_ERROR, "Unsupported JsonbType: {}",
240
0
                        static_cast<int>(json_type));
241
11
    }
242
11
}
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
175
    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
247
    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
3.80k
    size_t remaining() const {
273
3.80k
        assert(m_position <= m_end);
274
3.80k
        return m_end - m_position;
275
3.80k
    }
276
277
    /// Tells if the stream has been exhausted.
278
3.49k
    bool exhausted() const { return remaining() == 0; }
279
280
    /// Reads the next byte from the stream and moves the position forward.
281
167
    char read() {
282
167
        assert(!exhausted());
283
167
        return *m_position++;
284
167
    }
285
286
    /// Reads the next byte from the stream without moving the position forward.
287
1.99k
    char peek() const {
288
1.99k
        assert(!exhausted());
289
1.99k
        return *m_position;
290
1.99k
    }
291
292
    /// Moves the position to the next non-whitespace character.
293
652
    void skip_whitespace() {
294
652
        m_position = std::find_if_not(m_position, m_end, [](char c) { return std::isspace(c); });
295
652
    }
296
297
    /// Moves the position n bytes forward.
298
306
    void skip(size_t n) {
299
306
        assert(remaining() >= n);
300
306
        m_position += n;
301
306
        skip_whitespace();
302
306
    }
303
304
286
    void advance() { m_position++; }
305
306
399
    void clear_leg_ptr() { leg_ptr = nullptr; }
307
308
220
    void set_leg_ptr(char* ptr) {
309
220
        clear_leg_ptr();
310
220
        leg_ptr = ptr;
311
220
    }
312
313
279
    char* get_leg_ptr() { return leg_ptr; }
314
315
187
    void clear_leg_len() { leg_len = 0; }
316
317
348
    void add_leg_len() { leg_len++; }
318
319
318
    unsigned int get_leg_len() const { return leg_len; }
320
321
12
    void remove_escapes() {
322
12
        unsigned int new_len = 0;
323
86
        for (unsigned int i = 0; i < leg_len; ++i) {
324
75
            if (leg_ptr[i] != ESCAPE) {
325
45
                leg_ptr[new_len++] = leg_ptr[i];
326
45
                continue;
327
45
            }
328
329
30
            ++i;
330
30
            if (i >= leg_len) {
331
1
                break;
332
1
            }
333
334
29
            switch (leg_ptr[i]) {
335
2
            case 'b':
336
2
                leg_ptr[new_len++] = '\b';
337
2
                break;
338
2
            case 'f':
339
2
                leg_ptr[new_len++] = '\f';
340
2
                break;
341
3
            case 'n':
342
3
                leg_ptr[new_len++] = '\n';
343
3
                break;
344
2
            case 'r':
345
2
                leg_ptr[new_len++] = '\r';
346
2
                break;
347
2
            case 't':
348
2
                leg_ptr[new_len++] = '\t';
349
2
                break;
350
11
            case 'u': {
351
11
                if (i + 4 >= leg_len || leg_ptr[i + 1] != '0' || leg_ptr[i + 2] != '0') {
352
2
                    leg_ptr[new_len++] = leg_ptr[i];
353
2
                    break;
354
2
                }
355
356
18
                auto hex_to_int = [](char c) -> int {
357
18
                    if (c >= '0' && c <= '9') {
358
12
                        return c - '0';
359
12
                    }
360
6
                    if (c >= 'a' && c <= 'f') {
361
2
                        return c - 'a' + 10;
362
2
                    }
363
4
                    if (c >= 'A' && c <= 'F') {
364
1
                        return c - 'A' + 10;
365
1
                    }
366
3
                    return -1;
367
4
                };
368
9
                int high = hex_to_int(leg_ptr[i + 3]);
369
9
                int low = hex_to_int(leg_ptr[i + 4]);
370
9
                if (high < 0 || low < 0) {
371
3
                    leg_ptr[new_len++] = leg_ptr[i];
372
3
                    break;
373
3
                }
374
6
                leg_ptr[new_len++] = static_cast<char>((high << 4) | low);
375
6
                i += 4;
376
6
                break;
377
9
            }
378
7
            default:
379
7
                leg_ptr[new_len++] = leg_ptr[i];
380
7
                break;
381
29
            }
382
29
        }
383
12
        leg_ptr[new_len] = '\0';
384
12
        leg_len = new_len;
385
12
    }
386
387
191
    void set_has_escapes(bool has) { has_escapes = has; }
388
389
102
    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
32
    bool to_string(std::string* str) const {
427
32
        if (type == MEMBER_CODE) {
428
29
            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
29
            bool needs_quotes = leg_len == 0 || (!is_wildcard && *leg_ptr == WILDCARD);
435
29
            std::string tmp;
436
122
            for (auto* it = leg_ptr; it != (leg_ptr + leg_len); ++it) {
437
93
                auto c = static_cast<unsigned char>(*it);
438
93
                if (std::isspace(c) || *it == BEGIN_MEMBER || *it == BEGIN_ARRAY) {
439
13
                    needs_quotes = true;
440
13
                }
441
442
93
                switch (*it) {
443
4
                case '"':
444
4
                    tmp.append("\\\"");
445
4
                    break;
446
2
                case ESCAPE:
447
2
                    tmp.append("\\\\");
448
2
                    break;
449
2
                case '\b':
450
2
                    tmp.append("\\b");
451
2
                    break;
452
2
                case '\f':
453
2
                    tmp.append("\\f");
454
2
                    break;
455
3
                case '\n':
456
3
                    tmp.append("\\n");
457
3
                    break;
458
2
                case '\r':
459
2
                    tmp.append("\\r");
460
2
                    break;
461
2
                case '\t':
462
2
                    tmp.append("\\t");
463
2
                    break;
464
76
                default:
465
76
                    if (c < 0x20) {
466
6
                        constexpr char hex[] = "0123456789abcdef";
467
6
                        tmp.append("\\u00");
468
6
                        tmp.push_back(hex[c >> 4]);
469
6
                        tmp.push_back(hex[c & 0x0F]);
470
70
                    } else {
471
70
                        tmp.push_back(*it);
472
70
                    }
473
76
                    break;
474
93
                }
475
93
            }
476
29
            if (needs_quotes) {
477
16
                str->push_back(DOUBLE_QUOTE);
478
16
            }
479
29
            str->append(tmp);
480
29
            if (needs_quotes) {
481
16
                str->push_back(DOUBLE_QUOTE);
482
16
            }
483
29
            return true;
484
29
        } else if (type == ARRAY_CODE) {
485
3
            str->push_back(BEGIN_ARRAY);
486
3
            if (is_wildcard) {
487
2
                str->push_back(WILDCARD);
488
2
            } else {
489
1
                str->append(std::to_string(array_index));
490
1
            }
491
3
            str->push_back(END_ARRAY);
492
3
            return true;
493
3
        } else {
494
0
            return false;
495
0
        }
496
32
    }
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
202
    void add_leg_to_leg_vector(std::unique_ptr<leg_info> leg) {
511
202
        leg_vector.emplace_back(leg.release());
512
202
    }
513
514
0
    void pop_leg_from_leg_vector() { leg_vector.pop_back(); }
515
516
    // NOLINTNEXTLINE(readability-non-const-parameter): res is an output parameter.
517
17
    bool to_string(std::string* res) const {
518
17
        res->push_back(SCOPE);
519
21
        for (const auto& leg : leg_vector) {
520
21
            auto valid = leg->to_string(res);
521
21
            if (!valid) {
522
0
                return false;
523
0
            }
524
21
        }
525
17
        return true;
526
17
    }
527
528
417
    size_t get_leg_vector_size() const { return leg_vector.size(); }
529
530
662
    leg_info* get_leg_from_leg_vector(size_t i) const { return leg_vector[i].get(); }
531
532
42
    bool is_wildcard() const { return _is_wildcard; }
533
167
    bool is_supper_wildcard() const { return _is_supper_wildcard; }
534
535
9
    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
23.0k
    explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {}
_ZN5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEC2ERKS3_
Line
Count
Source
556
22.6k
    explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {}
_ZN5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEC2ERKS3_
Line
Count
Source
556
331
    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
23.3k
    bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEeqERKS5_
Line
Count
Source
562
21.7k
    bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEeqERKS5_
Line
Count
Source
562
1.60k
    bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); }
563
564
21.9k
    bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEneERKS5_
Line
Count
Source
564
20.4k
    bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEneERKS5_
Line
Count
Source
564
1.48k
    bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); }
565
566
2.77k
    bool operator<(const JsonbFwdIteratorT& rhs) const { return (current_ < rhs.current_); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEltERKS5_
Line
Count
Source
566
59
    bool operator<(const JsonbFwdIteratorT& rhs) const { return (current_ < rhs.current_); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEltERKS5_
Line
Count
Source
566
2.71k
    bool operator<(const JsonbFwdIteratorT& rhs) const { return (current_ < rhs.current_); }
567
568
    bool operator>(const JsonbFwdIteratorT& rhs) const { return !operator<(rhs); }
569
570
19.8k
    JsonbFwdIteratorT& operator++() {
571
19.8k
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
572
19.8k
        return *this;
573
19.8k
    }
_ZN5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEppEv
Line
Count
Source
570
19.1k
    JsonbFwdIteratorT& operator++() {
571
19.1k
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
572
19.1k
        return *this;
573
19.1k
    }
_ZN5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEppEv
Line
Count
Source
570
711
    JsonbFwdIteratorT& operator++() {
571
711
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
572
711
        return *this;
573
711
    }
574
575
    JsonbFwdIteratorT operator++(int) {
576
        auto tmp = *this;
577
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
578
        return tmp;
579
    }
580
581
683
    explicit operator pointer() { return current_; }
582
583
83
    reference operator*() const { return *current_; }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEdeEv
Line
Count
Source
583
19
    reference operator*() const { return *current_; }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEdeEv
Line
Count
Source
583
64
    reference operator*() const { return *current_; }
584
585
33.6k
    pointer operator->() const { return current_; }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEptEv
Line
Count
Source
585
33.6k
    pointer operator->() const { return current_; }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEptEv
Line
Count
Source
585
28
    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
1.70k
    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
3.37k
    uint8_t klen() const { return size; }
685
686
    // get the key string. Note the string may not be null terminated.
687
1.75k
    const char* getKeyStr() const { return key.str_; }
688
689
9.86k
    keyid_type getKeyId() const { return key.id_; }
690
691
38.2k
    unsigned int keyPackedBytes() const {
692
38.2k
        return size ? (sizeof(size) + size) : (sizeof(size) + sizeof(keyid_type));
693
38.2k
    }
694
695
19.0k
    const JsonbValue* value() const {
696
19.0k
        return (const JsonbValue*)(((char*)this) + keyPackedBytes());
697
19.0k
    }
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
4.39k
    bool isNull() const { return (type == JsonbType::T_Null); }
725
23
    bool isTrue() const { return (type == JsonbType::T_True); }
726
2
    bool isFalse() const { return (type == JsonbType::T_False); }
727
9.90k
    bool isInt() const { return isInt8() || isInt16() || isInt32() || isInt64() || isInt128(); }
728
9.90k
    bool isInt8() const { return (type == JsonbType::T_Int8); }
729
9.72k
    bool isInt16() const { return (type == JsonbType::T_Int16); }
730
9.63k
    bool isInt32() const { return (type == JsonbType::T_Int32); }
731
6.15k
    bool isInt64() const { return (type == JsonbType::T_Int64); }
732
215
    bool isDouble() const { return (type == JsonbType::T_Double); }
733
178
    bool isFloat() const { return (type == JsonbType::T_Float); }
734
117
    bool isString() const { return (type == JsonbType::T_String); }
735
1.12k
    bool isBinary() const { return (type == JsonbType::T_Binary); }
736
123
    bool isObject() const { return (type == JsonbType::T_Object); }
737
83
    bool isArray() const { return (type == JsonbType::T_Array); }
738
4.20k
    bool isInt128() const { return (type == JsonbType::T_Int128); }
739
84
    bool isDecimal() const {
740
84
        return (type == JsonbType::T_Decimal32 || type == JsonbType::T_Decimal64 ||
741
84
                type == JsonbType::T_Decimal128 || type == JsonbType::T_Decimal256);
742
84
    }
743
1
    bool isDecimal32() const { return (type == JsonbType::T_Decimal32); }
744
1
    bool isDecimal64() const { return (type == JsonbType::T_Decimal64); }
745
1
    bool isDecimal128() const { return (type == JsonbType::T_Decimal128); }
746
1
    bool isDecimal256() const { return (type == JsonbType::T_Decimal256); }
747
748
11
    PrimitiveType get_primitive_type() const { return get_primitive_type_from_json_type(type); }
749
750
0
    const char* typeName() const {
751
0
        switch (type) {
752
0
        case JsonbType::T_Null:
753
0
            return "null";
754
0
        case JsonbType::T_True:
755
0
        case JsonbType::T_False:
756
0
            return "bool";
757
0
        case JsonbType::T_Int8:
758
0
        case JsonbType::T_Int16:
759
0
        case JsonbType::T_Int32:
760
0
            return "int";
761
0
        case JsonbType::T_Int64:
762
0
            return "bigint";
763
0
        case JsonbType::T_Int128:
764
0
            return "largeint";
765
0
        case JsonbType::T_Double:
766
0
            return "double";
767
0
        case JsonbType::T_Float:
768
0
            return "float";
769
0
        case JsonbType::T_String:
770
0
            return "string";
771
0
        case JsonbType::T_Binary:
772
0
            return "binary";
773
0
        case JsonbType::T_Object:
774
0
            return "object";
775
0
        case JsonbType::T_Array:
776
0
            return "array";
777
0
        case JsonbType::T_Decimal32:
778
0
            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
0
        }
788
0
    }
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
58.7k
    const T* unpack() const {
824
58.7k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
58.7k
        return reinterpret_cast<const T*>(payload);
826
58.7k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_9ObjectValEEEPKT_v
Line
Count
Source
823
21.3k
    const T* unpack() const {
824
21.3k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
21.3k
        return reinterpret_cast<const T*>(payload);
826
21.3k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIaEEEEPKT_v
Line
Count
Source
823
1.20k
    const T* unpack() const {
824
1.20k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
1.20k
        return reinterpret_cast<const T*>(payload);
826
1.20k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIsEEEEPKT_v
Line
Count
Source
823
370
    const T* unpack() const {
824
370
        static_assert(is_pod_v<T>, "T must be a POD type");
825
370
        return reinterpret_cast<const T*>(payload);
826
370
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIiEEEEPKT_v
Line
Count
Source
823
3.55k
    const T* unpack() const {
824
3.55k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
3.55k
        return reinterpret_cast<const T*>(payload);
826
3.55k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIlEEEEPKT_v
Line
Count
Source
823
1.97k
    const T* unpack() const {
824
1.97k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
1.97k
        return reinterpret_cast<const T*>(payload);
826
1.97k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTInEEEEPKT_v
Line
Count
Source
823
4.18k
    const T* unpack() const {
824
4.18k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
4.18k
        return reinterpret_cast<const T*>(payload);
826
4.18k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIdEEEEPKT_v
Line
Count
Source
823
189
    const T* unpack() const {
824
189
        static_assert(is_pod_v<T>, "T must be a POD type");
825
189
        return reinterpret_cast<const T*>(payload);
826
189
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIfEEEEPKT_v
Line
Count
Source
823
28
    const T* unpack() const {
824
28
        static_assert(is_pod_v<T>, "T must be a POD type");
825
28
        return reinterpret_cast<const T*>(payload);
826
28
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_7DecimalIiEEEEEEPKT_v
Line
Count
Source
823
28
    const T* unpack() const {
824
28
        static_assert(is_pod_v<T>, "T must be a POD type");
825
28
        return reinterpret_cast<const T*>(payload);
826
28
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_7DecimalIlEEEEEEPKT_v
Line
Count
Source
823
16
    const T* unpack() const {
824
16
        static_assert(is_pod_v<T>, "T must be a POD type");
825
16
        return reinterpret_cast<const T*>(payload);
826
16
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_12Decimal128V3EEEEEPKT_v
Line
Count
Source
823
31
    const T* unpack() const {
824
31
        static_assert(is_pod_v<T>, "T must be a POD type");
825
31
        return reinterpret_cast<const T*>(payload);
826
31
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_7DecimalIN4wide7integerILm256EiEEEEEEEEPKT_v
Line
Count
Source
823
13
    const T* unpack() const {
824
13
        static_assert(is_pod_v<T>, "T must be a POD type");
825
13
        return reinterpret_cast<const T*>(payload);
826
13
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_14JsonbBinaryValEEEPKT_v
Line
Count
Source
823
9.93k
    const T* unpack() const {
824
9.93k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
9.93k
        return reinterpret_cast<const T*>(payload);
826
9.93k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_12ContainerValEEEPKT_v
Line
Count
Source
823
15.1k
    const T* unpack() const {
824
15.1k
        static_assert(is_pod_v<T>, "T must be a POD type");
825
15.1k
        return reinterpret_cast<const T*>(payload);
826
15.1k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_8ArrayValEEEPKT_v
Line
Count
Source
823
211
    const T* unpack() const {
824
211
        static_assert(is_pod_v<T>, "T must be a POD type");
825
211
        return reinterpret_cast<const T*>(payload);
826
211
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_14JsonbStringValEEEPKT_v
Line
Count
Source
823
567
    const T* unpack() const {
824
567
        static_assert(is_pod_v<T>, "T must be a POD type");
825
567
        return reinterpret_cast<const T*>(payload);
826
567
    }
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
19.9k
inline const ObjectVal* JsonbDocument::operator->() const {
854
19.9k
    return (((const JsonbValue*)payload_)->unpack<ObjectVal>());
855
19.9k
}
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
11.5k
    T val() const { return num; }
_ZNK5doris10NumberValTIaE3valEv
Line
Count
Source
865
1.20k
    T val() const { return num; }
_ZNK5doris10NumberValTIsE3valEv
Line
Count
Source
865
370
    T val() const { return num; }
_ZNK5doris10NumberValTIiE3valEv
Line
Count
Source
865
3.55k
    T val() const { return num; }
_ZNK5doris10NumberValTIlE3valEv
Line
Count
Source
865
1.97k
    T val() const { return num; }
_ZNK5doris10NumberValTInE3valEv
Line
Count
Source
865
4.18k
    T val() const { return num; }
_ZNK5doris10NumberValTIdE3valEv
Line
Count
Source
865
189
    T val() const { return num; }
_ZNK5doris10NumberValTIfE3valEv
Line
Count
Source
865
28
    T val() const { return num; }
866
867
    static unsigned int numPackedBytes() { return sizeof(JsonbValue) + sizeof(T); }
868
869
    T num;
870
};
871
872
9.90k
inline int128_t JsonbValue::int_val() const {
873
9.90k
    switch (type) {
874
196
    case JsonbType::T_Int8:
875
196
        return unpack<JsonbInt8Val>()->val();
876
94
    case JsonbType::T_Int16:
877
94
        return unpack<JsonbInt16Val>()->val();
878
3.48k
    case JsonbType::T_Int32:
879
3.48k
        return unpack<JsonbInt32Val>()->val();
880
1.94k
    case JsonbType::T_Int64:
881
1.94k
        return unpack<JsonbInt64Val>()->val();
882
4.18k
    case JsonbType::T_Int128:
883
4.18k
        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
9.90k
    }
888
9.90k
}
889
890
template <JsonbDecimalType T>
891
struct JsonbDecimalVal {
892
public:
893
    using NativeType = typename T::NativeType;
894
895
    // get the decimal value
896
56
    NativeType val() const {
897
        // to avoid memory alignment issues, we use memcpy to copy the value
898
56
        NativeType tmp;
899
56
        memcpy(&tmp, &value, sizeof(NativeType));
900
56
        return tmp;
901
56
    }
_ZNK5doris15JsonbDecimalValINS_7DecimalIiEEE3valEv
Line
Count
Source
896
19
    NativeType val() const {
897
        // to avoid memory alignment issues, we use memcpy to copy the value
898
19
        NativeType tmp;
899
19
        memcpy(&tmp, &value, sizeof(NativeType));
900
19
        return tmp;
901
19
    }
_ZNK5doris15JsonbDecimalValINS_7DecimalIlEEE3valEv
Line
Count
Source
896
9
    NativeType val() const {
897
        // to avoid memory alignment issues, we use memcpy to copy the value
898
9
        NativeType tmp;
899
9
        memcpy(&tmp, &value, sizeof(NativeType));
900
9
        return tmp;
901
9
    }
_ZNK5doris15JsonbDecimalValINS_12Decimal128V3EE3valEv
Line
Count
Source
896
22
    NativeType val() const {
897
        // to avoid memory alignment issues, we use memcpy to copy the value
898
22
        NativeType tmp;
899
22
        memcpy(&tmp, &value, sizeof(NativeType));
900
22
        return tmp;
901
22
    }
_ZNK5doris15JsonbDecimalValINS_7DecimalIN4wide7integerILm256EiEEEEE3valEv
Line
Count
Source
896
6
    NativeType val() const {
897
        // to avoid memory alignment issues, we use memcpy to copy the value
898
6
        NativeType tmp;
899
6
        memcpy(&tmp, &value, sizeof(NativeType));
900
6
        return tmp;
901
6
    }
902
903
130
    static constexpr int numPackedBytes() {
904
130
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
905
130
    }
_ZN5doris15JsonbDecimalValINS_7DecimalIiEEE14numPackedBytesEv
Line
Count
Source
903
47
    static constexpr int numPackedBytes() {
904
47
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
905
47
    }
_ZN5doris15JsonbDecimalValINS_7DecimalIlEEE14numPackedBytesEv
Line
Count
Source
903
33
    static constexpr int numPackedBytes() {
904
33
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
905
33
    }
_ZN5doris15JsonbDecimalValINS_12Decimal128V3EE14numPackedBytesEv
Line
Count
Source
903
44
    static constexpr int numPackedBytes() {
904
44
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
905
44
    }
_ZN5doris15JsonbDecimalValINS_7DecimalIN4wide7integerILm256EiEEEEE14numPackedBytesEv
Line
Count
Source
903
6
    static constexpr int numPackedBytes() {
904
6
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
905
6
    }
906
907
    uint32_t precision;
908
    uint32_t scale;
909
    NativeType value;
910
};
911
912
/*
913
 * BlobVal is the base class (derived from JsonbValue) for string and binary
914
 * types. The size indicates the total bytes of the payload.
915
 */
916
struct JsonbBinaryVal {
917
public:
918
    // size of the blob payload only
919
2.48k
    unsigned int getBlobLen() const { return size; }
920
921
    // return the blob as byte array
922
4.77k
    const char* getBlob() const { return payload; }
923
924
    // size of the total packed bytes
925
5.45k
    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
7
    size_t length() const {
945
        // It's an empty string
946
7
        if (0 == size) {
947
0
            return size;
948
0
        }
949
        // The string stored takes all the spaces in payload
950
7
        if (payload[size - 1] != 0) {
951
7
            return size;
952
7
        }
953
        // It's shorter than the size of payload
954
0
        return strnlen(payload, size);
955
7
    }
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
15.1k
    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
1
    const_iterator search(const char* key) const {
987
1
        if (!key) {
988
0
            return end();
989
0
        }
990
1
        return search(key, (unsigned int)strlen(key));
991
1
    }
992
993
92
    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
92
        if (!key) {
996
0
            return end();
997
0
        }
998
92
        return internalSearch(key, klen);
999
92
    }
1000
1001
    // Get number of elements in object
1002
58
    int numElem() const {
1003
58
        const char* pch = payload;
1004
58
        const char* fence = payload + size;
1005
1006
58
        unsigned int num = 0;
1007
150
        while (pch < fence) {
1008
92
            auto* pkey = (JsonbKeyValue*)(pch);
1009
92
            ++num;
1010
92
            pch += pkey->numPackedBytes();
1011
92
        }
1012
1013
58
        assert(pch == fence);
1014
1015
58
        return num;
1016
58
    }
1017
1018
    // find the JSONB value by a key string (null terminated)
1019
1
    const JsonbValue* find(const char* key) const {
1020
1
        if (!key) {
1021
0
            return nullptr;
1022
0
        }
1023
1
        return find(key, (unsigned int)strlen(key));
1024
1
    }
1025
1026
    // find the JSONB value by a key string (with length)
1027
90
    const JsonbValue* find(const char* key, unsigned int klen) const {
1028
90
        const_iterator kv = search(key, klen);
1029
90
        if (end() == kv) {
1030
15
            return nullptr;
1031
15
        }
1032
75
        return kv->value();
1033
90
    }
1034
1035
    // find the JSONB value by a key id, as stored when klen() == 0 (sMaxKeyId is the empty key)
1036
4
    const JsonbValue* find_by_key_id(JsonbKeyValue::keyid_type key_id) const {
1037
6
        for (auto it = begin(); it != end(); ++it) {
1038
4
            if (it->klen() == 0 && it->getKeyId() == key_id) {
1039
2
                return it->value();
1040
2
            }
1041
4
        }
1042
2
        return nullptr;
1043
4
    }
1044
1045
2.50k
    const_iterator begin() const { return const_iterator((pointer)payload); }
1046
1047
20.0k
    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
92
    const_iterator internalSearch(const char* key, unsigned int klen) const {
1053
92
        const char* pch = payload;
1054
92
        const char* fence = payload + size;
1055
1056
111
        while (pch < fence) {
1057
96
            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
96
            if (klen == 0 ? pkey->klen() == 0 && pkey->getKeyId() == JsonbKeyValue::sMaxKeyId
1061
96
                          : klen == pkey->klen() && strncmp(key, pkey->getKeyStr(), klen) == 0) {
1062
77
                return const_iterator(pkey);
1063
77
            }
1064
19
            pch += pkey->numPackedBytes();
1065
19
        }
1066
1067
92
        assert(pch == fence);
1068
1069
15
        return end();
1070
15
    }
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
100
    const JsonbValue* get(int idx) const {
1084
100
        if (idx < 0) {
1085
0
            return nullptr;
1086
0
        }
1087
1088
100
        const char* pch = payload;
1089
100
        const char* fence = payload + size;
1090
1091
579
        while (pch < fence && idx-- > 0) {
1092
479
            pch += ((const JsonbValue*)pch)->numPackedBytes();
1093
479
        }
1094
100
        if (idx > 0 || pch == fence) {
1095
11
            return nullptr;
1096
11
        }
1097
1098
89
        return (const JsonbValue*)pch;
1099
100
    }
1100
1101
    // Get number of elements in array
1102
30
    int numElem() const {
1103
30
        const char* pch = payload;
1104
30
        const char* fence = payload + size;
1105
1106
30
        unsigned int num = 0;
1107
99
        while (pch < fence) {
1108
69
            ++num;
1109
69
            pch += ((const JsonbValue*)pch)->numPackedBytes();
1110
69
        }
1111
1112
30
        assert(pch == fence);
1113
1114
30
        return num;
1115
30
    }
1116
1117
152
    const_iterator begin() const { return const_iterator((pointer)payload); }
1118
1119
179
    const_iterator end() const { return const_iterator((pointer)(payload + size)); }
1120
};
1121
1122
namespace jsonb_detail {
1123
1124
struct JsonbScaledDecimal {
1125
    wide::Int256 value;
1126
    uint32_t scale;
1127
};
1128
1129
26
inline void validate_decimal_scale(uint32_t scale) {
1130
26
    if (scale > static_cast<uint32_t>(BeConsts::MAX_DECIMALV3_SCALE)) {
1131
2
        throw Exception(ErrorCode::INTERNAL_ERROR,
1132
2
                        "Invalid JSONB decimal scale: {}, max allowed scale: {}", scale,
1133
2
                        BeConsts::MAX_DECIMALV3_SCALE);
1134
2
    }
1135
26
}
1136
1137
44
inline bool is_numeric(const JsonbValue* value) {
1138
44
    return value->isInt() || value->isDouble() || value->isFloat() || value->isDecimal();
1139
44
}
1140
1141
10
inline double floating_value(const JsonbValue* value) {
1142
10
    if (value->isDouble()) {
1143
10
        return value->unpack<JsonbDoubleVal>()->val();
1144
10
    }
1145
0
    return value->unpack<JsonbFloatVal>()->val();
1146
10
}
1147
1148
20
inline JsonbScaledDecimal get_scaled_decimal(const JsonbValue* value) {
1149
20
    switch (value->type) {
1150
12
    case JsonbType::T_Decimal32: {
1151
12
        const auto* decimal = value->unpack<JsonbDecimal32>();
1152
12
        validate_decimal_scale(decimal->scale);
1153
12
        return {wide::Int256(decimal->val()), decimal->scale};
1154
0
    }
1155
2
    case JsonbType::T_Decimal64: {
1156
2
        const auto* decimal = value->unpack<JsonbDecimal64>();
1157
2
        validate_decimal_scale(decimal->scale);
1158
2
        return {wide::Int256(decimal->val()), decimal->scale};
1159
0
    }
1160
6
    case JsonbType::T_Decimal128: {
1161
6
        const auto* decimal = value->unpack<JsonbDecimal128>();
1162
6
        validate_decimal_scale(decimal->scale);
1163
6
        return {wide::Int256(decimal->val()), decimal->scale};
1164
0
    }
1165
0
    case JsonbType::T_Decimal256: {
1166
0
        const auto* decimal = value->unpack<JsonbDecimal256>();
1167
0
        validate_decimal_scale(decimal->scale);
1168
0
        return {decimal->val(), decimal->scale};
1169
0
    }
1170
0
    default:
1171
0
        throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB decimal value type: {}",
1172
0
                        static_cast<int32_t>(value->type));
1173
20
    }
1174
20
}
1175
1176
inline bool scaled_decimal_equal_decimal(const JsonbScaledDecimal& lhs,
1177
4
                                         const JsonbScaledDecimal& rhs) {
1178
4
    if (lhs.scale == rhs.scale) {
1179
0
        return lhs.value == rhs.value;
1180
0
    }
1181
1182
4
    if (lhs.scale < rhs.scale) {
1183
2
        const auto scale_multiplier = decimal_scale_multiplier<wide::Int256>(rhs.scale - lhs.scale);
1184
2
        return rhs.value % scale_multiplier == 0 && lhs.value == rhs.value / scale_multiplier;
1185
2
    }
1186
1187
2
    const auto scale_multiplier = decimal_scale_multiplier<wide::Int256>(lhs.scale - rhs.scale);
1188
2
    return lhs.value % scale_multiplier == 0 && lhs.value / scale_multiplier == rhs.value;
1189
4
}
1190
1191
4
inline bool scaled_decimal_equal_integer(const JsonbScaledDecimal& decimal, int128_t integer) {
1192
4
    const auto integer_value = wide::Int256(integer);
1193
4
    if (decimal.scale == 0) {
1194
0
        return decimal.value == integer_value;
1195
0
    }
1196
1197
4
    const auto scale_multiplier = decimal_scale_multiplier<wide::Int256>(decimal.scale);
1198
4
    return decimal.value % scale_multiplier == 0 &&
1199
4
           decimal.value / scale_multiplier == integer_value;
1200
4
}
1201
1202
inline constexpr auto kPowersOfFive = [] {
1203
    std::array<wide::Int256, BeConsts::MAX_DECIMALV3_SCALE + 1> powers {};
1204
    powers[0] = 1;
1205
    for (size_t i = 1; i < powers.size(); ++i) {
1206
        powers[i] = powers[i - 1] * 5;
1207
    }
1208
    return powers;
1209
}();
1210
1211
6
inline wide::Int256 power_of_five(uint32_t exponent) {
1212
6
    validate_decimal_scale(exponent);
1213
6
    return kPowersOfFive[exponent];
1214
6
}
1215
1216
6
inline bool scaled_binary_equal(wide::Int256 value, int exponent, wide::Int256 significand) {
1217
6
    if (exponent < 0) {
1218
4
        const int divisor_exponent = -exponent;
1219
4
        if (divisor_exponent >= std::numeric_limits<int64_t>::digits) {
1220
0
            return false;
1221
0
        }
1222
4
        const auto divisor = wide::Int256(1) << divisor_exponent;
1223
4
        return significand % divisor == 0 && value == significand / divisor;
1224
4
    }
1225
2
    constexpr int max_positive_int256_shift = std::numeric_limits<wide::Int256>::digits;
1226
    // wide::Int256 is signed, so shifting 1 by 255 reaches the sign bit.
1227
2
    if (exponent >= max_positive_int256_shift) {
1228
0
        return false;
1229
0
    }
1230
2
    const auto multiplier = wide::Int256(1) << exponent;
1231
2
    return value % multiplier == 0 && value / multiplier == significand;
1232
2
}
1233
1234
4
inline bool floating_equal_integer(const JsonbValue* floating, int128_t integer) {
1235
4
    const double value = floating_value(floating);
1236
4
    int exponent = 0;
1237
4
    std::frexp(value, &exponent);
1238
4
    if (!std::isfinite(value) || std::trunc(value) != value) {
1239
1
        return false;
1240
1
    }
1241
3
    if (exponent >= 128) {
1242
0
        return value == -std::ldexp(1.0, 127) && integer == std::numeric_limits<int128_t>::min();
1243
0
    }
1244
3
    if (exponent <= -1) {
1245
0
        return false;
1246
0
    }
1247
3
    return static_cast<int128_t>(value) == integer;
1248
3
}
1249
1250
6
inline bool floating_equal_decimal(const JsonbValue* floating, const JsonbScaledDecimal& decimal) {
1251
6
    const double value = floating_value(floating);
1252
6
    if (!std::isfinite(value)) {
1253
0
        return false;
1254
0
    }
1255
6
    if (value == 0) {
1256
0
        return decimal.value == 0;
1257
0
    }
1258
1259
6
    int exponent = 0;
1260
6
    const double significand_fraction = std::frexp(value, &exponent);
1261
6
    const double significand_double =
1262
6
            std::ldexp(significand_fraction, std::numeric_limits<double>::digits);
1263
6
    auto significand = wide::Int256(static_cast<int64_t>(significand_double));
1264
6
    exponent -= std::numeric_limits<double>::digits;
1265
1266
6
    const auto five_multiplier = power_of_five(decimal.scale);
1267
6
    if (decimal.value % five_multiplier != 0) {
1268
0
        return false;
1269
0
    }
1270
6
    const auto binary_scaled_decimal = decimal.value / five_multiplier;
1271
6
    return scaled_binary_equal(binary_scaled_decimal, exponent + decimal.scale, significand);
1272
6
}
1273
1274
44
inline bool numeric_equal(const JsonbValue* lhs, const JsonbValue* rhs) {
1275
44
    if (!is_numeric(rhs)) {
1276
2
        return false;
1277
2
    }
1278
1279
42
    if ((lhs->isDouble() || lhs->isFloat()) && rhs->isInt()) {
1280
1
        return floating_equal_integer(lhs, rhs->int_val());
1281
1
    }
1282
1283
41
    if ((rhs->isDouble() || rhs->isFloat()) && lhs->isInt()) {
1284
3
        return floating_equal_integer(rhs, lhs->int_val());
1285
3
    }
1286
1287
38
    if ((lhs->isDouble() || lhs->isFloat()) && rhs->isDecimal()) {
1288
4
        return floating_equal_decimal(lhs, get_scaled_decimal(rhs));
1289
4
    }
1290
1291
34
    if ((rhs->isDouble() || rhs->isFloat()) && lhs->isDecimal()) {
1292
4
        return floating_equal_decimal(rhs, get_scaled_decimal(lhs));
1293
4
    }
1294
1295
30
    if (lhs->isDouble() || lhs->isFloat()) {
1296
0
        return (rhs->isDouble() || rhs->isFloat()) && floating_value(lhs) == floating_value(rhs);
1297
0
    }
1298
1299
30
    if (lhs->isDecimal()) {
1300
6
        const auto lhs_decimal = get_scaled_decimal(lhs);
1301
6
        if (rhs->isDecimal()) {
1302
4
            return scaled_decimal_equal_decimal(lhs_decimal, get_scaled_decimal(rhs));
1303
4
        }
1304
2
        return scaled_decimal_equal_integer(lhs_decimal, rhs->int_val());
1305
6
    }
1306
1307
24
    if (rhs->isDecimal()) {
1308
2
        return scaled_decimal_equal_integer(get_scaled_decimal(rhs), lhs->int_val());
1309
2
    }
1310
1311
22
    return lhs->int_val() == rhs->int_val();
1312
24
}
1313
1314
17
inline bool array_contains_value(const ArrayVal* target_array, const JsonbValue* candidate) {
1315
30
    for (auto it = target_array->begin(); it < target_array->end(); ++it) {
1316
25
        if (it->contains(candidate)) {
1317
12
            return true;
1318
12
        }
1319
25
    }
1320
5
    return false;
1321
17
}
1322
1323
10
inline bool array_contains_array(const ArrayVal* target_array, const ArrayVal* candidate_array) {
1324
21
    for (auto it = candidate_array->begin(); it < candidate_array->end(); ++it) {
1325
15
        if (!array_contains_value(target_array, &*it)) {
1326
4
            return false;
1327
4
        }
1328
15
    }
1329
6
    return true;
1330
10
}
1331
1332
} // namespace jsonb_detail
1333
1334
3.02k
inline const JsonbValue* JsonbDocument::createValue(const char* pb, size_t size) {
1335
3.02k
    if (!pb || size < sizeof(JsonbHeader) + sizeof(JsonbValue)) {
1336
0
        return nullptr;
1337
0
    }
1338
1339
3.02k
    auto* doc = (JsonbDocument*)pb;
1340
3.02k
    if (doc->header_.ver_ != JSONB_VER) {
1341
0
        return nullptr;
1342
0
    }
1343
1344
3.02k
    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
3.02k
    if (size != sizeof(JsonbHeader) + val->numPackedBytes()) {
1349
0
        return nullptr;
1350
0
    }
1351
1352
3.02k
    return val;
1353
3.02k
}
1354
1355
34
inline unsigned int JsonbDocument::numPackedBytes() const {
1356
34
    return ((const JsonbValue*)payload_)->numPackedBytes() + sizeof(header_);
1357
34
}
1358
1359
19.2k
inline unsigned int JsonbKeyValue::numPackedBytes() const {
1360
19.2k
    unsigned int ks = keyPackedBytes();
1361
19.2k
    const auto* val = (const JsonbValue*)(((char*)this) + ks);
1362
19.2k
    return ks + val->numPackedBytes();
1363
19.2k
}
1364
1365
// Poor man's "virtual" function JsonbValue::numPackedBytes
1366
37.5k
inline unsigned int JsonbValue::numPackedBytes() const {
1367
37.5k
    switch (type) {
1368
3.15k
    case JsonbType::T_Null:
1369
3.57k
    case JsonbType::T_True:
1370
3.91k
    case JsonbType::T_False: {
1371
3.91k
        return sizeof(type);
1372
3.57k
    }
1373
1374
1.84k
    case JsonbType::T_Int8: {
1375
1.84k
        return sizeof(type) + sizeof(int8_t);
1376
3.57k
    }
1377
428
    case JsonbType::T_Int16: {
1378
428
        return sizeof(type) + sizeof(int16_t);
1379
3.57k
    }
1380
3.69k
    case JsonbType::T_Int32: {
1381
3.69k
        return sizeof(type) + sizeof(int32_t);
1382
3.57k
    }
1383
2.10k
    case JsonbType::T_Int64: {
1384
2.10k
        return sizeof(type) + sizeof(int64_t);
1385
3.57k
    }
1386
504
    case JsonbType::T_Double: {
1387
504
        return sizeof(type) + sizeof(double);
1388
3.57k
    }
1389
44
    case JsonbType::T_Float: {
1390
44
        return sizeof(type) + sizeof(float);
1391
3.57k
    }
1392
4.22k
    case JsonbType::T_Int128: {
1393
4.22k
        return sizeof(type) + sizeof(int128_t);
1394
3.57k
    }
1395
929
    case JsonbType::T_String:
1396
5.45k
    case JsonbType::T_Binary: {
1397
5.45k
        return unpack<JsonbBinaryVal>()->numPackedBytes();
1398
929
    }
1399
1400
11.1k
    case JsonbType::T_Object:
1401
15.1k
    case JsonbType::T_Array: {
1402
15.1k
        return unpack<ContainerVal>()->numPackedBytes();
1403
11.1k
    }
1404
47
    case JsonbType::T_Decimal32: {
1405
47
        return JsonbDecimal32::numPackedBytes();
1406
11.1k
    }
1407
33
    case JsonbType::T_Decimal64: {
1408
33
        return JsonbDecimal64::numPackedBytes();
1409
11.1k
    }
1410
44
    case JsonbType::T_Decimal128: {
1411
44
        return JsonbDecimal128::numPackedBytes();
1412
11.1k
    }
1413
6
    case JsonbType::T_Decimal256: {
1414
6
        return JsonbDecimal256::numPackedBytes();
1415
11.1k
    }
1416
0
    case JsonbType::NUM_TYPES:
1417
0
        break;
1418
37.5k
    }
1419
1420
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1421
0
                    static_cast<int32_t>(type));
1422
37.5k
}
1423
1424
11
inline int JsonbValue::numElements() const {
1425
11
    switch (type) {
1426
1
    case JsonbType::T_Int8:
1427
1
    case JsonbType::T_Int16:
1428
1
    case JsonbType::T_Int32:
1429
1
    case JsonbType::T_Int64:
1430
1
    case JsonbType::T_Double:
1431
1
    case JsonbType::T_Float:
1432
1
    case JsonbType::T_Int128:
1433
2
    case JsonbType::T_String:
1434
2
    case JsonbType::T_Binary:
1435
3
    case JsonbType::T_Null:
1436
3
    case JsonbType::T_True:
1437
3
    case JsonbType::T_False:
1438
3
    case JsonbType::T_Decimal32:
1439
3
    case JsonbType::T_Decimal64:
1440
3
    case JsonbType::T_Decimal128:
1441
3
    case JsonbType::T_Decimal256: {
1442
3
        return 1;
1443
3
    }
1444
0
    case JsonbType::T_Object: {
1445
0
        return unpack<ObjectVal>()->numElem();
1446
3
    }
1447
8
    case JsonbType::T_Array: {
1448
8
        return unpack<ArrayVal>()->numElem();
1449
3
    }
1450
0
    case JsonbType::NUM_TYPES:
1451
0
        break;
1452
11
    }
1453
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1454
0
                    static_cast<int32_t>(type));
1455
11
}
1456
1457
64
inline bool JsonbValue::contains(const JsonbValue* rhs) const {
1458
64
    switch (type) {
1459
28
    case JsonbType::T_Int8:
1460
28
    case JsonbType::T_Int16:
1461
28
    case JsonbType::T_Int32:
1462
28
    case JsonbType::T_Int64:
1463
29
    case JsonbType::T_Int128:
1464
34
    case JsonbType::T_Double:
1465
34
    case JsonbType::T_Float:
1466
40
    case JsonbType::T_Decimal32:
1467
41
    case JsonbType::T_Decimal64:
1468
44
    case JsonbType::T_Decimal128:
1469
44
    case JsonbType::T_Decimal256: {
1470
44
        return jsonb_detail::numeric_equal(this, rhs);
1471
44
    }
1472
1
    case JsonbType::T_String:
1473
1
    case JsonbType::T_Binary: {
1474
1
        if (rhs->isString() || rhs->isBinary()) {
1475
1
            const auto* str_value1 = unpack<JsonbStringVal>();
1476
1
            const auto* str_value2 = rhs->unpack<JsonbStringVal>();
1477
1
            return str_value1->length() == str_value2->length() &&
1478
1
                   std::memcmp(str_value1->getBlob(), str_value2->getBlob(),
1479
1
                               str_value1->length()) == 0;
1480
1
        }
1481
0
        return false;
1482
1
    }
1483
12
    case JsonbType::T_Array: {
1484
12
        const auto* lhs_array = unpack<ArrayVal>();
1485
12
        if (rhs->isArray()) {
1486
10
            return jsonb_detail::array_contains_array(lhs_array, rhs->unpack<ArrayVal>());
1487
10
        }
1488
2
        return jsonb_detail::array_contains_value(lhs_array, rhs);
1489
12
    }
1490
7
    case JsonbType::T_Object: {
1491
7
        if (rhs->isObject()) {
1492
6
            const auto* obj_value1 = unpack<ObjectVal>();
1493
6
            const auto* obj_value2 = rhs->unpack<ObjectVal>();
1494
9
            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
6
                const JsonbValue* value = it->klen() == 0
1498
6
                                                  ? obj_value1->find_by_key_id(it->getKeyId())
1499
6
                                                  : obj_value1->find(it->getKeyStr(), it->klen());
1500
6
                if (value == nullptr || !value->contains(it->value())) {
1501
3
                    return false;
1502
3
                }
1503
6
            }
1504
3
            return true;
1505
6
        }
1506
1
        return false;
1507
7
    }
1508
0
    case JsonbType::T_Null: {
1509
0
        return rhs->isNull();
1510
7
    }
1511
0
    case JsonbType::T_True: {
1512
0
        return rhs->isTrue();
1513
7
    }
1514
0
    case JsonbType::T_False: {
1515
0
        return rhs->isFalse();
1516
7
    }
1517
0
    case JsonbType::NUM_TYPES:
1518
0
        break;
1519
64
    }
1520
1521
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1522
0
                    static_cast<int32_t>(type));
1523
64
}
1524
1525
167
inline bool JsonbPath::seek(const char* key_path, size_t kp_len) {
1526
167
    while (kp_len > 0 && std::isspace(key_path[kp_len - 1])) {
1527
0
        --kp_len;
1528
0
    }
1529
1530
    //path invalid
1531
167
    if (!key_path || kp_len == 0) {
1532
0
        return false;
1533
0
    }
1534
167
    Stream stream(key_path, kp_len);
1535
167
    stream.skip_whitespace();
1536
167
    if (stream.exhausted() || stream.read() != SCOPE) {
1537
        //path invalid
1538
0
        return false;
1539
0
    }
1540
1541
343
    while (!stream.exhausted()) {
1542
179
        stream.skip_whitespace();
1543
179
        stream.clear_leg_ptr();
1544
179
        stream.clear_leg_len();
1545
179
        stream.set_has_escapes(false);
1546
1547
179
        if (!JsonbPath::parsePath(&stream, this)) {
1548
            //path invalid
1549
3
            return false;
1550
3
        }
1551
179
    }
1552
164
    return true;
1553
167
}
1554
1555
179
inline bool JsonbPath::parsePath(Stream* stream, JsonbPath* path) {
1556
    // $[0]
1557
179
    if (stream->peek() == BEGIN_ARRAY) {
1558
68
        return parse_array(stream, path);
1559
68
    }
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
111
    else if (stream->peek() == BEGIN_MEMBER) {
1564
        // advance past the .
1565
109
        stream->skip(1);
1566
1567
109
        if (stream->exhausted()) {
1568
2
            return false;
1569
2
        }
1570
1571
        // $.[0]
1572
107
        if (stream->peek() == BEGIN_ARRAY) {
1573
0
            return parse_array(stream, path);
1574
0
        }
1575
        // $.a
1576
107
        else {
1577
107
            return parse_member(stream, path);
1578
107
        }
1579
107
    } else if (stream->peek() == WILDCARD) {
1580
2
        stream->skip(1);
1581
2
        if (stream->exhausted()) {
1582
0
            return false;
1583
0
        }
1584
1585
        // $**
1586
2
        if (stream->peek() == WILDCARD) {
1587
2
            path->_is_supper_wildcard = true;
1588
2
        }
1589
1590
2
        stream->skip(1);
1591
2
        if (stream->exhausted()) {
1592
0
            return false;
1593
0
        }
1594
1595
2
        if (stream->peek() == BEGIN_ARRAY) {
1596
0
            return parse_array(stream, path);
1597
2
        } else if (stream->peek() == BEGIN_MEMBER) {
1598
            // advance past the .
1599
2
            stream->skip(1);
1600
1601
2
            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
2
            if (stream->peek() == BEGIN_ARRAY) {
1608
0
                return parse_array(stream, path);
1609
0
            }
1610
            // $.a
1611
2
            else {
1612
2
                return parse_member(stream, path);
1613
2
            }
1614
2
        }
1615
0
        return false;
1616
2
    } else {
1617
0
        return false; //invalid json path
1618
0
    }
1619
179
}
1620
1621
68
inline bool JsonbPath::parse_array(Stream* stream, JsonbPath* path) {
1622
68
    assert(stream->peek() == BEGIN_ARRAY);
1623
68
    stream->skip(1);
1624
68
    if (stream->exhausted()) {
1625
0
        return false;
1626
0
    }
1627
1628
68
    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
2
        stream->set_leg_ptr(const_cast<char*>(stream->position()));
1632
2
        stream->add_leg_len();
1633
2
        stream->skip(1);
1634
2
        if (stream->exhausted()) {
1635
0
            return false;
1636
0
        }
1637
1638
2
        if (stream->peek() == END_ARRAY) {
1639
2
            std::unique_ptr<leg_info> leg(
1640
2
                    new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, ARRAY_CODE));
1641
2
            leg->is_wildcard = true;
1642
2
            path->add_leg_to_leg_vector(std::move(leg));
1643
2
            stream->skip(1);
1644
2
            path->_is_wildcard = true;
1645
2
            return true;
1646
2
        } else {
1647
0
            return false;
1648
0
        }
1649
2
    }
1650
1651
    // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1652
    // using const_cast is acceptable.
1653
66
    stream->set_leg_ptr(const_cast<char*>(stream->position()));
1654
1655
132
    for (; !stream->exhausted() && stream->peek() != END_ARRAY; stream->advance()) {
1656
66
        stream->add_leg_len();
1657
66
    }
1658
1659
66
    if (stream->exhausted() || stream->peek() != END_ARRAY) {
1660
0
        return false;
1661
66
    } else {
1662
66
        stream->skip(1);
1663
66
    }
1664
1665
    //parse array index to int
1666
1667
66
    std::string_view idx_string(stream->get_leg_ptr(), stream->get_leg_len());
1668
66
    int index = 0;
1669
1670
    // Match "last" case-insensitively for compatibility with existing JSONB
1671
    // paths such as [Last] and [LAST].
1672
66
    if (stream->get_leg_len() >= 4 &&
1673
66
        std::equal(LAST, LAST + 4, stream->get_leg_ptr(),
1674
0
                   [](char c1, char c2) { return std::tolower(c1) == std::tolower(c2); })) {
1675
0
        auto pos = idx_string.find(MINUS);
1676
1677
0
        if (pos != std::string::npos) {
1678
0
            for (size_t i = 4; i < pos; ++i) {
1679
0
                if (std::isspace(idx_string[i])) {
1680
0
                    continue;
1681
0
                } else {
1682
                    // leading zeroes are not allowed
1683
0
                    LOG(WARNING) << "Non-space char in idx_string: '" << idx_string << "'";
1684
0
                    return false;
1685
0
                }
1686
0
            }
1687
0
            idx_string = idx_string.substr(pos + 1);
1688
0
            idx_string = trim(idx_string);
1689
1690
            // Keep numeric-prefix parsing for last-N offsets as existing JSONB
1691
            // path behavior.
1692
0
            auto result = std::from_chars(idx_string.data(), idx_string.data() + idx_string.size(),
1693
0
                                          index);
1694
0
            if (result.ec != std::errc()) {
1695
0
                LOG(WARNING) << "Invalid index in JSON path: '" << idx_string << "'";
1696
0
                return false;
1697
0
            }
1698
1699
0
        } else if (stream->get_leg_len() > 4) {
1700
0
            return false;
1701
0
        }
1702
1703
0
        std::unique_ptr<leg_info> leg(new leg_info(nullptr, 0, -index - 1, ARRAY_CODE));
1704
0
        path->add_leg_to_leg_vector(std::move(leg));
1705
1706
0
        return true;
1707
0
    }
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
66
    auto result = std::from_chars(idx_string.data(), idx_string.data() + idx_string.size(), index);
1713
1714
66
    if (result.ec != std::errc()) {
1715
0
        return false;
1716
0
    }
1717
1718
66
    std::unique_ptr<leg_info> leg(new leg_info(nullptr, 0, index, ARRAY_CODE));
1719
66
    path->add_leg_to_leg_vector(std::move(leg));
1720
1721
66
    return true;
1722
66
}
1723
1724
109
inline bool JsonbPath::parse_member(Stream* stream, JsonbPath* path) {
1725
109
    if (stream->exhausted()) {
1726
0
        return false;
1727
0
    }
1728
1729
109
    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
6
        stream->set_leg_ptr(const_cast<char*>(stream->position()));
1733
6
        stream->add_leg_len();
1734
6
        stream->skip(1);
1735
6
        std::unique_ptr<leg_info> leg(
1736
6
                new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, MEMBER_CODE));
1737
6
        leg->is_wildcard = true;
1738
6
        path->add_leg_to_leg_vector(std::move(leg));
1739
6
        path->_is_wildcard = true;
1740
6
        return true;
1741
6
    }
1742
1743
    // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1744
    // using const_cast is acceptable.
1745
103
    stream->set_leg_ptr(const_cast<char*>(stream->position()));
1746
1747
103
    const char* left_quotation_marks = nullptr;
1748
103
    const char* right_quotation_marks = nullptr;
1749
1750
323
    for (; !stream->exhausted(); stream->advance()) {
1751
        // Only accept space characters quoted by double quotes.
1752
266
        if (std::isspace(stream->peek()) && left_quotation_marks == nullptr) {
1753
0
            return false;
1754
266
        } else if (stream->peek() == ESCAPE) {
1755
12
            stream->add_leg_len();
1756
12
            stream->skip(1);
1757
12
            stream->add_leg_len();
1758
12
            stream->set_has_escapes(true);
1759
12
            if (stream->exhausted()) {
1760
0
                return false;
1761
0
            }
1762
12
            continue;
1763
254
        } else if (stream->peek() == DOUBLE_QUOTE) {
1764
70
            if (left_quotation_marks == nullptr) {
1765
35
                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
35
                stream->set_leg_ptr(const_cast<char*>(++left_quotation_marks));
1769
35
                continue;
1770
35
            } else {
1771
35
                right_quotation_marks = stream->position();
1772
35
                stream->skip(1);
1773
35
                break;
1774
35
            }
1775
184
        } else if (stream->peek() == BEGIN_MEMBER || stream->peek() == BEGIN_ARRAY) {
1776
17
            if (left_quotation_marks == nullptr) {
1777
11
                break;
1778
11
            }
1779
17
        }
1780
1781
173
        stream->add_leg_len();
1782
173
    }
1783
1784
    // An empty member name is only valid when it is written explicitly as `""`.
1785
103
    if ((left_quotation_marks != nullptr && right_quotation_marks == nullptr) ||
1786
103
        stream->get_leg_ptr() == nullptr ||
1787
103
        (left_quotation_marks == nullptr && stream->get_leg_len() == 0)) {
1788
1
        return false; //invalid json path
1789
1
    }
1790
1791
102
    if (stream->get_has_escapes()) {
1792
4
        stream->remove_escapes();
1793
4
    }
1794
1795
102
    std::unique_ptr<leg_info> leg(
1796
102
            new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, MEMBER_CODE));
1797
102
    path->add_leg_to_leg_vector(std::move(leg));
1798
1799
102
    return true;
1800
103
}
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