Coverage Report

Created: 2026-03-14 13:33

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.72M
#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
14.9k
    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
471k
    size_t remaining() const {
270
471k
        assert(m_position <= m_end);
271
471k
        return m_end - m_position;
272
471k
    }
273
274
    /// Tells if the stream has been exhausted.
275
438k
    bool exhausted() const { return remaining() == 0; }
276
277
    /// Reads the next byte from the stream and moves the position forward.
278
14.9k
    char read() {
279
14.9k
        assert(!exhausted());
280
14.9k
        return *m_position++;
281
14.9k
    }
282
283
    /// Reads the next byte from the stream without moving the position forward.
284
264k
    char peek() const {
285
264k
        assert(!exhausted());
286
264k
        return *m_position;
287
264k
    }
288
289
    /// Moves the position to the next non-whitespace character.
290
68.7k
    void skip_whitespace() {
291
68.7k
        m_position = std::find_if_not(m_position, m_end, [](char c) { return std::isspace(c); });
292
68.7k
    }
293
294
    /// Moves the position n bytes forward.
295
32.8k
    void skip(size_t n) {
296
32.8k
        assert(remaining() >= n);
297
32.8k
        m_position += n;
298
32.8k
        skip_whitespace();
299
32.8k
    }
300
301
44.5k
    void advance() { m_position++; }
302
303
42.2k
    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.3k
    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.2k
    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.66k
    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
381k
    size_t get_leg_vector_size() const { return leg_vector.size(); }
426
427
1.16M
    leg_info* get_leg_from_leg_vector(size_t i) const { return leg_vector[i].get(); }
428
429
262
    bool is_wildcard() const { return _is_wildcard; }
430
146k
    bool is_supper_wildcard() const { return _is_supper_wildcard; }
431
432
72
    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
749k
    explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {}
_ZN5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEC2ERKS3_
Line
Count
Source
453
363k
    explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {}
_ZN5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEC2ERKS3_
Line
Count
Source
453
385k
    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.42M
    bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEeqERKS5_
Line
Count
Source
459
563k
    bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEeqERKS5_
Line
Count
Source
459
857k
    bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); }
460
461
1.11M
    bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEneERKS5_
Line
Count
Source
461
448k
    bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEneERKS5_
Line
Count
Source
461
665k
    bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); }
462
463
428k
    bool operator<(const JsonbFwdIteratorT& rhs) const { return (current_ < rhs.current_); }
464
465
    bool operator>(const JsonbFwdIteratorT& rhs) const { return !operator<(rhs); }
466
467
678k
    JsonbFwdIteratorT& operator++() {
468
678k
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
469
678k
        return *this;
470
678k
    }
_ZN5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEppEv
Line
Count
Source
467
440k
    JsonbFwdIteratorT& operator++() {
468
440k
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
469
440k
        return *this;
470
440k
    }
_ZN5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEppEv
Line
Count
Source
467
237k
    JsonbFwdIteratorT& operator++() {
468
237k
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
469
237k
        return *this;
470
237k
    }
471
472
    JsonbFwdIteratorT operator++(int) {
473
        auto tmp = *this;
474
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
475
        return tmp;
476
    }
477
478
236k
    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.02k
    reference operator*() const { return *current_; }
481
482
1.49M
    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
746k
    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
656k
    uint8_t klen() const { return size; }
582
583
    // get the key string. Note the string may not be null terminated.
584
329k
    const char* getKeyStr() const { return key.str_; }
585
586
112k
    keyid_type getKeyId() const { return key.id_; }
587
588
881k
    unsigned int keyPackedBytes() const {
589
881k
        return size ? (sizeof(size) + size) : (sizeof(size) + sizeof(keyid_type));
590
881k
    }
591
592
429k
    const JsonbValue* value() const {
593
429k
        return (const JsonbValue*)(((char*)this) + keyPackedBytes());
594
429k
    }
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
205k
    bool isNull() const { return (type == JsonbType::T_Null); }
622
344
    bool isTrue() const { return (type == JsonbType::T_True); }
623
13
    bool isFalse() const { return (type == JsonbType::T_False); }
624
401
    bool isInt() const { return isInt8() || isInt16() || isInt32() || isInt64() || isInt128(); }
625
401
    bool isInt8() const { return (type == JsonbType::T_Int8); }
626
297
    bool isInt16() const { return (type == JsonbType::T_Int16); }
627
198
    bool isInt32() const { return (type == JsonbType::T_Int32); }
628
201
    bool isInt64() const { return (type == JsonbType::T_Int64); }
629
166
    bool isDouble() const { return (type == JsonbType::T_Double); }
630
160
    bool isFloat() const { return (type == JsonbType::T_Float); }
631
46.1k
    bool isString() const { return (type == JsonbType::T_String); }
632
15.5k
    bool isBinary() const { return (type == JsonbType::T_Binary); }
633
1.73k
    bool isObject() const { return (type == JsonbType::T_Object); }
634
1.78k
    bool isArray() const { return (type == JsonbType::T_Array); }
635
196
    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
247k
    const T* unpack() const {
721
247k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
247k
        return reinterpret_cast<const T*>(payload);
723
247k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIaEEEEPKT_v
Line
Count
Source
720
30.6k
    const T* unpack() const {
721
30.6k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
30.6k
        return reinterpret_cast<const T*>(payload);
723
30.6k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIsEEEEPKT_v
Line
Count
Source
720
42.2k
    const T* unpack() const {
721
42.2k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
42.2k
        return reinterpret_cast<const T*>(payload);
723
42.2k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIiEEEEPKT_v
Line
Count
Source
720
16.8k
    const T* unpack() const {
721
16.8k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
16.8k
        return reinterpret_cast<const T*>(payload);
723
16.8k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIlEEEEPKT_v
Line
Count
Source
720
222k
    const T* unpack() const {
721
222k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
222k
        return reinterpret_cast<const T*>(payload);
723
222k
    }
_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
366k
    const T* unpack() const {
721
366k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
366k
        return reinterpret_cast<const T*>(payload);
723
366k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_12ContainerValEEEPKT_v
Line
Count
Source
720
1.02M
    const T* unpack() const {
721
1.02M
        static_assert(is_pod_v<T>, "T must be a POD type");
722
1.02M
        return reinterpret_cast<const T*>(payload);
723
1.02M
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_8ArrayValEEEPKT_v
Line
Count
Source
720
379k
    const T* unpack() const {
721
379k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
379k
        return reinterpret_cast<const T*>(payload);
723
379k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIdEEEEPKT_v
Line
Count
Source
720
12.3k
    const T* unpack() const {
721
12.3k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
12.3k
        return reinterpret_cast<const T*>(payload);
723
12.3k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIfEEEEPKT_v
Line
Count
Source
720
4.63k
    const T* unpack() const {
721
4.63k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
4.63k
        return reinterpret_cast<const T*>(payload);
723
4.63k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_14JsonbStringValEEEPKT_v
Line
Count
Source
720
471k
    const T* unpack() const {
721
471k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
471k
        return reinterpret_cast<const T*>(payload);
723
471k
    }
_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
348k
    T val() const { return num; }
_ZNK5doris10NumberValTIaE3valEv
Line
Count
Source
762
30.6k
    T val() const { return num; }
_ZNK5doris10NumberValTIsE3valEv
Line
Count
Source
762
42.2k
    T val() const { return num; }
_ZNK5doris10NumberValTIiE3valEv
Line
Count
Source
762
16.8k
    T val() const { return num; }
_ZNK5doris10NumberValTIlE3valEv
Line
Count
Source
762
223k
    T val() const { return num; }
_ZNK5doris10NumberValTInE3valEv
Line
Count
Source
762
18.7k
    T val() const { return num; }
_ZNK5doris10NumberValTIdE3valEv
Line
Count
Source
762
12.3k
    T val() const { return num; }
_ZNK5doris10NumberValTIfE3valEv
Line
Count
Source
762
4.63k
    T val() const { return num; }
763
764
    static unsigned int numPackedBytes() { return sizeof(JsonbValue) + sizeof(T); }
765
766
    T num;
767
};
768
769
145
inline int128_t JsonbValue::int_val() const {
770
145
    switch (type) {
771
93
    case JsonbType::T_Int8:
772
93
        return unpack<JsonbInt8Val>()->val();
773
47
    case JsonbType::T_Int16:
774
47
        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
145
    }
785
145
}
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
25.2k
    unsigned int getBlobLen() const { return size; }
817
818
    // return the blob as byte array
819
268k
    const char* getBlob() const { return payload; }
820
821
    // size of the total packed bytes
822
334k
    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
235k
    size_t length() const {
842
        // It's an empty string
843
235k
        if (0 == size) {
844
159
            return size;
845
159
        }
846
        // The string stored takes all the spaces in payload
847
235k
        if (payload[size - 1] != 0) {
848
235k
            return size;
849
235k
        }
850
        // It's shorter than the size of payload
851
3
        return strnlen(payload, size);
852
235k
    }
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.02M
    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.34k
    const_iterator search(const char* key, unsigned int klen) const {
891
7.34k
        if (!key || !klen) {
892
0
            return end();
893
0
        }
894
7.34k
        return internalSearch(key, klen);
895
7.34k
    }
896
897
    // Get number of elements in object
898
42
    int numElem() const {
899
42
        const char* pch = payload;
900
42
        const char* fence = payload + size;
901
902
42
        unsigned int num = 0;
903
131
        while (pch < fence) {
904
89
            auto* pkey = (JsonbKeyValue*)(pch);
905
89
            ++num;
906
89
            pch += pkey->numPackedBytes();
907
89
        }
908
909
42
        assert(pch == fence);
910
911
42
        return num;
912
42
    }
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.34k
    const JsonbValue* find(const char* key, unsigned int klen) const {
924
7.34k
        const_iterator kv = search(key, klen);
925
7.34k
        if (end() == kv) {
926
4.44k
            return nullptr;
927
4.44k
        }
928
2.89k
        return kv->value();
929
7.34k
    }
930
931
115k
    const_iterator begin() const { return const_iterator((pointer)payload); }
932
933
245k
    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.34k
    const_iterator internalSearch(const char* key, unsigned int klen) const {
939
7.34k
        const char* pch = payload;
940
7.34k
        const char* fence = payload + size;
941
942
19.4k
        while (pch < fence) {
943
14.9k
            const auto* pkey = (const JsonbKeyValue*)(pch);
944
14.9k
            if (klen == pkey->klen() && strncmp(key, pkey->getKeyStr(), klen) == 0) {
945
2.89k
                return const_iterator(pkey);
946
2.89k
            }
947
12.0k
            pch += pkey->numPackedBytes();
948
12.0k
        }
949
950
7.34k
        assert(pch == fence);
951
952
4.44k
        return end();
953
4.44k
    }
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
186k
    const JsonbValue* get(int idx) const {
967
186k
        if (idx < 0) {
968
65
            return nullptr;
969
65
        }
970
971
186k
        const char* pch = payload;
972
186k
        const char* fence = payload + size;
973
974
193k
        while (pch < fence && idx-- > 0) {
975
6.84k
            pch += ((const JsonbValue*)pch)->numPackedBytes();
976
6.84k
        }
977
187k
        if (idx > 0 || pch == fence) {
978
1.66k
            return nullptr;
979
1.66k
        }
980
981
184k
        return (const JsonbValue*)pch;
982
186k
    }
983
984
    // Get number of elements in array
985
1.20k
    int numElem() const {
986
1.20k
        const char* pch = payload;
987
1.20k
        const char* fence = payload + size;
988
989
1.20k
        unsigned int num = 0;
990
4.79k
        while (pch < fence) {
991
3.59k
            ++num;
992
3.59k
            pch += ((const JsonbValue*)pch)->numPackedBytes();
993
3.59k
        }
994
995
1.20k
        assert(pch == fence);
996
997
1.20k
        return num;
998
1.20k
    }
999
1000
192k
    const_iterator begin() const { return const_iterator((pointer)payload); }
1001
1002
192k
    const_iterator end() const { return const_iterator((pointer)(payload + size)); }
1003
};
1004
1005
inline const JsonbValue* JsonbDocument::createValue(const char* pb, size_t size) {
1006
    if (!pb || size < sizeof(JsonbHeader) + sizeof(JsonbValue)) {
1007
        return nullptr;
1008
    }
1009
1010
    auto* doc = (JsonbDocument*)pb;
1011
    if (doc->header_.ver_ != JSONB_VER) {
1012
        return nullptr;
1013
    }
1014
1015
    const auto* val = (const JsonbValue*)doc->payload_;
1016
    if (size != sizeof(JsonbHeader) + val->numPackedBytes()) {
1017
        return nullptr;
1018
    }
1019
1020
    return val;
1021
}
1022
1023
142
inline unsigned int JsonbDocument::numPackedBytes() const {
1024
142
    return ((const JsonbValue*)payload_)->numPackedBytes() + sizeof(header_);
1025
142
}
1026
1027
453k
inline unsigned int JsonbKeyValue::numPackedBytes() const {
1028
453k
    unsigned int ks = keyPackedBytes();
1029
453k
    const auto* val = (const JsonbValue*)(((char*)this) + ks);
1030
453k
    return ks + val->numPackedBytes();
1031
453k
}
1032
1033
// Poor man's "virtual" function JsonbValue::numPackedBytes
1034
1.99M
inline unsigned int JsonbValue::numPackedBytes() const {
1035
1.99M
    switch (type) {
1036
12.3k
    case JsonbType::T_Null:
1037
53.1k
    case JsonbType::T_True:
1038
64.2k
    case JsonbType::T_False: {
1039
64.2k
        return sizeof(type);
1040
53.1k
    }
1041
1042
39.7k
    case JsonbType::T_Int8: {
1043
39.7k
        return sizeof(type) + sizeof(int8_t);
1044
53.1k
    }
1045
46.8k
    case JsonbType::T_Int16: {
1046
46.8k
        return sizeof(type) + sizeof(int16_t);
1047
53.1k
    }
1048
20.8k
    case JsonbType::T_Int32: {
1049
20.8k
        return sizeof(type) + sizeof(int32_t);
1050
53.1k
    }
1051
383k
    case JsonbType::T_Int64: {
1052
383k
        return sizeof(type) + sizeof(int64_t);
1053
53.1k
    }
1054
56.7k
    case JsonbType::T_Double: {
1055
56.7k
        return sizeof(type) + sizeof(double);
1056
53.1k
    }
1057
4.79k
    case JsonbType::T_Float: {
1058
4.79k
        return sizeof(type) + sizeof(float);
1059
53.1k
    }
1060
31.6k
    case JsonbType::T_Int128: {
1061
31.6k
        return sizeof(type) + sizeof(int128_t);
1062
53.1k
    }
1063
309k
    case JsonbType::T_String:
1064
334k
    case JsonbType::T_Binary: {
1065
334k
        return unpack<JsonbBinaryVal>()->numPackedBytes();
1066
309k
    }
1067
1068
167k
    case JsonbType::T_Object:
1069
1.02M
    case JsonbType::T_Array: {
1070
1.02M
        return unpack<ContainerVal>()->numPackedBytes();
1071
167k
    }
1072
39
    case JsonbType::T_Decimal32: {
1073
39
        return JsonbDecimal32::numPackedBytes();
1074
167k
    }
1075
61
    case JsonbType::T_Decimal64: {
1076
61
        return JsonbDecimal64::numPackedBytes();
1077
167k
    }
1078
34
    case JsonbType::T_Decimal128: {
1079
34
        return JsonbDecimal128::numPackedBytes();
1080
167k
    }
1081
6
    case JsonbType::T_Decimal256: {
1082
6
        return JsonbDecimal256::numPackedBytes();
1083
167k
    }
1084
0
    case JsonbType::NUM_TYPES:
1085
0
        break;
1086
1.99M
    }
1087
1088
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1089
0
                    static_cast<int32_t>(type));
1090
1.99M
}
1091
1092
94
inline int JsonbValue::numElements() const {
1093
94
    switch (type) {
1094
6
    case JsonbType::T_Int8:
1095
16
    case JsonbType::T_Int16:
1096
18
    case JsonbType::T_Int32:
1097
21
    case JsonbType::T_Int64:
1098
23
    case JsonbType::T_Double:
1099
23
    case JsonbType::T_Float:
1100
25
    case JsonbType::T_Int128:
1101
32
    case JsonbType::T_String:
1102
32
    case JsonbType::T_Binary:
1103
37
    case JsonbType::T_Null:
1104
43
    case JsonbType::T_True:
1105
45
    case JsonbType::T_False:
1106
45
    case JsonbType::T_Decimal32:
1107
45
    case JsonbType::T_Decimal64:
1108
45
    case JsonbType::T_Decimal128:
1109
45
    case JsonbType::T_Decimal256: {
1110
45
        return 1;
1111
45
    }
1112
27
    case JsonbType::T_Object: {
1113
27
        return unpack<ObjectVal>()->numElem();
1114
45
    }
1115
22
    case JsonbType::T_Array: {
1116
22
        return unpack<ArrayVal>()->numElem();
1117
45
    }
1118
0
    case JsonbType::NUM_TYPES:
1119
0
        break;
1120
94
    }
1121
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1122
0
                    static_cast<int32_t>(type));
1123
94
}
1124
1125
366
inline bool JsonbValue::contains(const JsonbValue* rhs) const {
1126
366
    switch (type) {
1127
70
    case JsonbType::T_Int8:
1128
102
    case JsonbType::T_Int16:
1129
108
    case JsonbType::T_Int32:
1130
117
    case JsonbType::T_Int64:
1131
123
    case JsonbType::T_Int128: {
1132
123
        return rhs->isInt() && this->int_val() == rhs->int_val();
1133
117
    }
1134
22
    case JsonbType::T_Double:
1135
22
    case JsonbType::T_Float: {
1136
22
        if (!rhs->isDouble() && !rhs->isFloat()) {
1137
20
            return false;
1138
20
        }
1139
2
        double left = isDouble() ? unpack<JsonbDoubleVal>()->val() : unpack<JsonbFloatVal>()->val();
1140
2
        double right = rhs->isDouble() ? rhs->unpack<JsonbDoubleVal>()->val()
1141
2
                                       : rhs->unpack<JsonbFloatVal>()->val();
1142
2
        return left == right;
1143
22
    }
1144
56
    case JsonbType::T_String:
1145
56
    case JsonbType::T_Binary: {
1146
56
        if (rhs->isString() || rhs->isBinary()) {
1147
20
            const auto* str_value1 = unpack<JsonbStringVal>();
1148
20
            const auto* str_value2 = rhs->unpack<JsonbStringVal>();
1149
20
            return str_value1->length() == str_value2->length() &&
1150
20
                   std::memcmp(str_value1->getBlob(), str_value2->getBlob(),
1151
19
                               str_value1->length()) == 0;
1152
20
        }
1153
36
        return false;
1154
56
    }
1155
44
    case JsonbType::T_Array: {
1156
44
        int lhs_num = unpack<ArrayVal>()->numElem();
1157
44
        if (rhs->isArray()) {
1158
11
            int rhs_num = rhs->unpack<ArrayVal>()->numElem();
1159
11
            if (rhs_num > lhs_num) {
1160
2
                return false;
1161
2
            }
1162
9
            int contains_num = 0;
1163
39
            for (int i = 0; i < lhs_num; ++i) {
1164
81
                for (int j = 0; j < rhs_num; ++j) {
1165
56
                    if (unpack<ArrayVal>()->get(i)->contains(rhs->unpack<ArrayVal>()->get(j))) {
1166
5
                        contains_num++;
1167
5
                        break;
1168
5
                    }
1169
56
                }
1170
30
            }
1171
9
            return contains_num == rhs_num;
1172
11
        }
1173
95
        for (int i = 0; i < lhs_num; ++i) {
1174
73
            if (unpack<ArrayVal>()->get(i)->contains(rhs)) {
1175
11
                return true;
1176
11
            }
1177
73
        }
1178
22
        return false;
1179
33
    }
1180
81
    case JsonbType::T_Object: {
1181
81
        if (rhs->isObject()) {
1182
47
            const auto* obj_value1 = unpack<ObjectVal>();
1183
47
            const auto* obj_value2 = rhs->unpack<ObjectVal>();
1184
91
            for (auto it = obj_value2->begin(); it != obj_value2->end(); ++it) {
1185
65
                const JsonbValue* value = obj_value1->find(it->getKeyStr(), it->klen());
1186
65
                if (value == nullptr || !value->contains(it->value())) {
1187
21
                    return false;
1188
21
                }
1189
65
            }
1190
26
            return true;
1191
47
        }
1192
34
        return false;
1193
81
    }
1194
14
    case JsonbType::T_Null: {
1195
14
        return rhs->isNull();
1196
81
    }
1197
14
    case JsonbType::T_True: {
1198
14
        return rhs->isTrue();
1199
81
    }
1200
12
    case JsonbType::T_False: {
1201
12
        return rhs->isFalse();
1202
81
    }
1203
0
    case JsonbType::T_Decimal32: {
1204
0
        if (rhs->isDecimal32()) {
1205
0
            return unpack<JsonbDecimal32>()->val() == rhs->unpack<JsonbDecimal32>()->val() &&
1206
0
                   unpack<JsonbDecimal32>()->precision ==
1207
0
                           rhs->unpack<JsonbDecimal32>()->precision &&
1208
0
                   unpack<JsonbDecimal32>()->scale == rhs->unpack<JsonbDecimal32>()->scale;
1209
0
        }
1210
0
        return false;
1211
0
    }
1212
0
    case JsonbType::T_Decimal64: {
1213
0
        if (rhs->isDecimal64()) {
1214
0
            return unpack<JsonbDecimal64>()->val() == rhs->unpack<JsonbDecimal64>()->val() &&
1215
0
                   unpack<JsonbDecimal64>()->precision ==
1216
0
                           rhs->unpack<JsonbDecimal64>()->precision &&
1217
0
                   unpack<JsonbDecimal64>()->scale == rhs->unpack<JsonbDecimal64>()->scale;
1218
0
        }
1219
0
        return false;
1220
0
    }
1221
0
    case JsonbType::T_Decimal128: {
1222
0
        if (rhs->isDecimal128()) {
1223
0
            return unpack<JsonbDecimal128>()->val() == rhs->unpack<JsonbDecimal128>()->val() &&
1224
0
                   unpack<JsonbDecimal128>()->precision ==
1225
0
                           rhs->unpack<JsonbDecimal128>()->precision &&
1226
0
                   unpack<JsonbDecimal128>()->scale == rhs->unpack<JsonbDecimal128>()->scale;
1227
0
        }
1228
0
        return false;
1229
0
    }
1230
0
    case JsonbType::T_Decimal256: {
1231
0
        if (rhs->isDecimal256()) {
1232
0
            return unpack<JsonbDecimal256>()->val() == rhs->unpack<JsonbDecimal256>()->val() &&
1233
0
                   unpack<JsonbDecimal256>()->precision ==
1234
0
                           rhs->unpack<JsonbDecimal256>()->precision &&
1235
0
                   unpack<JsonbDecimal256>()->scale == rhs->unpack<JsonbDecimal256>()->scale;
1236
0
        }
1237
0
        return false;
1238
0
    }
1239
0
    case JsonbType::NUM_TYPES:
1240
0
        break;
1241
366
    }
1242
1243
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1244
0
                    static_cast<int32_t>(type));
1245
366
}
1246
1247
14.9k
inline bool JsonbPath::seek(const char* key_path, size_t kp_len) {
1248
14.9k
    while (kp_len > 0 && std::isspace(key_path[kp_len - 1])) {
1249
7
        --kp_len;
1250
7
    }
1251
1252
    //path invalid
1253
14.9k
    if (!key_path || kp_len == 0) {
1254
2
        return false;
1255
2
    }
1256
14.9k
    Stream stream(key_path, kp_len);
1257
14.9k
    stream.skip_whitespace();
1258
14.9k
    if (stream.exhausted() || stream.read() != SCOPE) {
1259
        //path invalid
1260
2
        return false;
1261
2
    }
1262
1263
35.9k
    while (!stream.exhausted()) {
1264
21.0k
        stream.skip_whitespace();
1265
21.0k
        stream.clear_leg_ptr();
1266
21.0k
        stream.clear_leg_len();
1267
1268
21.0k
        if (!JsonbPath::parsePath(&stream, this)) {
1269
            //path invalid
1270
20
            return false;
1271
20
        }
1272
21.0k
    }
1273
14.9k
    return true;
1274
14.9k
}
1275
1276
21.0k
inline bool JsonbPath::parsePath(Stream* stream, JsonbPath* path) {
1277
    // $[0]
1278
21.0k
    if (stream->peek() == BEGIN_ARRAY) {
1279
11.0k
        return parse_array(stream, path);
1280
11.0k
    }
1281
    // $.a or $.[0]
1282
9.96k
    else if (stream->peek() == BEGIN_MEMBER) {
1283
        // advance past the .
1284
9.96k
        stream->skip(1);
1285
1286
9.96k
        if (stream->exhausted()) {
1287
16
            return false;
1288
16
        }
1289
1290
        // $.[0]
1291
9.94k
        if (stream->peek() == BEGIN_ARRAY) {
1292
170
            return parse_array(stream, path);
1293
170
        }
1294
        // $.a
1295
9.77k
        else {
1296
9.77k
            return parse_member(stream, path);
1297
9.77k
        }
1298
9.94k
    } else if (stream->peek() == WILDCARD) {
1299
9
        stream->skip(1);
1300
9
        if (stream->exhausted()) {
1301
0
            return false;
1302
0
        }
1303
1304
        // $**
1305
9
        if (stream->peek() == WILDCARD) {
1306
9
            path->_is_supper_wildcard = true;
1307
9
        }
1308
1309
9
        stream->skip(1);
1310
9
        if (stream->exhausted()) {
1311
2
            return false;
1312
2
        }
1313
1314
7
        if (stream->peek() == BEGIN_ARRAY) {
1315
2
            return parse_array(stream, path);
1316
5
        } else if (stream->peek() == BEGIN_MEMBER) {
1317
            // advance past the .
1318
5
            stream->skip(1);
1319
1320
5
            if (stream->exhausted()) {
1321
0
                return false;
1322
0
            }
1323
1324
            // $.[0]
1325
5
            if (stream->peek() == BEGIN_ARRAY) {
1326
0
                return parse_array(stream, path);
1327
0
            }
1328
            // $.a
1329
5
            else {
1330
5
                return parse_member(stream, path);
1331
5
            }
1332
5
        }
1333
0
        return false;
1334
18.4E
    } else {
1335
18.4E
        return false; //invalid json path
1336
18.4E
    }
1337
21.0k
}
1338
1339
11.2k
inline bool JsonbPath::parse_array(Stream* stream, JsonbPath* path) {
1340
11.2k
    assert(stream->peek() == BEGIN_ARRAY);
1341
11.2k
    stream->skip(1);
1342
11.2k
    if (stream->exhausted()) {
1343
0
        return false;
1344
0
    }
1345
1346
11.2k
    if (stream->peek() == WILDCARD) {
1347
        // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1348
        // using const_cast is acceptable.
1349
20
        stream->set_leg_ptr(const_cast<char*>(stream->position()));
1350
20
        stream->add_leg_len();
1351
20
        stream->skip(1);
1352
20
        if (stream->exhausted()) {
1353
0
            return false;
1354
0
        }
1355
1356
20
        if (stream->peek() == END_ARRAY) {
1357
20
            std::unique_ptr<leg_info> leg(
1358
20
                    new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, ARRAY_CODE));
1359
20
            path->add_leg_to_leg_vector(std::move(leg));
1360
20
            stream->skip(1);
1361
20
            path->_is_wildcard = true;
1362
20
            return true;
1363
20
        } else {
1364
0
            return false;
1365
0
        }
1366
20
    }
1367
1368
    // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1369
    // using const_cast is acceptable.
1370
11.2k
    stream->set_leg_ptr(const_cast<char*>(stream->position()));
1371
1372
32.9k
    for (; !stream->exhausted() && stream->peek() != END_ARRAY; stream->advance()) {
1373
21.6k
        stream->add_leg_len();
1374
21.6k
    }
1375
1376
11.2k
    if (stream->exhausted() || stream->peek() != END_ARRAY) {
1377
0
        return false;
1378
11.2k
    } else {
1379
11.2k
        stream->skip(1);
1380
11.2k
    }
1381
1382
    //parse array index to int
1383
1384
11.2k
    std::string_view idx_string(stream->get_leg_ptr(), stream->get_leg_len());
1385
11.2k
    int index = 0;
1386
1387
11.2k
    if (stream->get_leg_len() >= 4 &&
1388
11.2k
        std::equal(LAST, LAST + 4, stream->get_leg_ptr(),
1389
6.71k
                   [](char c1, char c2) { return std::tolower(c1) == std::tolower(c2); })) {
1390
1.67k
        auto pos = idx_string.find(MINUS);
1391
1392
1.67k
        if (pos != std::string::npos) {
1393
1.34k
            for (size_t i = 4; i < pos; ++i) {
1394
6
                if (std::isspace(idx_string[i])) {
1395
4
                    continue;
1396
4
                } else {
1397
                    // leading zeroes are not allowed
1398
2
                    LOG(WARNING) << "Non-space char in idx_string: '" << idx_string << "'";
1399
2
                    return false;
1400
2
                }
1401
6
            }
1402
1.33k
            idx_string = idx_string.substr(pos + 1);
1403
1.33k
            idx_string = trim(idx_string);
1404
1405
1.33k
            auto result = std::from_chars(idx_string.data(), idx_string.data() + idx_string.size(),
1406
1.33k
                                          index);
1407
1.33k
            if (result.ec != std::errc()) {
1408
0
                LOG(WARNING) << "Invalid index in JSON path: '" << idx_string << "'";
1409
0
                return false;
1410
0
            }
1411
1412
1.33k
        } else if (stream->get_leg_len() > 4) {
1413
0
            return false;
1414
0
        }
1415
1416
1.67k
        std::unique_ptr<leg_info> leg(new leg_info(nullptr, 0, -index - 1, ARRAY_CODE));
1417
1.67k
        path->add_leg_to_leg_vector(std::move(leg));
1418
1419
1.67k
        return true;
1420
1.67k
    }
1421
1422
9.55k
    auto result = std::from_chars(idx_string.data(), idx_string.data() + idx_string.size(), index);
1423
1424
9.55k
    if (result.ec != std::errc()) {
1425
0
        return false;
1426
0
    }
1427
1428
9.55k
    std::unique_ptr<leg_info> leg(new leg_info(nullptr, 0, index, ARRAY_CODE));
1429
9.55k
    path->add_leg_to_leg_vector(std::move(leg));
1430
1431
9.55k
    return true;
1432
9.55k
}
1433
1434
9.77k
inline bool JsonbPath::parse_member(Stream* stream, JsonbPath* path) {
1435
9.77k
    if (stream->exhausted()) {
1436
0
        return false;
1437
0
    }
1438
1439
9.77k
    if (stream->peek() == WILDCARD) {
1440
        // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1441
        // using const_cast is acceptable.
1442
116
        stream->set_leg_ptr(const_cast<char*>(stream->position()));
1443
116
        stream->add_leg_len();
1444
116
        stream->skip(1);
1445
116
        std::unique_ptr<leg_info> leg(
1446
116
                new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, MEMBER_CODE));
1447
116
        path->add_leg_to_leg_vector(std::move(leg));
1448
116
        path->_is_wildcard = true;
1449
116
        return true;
1450
116
    }
1451
1452
    // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1453
    // using const_cast is acceptable.
1454
9.66k
    stream->set_leg_ptr(const_cast<char*>(stream->position()));
1455
1456
9.66k
    const char* left_quotation_marks = nullptr;
1457
9.66k
    const char* right_quotation_marks = nullptr;
1458
1459
32.5k
    for (; !stream->exhausted(); stream->advance()) {
1460
        // Only accept space characters quoted by double quotes.
1461
29.8k
        if (std::isspace(stream->peek()) && left_quotation_marks == nullptr) {
1462
0
            return false;
1463
29.8k
        } else if (stream->peek() == ESCAPE) {
1464
3
            stream->add_leg_len();
1465
3
            stream->skip(1);
1466
3
            stream->add_leg_len();
1467
3
            stream->set_has_escapes(true);
1468
3
            if (stream->exhausted()) {
1469
0
                return false;
1470
0
            }
1471
3
            continue;
1472
29.8k
        } else if (stream->peek() == DOUBLE_QUOTE) {
1473
378
            if (left_quotation_marks == nullptr) {
1474
189
                left_quotation_marks = stream->position();
1475
                // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1476
                // using const_cast is acceptable.
1477
189
                stream->set_leg_ptr(const_cast<char*>(++left_quotation_marks));
1478
189
                continue;
1479
189
            } else {
1480
189
                right_quotation_marks = stream->position();
1481
189
                stream->skip(1);
1482
189
                break;
1483
189
            }
1484
29.4k
        } else if (stream->peek() == BEGIN_MEMBER || stream->peek() == BEGIN_ARRAY) {
1485
7.08k
            if (left_quotation_marks == nullptr) {
1486
6.77k
                break;
1487
6.77k
            }
1488
7.08k
        }
1489
1490
22.6k
        stream->add_leg_len();
1491
22.6k
    }
1492
1493
9.66k
    if ((left_quotation_marks != nullptr && right_quotation_marks == nullptr) ||
1494
9.66k
        stream->get_leg_ptr() == nullptr || stream->get_leg_len() == 0) {
1495
0
        return false; //invalid json path
1496
0
    }
1497
1498
9.66k
    if (stream->get_has_escapes()) {
1499
3
        stream->remove_escapes();
1500
3
    }
1501
1502
9.66k
    std::unique_ptr<leg_info> leg(
1503
9.66k
            new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, MEMBER_CODE));
1504
9.66k
    path->add_leg_to_leg_vector(std::move(leg));
1505
1506
9.66k
    return true;
1507
9.66k
}
1508
1509
static_assert(is_pod_v<JsonbDocument>, "JsonbDocument must be standard layout and trivial");
1510
static_assert(is_pod_v<JsonbValue>, "JsonbValue must be standard layout and trivial");
1511
static_assert(is_pod_v<JsonbDecimal32>, "JsonbDecimal32 must be standard layout and trivial");
1512
static_assert(is_pod_v<JsonbDecimal64>, "JsonbDecimal64 must be standard layout and trivial");
1513
static_assert(is_pod_v<JsonbDecimal128>, "JsonbDecimal128 must be standard layout and trivial");
1514
static_assert(is_pod_v<JsonbDecimal256>, "JsonbDecimal256 must be standard layout and trivial");
1515
static_assert(is_pod_v<JsonbInt8Val>, "JsonbInt8Val must be standard layout and trivial");
1516
static_assert(is_pod_v<JsonbInt32Val>, "JsonbInt32Val must be standard layout and trivial");
1517
static_assert(is_pod_v<JsonbInt64Val>, "JsonbInt64Val must be standard layout and trivial");
1518
static_assert(is_pod_v<JsonbInt128Val>, "JsonbInt128Val must be standard layout and trivial");
1519
static_assert(is_pod_v<JsonbDoubleVal>, "JsonbDoubleVal must be standard layout and trivial");
1520
static_assert(is_pod_v<JsonbFloatVal>, "JsonbFloatVal must be standard layout and trivial");
1521
static_assert(is_pod_v<JsonbBinaryVal>, "JsonbBinaryVal must be standard layout and trivial");
1522
static_assert(is_pod_v<ContainerVal>, "ContainerVal must be standard layout and trivial");
1523
1524
#define ASSERT_DECIMAL_LAYOUT(type)                \
1525
    static_assert(offsetof(type, precision) == 0); \
1526
    static_assert(offsetof(type, scale) == 4);     \
1527
    static_assert(offsetof(type, value) == 8);
1528
1529
ASSERT_DECIMAL_LAYOUT(JsonbDecimal32)
1530
ASSERT_DECIMAL_LAYOUT(JsonbDecimal64)
1531
ASSERT_DECIMAL_LAYOUT(JsonbDecimal128)
1532
ASSERT_DECIMAL_LAYOUT(JsonbDecimal256)
1533
1534
#define ASSERT_NUMERIC_LAYOUT(type) static_assert(offsetof(type, num) == 0);
1535
1536
ASSERT_NUMERIC_LAYOUT(JsonbInt8Val)
1537
ASSERT_NUMERIC_LAYOUT(JsonbInt32Val)
1538
ASSERT_NUMERIC_LAYOUT(JsonbInt64Val)
1539
ASSERT_NUMERIC_LAYOUT(JsonbInt128Val)
1540
ASSERT_NUMERIC_LAYOUT(JsonbDoubleVal)
1541
1542
static_assert(offsetof(JsonbBinaryVal, size) == 0);
1543
static_assert(offsetof(JsonbBinaryVal, payload) == 4);
1544
1545
static_assert(offsetof(ContainerVal, size) == 0);
1546
static_assert(offsetof(ContainerVal, payload) == 4);
1547
1548
#pragma pack(pop)
1549
#if defined(__clang__)
1550
#pragma clang diagnostic pop
1551
#endif
1552
} // namespace doris
1553
1554
#endif // JSONB_JSONBDOCUMENT_H