Coverage Report

Created: 2026-05-19 15:24

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.94M
#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.7k
    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.5k
    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
475k
    size_t remaining() const {
270
475k
        assert(m_position <= m_end);
271
475k
        return m_end - m_position;
272
475k
    }
273
274
    /// Tells if the stream has been exhausted.
275
442k
    bool exhausted() const { return remaining() == 0; }
276
277
    /// Reads the next byte from the stream and moves the position forward.
278
15.7k
    char read() {
279
15.7k
        assert(!exhausted());
280
15.7k
        return *m_position++;
281
15.7k
    }
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.9k
    void skip_whitespace() {
291
69.9k
        m_position = std::find_if_not(m_position, m_end, [](char c) { return std::isspace(c); });
292
69.9k
    }
293
294
    /// Moves the position n bytes forward.
295
33.0k
    void skip(size_t n) {
296
33.0k
        assert(remaining() >= n);
297
33.0k
        m_position += n;
298
33.0k
        skip_whitespace();
299
33.0k
    }
300
301
44.6k
    void advance() { m_position++; }
302
303
42.4k
    void clear_leg_ptr() { leg_ptr = nullptr; }
304
305
21.3k
    void set_leg_ptr(char* ptr) {
306
21.3k
        clear_leg_ptr();
307
21.3k
        leg_ptr = ptr;
308
21.3k
    }
309
310
32.4k
    char* get_leg_ptr() { return leg_ptr; }
311
312
21.1k
    void clear_leg_len() { leg_len = 0; }
313
314
44.6k
    void add_leg_len() { leg_len++; }
315
316
42.4k
    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
379
    bool to_string(std::string* str) const {
364
379
        if (type == MEMBER_CODE) {
365
121
            str->push_back(BEGIN_MEMBER);
366
121
            bool contains_space = false;
367
121
            std::string tmp;
368
311
            for (auto* it = leg_ptr; it != (leg_ptr + leg_len); ++it) {
369
190
                if (std::isspace(*it)) {
370
3
                    contains_space = true;
371
187
                } else if (*it == '"' || *it == ESCAPE || *it == '\r' || *it == '\n' ||
372
187
                           *it == '\b' || *it == '\t') {
373
2
                    tmp.push_back(ESCAPE);
374
2
                }
375
190
                tmp.push_back(*it);
376
190
            }
377
121
            if (contains_space) {
378
3
                str->push_back(DOUBLE_QUOTE);
379
3
            }
380
121
            str->append(tmp);
381
121
            if (contains_space) {
382
3
                str->push_back(DOUBLE_QUOTE);
383
3
            }
384
121
            return true;
385
258
        } else if (type == ARRAY_CODE) {
386
258
            str->push_back(BEGIN_ARRAY);
387
258
            std::string int_str = std::to_string(array_index);
388
258
            str->append(int_str);
389
258
            str->push_back(END_ARRAY);
390
258
            return true;
391
258
        } else {
392
0
            return false;
393
0
        }
394
379
    }
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
22.0k
    void add_leg_to_leg_vector(std::unique_ptr<leg_info> leg) {
409
22.0k
        leg_vector.emplace_back(leg.release());
410
22.0k
    }
411
412
624
    void pop_leg_from_leg_vector() { leg_vector.pop_back(); }
413
414
240
    bool to_string(std::string* res) const {
415
240
        res->push_back(SCOPE);
416
379
        for (const auto& leg : leg_vector) {
417
379
            auto valid = leg->to_string(res);
418
379
            if (!valid) {
419
0
                return false;
420
0
            }
421
379
        }
422
240
        return true;
423
240
    }
424
425
396k
    size_t get_leg_vector_size() const { return leg_vector.size(); }
426
427
1.27M
    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
150k
    bool is_supper_wildcard() const { return _is_supper_wildcard; }
431
432
70
    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
337k
    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
572k
    bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEeqERKS5_
Line
Count
Source
459
765k
    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
596k
    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
661k
    JsonbFwdIteratorT& operator++() {
468
661k
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
469
661k
        return *this;
470
661k
    }
_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
213k
    explicit operator pointer() { return current_; }
479
480
1.34k
    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.03k
    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
728k
    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
669k
    uint8_t klen() const { return size; }
582
583
    // get the key string. Note the string may not be null terminated.
584
336k
    const char* getKeyStr() const { return key.str_; }
585
586
111k
    keyid_type getKeyId() const { return key.id_; }
587
588
894k
    unsigned int keyPackedBytes() const {
589
894k
        return size ? (sizeof(size) + size) : (sizeof(size) + sizeof(keyid_type));
590
894k
    }
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
216k
    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
415
    bool isInt() const { return isInt8() || isInt16() || isInt32() || isInt64() || isInt128(); }
625
415
    bool isInt8() const { return (type == JsonbType::T_Int8); }
626
297
    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.3k
    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.95k
    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
204k
    const T* unpack() const {
721
204k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
204k
        return reinterpret_cast<const T*>(payload);
723
204k
    }
_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.06M
    const T* unpack() const {
721
1.06M
        static_assert(is_pod_v<T>, "T must be a POD type");
722
1.06M
        return reinterpret_cast<const T*>(payload);
723
1.06M
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_8ArrayValEEEPKT_v
Line
Count
Source
720
371k
    const T* unpack() const {
721
371k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
371k
        return reinterpret_cast<const T*>(payload);
723
371k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIdEEEEPKT_v
Line
Count
Source
720
11.8k
    const T* unpack() const {
721
11.8k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
11.8k
        return reinterpret_cast<const T*>(payload);
723
11.8k
    }
_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
331k
    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
204k
    T val() const { return num; }
_ZNK5doris10NumberValTInE3valEv
Line
Count
Source
762
18.7k
    T val() const { return num; }
_ZNK5doris10NumberValTIdE3valEv
Line
Count
Source
762
11.8k
    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
169
inline int128_t JsonbValue::int_val() const {
770
169
    switch (type) {
771
121
    case JsonbType::T_Int8:
772
121
        return unpack<JsonbInt8Val>()->val();
773
43
    case JsonbType::T_Int16:
774
43
        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
169
    }
785
169
}
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
167
            return size;
845
167
        }
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.06M
    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.39k
    const_iterator search(const char* key, unsigned int klen) const {
891
7.39k
        if (!key || !klen) {
892
0
            return end();
893
0
        }
894
7.39k
        return internalSearch(key, klen);
895
7.39k
    }
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.39k
    const JsonbValue* find(const char* key, unsigned int klen) const {
924
7.39k
        const_iterator kv = search(key, klen);
925
7.39k
        if (end() == kv) {
926
4.45k
            return nullptr;
927
4.45k
        }
928
2.94k
        return kv->value();
929
7.39k
    }
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.39k
    const_iterator internalSearch(const char* key, unsigned int klen) const {
939
7.39k
        const char* pch = payload;
940
7.39k
        const char* fence = payload + size;
941
942
19.2k
        while (pch < fence) {
943
14.7k
            const auto* pkey = (const JsonbKeyValue*)(pch);
944
14.7k
            if (klen == pkey->klen() && strncmp(key, pkey->getKeyStr(), klen) == 0) {
945
2.94k
                return const_iterator(pkey);
946
2.94k
            }
947
11.8k
            pch += pkey->numPackedBytes();
948
11.8k
        }
949
950
7.39k
        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
201k
    const JsonbValue* get(int idx) const {
967
201k
        if (idx < 0) {
968
65
            return nullptr;
969
65
        }
970
971
201k
        const char* pch = payload;
972
201k
        const char* fence = payload + size;
973
974
208k
        while (pch < fence && idx-- > 0) {
975
6.82k
            pch += ((const JsonbValue*)pch)->numPackedBytes();
976
6.82k
        }
977
201k
        if (idx > 0 || pch == fence) {
978
1.65k
            return nullptr;
979
1.65k
        }
980
981
199k
        return (const JsonbValue*)pch;
982
201k
    }
983
984
    // Get number of elements in array
985
1.91k
    int numElem() const {
986
1.91k
        const char* pch = payload;
987
1.91k
        const char* fence = payload + size;
988
989
1.91k
        unsigned int num = 0;
990
112k
        while (pch < fence) {
991
110k
            ++num;
992
110k
            pch += ((const JsonbValue*)pch)->numPackedBytes();
993
110k
        }
994
995
1.91k
        assert(pch == fence);
996
997
1.91k
        return num;
998
1.91k
    }
999
1000
168k
    const_iterator begin() const { return const_iterator((pointer)payload); }
1001
1002
168k
    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
459k
inline unsigned int JsonbKeyValue::numPackedBytes() const {
1052
459k
    unsigned int ks = keyPackedBytes();
1053
459k
    const auto* val = (const JsonbValue*)(((char*)this) + ks);
1054
459k
    return ks + val->numPackedBytes();
1055
459k
}
1056
1057
// Poor man's "virtual" function JsonbValue::numPackedBytes
1058
1.96M
inline unsigned int JsonbValue::numPackedBytes() const {
1059
1.96M
    switch (type) {
1060
12.3k
    case JsonbType::T_Null:
1061
53.1k
    case JsonbType::T_True:
1062
64.2k
    case JsonbType::T_False: {
1063
64.2k
        return sizeof(type);
1064
53.1k
    }
1065
1066
41.0k
    case JsonbType::T_Int8: {
1067
41.0k
        return sizeof(type) + sizeof(int8_t);
1068
53.1k
    }
1069
47.0k
    case JsonbType::T_Int16: {
1070
47.0k
        return sizeof(type) + sizeof(int16_t);
1071
53.1k
    }
1072
20.8k
    case JsonbType::T_Int32: {
1073
20.8k
        return sizeof(type) + sizeof(int32_t);
1074
53.1k
    }
1075
357k
    case JsonbType::T_Int64: {
1076
357k
        return sizeof(type) + sizeof(int64_t);
1077
53.1k
    }
1078
25.5k
    case JsonbType::T_Double: {
1079
25.5k
        return sizeof(type) + sizeof(double);
1080
53.1k
    }
1081
4.77k
    case JsonbType::T_Float: {
1082
4.77k
        return sizeof(type) + sizeof(float);
1083
53.1k
    }
1084
31.5k
    case JsonbType::T_Int128: {
1085
31.5k
        return sizeof(type) + sizeof(int128_t);
1086
53.1k
    }
1087
287k
    case JsonbType::T_String:
1088
311k
    case JsonbType::T_Binary: {
1089
311k
        return unpack<JsonbBinaryVal>()->numPackedBytes();
1090
287k
    }
1091
1092
278k
    case JsonbType::T_Object:
1093
1.06M
    case JsonbType::T_Array: {
1094
1.06M
        return unpack<ContainerVal>()->numPackedBytes();
1095
278k
    }
1096
39
    case JsonbType::T_Decimal32: {
1097
39
        return JsonbDecimal32::numPackedBytes();
1098
278k
    }
1099
61
    case JsonbType::T_Decimal64: {
1100
61
        return JsonbDecimal64::numPackedBytes();
1101
278k
    }
1102
34
    case JsonbType::T_Decimal128: {
1103
34
        return JsonbDecimal128::numPackedBytes();
1104
278k
    }
1105
6
    case JsonbType::T_Decimal256: {
1106
6
        return JsonbDecimal256::numPackedBytes();
1107
278k
    }
1108
0
    case JsonbType::NUM_TYPES:
1109
0
        break;
1110
1.96M
    }
1111
1112
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1113
0
                    static_cast<int32_t>(type));
1114
1.96M
}
1115
1116
802
inline int JsonbValue::numElements() const {
1117
802
    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
730
    case JsonbType::T_Array: {
1140
730
        return unpack<ArrayVal>()->numElem();
1141
45
    }
1142
0
    case JsonbType::NUM_TYPES:
1143
0
        break;
1144
802
    }
1145
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1146
0
                    static_cast<int32_t>(type));
1147
802
}
1148
1149
367
inline bool JsonbValue::contains(const JsonbValue* rhs) const {
1150
367
    switch (type) {
1151
86
    case JsonbType::T_Int8:
1152
116
    case JsonbType::T_Int16:
1153
122
    case JsonbType::T_Int32:
1154
131
    case JsonbType::T_Int64:
1155
137
    case JsonbType::T_Int128: {
1156
137
        return rhs->isInt() && this->int_val() == rhs->int_val();
1157
131
    }
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
45
    case JsonbType::T_String:
1169
45
    case JsonbType::T_Binary: {
1170
45
        if (rhs->isString() || rhs->isBinary()) {
1171
17
            const auto* str_value1 = unpack<JsonbStringVal>();
1172
17
            const auto* str_value2 = rhs->unpack<JsonbStringVal>();
1173
17
            return str_value1->length() == str_value2->length() &&
1174
17
                   std::memcmp(str_value1->getBlob(), str_value2->getBlob(),
1175
16
                               str_value1->length()) == 0;
1176
17
        }
1177
28
        return false;
1178
45
    }
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
81
    case JsonbType::T_Object: {
1187
81
        if (rhs->isObject()) {
1188
48
            const auto* obj_value1 = unpack<ObjectVal>();
1189
48
            const auto* obj_value2 = rhs->unpack<ObjectVal>();
1190
93
            for (auto it = obj_value2->begin(); it != obj_value2->end(); ++it) {
1191
66
                const JsonbValue* value = obj_value1->find(it->getKeyStr(), it->klen());
1192
66
                if (value == nullptr || !value->contains(it->value())) {
1193
21
                    return false;
1194
21
                }
1195
66
            }
1196
27
            return true;
1197
48
        }
1198
33
        return false;
1199
81
    }
1200
12
    case JsonbType::T_Null: {
1201
12
        return rhs->isNull();
1202
81
    }
1203
12
    case JsonbType::T_True: {
1204
12
        return rhs->isTrue();
1205
81
    }
1206
10
    case JsonbType::T_False: {
1207
10
        return rhs->isFalse();
1208
81
    }
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
367
    }
1248
1249
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1250
0
                    static_cast<int32_t>(type));
1251
367
}
1252
1253
15.7k
inline bool JsonbPath::seek(const char* key_path, size_t kp_len) {
1254
15.7k
    while (kp_len > 0 && std::isspace(key_path[kp_len - 1])) {
1255
7
        --kp_len;
1256
7
    }
1257
1258
    //path invalid
1259
15.7k
    if (!key_path || kp_len == 0) {
1260
2
        return false;
1261
2
    }
1262
15.7k
    Stream stream(key_path, kp_len);
1263
15.7k
    stream.skip_whitespace();
1264
15.7k
    if (stream.exhausted() || stream.read() != SCOPE) {
1265
        //path invalid
1266
4
        return false;
1267
4
    }
1268
1269
36.8k
    while (!stream.exhausted()) {
1270
21.1k
        stream.skip_whitespace();
1271
21.1k
        stream.clear_leg_ptr();
1272
21.1k
        stream.clear_leg_len();
1273
1274
21.1k
        if (!JsonbPath::parsePath(&stream, this)) {
1275
            //path invalid
1276
21
            return false;
1277
21
        }
1278
21.1k
    }
1279
15.6k
    return true;
1280
15.7k
}
1281
1282
21.1k
inline bool JsonbPath::parsePath(Stream* stream, JsonbPath* path) {
1283
    // $[0]
1284
21.1k
    if (stream->peek() == BEGIN_ARRAY) {
1285
11.0k
        return parse_array(stream, path);
1286
11.0k
    }
1287
    // $.a or $.[0]
1288
10.0k
    else if (stream->peek() == BEGIN_MEMBER) {
1289
        // advance past the .
1290
10.0k
        stream->skip(1);
1291
1292
10.0k
        if (stream->exhausted()) {
1293
17
            return false;
1294
17
        }
1295
1296
        // $.[0]
1297
10.0k
        if (stream->peek() == BEGIN_ARRAY) {
1298
257
            return parse_array(stream, path);
1299
257
        }
1300
        // $.a
1301
9.78k
        else {
1302
9.78k
            return parse_member(stream, path);
1303
9.78k
        }
1304
10.0k
    } else if (stream->peek() == WILDCARD) {
1305
13
        stream->skip(1);
1306
13
        if (stream->exhausted()) {
1307
0
            return false;
1308
0
        }
1309
1310
        // $**
1311
13
        if (stream->peek() == WILDCARD) {
1312
13
            path->_is_supper_wildcard = true;
1313
13
        }
1314
1315
13
        stream->skip(1);
1316
13
        if (stream->exhausted()) {
1317
2
            return false;
1318
2
        }
1319
1320
11
        if (stream->peek() == BEGIN_ARRAY) {
1321
2
            return parse_array(stream, path);
1322
9
        } else if (stream->peek() == BEGIN_MEMBER) {
1323
            // advance past the .
1324
9
            stream->skip(1);
1325
1326
9
            if (stream->exhausted()) {
1327
0
                return false;
1328
0
            }
1329
1330
            // $.[0]
1331
9
            if (stream->peek() == BEGIN_ARRAY) {
1332
0
                return parse_array(stream, path);
1333
0
            }
1334
            // $.a
1335
9
            else {
1336
9
                return parse_member(stream, path);
1337
9
            }
1338
9
        }
1339
0
        return false;
1340
11
    } else {
1341
0
        return false; //invalid json path
1342
0
    }
1343
21.1k
}
1344
1345
11.3k
inline bool JsonbPath::parse_array(Stream* stream, JsonbPath* path) {
1346
11.3k
    assert(stream->peek() == BEGIN_ARRAY);
1347
11.3k
    stream->skip(1);
1348
11.3k
    if (stream->exhausted()) {
1349
0
        return false;
1350
0
    }
1351
1352
11.3k
    if (stream->peek() == WILDCARD) {
1353
        // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1354
        // using const_cast is acceptable.
1355
20
        stream->set_leg_ptr(const_cast<char*>(stream->position()));
1356
20
        stream->add_leg_len();
1357
20
        stream->skip(1);
1358
20
        if (stream->exhausted()) {
1359
0
            return false;
1360
0
        }
1361
1362
20
        if (stream->peek() == END_ARRAY) {
1363
20
            std::unique_ptr<leg_info> leg(
1364
20
                    new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, ARRAY_CODE));
1365
20
            path->add_leg_to_leg_vector(std::move(leg));
1366
20
            stream->skip(1);
1367
20
            path->_is_wildcard = true;
1368
20
            return true;
1369
20
        } else {
1370
0
            return false;
1371
0
        }
1372
20
    }
1373
1374
    // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1375
    // using const_cast is acceptable.
1376
11.3k
    stream->set_leg_ptr(const_cast<char*>(stream->position()));
1377
1378
33.0k
    for (; !stream->exhausted() && stream->peek() != END_ARRAY; stream->advance()) {
1379
21.7k
        stream->add_leg_len();
1380
21.7k
    }
1381
1382
11.3k
    if (stream->exhausted() || stream->peek() != END_ARRAY) {
1383
0
        return false;
1384
11.3k
    } else {
1385
11.3k
        stream->skip(1);
1386
11.3k
    }
1387
1388
    //parse array index to int
1389
1390
11.3k
    std::string_view idx_string(stream->get_leg_ptr(), stream->get_leg_len());
1391
11.3k
    int index = 0;
1392
1393
11.3k
    if (stream->get_leg_len() >= 4 &&
1394
11.3k
        std::equal(LAST, LAST + 4, stream->get_leg_ptr(),
1395
6.71k
                   [](char c1, char c2) { return std::tolower(c1) == std::tolower(c2); })) {
1396
1.67k
        auto pos = idx_string.find(MINUS);
1397
1398
1.67k
        if (pos != std::string::npos) {
1399
1.34k
            for (size_t i = 4; i < pos; ++i) {
1400
6
                if (std::isspace(idx_string[i])) {
1401
4
                    continue;
1402
4
                } else {
1403
                    // leading zeroes are not allowed
1404
2
                    LOG(WARNING) << "Non-space char in idx_string: '" << idx_string << "'";
1405
2
                    return false;
1406
2
                }
1407
6
            }
1408
1.33k
            idx_string = idx_string.substr(pos + 1);
1409
1.33k
            idx_string = trim(idx_string);
1410
1411
1.33k
            auto result = std::from_chars(idx_string.data(), idx_string.data() + idx_string.size(),
1412
1.33k
                                          index);
1413
1.33k
            if (result.ec != std::errc()) {
1414
0
                LOG(WARNING) << "Invalid index in JSON path: '" << idx_string << "'";
1415
0
                return false;
1416
0
            }
1417
1418
1.33k
        } else if (stream->get_leg_len() > 4) {
1419
0
            return false;
1420
0
        }
1421
1422
1.67k
        std::unique_ptr<leg_info> leg(new leg_info(nullptr, 0, -index - 1, ARRAY_CODE));
1423
1.67k
        path->add_leg_to_leg_vector(std::move(leg));
1424
1425
1.67k
        return true;
1426
1.67k
    }
1427
1428
9.62k
    auto result = std::from_chars(idx_string.data(), idx_string.data() + idx_string.size(), index);
1429
1430
9.62k
    if (result.ec != std::errc()) {
1431
0
        return false;
1432
0
    }
1433
1434
9.62k
    std::unique_ptr<leg_info> leg(new leg_info(nullptr, 0, index, ARRAY_CODE));
1435
9.62k
    path->add_leg_to_leg_vector(std::move(leg));
1436
1437
9.62k
    return true;
1438
9.62k
}
1439
1440
9.79k
inline bool JsonbPath::parse_member(Stream* stream, JsonbPath* path) {
1441
9.79k
    if (stream->exhausted()) {
1442
0
        return false;
1443
0
    }
1444
1445
9.79k
    if (stream->peek() == WILDCARD) {
1446
        // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1447
        // using const_cast is acceptable.
1448
116
        stream->set_leg_ptr(const_cast<char*>(stream->position()));
1449
116
        stream->add_leg_len();
1450
116
        stream->skip(1);
1451
116
        std::unique_ptr<leg_info> leg(
1452
116
                new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, MEMBER_CODE));
1453
116
        path->add_leg_to_leg_vector(std::move(leg));
1454
116
        path->_is_wildcard = true;
1455
116
        return true;
1456
116
    }
1457
1458
    // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1459
    // using const_cast is acceptable.
1460
9.68k
    stream->set_leg_ptr(const_cast<char*>(stream->position()));
1461
1462
9.68k
    const char* left_quotation_marks = nullptr;
1463
9.68k
    const char* right_quotation_marks = nullptr;
1464
1465
32.6k
    for (; !stream->exhausted(); stream->advance()) {
1466
        // Only accept space characters quoted by double quotes.
1467
29.8k
        if (std::isspace(stream->peek()) && left_quotation_marks == nullptr) {
1468
0
            return false;
1469
29.8k
        } else if (stream->peek() == ESCAPE) {
1470
3
            stream->add_leg_len();
1471
3
            stream->skip(1);
1472
3
            stream->add_leg_len();
1473
3
            stream->set_has_escapes(true);
1474
3
            if (stream->exhausted()) {
1475
0
                return false;
1476
0
            }
1477
3
            continue;
1478
29.8k
        } else if (stream->peek() == DOUBLE_QUOTE) {
1479
378
            if (left_quotation_marks == nullptr) {
1480
189
                left_quotation_marks = stream->position();
1481
                // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1482
                // using const_cast is acceptable.
1483
189
                stream->set_leg_ptr(const_cast<char*>(++left_quotation_marks));
1484
189
                continue;
1485
189
            } else {
1486
189
                right_quotation_marks = stream->position();
1487
189
                stream->skip(1);
1488
189
                break;
1489
189
            }
1490
29.4k
        } else if (stream->peek() == BEGIN_MEMBER || stream->peek() == BEGIN_ARRAY) {
1491
7.06k
            if (left_quotation_marks == nullptr) {
1492
6.76k
                break;
1493
6.76k
            }
1494
7.06k
        }
1495
1496
22.7k
        stream->add_leg_len();
1497
22.7k
    }
1498
1499
9.68k
    if ((left_quotation_marks != nullptr && right_quotation_marks == nullptr) ||
1500
9.68k
        stream->get_leg_ptr() == nullptr || stream->get_leg_len() == 0) {
1501
0
        return false; //invalid json path
1502
0
    }
1503
1504
9.68k
    if (stream->get_has_escapes()) {
1505
3
        stream->remove_escapes();
1506
3
    }
1507
1508
9.68k
    std::unique_ptr<leg_info> leg(
1509
9.68k
            new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, MEMBER_CODE));
1510
9.68k
    path->add_leg_to_leg_vector(std::move(leg));
1511
1512
9.68k
    return true;
1513
9.68k
}
1514
1515
static_assert(is_pod_v<JsonbDocument>, "JsonbDocument must be standard layout and trivial");
1516
static_assert(is_pod_v<JsonbValue>, "JsonbValue must be standard layout and trivial");
1517
static_assert(is_pod_v<JsonbDecimal32>, "JsonbDecimal32 must be standard layout and trivial");
1518
static_assert(is_pod_v<JsonbDecimal64>, "JsonbDecimal64 must be standard layout and trivial");
1519
static_assert(is_pod_v<JsonbDecimal128>, "JsonbDecimal128 must be standard layout and trivial");
1520
static_assert(is_pod_v<JsonbDecimal256>, "JsonbDecimal256 must be standard layout and trivial");
1521
static_assert(is_pod_v<JsonbInt8Val>, "JsonbInt8Val must be standard layout and trivial");
1522
static_assert(is_pod_v<JsonbInt32Val>, "JsonbInt32Val must be standard layout and trivial");
1523
static_assert(is_pod_v<JsonbInt64Val>, "JsonbInt64Val must be standard layout and trivial");
1524
static_assert(is_pod_v<JsonbInt128Val>, "JsonbInt128Val must be standard layout and trivial");
1525
static_assert(is_pod_v<JsonbDoubleVal>, "JsonbDoubleVal must be standard layout and trivial");
1526
static_assert(is_pod_v<JsonbFloatVal>, "JsonbFloatVal must be standard layout and trivial");
1527
static_assert(is_pod_v<JsonbBinaryVal>, "JsonbBinaryVal must be standard layout and trivial");
1528
static_assert(is_pod_v<ContainerVal>, "ContainerVal must be standard layout and trivial");
1529
1530
#define ASSERT_DECIMAL_LAYOUT(type)                \
1531
    static_assert(offsetof(type, precision) == 0); \
1532
    static_assert(offsetof(type, scale) == 4);     \
1533
    static_assert(offsetof(type, value) == 8);
1534
1535
ASSERT_DECIMAL_LAYOUT(JsonbDecimal32)
1536
ASSERT_DECIMAL_LAYOUT(JsonbDecimal64)
1537
ASSERT_DECIMAL_LAYOUT(JsonbDecimal128)
1538
ASSERT_DECIMAL_LAYOUT(JsonbDecimal256)
1539
1540
#define ASSERT_NUMERIC_LAYOUT(type) static_assert(offsetof(type, num) == 0);
1541
1542
ASSERT_NUMERIC_LAYOUT(JsonbInt8Val)
1543
ASSERT_NUMERIC_LAYOUT(JsonbInt32Val)
1544
ASSERT_NUMERIC_LAYOUT(JsonbInt64Val)
1545
ASSERT_NUMERIC_LAYOUT(JsonbInt128Val)
1546
ASSERT_NUMERIC_LAYOUT(JsonbDoubleVal)
1547
1548
static_assert(offsetof(JsonbBinaryVal, size) == 0);
1549
static_assert(offsetof(JsonbBinaryVal, payload) == 4);
1550
1551
static_assert(offsetof(ContainerVal, size) == 0);
1552
static_assert(offsetof(ContainerVal, payload) == 4);
1553
1554
#pragma pack(pop)
1555
#if defined(__clang__)
1556
#pragma clang diagnostic pop
1557
#endif
1558
} // namespace doris
1559
1560
#endif // JSONB_JSONBDOCUMENT_H