Coverage Report

Created: 2026-05-20 10:53

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 <cctype>
71
#include <charconv>
72
#include <cstddef>
73
#include <cstdint>
74
#include <string>
75
#include <string_view>
76
#include <type_traits>
77
78
#include "common/compiler_util.h" // IWYU pragma: keep
79
#include "common/status.h"
80
#include "core/data_type/define_primitive_type.h"
81
#include "core/string_ref.h"
82
#include "core/types.h"
83
#include "util/string_util.h"
84
85
// #include "util/string_parser.hpp"
86
87
// Concept to check for supported decimal types
88
template <typename T>
89
concept JsonbDecimalType =
90
        std::same_as<T, doris::Decimal256> || std::same_as<T, doris::Decimal64> ||
91
        std::same_as<T, doris::Decimal128V3> || std::same_as<T, doris::Decimal32>;
92
93
namespace doris {
94
95
template <typename T>
96
constexpr bool is_pod_v = std::is_trivial_v<T> && std::is_standard_layout_v<T>;
97
98
struct JsonbStringVal;
99
struct ObjectVal;
100
struct ArrayVal;
101
struct JsonbBinaryVal;
102
struct ContainerVal;
103
104
template <JsonbDecimalType T>
105
struct JsonbDecimalVal;
106
107
using JsonbDecimal256 = JsonbDecimalVal<Decimal256>;
108
using JsonbDecimal128 = JsonbDecimalVal<Decimal128V3>;
109
using JsonbDecimal64 = JsonbDecimalVal<Decimal64>;
110
using JsonbDecimal32 = JsonbDecimalVal<Decimal32>;
111
112
template <typename T>
113
    requires std::is_integral_v<T> || std::is_floating_point_v<T>
114
struct NumberValT;
115
116
using JsonbInt8Val = NumberValT<int8_t>;
117
using JsonbInt16Val = NumberValT<int16_t>;
118
using JsonbInt32Val = NumberValT<int32_t>;
119
using JsonbInt64Val = NumberValT<int64_t>;
120
using JsonbInt128Val = NumberValT<int128_t>;
121
using JsonbDoubleVal = NumberValT<double>;
122
using JsonbFloatVal = NumberValT<float>;
123
124
template <typename T>
125
concept JsonbPodType = (std::same_as<T, JsonbStringVal> || std::same_as<T, ObjectVal> ||
126
                        std::same_as<T, ContainerVal> || std::same_as<T, ArrayVal> ||
127
                        std::same_as<T, JsonbBinaryVal> || std::same_as<T, JsonbDecimal32> ||
128
                        std::same_as<T, JsonbDecimal64> || std::same_as<T, JsonbDecimal128> ||
129
                        std::same_as<T, JsonbDecimal256> || std::same_as<T, JsonbDecimal32> ||
130
                        std::same_as<T, JsonbInt8Val> || std::same_as<T, JsonbInt16Val> ||
131
                        std::same_as<T, JsonbInt32Val> || std::same_as<T, JsonbInt64Val> ||
132
                        std::same_as<T, JsonbInt128Val> || std::same_as<T, JsonbFloatVal> ||
133
                        std::same_as<T, JsonbFloatVal> || std::same_as<T, JsonbDoubleVal>);
134
135
4.95M
#define JSONB_VER 1
136
137
using int128_t = __int128;
138
139
// forward declaration
140
struct JsonbValue;
141
142
class JsonbOutStream;
143
144
template <class OS_TYPE>
145
class JsonbWriterT;
146
147
using JsonbWriter = JsonbWriterT<JsonbOutStream>;
148
149
const int MaxNestingLevel = 100;
150
151
/*
152
 * JsonbType defines 10 primitive types and 2 container types, as described
153
 * below.
154
 * NOTE: Do NOT modify the existing values or their order in this enum.
155
 *      You may only append new entries at the end before `NUM_TYPES`.
156
 *      This enum will be used in serialized data and/or persisted data.
157
 *      Changing existing values may break backward compatibility
158
 *      with previously stored or transmitted data.
159
 *
160
 * primitive_value ::=
161
 *   0x00        //null value (0 byte)
162
 * | 0x01        //boolean true (0 byte)
163
 * | 0x02        //boolean false (0 byte)
164
 * | 0x03 int8   //char/int8 (1 byte)
165
 * | 0x04 int16  //int16 (2 bytes)
166
 * | 0x05 int32  //int32 (4 bytes)
167
 * | 0x06 int64  //int64 (8 bytes)
168
 * | 0x07 double //floating point (8 bytes)
169
 * | 0x08 string //variable length string
170
 * | 0x09 binary //variable length binary
171
 *
172
 * container ::=
173
 *   0x0A int32 key_value_list //object, int32 is the total bytes of the object
174
 * | 0x0B int32 value_list     //array, int32 is the total bytes of the array
175
 */
176
enum class JsonbType : char {
177
    T_Null = 0x00,
178
    T_True = 0x01,
179
    T_False = 0x02,
180
    T_Int8 = 0x03,
181
    T_Int16 = 0x04,
182
    T_Int32 = 0x05,
183
    T_Int64 = 0x06,
184
    T_Double = 0x07,
185
    T_String = 0x08,
186
    T_Binary = 0x09,
187
    T_Object = 0x0A,
188
    T_Array = 0x0B,
189
    T_Int128 = 0x0C,
190
    T_Float = 0x0D,
191
    T_Decimal32 = 0x0E,  // DecimalV3 only
192
    T_Decimal64 = 0x0F,  // DecimalV3 only
193
    T_Decimal128 = 0x10, // DecimalV3 only
194
    T_Decimal256 = 0x11, // DecimalV3 only
195
    NUM_TYPES,
196
};
197
198
inline PrimitiveType get_primitive_type_from_json_type(JsonbType json_type) {
199
    switch (json_type) {
200
    case JsonbType::T_Null:
201
        return TYPE_NULL;
202
    case JsonbType::T_True:
203
    case JsonbType::T_False:
204
        return TYPE_BOOLEAN;
205
    case JsonbType::T_Int8:
206
        return TYPE_TINYINT;
207
    case JsonbType::T_Int16:
208
        return TYPE_SMALLINT;
209
    case JsonbType::T_Int32:
210
        return TYPE_INT;
211
    case JsonbType::T_Int64:
212
        return TYPE_BIGINT;
213
    case JsonbType::T_Double:
214
        return TYPE_DOUBLE;
215
    case JsonbType::T_String:
216
        return TYPE_STRING;
217
    case JsonbType::T_Binary:
218
        return TYPE_BINARY;
219
    case JsonbType::T_Object:
220
        return TYPE_STRUCT;
221
    case JsonbType::T_Array:
222
        return TYPE_ARRAY;
223
    case JsonbType::T_Int128:
224
        return TYPE_LARGEINT;
225
    case JsonbType::T_Float:
226
        return TYPE_FLOAT;
227
    case JsonbType::T_Decimal32:
228
        return TYPE_DECIMAL32;
229
    case JsonbType::T_Decimal64:
230
        return TYPE_DECIMAL64;
231
    case JsonbType::T_Decimal128:
232
        return TYPE_DECIMAL128I;
233
    case JsonbType::T_Decimal256:
234
        return TYPE_DECIMAL256;
235
    default:
236
        throw Exception(ErrorCode::INTERNAL_ERROR, "Unsupported JsonbType: {}",
237
                        static_cast<int>(json_type));
238
    }
239
}
240
241
//for parse json path
242
constexpr char SCOPE = '$';
243
constexpr char BEGIN_MEMBER = '.';
244
constexpr char BEGIN_ARRAY = '[';
245
constexpr char END_ARRAY = ']';
246
constexpr char DOUBLE_QUOTE = '"';
247
constexpr char WILDCARD = '*';
248
constexpr char MINUS = '-';
249
constexpr char LAST[] = "last";
250
constexpr char ESCAPE = '\\';
251
constexpr unsigned int MEMBER_CODE = 0;
252
constexpr unsigned int ARRAY_CODE = 1;
253
254
/// A simple input stream class for the JSON path parser.
255
class Stream {
256
public:
257
    /// Creates an input stream reading from a character string.
258
    /// @param string  the input string
259
    /// @param length  the length of the input string
260
15.6k
    Stream(const char* string, size_t length) : m_position(string), m_end(string + length) {}
261
262
    /// Returns a pointer to the current position in the stream.
263
21.4k
    const char* position() const { return m_position; }
264
265
    /// Returns a pointer to the position just after the end of the stream.
266
0
    const char* end() const { return m_end; }
267
268
    /// Returns the number of bytes remaining in the stream.
269
474k
    size_t remaining() const {
270
474k
        assert(m_position <= m_end);
271
474k
        return m_end - m_position;
272
474k
    }
273
274
    /// Tells if the stream has been exhausted.
275
441k
    bool exhausted() const { return remaining() == 0; }
276
277
    /// Reads the next byte from the stream and moves the position forward.
278
15.6k
    char read() {
279
15.6k
        assert(!exhausted());
280
15.6k
        return *m_position++;
281
15.6k
    }
282
283
    /// Reads the next byte from the stream without moving the position forward.
284
265k
    char peek() const {
285
265k
        assert(!exhausted());
286
265k
        return *m_position;
287
265k
    }
288
289
    /// Moves the position to the next non-whitespace character.
290
69.6k
    void skip_whitespace() {
291
69.6k
        m_position = std::find_if_not(m_position, m_end, [](char c) { return std::isspace(c); });
292
69.6k
    }
293
294
    /// Moves the position n bytes forward.
295
32.9k
    void skip(size_t n) {
296
32.9k
        assert(remaining() >= n);
297
32.9k
        m_position += n;
298
32.9k
        skip_whitespace();
299
32.9k
    }
300
301
44.6k
    void advance() { m_position++; }
302
303
42.3k
    void clear_leg_ptr() { leg_ptr = nullptr; }
304
305
21.2k
    void set_leg_ptr(char* ptr) {
306
21.2k
        clear_leg_ptr();
307
21.2k
        leg_ptr = ptr;
308
21.2k
    }
309
310
32.4k
    char* get_leg_ptr() { return leg_ptr; }
311
312
21.0k
    void clear_leg_len() { leg_len = 0; }
313
314
44.5k
    void add_leg_len() { leg_len++; }
315
316
42.3k
    unsigned int get_leg_len() const { return leg_len; }
317
318
3
    void remove_escapes() {
319
3
        int new_len = 0;
320
27
        for (int i = 0; i < leg_len; i++) {
321
24
            if (leg_ptr[i] != '\\') {
322
21
                leg_ptr[new_len++] = leg_ptr[i];
323
21
            }
324
24
        }
325
3
        leg_ptr[new_len] = '\0';
326
3
        leg_len = new_len;
327
3
    }
328
329
3
    void set_has_escapes(bool has) { has_escapes = has; }
330
331
9.68k
    bool get_has_escapes() const { return has_escapes; }
332
333
private:
334
    /// The current position in the stream.
335
    const char* m_position = nullptr;
336
337
    /// The end of the stream.
338
    const char* const m_end;
339
340
    ///path leg ptr
341
    char* leg_ptr = nullptr;
342
343
    ///path leg len
344
    unsigned int leg_len;
345
346
    ///Whether to contain escape characters
347
    bool has_escapes = false;
348
};
349
350
struct leg_info {
351
    ///path leg ptr
352
    char* leg_ptr = nullptr;
353
354
    ///path leg len
355
    unsigned int leg_len;
356
357
    ///array_index
358
    int array_index;
359
360
    ///type: 0 is member 1 is array
361
    unsigned int type;
362
363
341
    bool to_string(std::string* str) const {
364
341
        if (type == MEMBER_CODE) {
365
109
            str->push_back(BEGIN_MEMBER);
366
109
            bool contains_space = false;
367
109
            std::string tmp;
368
287
            for (auto* it = leg_ptr; it != (leg_ptr + leg_len); ++it) {
369
178
                if (std::isspace(*it)) {
370
3
                    contains_space = true;
371
175
                } else if (*it == '"' || *it == ESCAPE || *it == '\r' || *it == '\n' ||
372
175
                           *it == '\b' || *it == '\t') {
373
2
                    tmp.push_back(ESCAPE);
374
2
                }
375
178
                tmp.push_back(*it);
376
178
            }
377
109
            if (contains_space) {
378
3
                str->push_back(DOUBLE_QUOTE);
379
3
            }
380
109
            str->append(tmp);
381
109
            if (contains_space) {
382
3
                str->push_back(DOUBLE_QUOTE);
383
3
            }
384
109
            return true;
385
232
        } else if (type == ARRAY_CODE) {
386
232
            str->push_back(BEGIN_ARRAY);
387
232
            std::string int_str = std::to_string(array_index);
388
232
            str->append(int_str);
389
232
            str->push_back(END_ARRAY);
390
232
            return true;
391
232
        } else {
392
0
            return false;
393
0
        }
394
341
    }
395
};
396
397
class JsonbPath {
398
public:
399
    // parse json path
400
    static bool parsePath(Stream* stream, JsonbPath* path);
401
402
    static bool parse_array(Stream* stream, JsonbPath* path);
403
    static bool parse_member(Stream* stream, JsonbPath* path);
404
405
    //return true if json path valid else return false
406
    bool seek(const char* string, size_t length);
407
408
21.9k
    void add_leg_to_leg_vector(std::unique_ptr<leg_info> leg) {
409
21.9k
        leg_vector.emplace_back(leg.release());
410
21.9k
    }
411
412
586
    void pop_leg_from_leg_vector() { leg_vector.pop_back(); }
413
414
218
    bool to_string(std::string* res) const {
415
218
        res->push_back(SCOPE);
416
341
        for (const auto& leg : leg_vector) {
417
341
            auto valid = leg->to_string(res);
418
341
            if (!valid) {
419
0
                return false;
420
0
            }
421
341
        }
422
218
        return true;
423
218
    }
424
425
386k
    size_t get_leg_vector_size() const { return leg_vector.size(); }
426
427
1.19M
    leg_info* get_leg_from_leg_vector(size_t i) const { return leg_vector[i].get(); }
428
429
246
    bool is_wildcard() const { return _is_wildcard; }
430
148k
    bool is_supper_wildcard() const { return _is_supper_wildcard; }
431
432
68
    void clean() { leg_vector.clear(); }
433
434
private:
435
    std::vector<std::unique_ptr<leg_info>> leg_vector;
436
    bool _is_wildcard = false;        // whether the path is a wildcard path
437
    bool _is_supper_wildcard = false; // supper wildcard likes '$**.a' or '$**[1]'
438
};
439
440
/*
441
 * JsonbFwdIteratorT implements JSONB's iterator template.
442
 *
443
 * Note: it is an FORWARD iterator only due to the design of JSONB format.
444
 */
445
template <class Iter_Type, class Cont_Type>
446
class JsonbFwdIteratorT {
447
public:
448
    using iterator = Iter_Type;
449
    using pointer = typename std::iterator_traits<Iter_Type>::pointer;
450
    using reference = typename std::iterator_traits<Iter_Type>::reference;
451
452
    explicit JsonbFwdIteratorT() : current_(nullptr) {}
453
707k
    explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {}
_ZN5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEC2ERKS3_
Line
Count
Source
453
369k
    explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {}
_ZN5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEC2ERKS3_
Line
Count
Source
453
338k
    explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {}
454
455
    // allow non-const to const iterator conversion (same container type)
456
    template <class Iter_Ty>
457
    JsonbFwdIteratorT(const JsonbFwdIteratorT<Iter_Ty, Cont_Type>& rhs) : current_(rhs.base()) {}
458
459
1.33M
    bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEeqERKS5_
Line
Count
Source
459
571k
    bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEeqERKS5_
Line
Count
Source
459
766k
    bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); }
460
461
1.05M
    bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEneERKS5_
Line
Count
Source
461
454k
    bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEneERKS5_
Line
Count
Source
461
597k
    bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); }
462
463
437k
    bool operator<(const JsonbFwdIteratorT& rhs) const { return (current_ < rhs.current_); }
464
465
    bool operator>(const JsonbFwdIteratorT& rhs) const { return !operator<(rhs); }
466
467
660k
    JsonbFwdIteratorT& operator++() {
468
660k
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
469
660k
        return *this;
470
660k
    }
_ZN5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEppEv
Line
Count
Source
467
446k
    JsonbFwdIteratorT& operator++() {
468
446k
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
469
446k
        return *this;
470
446k
    }
_ZN5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEppEv
Line
Count
Source
467
214k
    JsonbFwdIteratorT& operator++() {
468
214k
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
469
214k
        return *this;
470
214k
    }
471
472
    JsonbFwdIteratorT operator++(int) {
473
        auto tmp = *this;
474
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
475
        return tmp;
476
    }
477
478
214k
    explicit operator pointer() { return current_; }
479
480
1.33k
    reference operator*() const { return *current_; }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEdeEv
Line
Count
Source
480
311
    reference operator*() const { return *current_; }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEdeEv
Line
Count
Source
480
1.01k
    reference operator*() const { return *current_; }
481
482
1.52M
    pointer operator->() const { return current_; }
483
484
    iterator base() const { return current_; }
485
486
private:
487
    iterator current_;
488
};
489
using JsonbTypeUnder = std::underlying_type_t<JsonbType>;
490
491
#if defined(__clang__)
492
#pragma clang diagnostic push
493
#pragma clang diagnostic ignored "-Wzero-length-array"
494
#endif
495
#pragma pack(push, 1)
496
497
/*
498
 * JsonbDocument is the main object that accesses and queries JSONB packed
499
 * bytes. NOTE: JsonbDocument only allows object container as the top level
500
 * JSONB value. However, you can use the static method "createValue" to get any
501
 * JsonbValue object from the packed bytes.
502
 *
503
 * JsonbDocument object also dereferences to an object container value
504
 * (ObjectVal) once JSONB is loaded.
505
 *
506
 * ** Load **
507
 * JsonbDocument is usable after loading packed bytes (memory location) into
508
 * the object. We only need the header and first few bytes of the payload after
509
 * header to verify the JSONB.
510
 *
511
 * Note: creating an JsonbDocument (through createDocument) does not allocate
512
 * any memory. The document object is an efficient wrapper on the packed bytes
513
 * which is accessed directly.
514
 *
515
 * ** Query **
516
 * Query is through dereferencing into ObjectVal.
517
 */
518
class JsonbDocument {
519
public:
520
    // create an JsonbDocument object from JSONB packed bytes
521
    [[nodiscard]] static Status checkAndCreateDocument(const char* pb, size_t size,
522
                                                       const JsonbDocument** doc);
523
524
    // create an JsonbValue from JSONB packed bytes
525
    static const JsonbValue* createValue(const char* pb, size_t size);
526
527
0
    uint8_t version() const { return header_.ver_; }
528
529
714k
    const JsonbValue* getValue() const { return ((const JsonbValue*)payload_); }
530
531
    unsigned int numPackedBytes() const;
532
533
    const ObjectVal* operator->() const;
534
535
private:
536
    /*
537
   * JsonbHeader class defines JSONB header (internal to JsonbDocument).
538
   *
539
   * Currently it only contains version information (1-byte). We may expand the
540
   * header to include checksum of the JSONB binary for more security.
541
   */
542
    struct JsonbHeader {
543
        uint8_t ver_;
544
    } header_;
545
546
    char payload_[0];
547
};
548
549
/*
550
 * JsonbKeyValue class defines JSONB key type, as described below.
551
 *
552
 * key ::=
553
 *   0x00 int8    //1-byte dictionary id
554
 * | int8 (byte*) //int8 (>0) is the size of the key string
555
 *
556
 * value ::= primitive_value | container
557
 *
558
 * JsonbKeyValue can be either an id mapping to the key string in an external
559
 * dictionary, or it is the original key string. Whether to read an id or a
560
 * string is decided by the first byte (size).
561
 *
562
 * Note: a key object must be followed by a value object. Therefore, a key
563
 * object implicitly refers to a key-value pair, and you can get the value
564
 * object right after the key object. The function numPackedBytes hence
565
 * indicates the total size of the key-value pair, so that we will be able go
566
 * to next pair from the key.
567
 *
568
 * ** Dictionary size **
569
 * By default, the dictionary size is 255 (1-byte). Users can define
570
 * "USE_LARGE_DICT" to increase the dictionary size to 655535 (2-byte).
571
 */
572
class JsonbKeyValue {
573
public:
574
    // now we use sMaxKeyId to represent an empty key
575
    static const int sMaxKeyId = 65535;
576
    using keyid_type = uint16_t;
577
578
    static const uint8_t sMaxKeyLen = 64;
579
580
    // size of the key. 0 indicates it is stored as id
581
668k
    uint8_t klen() const { return size; }
582
583
    // get the key string. Note the string may not be null terminated.
584
335k
    const char* getKeyStr() const { return key.str_; }
585
586
111k
    keyid_type getKeyId() const { return key.id_; }
587
588
893k
    unsigned int keyPackedBytes() const {
589
893k
        return size ? (sizeof(size) + size) : (sizeof(size) + sizeof(keyid_type));
590
893k
    }
591
592
435k
    const JsonbValue* value() const {
593
435k
        return (const JsonbValue*)(((char*)this) + keyPackedBytes());
594
435k
    }
595
596
    // size of the total packed bytes (key+value)
597
    unsigned int numPackedBytes() const;
598
599
    uint8_t size;
600
601
    union key_ {
602
        keyid_type id_;
603
        char str_[1];
604
    } key;
605
};
606
607
struct JsonbFindResult {
608
    const JsonbValue* value = nullptr;   // found value
609
    std::unique_ptr<JsonbWriter> writer; // writer to write the value
610
    bool is_wildcard = false;            // whether the path is a wildcard path
611
};
612
613
/*
614
 * JsonbValue is the base class of all JSONB types. It contains only one member
615
 * variable - type info, which can be retrieved by member functions is[Type]()
616
 * or type().
617
 */
618
struct JsonbValue {
619
    static const uint32_t sMaxValueLen = 1 << 24; // 16M
620
621
212k
    bool isNull() const { return (type == JsonbType::T_Null); }
622
342
    bool isTrue() const { return (type == JsonbType::T_True); }
623
11
    bool isFalse() const { return (type == JsonbType::T_False); }
624
413
    bool isInt() const { return isInt8() || isInt16() || isInt32() || isInt64() || isInt128(); }
625
413
    bool isInt8() const { return (type == JsonbType::T_Int8); }
626
295
    bool isInt16() const { return (type == JsonbType::T_Int16); }
627
200
    bool isInt32() const { return (type == JsonbType::T_Int32); }
628
203
    bool isInt64() const { return (type == JsonbType::T_Int64); }
629
162
    bool isDouble() const { return (type == JsonbType::T_Double); }
630
156
    bool isFloat() const { return (type == JsonbType::T_Float); }
631
19.4k
    bool isString() const { return (type == JsonbType::T_String); }
632
15.4k
    bool isBinary() const { return (type == JsonbType::T_Binary); }
633
10.1k
    bool isObject() const { return (type == JsonbType::T_Object); }
634
9.94k
    bool isArray() const { return (type == JsonbType::T_Array); }
635
198
    bool isInt128() const { return (type == JsonbType::T_Int128); }
636
140
    bool isDecimal() const {
637
140
        return (type == JsonbType::T_Decimal32 || type == JsonbType::T_Decimal64 ||
638
140
                type == JsonbType::T_Decimal128 || type == JsonbType::T_Decimal256);
639
140
    }
640
1
    bool isDecimal32() const { return (type == JsonbType::T_Decimal32); }
641
1
    bool isDecimal64() const { return (type == JsonbType::T_Decimal64); }
642
1
    bool isDecimal128() const { return (type == JsonbType::T_Decimal128); }
643
1
    bool isDecimal256() const { return (type == JsonbType::T_Decimal256); }
644
645
    PrimitiveType get_primitive_type() const { return get_primitive_type_from_json_type(type); }
646
647
555
    const char* typeName() const {
648
555
        switch (type) {
649
24
        case JsonbType::T_Null:
650
24
            return "null";
651
20
        case JsonbType::T_True:
652
40
        case JsonbType::T_False:
653
40
            return "bool";
654
44
        case JsonbType::T_Int8:
655
82
        case JsonbType::T_Int16:
656
96
        case JsonbType::T_Int32:
657
96
            return "int";
658
126
        case JsonbType::T_Int64:
659
126
            return "bigint";
660
18
        case JsonbType::T_Int128:
661
18
            return "largeint";
662
43
        case JsonbType::T_Double:
663
43
            return "double";
664
0
        case JsonbType::T_Float:
665
0
            return "float";
666
67
        case JsonbType::T_String:
667
67
            return "string";
668
0
        case JsonbType::T_Binary:
669
0
            return "binary";
670
103
        case JsonbType::T_Object:
671
103
            return "object";
672
38
        case JsonbType::T_Array:
673
38
            return "array";
674
0
        case JsonbType::T_Decimal32:
675
0
            return "Decimal32";
676
0
        case JsonbType::T_Decimal64:
677
0
            return "Decimal64";
678
0
        case JsonbType::T_Decimal128:
679
0
            return "Decimal128";
680
0
        case JsonbType::T_Decimal256:
681
0
            return "Decimal256";
682
0
        default:
683
0
            return "unknown";
684
555
        }
685
555
    }
686
687
    // size of the total packed bytes
688
    unsigned int numPackedBytes() const;
689
690
    // size of the value in bytes
691
    unsigned int size() const;
692
693
    //Get the number of jsonbvalue elements
694
    int numElements() const;
695
696
    //Whether to include the jsonbvalue rhs
697
    bool contains(const JsonbValue* rhs) const;
698
699
    // find the JSONB value by JsonbPath
700
    JsonbFindResult findValue(JsonbPath& path) const;
701
    friend class JsonbDocument;
702
703
    JsonbType type; // type info
704
705
    char payload[0]; // payload, which is the packed bytes of the value
706
707
    /**
708
    * @brief Unpacks the underlying Jsonb binary content as a pointer to type `T`.
709
    *
710
    * @tparam T A POD (Plain Old Data) type that must satisfy the `JsonbPodType` concept.
711
    *           This ensures that `T` is trivially copyable, standard-layout, and safe to
712
    *           reinterpret from raw bytes without invoking undefined behavior.
713
    *
714
    * @return A pointer to a `const T` object, interpreted from the internal buffer.
715
    *
716
    * @note The caller must ensure that the current JsonbValue actually contains data
717
    *       compatible with type `T`, otherwise the result is undefined.
718
    */
719
    template <JsonbPodType T>
720
2.83M
    const T* unpack() const {
721
2.83M
        static_assert(is_pod_v<T>, "T must be a POD type");
722
2.83M
        return reinterpret_cast<const T*>(payload);
723
2.83M
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_9ObjectValEEEPKT_v
Line
Count
Source
720
249k
    const T* unpack() const {
721
249k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
249k
        return reinterpret_cast<const T*>(payload);
723
249k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIaEEEEPKT_v
Line
Count
Source
720
31.9k
    const T* unpack() const {
721
31.9k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
31.9k
        return reinterpret_cast<const T*>(payload);
723
31.9k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIsEEEEPKT_v
Line
Count
Source
720
42.4k
    const T* unpack() const {
721
42.4k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
42.4k
        return reinterpret_cast<const T*>(payload);
723
42.4k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIiEEEEPKT_v
Line
Count
Source
720
16.9k
    const T* unpack() const {
721
16.9k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
16.9k
        return reinterpret_cast<const T*>(payload);
723
16.9k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIlEEEEPKT_v
Line
Count
Source
720
201k
    const T* unpack() const {
721
201k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
201k
        return reinterpret_cast<const T*>(payload);
723
201k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTInEEEEPKT_v
Line
Count
Source
720
18.7k
    const T* unpack() const {
721
18.7k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
18.7k
        return reinterpret_cast<const T*>(payload);
723
18.7k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_14JsonbBinaryValEEEPKT_v
Line
Count
Source
720
336k
    const T* unpack() const {
721
336k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
336k
        return reinterpret_cast<const T*>(payload);
723
336k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_12ContainerValEEEPKT_v
Line
Count
Source
720
1.08M
    const T* unpack() const {
721
1.08M
        static_assert(is_pod_v<T>, "T must be a POD type");
722
1.08M
        return reinterpret_cast<const T*>(payload);
723
1.08M
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_8ArrayValEEEPKT_v
Line
Count
Source
720
361k
    const T* unpack() const {
721
361k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
361k
        return reinterpret_cast<const T*>(payload);
723
361k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIdEEEEPKT_v
Line
Count
Source
720
11.9k
    const T* unpack() const {
721
11.9k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
11.9k
        return reinterpret_cast<const T*>(payload);
723
11.9k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIfEEEEPKT_v
Line
Count
Source
720
4.61k
    const T* unpack() const {
721
4.61k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
4.61k
        return reinterpret_cast<const T*>(payload);
723
4.61k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_14JsonbStringValEEEPKT_v
Line
Count
Source
720
479k
    const T* unpack() const {
721
479k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
479k
        return reinterpret_cast<const T*>(payload);
723
479k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_7DecimalIiEEEEEEPKT_v
Line
Count
Source
720
50
    const T* unpack() const {
721
50
        static_assert(is_pod_v<T>, "T must be a POD type");
722
50
        return reinterpret_cast<const T*>(payload);
723
50
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_7DecimalIlEEEEEEPKT_v
Line
Count
Source
720
43
    const T* unpack() const {
721
43
        static_assert(is_pod_v<T>, "T must be a POD type");
722
43
        return reinterpret_cast<const T*>(payload);
723
43
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_12Decimal128V3EEEEEPKT_v
Line
Count
Source
720
41
    const T* unpack() const {
721
41
        static_assert(is_pod_v<T>, "T must be a POD type");
722
41
        return reinterpret_cast<const T*>(payload);
723
41
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_7DecimalIN4wide7integerILm256EiEEEEEEEEPKT_v
Line
Count
Source
720
13
    const T* unpack() const {
721
13
        static_assert(is_pod_v<T>, "T must be a POD type");
722
13
        return reinterpret_cast<const T*>(payload);
723
13
    }
724
725
    // /**
726
    // * @brief Unpacks the underlying Jsonb binary content as a pointer to type `T`.
727
    // *
728
    // * @tparam T A POD (Plain Old Data) type that must satisfy the `JsonbPodType` concept.
729
    // *           This ensures that `T` is trivially copyable, standard-layout, and safe to
730
    // *           reinterpret from raw bytes without invoking undefined behavior.
731
    // *
732
    // * @return A pointer to a `T` object, interpreted from the internal buffer.
733
    // *
734
    // * @note The caller must ensure that the current JsonbValue actually contains data
735
    // *       compatible with type `T`, otherwise the result is undefined.
736
    // */
737
    // template <JsonbPodType T>
738
    // T* unpack() {
739
    //     static_assert(is_pod_v<T>, "T must be a POD type");
740
    //     return reinterpret_cast<T*>(payload);
741
    // }
742
743
    int128_t int_val() const;
744
};
745
746
// inline ObjectVal* JsonbDocument::operator->() {
747
//     return (((JsonbValue*)payload_)->unpack<ObjectVal>());
748
// }
749
750
131k
inline const ObjectVal* JsonbDocument::operator->() const {
751
131k
    return (((const JsonbValue*)payload_)->unpack<ObjectVal>());
752
131k
}
753
754
/*
755
 * NumerValT is the template class (derived from JsonbValue) of all number
756
 * types (integers and double).
757
 */
758
template <typename T>
759
    requires std::is_integral_v<T> || std::is_floating_point_v<T>
760
struct NumberValT {
761
public:
762
328k
    T val() const { return num; }
_ZNK5doris10NumberValTIaE3valEv
Line
Count
Source
762
31.9k
    T val() const { return num; }
_ZNK5doris10NumberValTIsE3valEv
Line
Count
Source
762
42.4k
    T val() const { return num; }
_ZNK5doris10NumberValTIiE3valEv
Line
Count
Source
762
16.9k
    T val() const { return num; }
_ZNK5doris10NumberValTIlE3valEv
Line
Count
Source
762
201k
    T val() const { return num; }
_ZNK5doris10NumberValTInE3valEv
Line
Count
Source
762
18.7k
    T val() const { return num; }
_ZNK5doris10NumberValTIdE3valEv
Line
Count
Source
762
11.9k
    T val() const { return num; }
_ZNK5doris10NumberValTIfE3valEv
Line
Count
Source
762
4.61k
    T val() const { return num; }
763
764
    static unsigned int numPackedBytes() { return sizeof(JsonbValue) + sizeof(T); }
765
766
    T num;
767
};
768
769
165
inline int128_t JsonbValue::int_val() const {
770
165
    switch (type) {
771
121
    case JsonbType::T_Int8:
772
121
        return unpack<JsonbInt8Val>()->val();
773
39
    case JsonbType::T_Int16:
774
39
        return unpack<JsonbInt16Val>()->val();
775
0
    case JsonbType::T_Int32:
776
0
        return unpack<JsonbInt32Val>()->val();
777
3
    case JsonbType::T_Int64:
778
3
        return unpack<JsonbInt64Val>()->val();
779
2
    case JsonbType::T_Int128:
780
2
        return unpack<JsonbInt128Val>()->val();
781
0
    default:
782
0
        throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
783
0
                        static_cast<int32_t>(type));
784
165
    }
785
165
}
786
787
template <JsonbDecimalType T>
788
struct JsonbDecimalVal {
789
public:
790
    using NativeType = typename T::NativeType;
791
792
    // get the decimal value
793
111
    NativeType val() const {
794
        // to avoid memory alignment issues, we use memcpy to copy the value
795
111
        NativeType tmp;
796
111
        memcpy(&tmp, &value, sizeof(NativeType));
797
111
        return tmp;
798
111
    }
_ZNK5doris15JsonbDecimalValINS_7DecimalIiEEE3valEv
Line
Count
Source
793
38
    NativeType val() const {
794
        // to avoid memory alignment issues, we use memcpy to copy the value
795
38
        NativeType tmp;
796
38
        memcpy(&tmp, &value, sizeof(NativeType));
797
38
        return tmp;
798
38
    }
_ZNK5doris15JsonbDecimalValINS_7DecimalIlEEE3valEv
Line
Count
Source
793
36
    NativeType val() const {
794
        // to avoid memory alignment issues, we use memcpy to copy the value
795
36
        NativeType tmp;
796
36
        memcpy(&tmp, &value, sizeof(NativeType));
797
36
        return tmp;
798
36
    }
_ZNK5doris15JsonbDecimalValINS_12Decimal128V3EE3valEv
Line
Count
Source
793
31
    NativeType val() const {
794
        // to avoid memory alignment issues, we use memcpy to copy the value
795
31
        NativeType tmp;
796
31
        memcpy(&tmp, &value, sizeof(NativeType));
797
31
        return tmp;
798
31
    }
_ZNK5doris15JsonbDecimalValINS_7DecimalIN4wide7integerILm256EiEEEEE3valEv
Line
Count
Source
793
6
    NativeType val() const {
794
        // to avoid memory alignment issues, we use memcpy to copy the value
795
6
        NativeType tmp;
796
6
        memcpy(&tmp, &value, sizeof(NativeType));
797
6
        return tmp;
798
6
    }
799
800
140
    static constexpr int numPackedBytes() {
801
140
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
802
140
    }
_ZN5doris15JsonbDecimalValINS_7DecimalIiEEE14numPackedBytesEv
Line
Count
Source
800
39
    static constexpr int numPackedBytes() {
801
39
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
802
39
    }
_ZN5doris15JsonbDecimalValINS_7DecimalIlEEE14numPackedBytesEv
Line
Count
Source
800
61
    static constexpr int numPackedBytes() {
801
61
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
802
61
    }
_ZN5doris15JsonbDecimalValINS_12Decimal128V3EE14numPackedBytesEv
Line
Count
Source
800
34
    static constexpr int numPackedBytes() {
801
34
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
802
34
    }
_ZN5doris15JsonbDecimalValINS_7DecimalIN4wide7integerILm256EiEEEEE14numPackedBytesEv
Line
Count
Source
800
6
    static constexpr int numPackedBytes() {
801
6
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
802
6
    }
803
804
    uint32_t precision;
805
    uint32_t scale;
806
    NativeType value;
807
};
808
809
/*
810
 * BlobVal is the base class (derived from JsonbValue) for string and binary
811
 * types. The size indicates the total bytes of the payload.
812
 */
813
struct JsonbBinaryVal {
814
public:
815
    // size of the blob payload only
816
17.2k
    unsigned int getBlobLen() const { return size; }
817
818
    // return the blob as byte array
819
264k
    const char* getBlob() const { return payload; }
820
821
    // size of the total packed bytes
822
311k
    unsigned int numPackedBytes() const { return sizeof(JsonbValue) + sizeof(size) + size; }
823
    friend class JsonbDocument;
824
825
    uint32_t size;
826
    char payload[0];
827
};
828
829
/*
830
 * String type
831
 * Note: JSONB string may not be a c-string (NULL-terminated)
832
 */
833
struct JsonbStringVal : public JsonbBinaryVal {
834
public:
835
    /*
836
    This function return the actual size of a string. Since for
837
    a string, it can be null-terminated with null paddings or it
838
    can take all the space in the payload without null in the end.
839
    So we need to check it to get the true actual length of a string.
840
  */
841
239k
    size_t length() const {
842
        // It's an empty string
843
239k
        if (0 == size) {
844
147
            return size;
845
147
        }
846
        // The string stored takes all the spaces in payload
847
239k
        if (payload[size - 1] != 0) {
848
239k
            return size;
849
239k
        }
850
        // It's shorter than the size of payload
851
0
        return strnlen(payload, size);
852
239k
    }
853
};
854
855
/*
856
 * ContainerVal is the base class (derived from JsonbValue) for object and
857
 * array types. The size indicates the total bytes of the payload.
858
 */
859
struct ContainerVal {
860
    // size of the container payload only
861
0
    unsigned int getContainerSize() const { return size; }
862
863
    // return the container payload as byte array
864
0
    const char* getPayload() const { return payload; }
865
866
    // size of the total packed bytes
867
1.08M
    unsigned int numPackedBytes() const { return sizeof(JsonbValue) + sizeof(size) + size; }
868
    friend class JsonbDocument;
869
870
    uint32_t size;
871
    char payload[0];
872
};
873
874
/*
875
 * Object type
876
 */
877
struct ObjectVal : public ContainerVal {
878
    using value_type = JsonbKeyValue;
879
    using pointer = value_type*;
880
    using const_pointer = const value_type*;
881
    using const_iterator = JsonbFwdIteratorT<const_pointer, ObjectVal>;
882
883
    const_iterator search(const char* key) const {
884
        if (!key) {
885
            return end();
886
        }
887
        return search(key, (unsigned int)strlen(key));
888
    }
889
890
7.41k
    const_iterator search(const char* key, unsigned int klen) const {
891
7.41k
        if (!key || !klen) {
892
0
            return end();
893
0
        }
894
7.41k
        return internalSearch(key, klen);
895
7.41k
    }
896
897
    // Get number of elements in object
898
174
    int numElem() const {
899
174
        const char* pch = payload;
900
174
        const char* fence = payload + size;
901
902
174
        unsigned int num = 0;
903
449
        while (pch < fence) {
904
275
            auto* pkey = (JsonbKeyValue*)(pch);
905
275
            ++num;
906
275
            pch += pkey->numPackedBytes();
907
275
        }
908
909
174
        assert(pch == fence);
910
911
174
        return num;
912
174
    }
913
914
    // find the JSONB value by a key string (null terminated)
915
    const JsonbValue* find(const char* key) const {
916
        if (!key) {
917
            return nullptr;
918
        }
919
        return find(key, (unsigned int)strlen(key));
920
    }
921
922
    // find the JSONB value by a key string (with length)
923
7.40k
    const JsonbValue* find(const char* key, unsigned int klen) const {
924
7.40k
        const_iterator kv = search(key, klen);
925
7.40k
        if (end() == kv) {
926
4.45k
            return nullptr;
927
4.45k
        }
928
2.95k
        return kv->value();
929
7.40k
    }
930
931
118k
    const_iterator begin() const { return const_iterator((pointer)payload); }
932
933
248k
    const_iterator end() const { return const_iterator((pointer)(payload + size)); }
934
935
    std::vector<std::pair<StringRef, const JsonbValue*>> get_ordered_key_value_pairs() const;
936
937
private:
938
7.41k
    const_iterator internalSearch(const char* key, unsigned int klen) const {
939
7.41k
        const char* pch = payload;
940
7.41k
        const char* fence = payload + size;
941
942
19.3k
        while (pch < fence) {
943
14.8k
            const auto* pkey = (const JsonbKeyValue*)(pch);
944
14.8k
            if (klen == pkey->klen() && strncmp(key, pkey->getKeyStr(), klen) == 0) {
945
2.95k
                return const_iterator(pkey);
946
2.95k
            }
947
11.9k
            pch += pkey->numPackedBytes();
948
11.9k
        }
949
950
7.41k
        assert(pch == fence);
951
952
4.45k
        return end();
953
4.45k
    }
954
};
955
956
/*
957
 * Array type
958
 */
959
struct ArrayVal : public ContainerVal {
960
    using value_type = JsonbValue;
961
    using pointer = value_type*;
962
    using const_pointer = const value_type*;
963
    using const_iterator = JsonbFwdIteratorT<const_pointer, ArrayVal>;
964
965
    // get the JSONB value at index
966
190k
    const JsonbValue* get(int idx) const {
967
190k
        if (idx < 0) {
968
65
            return nullptr;
969
65
        }
970
971
189k
        const char* pch = payload;
972
189k
        const char* fence = payload + size;
973
974
196k
        while (pch < fence && idx-- > 0) {
975
6.79k
            pch += ((const JsonbValue*)pch)->numPackedBytes();
976
6.79k
        }
977
189k
        if (idx > 0 || pch == fence) {
978
1.65k
            return nullptr;
979
1.65k
        }
980
981
188k
        return (const JsonbValue*)pch;
982
189k
    }
983
984
    // Get number of elements in array
985
1.86k
    int numElem() const {
986
1.86k
        const char* pch = payload;
987
1.86k
        const char* fence = payload + size;
988
989
1.86k
        unsigned int num = 0;
990
110k
        while (pch < fence) {
991
108k
            ++num;
992
108k
            pch += ((const JsonbValue*)pch)->numPackedBytes();
993
108k
        }
994
995
1.86k
        assert(pch == fence);
996
997
1.86k
        return num;
998
1.86k
    }
999
1000
168k
    const_iterator begin() const { return const_iterator((pointer)payload); }
1001
1002
169k
    const_iterator end() const { return const_iterator((pointer)(payload + size)); }
1003
};
1004
1005
namespace jsonb_detail {
1006
1007
59
inline bool array_contains_value(const ArrayVal* target_array, const JsonbValue* candidate) {
1008
59
    const int target_num = target_array->numElem();
1009
158
    for (int i = 0; i < target_num; ++i) {
1010
125
        if (target_array->get(i)->contains(candidate)) {
1011
26
            return true;
1012
26
        }
1013
125
    }
1014
33
    return false;
1015
59
}
1016
1017
18
inline bool array_contains_array(const ArrayVal* target_array, const ArrayVal* candidate_array) {
1018
18
    const int candidate_num = candidate_array->numElem();
1019
33
    for (int i = 0; i < candidate_num; ++i) {
1020
25
        if (!array_contains_value(target_array, candidate_array->get(i))) {
1021
10
            return false;
1022
10
        }
1023
25
    }
1024
8
    return true;
1025
18
}
1026
1027
} // namespace jsonb_detail
1028
1029
inline const JsonbValue* JsonbDocument::createValue(const char* pb, size_t size) {
1030
    if (!pb || size < sizeof(JsonbHeader) + sizeof(JsonbValue)) {
1031
        return nullptr;
1032
    }
1033
1034
    auto* doc = (JsonbDocument*)pb;
1035
    if (doc->header_.ver_ != JSONB_VER) {
1036
        return nullptr;
1037
    }
1038
1039
    const auto* val = (const JsonbValue*)doc->payload_;
1040
    if (size != sizeof(JsonbHeader) + val->numPackedBytes()) {
1041
        return nullptr;
1042
    }
1043
1044
    return val;
1045
}
1046
1047
124
inline unsigned int JsonbDocument::numPackedBytes() const {
1048
124
    return ((const JsonbValue*)payload_)->numPackedBytes() + sizeof(header_);
1049
124
}
1050
1051
458k
inline unsigned int JsonbKeyValue::numPackedBytes() const {
1052
458k
    unsigned int ks = keyPackedBytes();
1053
458k
    const auto* val = (const JsonbValue*)(((char*)this) + ks);
1054
458k
    return ks + val->numPackedBytes();
1055
458k
}
1056
1057
// Poor man's "virtual" function JsonbValue::numPackedBytes
1058
1.97M
inline unsigned int JsonbValue::numPackedBytes() const {
1059
1.97M
    switch (type) {
1060
12.3k
    case JsonbType::T_Null:
1061
53.0k
    case JsonbType::T_True:
1062
64.1k
    case JsonbType::T_False: {
1063
64.1k
        return sizeof(type);
1064
53.0k
    }
1065
1066
41.0k
    case JsonbType::T_Int8: {
1067
41.0k
        return sizeof(type) + sizeof(int8_t);
1068
53.0k
    }
1069
47.0k
    case JsonbType::T_Int16: {
1070
47.0k
        return sizeof(type) + sizeof(int16_t);
1071
53.0k
    }
1072
20.8k
    case JsonbType::T_Int32: {
1073
20.8k
        return sizeof(type) + sizeof(int32_t);
1074
53.0k
    }
1075
352k
    case JsonbType::T_Int64: {
1076
352k
        return sizeof(type) + sizeof(int64_t);
1077
53.0k
    }
1078
25.5k
    case JsonbType::T_Double: {
1079
25.5k
        return sizeof(type) + sizeof(double);
1080
53.0k
    }
1081
4.77k
    case JsonbType::T_Float: {
1082
4.77k
        return sizeof(type) + sizeof(float);
1083
53.0k
    }
1084
31.5k
    case JsonbType::T_Int128: {
1085
31.5k
        return sizeof(type) + sizeof(int128_t);
1086
53.0k
    }
1087
287k
    case JsonbType::T_String:
1088
311k
    case JsonbType::T_Binary: {
1089
311k
        return unpack<JsonbBinaryVal>()->numPackedBytes();
1090
287k
    }
1091
1092
276k
    case JsonbType::T_Object:
1093
1.08M
    case JsonbType::T_Array: {
1094
1.08M
        return unpack<ContainerVal>()->numPackedBytes();
1095
276k
    }
1096
39
    case JsonbType::T_Decimal32: {
1097
39
        return JsonbDecimal32::numPackedBytes();
1098
276k
    }
1099
61
    case JsonbType::T_Decimal64: {
1100
61
        return JsonbDecimal64::numPackedBytes();
1101
276k
    }
1102
34
    case JsonbType::T_Decimal128: {
1103
34
        return JsonbDecimal128::numPackedBytes();
1104
276k
    }
1105
6
    case JsonbType::T_Decimal256: {
1106
6
        return JsonbDecimal256::numPackedBytes();
1107
276k
    }
1108
0
    case JsonbType::NUM_TYPES:
1109
0
        break;
1110
1.97M
    }
1111
1112
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1113
0
                    static_cast<int32_t>(type));
1114
1.97M
}
1115
1116
782
inline int JsonbValue::numElements() const {
1117
782
    switch (type) {
1118
6
    case JsonbType::T_Int8:
1119
16
    case JsonbType::T_Int16:
1120
18
    case JsonbType::T_Int32:
1121
21
    case JsonbType::T_Int64:
1122
23
    case JsonbType::T_Double:
1123
23
    case JsonbType::T_Float:
1124
25
    case JsonbType::T_Int128:
1125
32
    case JsonbType::T_String:
1126
32
    case JsonbType::T_Binary:
1127
37
    case JsonbType::T_Null:
1128
43
    case JsonbType::T_True:
1129
45
    case JsonbType::T_False:
1130
45
    case JsonbType::T_Decimal32:
1131
45
    case JsonbType::T_Decimal64:
1132
45
    case JsonbType::T_Decimal128:
1133
45
    case JsonbType::T_Decimal256: {
1134
45
        return 1;
1135
45
    }
1136
27
    case JsonbType::T_Object: {
1137
27
        return unpack<ObjectVal>()->numElem();
1138
45
    }
1139
710
    case JsonbType::T_Array: {
1140
710
        return unpack<ArrayVal>()->numElem();
1141
45
    }
1142
0
    case JsonbType::NUM_TYPES:
1143
0
        break;
1144
782
    }
1145
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1146
0
                    static_cast<int32_t>(type));
1147
782
}
1148
1149
361
inline bool JsonbValue::contains(const JsonbValue* rhs) const {
1150
361
    switch (type) {
1151
86
    case JsonbType::T_Int8:
1152
114
    case JsonbType::T_Int16:
1153
120
    case JsonbType::T_Int32:
1154
129
    case JsonbType::T_Int64:
1155
135
    case JsonbType::T_Int128: {
1156
135
        return rhs->isInt() && this->int_val() == rhs->int_val();
1157
129
    }
1158
18
    case JsonbType::T_Double:
1159
18
    case JsonbType::T_Float: {
1160
18
        if (!rhs->isDouble() && !rhs->isFloat()) {
1161
16
            return false;
1162
16
        }
1163
2
        double left = isDouble() ? unpack<JsonbDoubleVal>()->val() : unpack<JsonbFloatVal>()->val();
1164
2
        double right = rhs->isDouble() ? rhs->unpack<JsonbDoubleVal>()->val()
1165
2
                                       : rhs->unpack<JsonbFloatVal>()->val();
1166
2
        return left == right;
1167
18
    }
1168
43
    case JsonbType::T_String:
1169
43
    case JsonbType::T_Binary: {
1170
43
        if (rhs->isString() || rhs->isBinary()) {
1171
15
            const auto* str_value1 = unpack<JsonbStringVal>();
1172
15
            const auto* str_value2 = rhs->unpack<JsonbStringVal>();
1173
15
            return str_value1->length() == str_value2->length() &&
1174
15
                   std::memcmp(str_value1->getBlob(), str_value2->getBlob(),
1175
14
                               str_value1->length()) == 0;
1176
15
        }
1177
28
        return false;
1178
43
    }
1179
52
    case JsonbType::T_Array: {
1180
52
        const auto* lhs_array = unpack<ArrayVal>();
1181
52
        if (rhs->isArray()) {
1182
18
            return jsonb_detail::array_contains_array(lhs_array, rhs->unpack<ArrayVal>());
1183
18
        }
1184
34
        return jsonb_detail::array_contains_value(lhs_array, rhs);
1185
52
    }
1186
79
    case JsonbType::T_Object: {
1187
79
        if (rhs->isObject()) {
1188
46
            const auto* obj_value1 = unpack<ObjectVal>();
1189
46
            const auto* obj_value2 = rhs->unpack<ObjectVal>();
1190
87
            for (auto it = obj_value2->begin(); it != obj_value2->end(); ++it) {
1191
62
                const JsonbValue* value = obj_value1->find(it->getKeyStr(), it->klen());
1192
62
                if (value == nullptr || !value->contains(it->value())) {
1193
21
                    return false;
1194
21
                }
1195
62
            }
1196
25
            return true;
1197
46
        }
1198
33
        return false;
1199
79
    }
1200
12
    case JsonbType::T_Null: {
1201
12
        return rhs->isNull();
1202
79
    }
1203
12
    case JsonbType::T_True: {
1204
12
        return rhs->isTrue();
1205
79
    }
1206
10
    case JsonbType::T_False: {
1207
10
        return rhs->isFalse();
1208
79
    }
1209
0
    case JsonbType::T_Decimal32: {
1210
0
        if (rhs->isDecimal32()) {
1211
0
            return unpack<JsonbDecimal32>()->val() == rhs->unpack<JsonbDecimal32>()->val() &&
1212
0
                   unpack<JsonbDecimal32>()->precision ==
1213
0
                           rhs->unpack<JsonbDecimal32>()->precision &&
1214
0
                   unpack<JsonbDecimal32>()->scale == rhs->unpack<JsonbDecimal32>()->scale;
1215
0
        }
1216
0
        return false;
1217
0
    }
1218
0
    case JsonbType::T_Decimal64: {
1219
0
        if (rhs->isDecimal64()) {
1220
0
            return unpack<JsonbDecimal64>()->val() == rhs->unpack<JsonbDecimal64>()->val() &&
1221
0
                   unpack<JsonbDecimal64>()->precision ==
1222
0
                           rhs->unpack<JsonbDecimal64>()->precision &&
1223
0
                   unpack<JsonbDecimal64>()->scale == rhs->unpack<JsonbDecimal64>()->scale;
1224
0
        }
1225
0
        return false;
1226
0
    }
1227
0
    case JsonbType::T_Decimal128: {
1228
0
        if (rhs->isDecimal128()) {
1229
0
            return unpack<JsonbDecimal128>()->val() == rhs->unpack<JsonbDecimal128>()->val() &&
1230
0
                   unpack<JsonbDecimal128>()->precision ==
1231
0
                           rhs->unpack<JsonbDecimal128>()->precision &&
1232
0
                   unpack<JsonbDecimal128>()->scale == rhs->unpack<JsonbDecimal128>()->scale;
1233
0
        }
1234
0
        return false;
1235
0
    }
1236
0
    case JsonbType::T_Decimal256: {
1237
0
        if (rhs->isDecimal256()) {
1238
0
            return unpack<JsonbDecimal256>()->val() == rhs->unpack<JsonbDecimal256>()->val() &&
1239
0
                   unpack<JsonbDecimal256>()->precision ==
1240
0
                           rhs->unpack<JsonbDecimal256>()->precision &&
1241
0
                   unpack<JsonbDecimal256>()->scale == rhs->unpack<JsonbDecimal256>()->scale;
1242
0
        }
1243
0
        return false;
1244
0
    }
1245
0
    case JsonbType::NUM_TYPES:
1246
0
        break;
1247
361
    }
1248
1249
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1250
0
                    static_cast<int32_t>(type));
1251
361
}
1252
1253
15.6k
inline bool JsonbPath::seek(const char* key_path, size_t kp_len) {
1254
15.6k
    while (kp_len > 0 && std::isspace(key_path[kp_len - 1])) {
1255
7
        --kp_len;
1256
7
    }
1257
1258
    //path invalid
1259
15.6k
    if (!key_path || kp_len == 0) {
1260
2
        return false;
1261
2
    }
1262
15.6k
    Stream stream(key_path, kp_len);
1263
15.6k
    stream.skip_whitespace();
1264
15.6k
    if (stream.exhausted() || stream.read() != SCOPE) {
1265
        //path invalid
1266
4
        return false;
1267
4
    }
1268
1269
36.7k
    while (!stream.exhausted()) {
1270
21.0k
        stream.skip_whitespace();
1271
21.0k
        stream.clear_leg_ptr();
1272
21.0k
        stream.clear_leg_len();
1273
1274
21.0k
        if (!JsonbPath::parsePath(&stream, this)) {
1275
            //path invalid
1276
20
            return false;
1277
20
        }
1278
21.0k
    }
1279
15.6k
    return true;
1280
15.6k
}
1281
1282
21.0k
inline bool JsonbPath::parsePath(Stream* stream, JsonbPath* path) {
1283
    // $[0]
1284
21.0k
    if (stream->peek() == BEGIN_ARRAY) {
1285
11.0k
        return parse_array(stream, path);
1286
11.0k
    }
1287
    // $.a or $.[0]
1288
    // Keep $.[0] for backward compatibility: although the dot before an array
1289
    // leg is non-standard, existing JSONB users may rely on it.
1290
10.0k
    else if (stream->peek() == BEGIN_MEMBER) {
1291
        // advance past the .
1292
10.0k
        stream->skip(1);
1293
1294
10.0k
        if (stream->exhausted()) {
1295
16
            return false;
1296
16
        }
1297
1298
        // $.[0]
1299
9.99k
        if (stream->peek() == BEGIN_ARRAY) {
1300
205
            return parse_array(stream, path);
1301
205
        }
1302
        // $.a
1303
9.78k
        else {
1304
9.78k
            return parse_member(stream, path);
1305
9.78k
        }
1306
9.99k
    } else if (stream->peek() == WILDCARD) {
1307
13
        stream->skip(1);
1308
13
        if (stream->exhausted()) {
1309
0
            return false;
1310
0
        }
1311
1312
        // $**
1313
13
        if (stream->peek() == WILDCARD) {
1314
13
            path->_is_supper_wildcard = true;
1315
13
        }
1316
1317
13
        stream->skip(1);
1318
13
        if (stream->exhausted()) {
1319
2
            return false;
1320
2
        }
1321
1322
11
        if (stream->peek() == BEGIN_ARRAY) {
1323
2
            return parse_array(stream, path);
1324
9
        } else if (stream->peek() == BEGIN_MEMBER) {
1325
            // advance past the .
1326
9
            stream->skip(1);
1327
1328
9
            if (stream->exhausted()) {
1329
0
                return false;
1330
0
            }
1331
1332
            // $**.[0]
1333
            // Keep the dot-array form compatible with the root path behavior.
1334
9
            if (stream->peek() == BEGIN_ARRAY) {
1335
0
                return parse_array(stream, path);
1336
0
            }
1337
            // $.a
1338
9
            else {
1339
9
                return parse_member(stream, path);
1340
9
            }
1341
9
        }
1342
0
        return false;
1343
11
    } else {
1344
0
        return false; //invalid json path
1345
0
    }
1346
21.0k
}
1347
1348
11.2k
inline bool JsonbPath::parse_array(Stream* stream, JsonbPath* path) {
1349
11.2k
    assert(stream->peek() == BEGIN_ARRAY);
1350
11.2k
    stream->skip(1);
1351
11.2k
    if (stream->exhausted()) {
1352
0
        return false;
1353
0
    }
1354
1355
11.2k
    if (stream->peek() == WILDCARD) {
1356
        // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1357
        // using const_cast is acceptable.
1358
20
        stream->set_leg_ptr(const_cast<char*>(stream->position()));
1359
20
        stream->add_leg_len();
1360
20
        stream->skip(1);
1361
20
        if (stream->exhausted()) {
1362
0
            return false;
1363
0
        }
1364
1365
20
        if (stream->peek() == END_ARRAY) {
1366
20
            std::unique_ptr<leg_info> leg(
1367
20
                    new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, ARRAY_CODE));
1368
20
            path->add_leg_to_leg_vector(std::move(leg));
1369
20
            stream->skip(1);
1370
20
            path->_is_wildcard = true;
1371
20
            return true;
1372
20
        } else {
1373
0
            return false;
1374
0
        }
1375
20
    }
1376
1377
    // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1378
    // using const_cast is acceptable.
1379
11.2k
    stream->set_leg_ptr(const_cast<char*>(stream->position()));
1380
1381
32.9k
    for (; !stream->exhausted() && stream->peek() != END_ARRAY; stream->advance()) {
1382
21.7k
        stream->add_leg_len();
1383
21.7k
    }
1384
1385
11.2k
    if (stream->exhausted() || stream->peek() != END_ARRAY) {
1386
0
        return false;
1387
11.2k
    } else {
1388
11.2k
        stream->skip(1);
1389
11.2k
    }
1390
1391
    //parse array index to int
1392
1393
11.2k
    std::string_view idx_string(stream->get_leg_ptr(), stream->get_leg_len());
1394
11.2k
    int index = 0;
1395
1396
    // Match "last" case-insensitively for compatibility with existing JSONB
1397
    // paths such as [Last] and [LAST].
1398
11.2k
    if (stream->get_leg_len() >= 4 &&
1399
11.2k
        std::equal(LAST, LAST + 4, stream->get_leg_ptr(),
1400
6.71k
                   [](char c1, char c2) { return std::tolower(c1) == std::tolower(c2); })) {
1401
1.67k
        auto pos = idx_string.find(MINUS);
1402
1403
1.67k
        if (pos != std::string::npos) {
1404
1.34k
            for (size_t i = 4; i < pos; ++i) {
1405
6
                if (std::isspace(idx_string[i])) {
1406
4
                    continue;
1407
4
                } else {
1408
                    // leading zeroes are not allowed
1409
2
                    LOG(WARNING) << "Non-space char in idx_string: '" << idx_string << "'";
1410
2
                    return false;
1411
2
                }
1412
6
            }
1413
1.33k
            idx_string = idx_string.substr(pos + 1);
1414
1.33k
            idx_string = trim(idx_string);
1415
1416
            // Keep numeric-prefix parsing for last-N offsets as existing JSONB
1417
            // path behavior.
1418
1.33k
            auto result = std::from_chars(idx_string.data(), idx_string.data() + idx_string.size(),
1419
1.33k
                                          index);
1420
1.33k
            if (result.ec != std::errc()) {
1421
0
                LOG(WARNING) << "Invalid index in JSON path: '" << idx_string << "'";
1422
0
                return false;
1423
0
            }
1424
1425
1.33k
        } else if (stream->get_leg_len() > 4) {
1426
0
            return false;
1427
0
        }
1428
1429
1.67k
        std::unique_ptr<leg_info> leg(new leg_info(nullptr, 0, -index - 1, ARRAY_CODE));
1430
1.67k
        path->add_leg_to_leg_vector(std::move(leg));
1431
1432
1.67k
        return true;
1433
1.67k
    }
1434
1435
    // Preserve legacy numeric-prefix parsing for array indexes. std::from_chars
1436
    // may stop before the end (for example [1.5] is parsed as index 1), and
1437
    // current JSONB path semantics treat that as supported behavior.
1438
9.57k
    auto result = std::from_chars(idx_string.data(), idx_string.data() + idx_string.size(), index);
1439
1440
9.57k
    if (result.ec != std::errc()) {
1441
0
        return false;
1442
0
    }
1443
1444
9.57k
    std::unique_ptr<leg_info> leg(new leg_info(nullptr, 0, index, ARRAY_CODE));
1445
9.57k
    path->add_leg_to_leg_vector(std::move(leg));
1446
1447
9.57k
    return true;
1448
9.57k
}
1449
1450
9.79k
inline bool JsonbPath::parse_member(Stream* stream, JsonbPath* path) {
1451
9.79k
    if (stream->exhausted()) {
1452
0
        return false;
1453
0
    }
1454
1455
9.79k
    if (stream->peek() == WILDCARD) {
1456
        // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1457
        // using const_cast is acceptable.
1458
116
        stream->set_leg_ptr(const_cast<char*>(stream->position()));
1459
116
        stream->add_leg_len();
1460
116
        stream->skip(1);
1461
116
        std::unique_ptr<leg_info> leg(
1462
116
                new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, MEMBER_CODE));
1463
116
        path->add_leg_to_leg_vector(std::move(leg));
1464
116
        path->_is_wildcard = true;
1465
116
        return true;
1466
116
    }
1467
1468
    // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1469
    // using const_cast is acceptable.
1470
9.68k
    stream->set_leg_ptr(const_cast<char*>(stream->position()));
1471
1472
9.68k
    const char* left_quotation_marks = nullptr;
1473
9.68k
    const char* right_quotation_marks = nullptr;
1474
1475
32.5k
    for (; !stream->exhausted(); stream->advance()) {
1476
        // Only accept space characters quoted by double quotes.
1477
29.8k
        if (std::isspace(stream->peek()) && left_quotation_marks == nullptr) {
1478
0
            return false;
1479
29.8k
        } else if (stream->peek() == ESCAPE) {
1480
3
            stream->add_leg_len();
1481
3
            stream->skip(1);
1482
3
            stream->add_leg_len();
1483
3
            stream->set_has_escapes(true);
1484
3
            if (stream->exhausted()) {
1485
0
                return false;
1486
0
            }
1487
3
            continue;
1488
29.8k
        } else if (stream->peek() == DOUBLE_QUOTE) {
1489
378
            if (left_quotation_marks == nullptr) {
1490
189
                left_quotation_marks = stream->position();
1491
                // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1492
                // using const_cast is acceptable.
1493
189
                stream->set_leg_ptr(const_cast<char*>(++left_quotation_marks));
1494
189
                continue;
1495
189
            } else {
1496
189
                right_quotation_marks = stream->position();
1497
189
                stream->skip(1);
1498
189
                break;
1499
189
            }
1500
29.4k
        } else if (stream->peek() == BEGIN_MEMBER || stream->peek() == BEGIN_ARRAY) {
1501
7.06k
            if (left_quotation_marks == nullptr) {
1502
6.75k
                break;
1503
6.75k
            }
1504
7.06k
        }
1505
1506
22.7k
        stream->add_leg_len();
1507
22.7k
    }
1508
1509
9.68k
    if ((left_quotation_marks != nullptr && right_quotation_marks == nullptr) ||
1510
9.68k
        stream->get_leg_ptr() == nullptr || stream->get_leg_len() == 0) {
1511
0
        return false; //invalid json path
1512
0
    }
1513
1514
9.68k
    if (stream->get_has_escapes()) {
1515
3
        stream->remove_escapes();
1516
3
    }
1517
1518
9.68k
    std::unique_ptr<leg_info> leg(
1519
9.68k
            new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, MEMBER_CODE));
1520
9.68k
    path->add_leg_to_leg_vector(std::move(leg));
1521
1522
9.68k
    return true;
1523
9.68k
}
1524
1525
static_assert(is_pod_v<JsonbDocument>, "JsonbDocument must be standard layout and trivial");
1526
static_assert(is_pod_v<JsonbValue>, "JsonbValue must be standard layout and trivial");
1527
static_assert(is_pod_v<JsonbDecimal32>, "JsonbDecimal32 must be standard layout and trivial");
1528
static_assert(is_pod_v<JsonbDecimal64>, "JsonbDecimal64 must be standard layout and trivial");
1529
static_assert(is_pod_v<JsonbDecimal128>, "JsonbDecimal128 must be standard layout and trivial");
1530
static_assert(is_pod_v<JsonbDecimal256>, "JsonbDecimal256 must be standard layout and trivial");
1531
static_assert(is_pod_v<JsonbInt8Val>, "JsonbInt8Val must be standard layout and trivial");
1532
static_assert(is_pod_v<JsonbInt32Val>, "JsonbInt32Val must be standard layout and trivial");
1533
static_assert(is_pod_v<JsonbInt64Val>, "JsonbInt64Val must be standard layout and trivial");
1534
static_assert(is_pod_v<JsonbInt128Val>, "JsonbInt128Val must be standard layout and trivial");
1535
static_assert(is_pod_v<JsonbDoubleVal>, "JsonbDoubleVal must be standard layout and trivial");
1536
static_assert(is_pod_v<JsonbFloatVal>, "JsonbFloatVal must be standard layout and trivial");
1537
static_assert(is_pod_v<JsonbBinaryVal>, "JsonbBinaryVal must be standard layout and trivial");
1538
static_assert(is_pod_v<ContainerVal>, "ContainerVal must be standard layout and trivial");
1539
1540
#define ASSERT_DECIMAL_LAYOUT(type)                \
1541
    static_assert(offsetof(type, precision) == 0); \
1542
    static_assert(offsetof(type, scale) == 4);     \
1543
    static_assert(offsetof(type, value) == 8);
1544
1545
ASSERT_DECIMAL_LAYOUT(JsonbDecimal32)
1546
ASSERT_DECIMAL_LAYOUT(JsonbDecimal64)
1547
ASSERT_DECIMAL_LAYOUT(JsonbDecimal128)
1548
ASSERT_DECIMAL_LAYOUT(JsonbDecimal256)
1549
1550
#define ASSERT_NUMERIC_LAYOUT(type) static_assert(offsetof(type, num) == 0);
1551
1552
ASSERT_NUMERIC_LAYOUT(JsonbInt8Val)
1553
ASSERT_NUMERIC_LAYOUT(JsonbInt32Val)
1554
ASSERT_NUMERIC_LAYOUT(JsonbInt64Val)
1555
ASSERT_NUMERIC_LAYOUT(JsonbInt128Val)
1556
ASSERT_NUMERIC_LAYOUT(JsonbDoubleVal)
1557
1558
static_assert(offsetof(JsonbBinaryVal, size) == 0);
1559
static_assert(offsetof(JsonbBinaryVal, payload) == 4);
1560
1561
static_assert(offsetof(ContainerVal, size) == 0);
1562
static_assert(offsetof(ContainerVal, payload) == 4);
1563
1564
#pragma pack(pop)
1565
#if defined(__clang__)
1566
#pragma clang diagnostic pop
1567
#endif
1568
} // namespace doris
1569
1570
#endif // JSONB_JSONBDOCUMENT_H