Coverage Report

Created: 2026-10-19 22:54

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