Coverage Report

Created: 2026-05-20 14:58

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
1.21M
#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
11
inline PrimitiveType get_primitive_type_from_json_type(JsonbType json_type) {
199
11
    switch (json_type) {
200
1
    case JsonbType::T_Null:
201
1
        return TYPE_NULL;
202
1
    case JsonbType::T_True:
203
2
    case JsonbType::T_False:
204
2
        return TYPE_BOOLEAN;
205
0
    case JsonbType::T_Int8:
206
0
        return TYPE_TINYINT;
207
0
    case JsonbType::T_Int16:
208
0
        return TYPE_SMALLINT;
209
0
    case JsonbType::T_Int32:
210
0
        return TYPE_INT;
211
0
    case JsonbType::T_Int64:
212
0
        return TYPE_BIGINT;
213
0
    case JsonbType::T_Double:
214
0
        return TYPE_DOUBLE;
215
1
    case JsonbType::T_String:
216
1
        return TYPE_STRING;
217
0
    case JsonbType::T_Binary:
218
0
        return TYPE_BINARY;
219
0
    case JsonbType::T_Object:
220
0
        return TYPE_STRUCT;
221
1
    case JsonbType::T_Array:
222
1
        return TYPE_ARRAY;
223
1
    case JsonbType::T_Int128:
224
1
        return TYPE_LARGEINT;
225
1
    case JsonbType::T_Float:
226
1
        return TYPE_FLOAT;
227
1
    case JsonbType::T_Decimal32:
228
1
        return TYPE_DECIMAL32;
229
1
    case JsonbType::T_Decimal64:
230
1
        return TYPE_DECIMAL64;
231
1
    case JsonbType::T_Decimal128:
232
1
        return TYPE_DECIMAL128I;
233
1
    case JsonbType::T_Decimal256:
234
1
        return TYPE_DECIMAL256;
235
0
    default:
236
0
        throw Exception(ErrorCode::INTERNAL_ERROR, "Unsupported JsonbType: {}",
237
0
                        static_cast<int>(json_type));
238
11
    }
239
11
}
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
100
    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
94
    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
1.80k
    size_t remaining() const {
270
1.80k
        assert(m_position <= m_end);
271
1.80k
        return m_end - m_position;
272
1.80k
    }
273
274
    /// Tells if the stream has been exhausted.
275
1.64k
    bool exhausted() const { return remaining() == 0; }
276
277
    /// Reads the next byte from the stream and moves the position forward.
278
100
    char read() {
279
100
        assert(!exhausted());
280
100
        return *m_position++;
281
100
    }
282
283
    /// Reads the next byte from the stream without moving the position forward.
284
840
    char peek() const {
285
840
        assert(!exhausted());
286
840
        return *m_position;
287
840
    }
288
289
    /// Moves the position to the next non-whitespace character.
290
350
    void skip_whitespace() {
291
350
        m_position = std::find_if_not(m_position, m_end, [](char c) { return std::isspace(c); });
292
350
    }
293
294
    /// Moves the position n bytes forward.
295
156
    void skip(size_t n) {
296
156
        assert(remaining() >= n);
297
156
        m_position += n;
298
156
        skip_whitespace();
299
156
    }
300
301
126
    void advance() { m_position++; }
302
303
188
    void clear_leg_ptr() { leg_ptr = nullptr; }
304
305
94
    void set_leg_ptr(char* ptr) {
306
94
        clear_leg_ptr();
307
94
        leg_ptr = ptr;
308
94
    }
309
310
130
    char* get_leg_ptr() { return leg_ptr; }
311
312
94
    void clear_leg_len() { leg_len = 0; }
313
314
126
    void add_leg_len() { leg_len++; }
315
316
188
    unsigned int get_leg_len() const { return leg_len; }
317
318
0
    void remove_escapes() {
319
0
        int new_len = 0;
320
0
        for (int i = 0; i < leg_len; i++) {
321
0
            if (leg_ptr[i] != '\\') {
322
0
                leg_ptr[new_len++] = leg_ptr[i];
323
0
            }
324
0
        }
325
0
        leg_ptr[new_len] = '\0';
326
0
        leg_len = new_len;
327
0
    }
328
329
0
    void set_has_escapes(bool has) { has_escapes = has; }
330
331
36
    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
0
    bool to_string(std::string* str) const {
364
0
        if (type == MEMBER_CODE) {
365
0
            str->push_back(BEGIN_MEMBER);
366
0
            bool contains_space = false;
367
0
            std::string tmp;
368
0
            for (auto* it = leg_ptr; it != (leg_ptr + leg_len); ++it) {
369
0
                if (std::isspace(*it)) {
370
0
                    contains_space = true;
371
0
                } else if (*it == '"' || *it == ESCAPE || *it == '\r' || *it == '\n' ||
372
0
                           *it == '\b' || *it == '\t') {
373
0
                    tmp.push_back(ESCAPE);
374
0
                }
375
0
                tmp.push_back(*it);
376
0
            }
377
0
            if (contains_space) {
378
0
                str->push_back(DOUBLE_QUOTE);
379
0
            }
380
0
            str->append(tmp);
381
0
            if (contains_space) {
382
0
                str->push_back(DOUBLE_QUOTE);
383
0
            }
384
0
            return true;
385
0
        } else if (type == ARRAY_CODE) {
386
0
            str->push_back(BEGIN_ARRAY);
387
0
            std::string int_str = std::to_string(array_index);
388
0
            str->append(int_str);
389
0
            str->push_back(END_ARRAY);
390
0
            return true;
391
0
        } else {
392
0
            return false;
393
0
        }
394
0
    }
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
94
    void add_leg_to_leg_vector(std::unique_ptr<leg_info> leg) {
409
94
        leg_vector.emplace_back(leg.release());
410
94
    }
411
412
0
    void pop_leg_from_leg_vector() { leg_vector.pop_back(); }
413
414
0
    bool to_string(std::string* res) const {
415
0
        res->push_back(SCOPE);
416
0
        for (const auto& leg : leg_vector) {
417
0
            auto valid = leg->to_string(res);
418
0
            if (!valid) {
419
0
                return false;
420
0
            }
421
0
        }
422
0
        return true;
423
0
    }
424
425
189
    size_t get_leg_vector_size() const { return leg_vector.size(); }
426
427
305
    leg_info* get_leg_from_leg_vector(size_t i) const { return leg_vector[i].get(); }
428
429
3
    bool is_wildcard() const { return _is_wildcard; }
430
100
    bool is_supper_wildcard() const { return _is_supper_wildcard; }
431
432
6
    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
20.4k
    explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {}
_ZN5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEC2ERKS3_
Line
Count
Source
453
20.3k
    explicit JsonbFwdIteratorT(const iterator& i) : current_(i) {}
_ZN5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEC2ERKS3_
Line
Count
Source
453
145
    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
20.6k
    bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEeqERKS5_
Line
Count
Source
459
19.2k
    bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEeqERKS5_
Line
Count
Source
459
1.36k
    bool operator==(const JsonbFwdIteratorT& rhs) const { return (current_ == rhs.current_); }
460
461
20.0k
    bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEneERKS5_
Line
Count
Source
461
18.7k
    bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEneERKS5_
Line
Count
Source
461
1.29k
    bool operator!=(const JsonbFwdIteratorT& rhs) const { return !operator==(rhs); }
462
463
1.14k
    bool operator<(const JsonbFwdIteratorT& rhs) const { return (current_ < rhs.current_); }
464
465
    bool operator>(const JsonbFwdIteratorT& rhs) const { return !operator<(rhs); }
466
467
18.1k
    JsonbFwdIteratorT& operator++() {
468
18.1k
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
469
18.1k
        return *this;
470
18.1k
    }
_ZN5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEppEv
Line
Count
Source
467
17.5k
    JsonbFwdIteratorT& operator++() {
468
17.5k
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
469
17.5k
        return *this;
470
17.5k
    }
_ZN5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEppEv
Line
Count
Source
467
613
    JsonbFwdIteratorT& operator++() {
468
613
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
469
613
        return *this;
470
613
    }
471
472
    JsonbFwdIteratorT operator++(int) {
473
        auto tmp = *this;
474
        current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
475
        return tmp;
476
    }
477
478
613
    explicit operator pointer() { return current_; }
479
480
39
    reference operator*() const { return *current_; }
Unexecuted instantiation: _ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEdeEv
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEdeEv
Line
Count
Source
480
39
    reference operator*() const { return *current_; }
481
482
28.8k
    pointer operator->() const { return current_; }
_ZNK5doris17JsonbFwdIteratorTIPKNS_13JsonbKeyValueENS_9ObjectValEEptEv
Line
Count
Source
482
28.8k
    pointer operator->() const { return current_; }
_ZNK5doris17JsonbFwdIteratorTIPKNS_10JsonbValueENS_8ArrayValEEptEv
Line
Count
Source
482
3
    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
26.5k
    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
1.41k
    uint8_t klen() const { return size; }
582
583
    // get the key string. Note the string may not be null terminated.
584
766
    const char* getKeyStr() const { return key.str_; }
585
586
9.22k
    keyid_type getKeyId() const { return key.id_; }
587
588
35.2k
    unsigned int keyPackedBytes() const {
589
35.2k
        return size ? (sizeof(size) + size) : (sizeof(size) + sizeof(keyid_type));
590
35.2k
    }
591
592
17.6k
    const JsonbValue* value() const {
593
17.6k
        return (const JsonbValue*)(((char*)this) + keyPackedBytes());
594
17.6k
    }
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
4.26k
    bool isNull() const { return (type == JsonbType::T_Null); }
622
21
    bool isTrue() const { return (type == JsonbType::T_True); }
623
1
    bool isFalse() const { return (type == JsonbType::T_False); }
624
22
    bool isInt() const { return isInt8() || isInt16() || isInt32() || isInt64() || isInt128(); }
625
22
    bool isInt8() const { return (type == JsonbType::T_Int8); }
626
4
    bool isInt16() const { return (type == JsonbType::T_Int16); }
627
2
    bool isInt32() const { return (type == JsonbType::T_Int32); }
628
5
    bool isInt64() const { return (type == JsonbType::T_Int64); }
629
1
    bool isDouble() const { return (type == JsonbType::T_Double); }
630
1
    bool isFloat() const { return (type == JsonbType::T_Float); }
631
45
    bool isString() const { return (type == JsonbType::T_String); }
632
1.07k
    bool isBinary() const { return (type == JsonbType::T_Binary); }
633
97
    bool isObject() const { return (type == JsonbType::T_Object); }
634
15
    bool isArray() const { return (type == JsonbType::T_Array); }
635
5
    bool isInt128() const { return (type == JsonbType::T_Int128); }
636
4
    bool isDecimal() const {
637
4
        return (type == JsonbType::T_Decimal32 || type == JsonbType::T_Decimal64 ||
638
4
                type == JsonbType::T_Decimal128 || type == JsonbType::T_Decimal256);
639
4
    }
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
11
    PrimitiveType get_primitive_type() const { return get_primitive_type_from_json_type(type); }
646
647
0
    const char* typeName() const {
648
0
        switch (type) {
649
0
        case JsonbType::T_Null:
650
0
            return "null";
651
0
        case JsonbType::T_True:
652
0
        case JsonbType::T_False:
653
0
            return "bool";
654
0
        case JsonbType::T_Int8:
655
0
        case JsonbType::T_Int16:
656
0
        case JsonbType::T_Int32:
657
0
            return "int";
658
0
        case JsonbType::T_Int64:
659
0
            return "bigint";
660
0
        case JsonbType::T_Int128:
661
0
            return "largeint";
662
0
        case JsonbType::T_Double:
663
0
            return "double";
664
0
        case JsonbType::T_Float:
665
0
            return "float";
666
0
        case JsonbType::T_String:
667
0
            return "string";
668
0
        case JsonbType::T_Binary:
669
0
            return "binary";
670
0
        case JsonbType::T_Object:
671
0
            return "object";
672
0
        case JsonbType::T_Array:
673
0
            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
0
        }
685
0
    }
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
52.4k
    const T* unpack() const {
721
52.4k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
52.4k
        return reinterpret_cast<const T*>(payload);
723
52.4k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_9ObjectValEEEPKT_v
Line
Count
Source
720
19.6k
    const T* unpack() const {
721
19.6k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
19.6k
        return reinterpret_cast<const T*>(payload);
723
19.6k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIaEEEEPKT_v
Line
Count
Source
720
723
    const T* unpack() const {
721
723
        static_assert(is_pod_v<T>, "T must be a POD type");
722
723
        return reinterpret_cast<const T*>(payload);
723
723
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIsEEEEPKT_v
Line
Count
Source
720
105
    const T* unpack() const {
721
105
        static_assert(is_pod_v<T>, "T must be a POD type");
722
105
        return reinterpret_cast<const T*>(payload);
723
105
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIiEEEEPKT_v
Line
Count
Source
720
3.47k
    const T* unpack() const {
721
3.47k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
3.47k
        return reinterpret_cast<const T*>(payload);
723
3.47k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIlEEEEPKT_v
Line
Count
Source
720
1.90k
    const T* unpack() const {
721
1.90k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
1.90k
        return reinterpret_cast<const T*>(payload);
723
1.90k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTInEEEEPKT_v
Line
Count
Source
720
4.16k
    const T* unpack() const {
721
4.16k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
4.16k
        return reinterpret_cast<const T*>(payload);
723
4.16k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_14JsonbBinaryValEEEPKT_v
Line
Count
Source
720
19.7k
    const T* unpack() const {
721
19.7k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
19.7k
        return reinterpret_cast<const T*>(payload);
723
19.7k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_12ContainerValEEEPKT_v
Line
Count
Source
720
1.96k
    const T* unpack() const {
721
1.96k
        static_assert(is_pod_v<T>, "T must be a POD type");
722
1.96k
        return reinterpret_cast<const T*>(payload);
723
1.96k
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_8ArrayValEEEPKT_v
Line
Count
Source
720
120
    const T* unpack() const {
721
120
        static_assert(is_pod_v<T>, "T must be a POD type");
722
120
        return reinterpret_cast<const T*>(payload);
723
120
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIdEEEEPKT_v
Line
Count
Source
720
168
    const T* unpack() const {
721
168
        static_assert(is_pod_v<T>, "T must be a POD type");
722
168
        return reinterpret_cast<const T*>(payload);
723
168
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_10NumberValTIfEEEEPKT_v
Line
Count
Source
720
25
    const T* unpack() const {
721
25
        static_assert(is_pod_v<T>, "T must be a POD type");
722
25
        return reinterpret_cast<const T*>(payload);
723
25
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_14JsonbStringValEEEPKT_v
Line
Count
Source
720
337
    const T* unpack() const {
721
337
        static_assert(is_pod_v<T>, "T must be a POD type");
722
337
        return reinterpret_cast<const T*>(payload);
723
337
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_7DecimalIiEEEEEEPKT_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
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_7DecimalIlEEEEEEPKT_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
    }
_ZNK5doris10JsonbValue6unpackITkNS_12JsonbPodTypeENS_15JsonbDecimalValINS_12Decimal128V3EEEEEPKT_v
Line
Count
Source
720
17
    const T* unpack() const {
721
17
        static_assert(is_pod_v<T>, "T must be a POD type");
722
17
        return reinterpret_cast<const T*>(payload);
723
17
    }
_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
19.0k
inline const ObjectVal* JsonbDocument::operator->() const {
751
19.0k
    return (((const JsonbValue*)payload_)->unpack<ObjectVal>());
752
19.0k
}
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
10.5k
    T val() const { return num; }
_ZNK5doris10NumberValTIaE3valEv
Line
Count
Source
762
723
    T val() const { return num; }
_ZNK5doris10NumberValTIsE3valEv
Line
Count
Source
762
105
    T val() const { return num; }
_ZNK5doris10NumberValTIiE3valEv
Line
Count
Source
762
3.47k
    T val() const { return num; }
_ZNK5doris10NumberValTIlE3valEv
Line
Count
Source
762
1.90k
    T val() const { return num; }
_ZNK5doris10NumberValTInE3valEv
Line
Count
Source
762
4.16k
    T val() const { return num; }
_ZNK5doris10NumberValTIdE3valEv
Line
Count
Source
762
168
    T val() const { return num; }
_ZNK5doris10NumberValTIfE3valEv
Line
Count
Source
762
25
    T val() const { return num; }
763
764
    static unsigned int numPackedBytes() { return sizeof(JsonbValue) + sizeof(T); }
765
766
    T num;
767
};
768
769
41
inline int128_t JsonbValue::int_val() const {
770
41
    switch (type) {
771
35
    case JsonbType::T_Int8:
772
35
        return unpack<JsonbInt8Val>()->val();
773
1
    case JsonbType::T_Int16:
774
1
        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
41
    }
785
41
}
786
787
template <JsonbDecimalType T>
788
struct JsonbDecimalVal {
789
public:
790
    using NativeType = typename T::NativeType;
791
792
    // get the decimal value
793
26
    NativeType val() const {
794
        // to avoid memory alignment issues, we use memcpy to copy the value
795
26
        NativeType tmp;
796
26
        memcpy(&tmp, &value, sizeof(NativeType));
797
26
        return tmp;
798
26
    }
_ZNK5doris15JsonbDecimalValINS_7DecimalIiEEE3valEv
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
    }
_ZNK5doris15JsonbDecimalValINS_7DecimalIlEEE3valEv
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
    }
_ZNK5doris15JsonbDecimalValINS_12Decimal128V3EE3valEv
Line
Count
Source
793
8
    NativeType val() const {
794
        // to avoid memory alignment issues, we use memcpy to copy the value
795
8
        NativeType tmp;
796
8
        memcpy(&tmp, &value, sizeof(NativeType));
797
8
        return tmp;
798
8
    }
_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
29
    static constexpr int numPackedBytes() {
801
29
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
802
29
    }
_ZN5doris15JsonbDecimalValINS_7DecimalIiEEE14numPackedBytesEv
Line
Count
Source
800
7
    static constexpr int numPackedBytes() {
801
7
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
802
7
    }
_ZN5doris15JsonbDecimalValINS_7DecimalIlEEE14numPackedBytesEv
Line
Count
Source
800
7
    static constexpr int numPackedBytes() {
801
7
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
802
7
    }
_ZN5doris15JsonbDecimalValINS_12Decimal128V3EE14numPackedBytesEv
Line
Count
Source
800
9
    static constexpr int numPackedBytes() {
801
9
        return sizeof(JsonbValue) + sizeof(precision) + sizeof(scale) + sizeof(value);
802
9
    }
_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
2.12k
    unsigned int getBlobLen() const { return size; }
817
818
    // return the blob as byte array
819
4.55k
    const char* getBlob() const { return payload; }
820
821
    // size of the total packed bytes
822
15.3k
    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
169
    size_t length() const {
842
        // It's an empty string
843
169
        if (0 == size) {
844
0
            return size;
845
0
        }
846
        // The string stored takes all the spaces in payload
847
169
        if (payload[size - 1] != 0) {
848
169
            return size;
849
169
        }
850
        // It's shorter than the size of payload
851
0
        return strnlen(payload, size);
852
169
    }
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.96k
    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
1
    const_iterator search(const char* key) const {
884
1
        if (!key) {
885
0
            return end();
886
0
        }
887
1
        return search(key, (unsigned int)strlen(key));
888
1
    }
889
890
33
    const_iterator search(const char* key, unsigned int klen) const {
891
33
        if (!key || !klen) {
892
0
            return end();
893
0
        }
894
33
        return internalSearch(key, klen);
895
33
    }
896
897
    // Get number of elements in object
898
57
    int numElem() const {
899
57
        const char* pch = payload;
900
57
        const char* fence = payload + size;
901
902
57
        unsigned int num = 0;
903
149
        while (pch < fence) {
904
92
            auto* pkey = (JsonbKeyValue*)(pch);
905
92
            ++num;
906
92
            pch += pkey->numPackedBytes();
907
92
        }
908
909
57
        assert(pch == fence);
910
911
57
        return num;
912
57
    }
913
914
    // find the JSONB value by a key string (null terminated)
915
1
    const JsonbValue* find(const char* key) const {
916
1
        if (!key) {
917
0
            return nullptr;
918
0
        }
919
1
        return find(key, (unsigned int)strlen(key));
920
1
    }
921
922
    // find the JSONB value by a key string (with length)
923
31
    const JsonbValue* find(const char* key, unsigned int klen) const {
924
31
        const_iterator kv = search(key, klen);
925
31
        if (end() == kv) {
926
2
            return nullptr;
927
2
        }
928
29
        return kv->value();
929
31
    }
930
931
1.69k
    const_iterator begin() const { return const_iterator((pointer)payload); }
932
933
18.5k
    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
33
    const_iterator internalSearch(const char* key, unsigned int klen) const {
939
33
        const char* pch = payload;
940
33
        const char* fence = payload + size;
941
942
43
        while (pch < fence) {
943
41
            const auto* pkey = (const JsonbKeyValue*)(pch);
944
41
            if (klen == pkey->klen() && strncmp(key, pkey->getKeyStr(), klen) == 0) {
945
31
                return const_iterator(pkey);
946
31
            }
947
10
            pch += pkey->numPackedBytes();
948
10
        }
949
950
33
        assert(pch == fence);
951
952
2
        return end();
953
2
    }
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
64
    const JsonbValue* get(int idx) const {
967
64
        if (idx < 0) {
968
0
            return nullptr;
969
0
        }
970
971
64
        const char* pch = payload;
972
64
        const char* fence = payload + size;
973
974
119
        while (pch < fence && idx-- > 0) {
975
55
            pch += ((const JsonbValue*)pch)->numPackedBytes();
976
55
        }
977
64
        if (idx > 0 || pch == fence) {
978
7
            return nullptr;
979
7
        }
980
981
57
        return (const JsonbValue*)pch;
982
64
    }
983
984
    // Get number of elements in array
985
28
    int numElem() const {
986
28
        const char* pch = payload;
987
28
        const char* fence = payload + size;
988
989
28
        unsigned int num = 0;
990
91
        while (pch < fence) {
991
63
            ++num;
992
63
            pch += ((const JsonbValue*)pch)->numPackedBytes();
993
63
        }
994
995
28
        assert(pch == fence);
996
997
28
        return num;
998
28
    }
999
1000
73
    const_iterator begin() const { return const_iterator((pointer)payload); }
1001
1002
72
    const_iterator end() const { return const_iterator((pointer)(payload + size)); }
1003
};
1004
1005
namespace jsonb_detail {
1006
1007
14
inline bool array_contains_value(const ArrayVal* target_array, const JsonbValue* candidate) {
1008
14
    const int target_num = target_array->numElem();
1009
25
    for (int i = 0; i < target_num; ++i) {
1010
22
        if (target_array->get(i)->contains(candidate)) {
1011
11
            return true;
1012
11
        }
1013
22
    }
1014
3
    return false;
1015
14
}
1016
1017
7
inline bool array_contains_array(const ArrayVal* target_array, const ArrayVal* candidate_array) {
1018
7
    const int candidate_num = candidate_array->numElem();
1019
17
    for (int i = 0; i < candidate_num; ++i) {
1020
12
        if (!array_contains_value(target_array, candidate_array->get(i))) {
1021
2
            return false;
1022
2
        }
1023
12
    }
1024
5
    return true;
1025
7
}
1026
1027
} // namespace jsonb_detail
1028
1029
12
inline const JsonbValue* JsonbDocument::createValue(const char* pb, size_t size) {
1030
12
    if (!pb || size < sizeof(JsonbHeader) + sizeof(JsonbValue)) {
1031
0
        return nullptr;
1032
0
    }
1033
1034
12
    auto* doc = (JsonbDocument*)pb;
1035
12
    if (doc->header_.ver_ != JSONB_VER) {
1036
0
        return nullptr;
1037
0
    }
1038
1039
12
    const auto* val = (const JsonbValue*)doc->payload_;
1040
12
    if (size != sizeof(JsonbHeader) + val->numPackedBytes()) {
1041
0
        return nullptr;
1042
0
    }
1043
1044
12
    return val;
1045
12
}
1046
1047
0
inline unsigned int JsonbDocument::numPackedBytes() const {
1048
0
    return ((const JsonbValue*)payload_)->numPackedBytes() + sizeof(header_);
1049
0
}
1050
1051
17.6k
inline unsigned int JsonbKeyValue::numPackedBytes() const {
1052
17.6k
    unsigned int ks = keyPackedBytes();
1053
17.6k
    const auto* val = (const JsonbValue*)(((char*)this) + ks);
1054
17.6k
    return ks + val->numPackedBytes();
1055
17.6k
}
1056
1057
// Poor man's "virtual" function JsonbValue::numPackedBytes
1058
71.5k
inline unsigned int JsonbValue::numPackedBytes() const {
1059
71.5k
    switch (type) {
1060
2.76k
    case JsonbType::T_Null:
1061
12.3k
    case JsonbType::T_True:
1062
12.8k
    case JsonbType::T_False: {
1063
12.8k
        return sizeof(type);
1064
12.3k
    }
1065
1066
837
    case JsonbType::T_Int8: {
1067
837
        return sizeof(type) + sizeof(int8_t);
1068
12.3k
    }
1069
122
    case JsonbType::T_Int16: {
1070
122
        return sizeof(type) + sizeof(int16_t);
1071
12.3k
    }
1072
3.49k
    case JsonbType::T_Int32: {
1073
3.49k
        return sizeof(type) + sizeof(int32_t);
1074
12.3k
    }
1075
12.2k
    case JsonbType::T_Int64: {
1076
12.2k
        return sizeof(type) + sizeof(int64_t);
1077
12.3k
    }
1078
10.6k
    case JsonbType::T_Double: {
1079
10.6k
        return sizeof(type) + sizeof(double);
1080
12.3k
    }
1081
26
    case JsonbType::T_Float: {
1082
26
        return sizeof(type) + sizeof(float);
1083
12.3k
    }
1084
13.9k
    case JsonbType::T_Int128: {
1085
13.9k
        return sizeof(type) + sizeof(int128_t);
1086
12.3k
    }
1087
10.9k
    case JsonbType::T_String:
1088
15.3k
    case JsonbType::T_Binary: {
1089
15.3k
        return unpack<JsonbBinaryVal>()->numPackedBytes();
1090
10.9k
    }
1091
1092
1.77k
    case JsonbType::T_Object:
1093
1.96k
    case JsonbType::T_Array: {
1094
1.96k
        return unpack<ContainerVal>()->numPackedBytes();
1095
1.77k
    }
1096
7
    case JsonbType::T_Decimal32: {
1097
7
        return JsonbDecimal32::numPackedBytes();
1098
1.77k
    }
1099
7
    case JsonbType::T_Decimal64: {
1100
7
        return JsonbDecimal64::numPackedBytes();
1101
1.77k
    }
1102
9
    case JsonbType::T_Decimal128: {
1103
9
        return JsonbDecimal128::numPackedBytes();
1104
1.77k
    }
1105
6
    case JsonbType::T_Decimal256: {
1106
6
        return JsonbDecimal256::numPackedBytes();
1107
1.77k
    }
1108
0
    case JsonbType::NUM_TYPES:
1109
0
        break;
1110
71.5k
    }
1111
1112
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1113
0
                    static_cast<int32_t>(type));
1114
71.5k
}
1115
1116
6
inline int JsonbValue::numElements() const {
1117
6
    switch (type) {
1118
0
    case JsonbType::T_Int8:
1119
0
    case JsonbType::T_Int16:
1120
0
    case JsonbType::T_Int32:
1121
0
    case JsonbType::T_Int64:
1122
0
    case JsonbType::T_Double:
1123
0
    case JsonbType::T_Float:
1124
0
    case JsonbType::T_Int128:
1125
1
    case JsonbType::T_String:
1126
1
    case JsonbType::T_Binary:
1127
2
    case JsonbType::T_Null:
1128
2
    case JsonbType::T_True:
1129
2
    case JsonbType::T_False:
1130
2
    case JsonbType::T_Decimal32:
1131
2
    case JsonbType::T_Decimal64:
1132
2
    case JsonbType::T_Decimal128:
1133
2
    case JsonbType::T_Decimal256: {
1134
2
        return 1;
1135
2
    }
1136
0
    case JsonbType::T_Object: {
1137
0
        return unpack<ObjectVal>()->numElem();
1138
2
    }
1139
4
    case JsonbType::T_Array: {
1140
4
        return unpack<ArrayVal>()->numElem();
1141
2
    }
1142
0
    case JsonbType::NUM_TYPES:
1143
0
        break;
1144
6
    }
1145
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1146
0
                    static_cast<int32_t>(type));
1147
6
}
1148
1149
32
inline bool JsonbValue::contains(const JsonbValue* rhs) const {
1150
32
    switch (type) {
1151
19
    case JsonbType::T_Int8:
1152
19
    case JsonbType::T_Int16:
1153
19
    case JsonbType::T_Int32:
1154
19
    case JsonbType::T_Int64:
1155
19
    case JsonbType::T_Int128: {
1156
19
        return rhs->isInt() && this->int_val() == rhs->int_val();
1157
19
    }
1158
0
    case JsonbType::T_Double:
1159
0
    case JsonbType::T_Float: {
1160
0
        if (!rhs->isDouble() && !rhs->isFloat()) {
1161
0
            return false;
1162
0
        }
1163
0
        double left = isDouble() ? unpack<JsonbDoubleVal>()->val() : unpack<JsonbFloatVal>()->val();
1164
0
        double right = rhs->isDouble() ? rhs->unpack<JsonbDoubleVal>()->val()
1165
0
                                       : rhs->unpack<JsonbFloatVal>()->val();
1166
0
        return left == right;
1167
0
    }
1168
1
    case JsonbType::T_String:
1169
1
    case JsonbType::T_Binary: {
1170
1
        if (rhs->isString() || rhs->isBinary()) {
1171
1
            const auto* str_value1 = unpack<JsonbStringVal>();
1172
1
            const auto* str_value2 = rhs->unpack<JsonbStringVal>();
1173
1
            return str_value1->length() == str_value2->length() &&
1174
1
                   std::memcmp(str_value1->getBlob(), str_value2->getBlob(),
1175
1
                               str_value1->length()) == 0;
1176
1
        }
1177
0
        return false;
1178
1
    }
1179
9
    case JsonbType::T_Array: {
1180
9
        const auto* lhs_array = unpack<ArrayVal>();
1181
9
        if (rhs->isArray()) {
1182
7
            return jsonb_detail::array_contains_array(lhs_array, rhs->unpack<ArrayVal>());
1183
7
        }
1184
2
        return jsonb_detail::array_contains_value(lhs_array, rhs);
1185
9
    }
1186
3
    case JsonbType::T_Object: {
1187
3
        if (rhs->isObject()) {
1188
2
            const auto* obj_value1 = unpack<ObjectVal>();
1189
2
            const auto* obj_value2 = rhs->unpack<ObjectVal>();
1190
3
            for (auto it = obj_value2->begin(); it != obj_value2->end(); ++it) {
1191
2
                const JsonbValue* value = obj_value1->find(it->getKeyStr(), it->klen());
1192
2
                if (value == nullptr || !value->contains(it->value())) {
1193
1
                    return false;
1194
1
                }
1195
2
            }
1196
1
            return true;
1197
2
        }
1198
1
        return false;
1199
3
    }
1200
0
    case JsonbType::T_Null: {
1201
0
        return rhs->isNull();
1202
3
    }
1203
0
    case JsonbType::T_True: {
1204
0
        return rhs->isTrue();
1205
3
    }
1206
0
    case JsonbType::T_False: {
1207
0
        return rhs->isFalse();
1208
3
    }
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
32
    }
1248
1249
0
    throw Exception(ErrorCode::INTERNAL_ERROR, "Invalid JSONB value type: {}",
1250
0
                    static_cast<int32_t>(type));
1251
32
}
1252
1253
100
inline bool JsonbPath::seek(const char* key_path, size_t kp_len) {
1254
100
    while (kp_len > 0 && std::isspace(key_path[kp_len - 1])) {
1255
0
        --kp_len;
1256
0
    }
1257
1258
    //path invalid
1259
100
    if (!key_path || kp_len == 0) {
1260
0
        return false;
1261
0
    }
1262
100
    Stream stream(key_path, kp_len);
1263
100
    stream.skip_whitespace();
1264
100
    if (stream.exhausted() || stream.read() != SCOPE) {
1265
        //path invalid
1266
0
        return false;
1267
0
    }
1268
1269
194
    while (!stream.exhausted()) {
1270
94
        stream.skip_whitespace();
1271
94
        stream.clear_leg_ptr();
1272
94
        stream.clear_leg_len();
1273
1274
94
        if (!JsonbPath::parsePath(&stream, this)) {
1275
            //path invalid
1276
0
            return false;
1277
0
        }
1278
94
    }
1279
100
    return true;
1280
100
}
1281
1282
94
inline bool JsonbPath::parsePath(Stream* stream, JsonbPath* path) {
1283
    // $[0]
1284
94
    if (stream->peek() == BEGIN_ARRAY) {
1285
58
        return parse_array(stream, path);
1286
58
    }
1287
    // $.a or $.[0]
1288
    // Keep $.[0] for backward compatibility: although the dot before an array
1289
    // leg is non-standard, existing JSONB users may rely on it.
1290
36
    else if (stream->peek() == BEGIN_MEMBER) {
1291
        // advance past the .
1292
34
        stream->skip(1);
1293
1294
34
        if (stream->exhausted()) {
1295
0
            return false;
1296
0
        }
1297
1298
        // $.[0]
1299
34
        if (stream->peek() == BEGIN_ARRAY) {
1300
0
            return parse_array(stream, path);
1301
0
        }
1302
        // $.a
1303
34
        else {
1304
34
            return parse_member(stream, path);
1305
34
        }
1306
34
    } else if (stream->peek() == WILDCARD) {
1307
2
        stream->skip(1);
1308
2
        if (stream->exhausted()) {
1309
0
            return false;
1310
0
        }
1311
1312
        // $**
1313
2
        if (stream->peek() == WILDCARD) {
1314
2
            path->_is_supper_wildcard = true;
1315
2
        }
1316
1317
2
        stream->skip(1);
1318
2
        if (stream->exhausted()) {
1319
0
            return false;
1320
0
        }
1321
1322
2
        if (stream->peek() == BEGIN_ARRAY) {
1323
0
            return parse_array(stream, path);
1324
2
        } else if (stream->peek() == BEGIN_MEMBER) {
1325
            // advance past the .
1326
2
            stream->skip(1);
1327
1328
2
            if (stream->exhausted()) {
1329
0
                return false;
1330
0
            }
1331
1332
            // $**.[0]
1333
            // Keep the dot-array form compatible with the root path behavior.
1334
2
            if (stream->peek() == BEGIN_ARRAY) {
1335
0
                return parse_array(stream, path);
1336
0
            }
1337
            // $.a
1338
2
            else {
1339
2
                return parse_member(stream, path);
1340
2
            }
1341
2
        }
1342
0
        return false;
1343
2
    } else {
1344
0
        return false; //invalid json path
1345
0
    }
1346
94
}
1347
1348
58
inline bool JsonbPath::parse_array(Stream* stream, JsonbPath* path) {
1349
58
    assert(stream->peek() == BEGIN_ARRAY);
1350
58
    stream->skip(1);
1351
58
    if (stream->exhausted()) {
1352
0
        return false;
1353
0
    }
1354
1355
58
    if (stream->peek() == WILDCARD) {
1356
        // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1357
        // using const_cast is acceptable.
1358
0
        stream->set_leg_ptr(const_cast<char*>(stream->position()));
1359
0
        stream->add_leg_len();
1360
0
        stream->skip(1);
1361
0
        if (stream->exhausted()) {
1362
0
            return false;
1363
0
        }
1364
1365
0
        if (stream->peek() == END_ARRAY) {
1366
0
            std::unique_ptr<leg_info> leg(
1367
0
                    new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, ARRAY_CODE));
1368
0
            path->add_leg_to_leg_vector(std::move(leg));
1369
0
            stream->skip(1);
1370
0
            path->_is_wildcard = true;
1371
0
            return true;
1372
0
        } else {
1373
0
            return false;
1374
0
        }
1375
0
    }
1376
1377
    // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1378
    // using const_cast is acceptable.
1379
58
    stream->set_leg_ptr(const_cast<char*>(stream->position()));
1380
1381
116
    for (; !stream->exhausted() && stream->peek() != END_ARRAY; stream->advance()) {
1382
58
        stream->add_leg_len();
1383
58
    }
1384
1385
58
    if (stream->exhausted() || stream->peek() != END_ARRAY) {
1386
0
        return false;
1387
58
    } else {
1388
58
        stream->skip(1);
1389
58
    }
1390
1391
    //parse array index to int
1392
1393
58
    std::string_view idx_string(stream->get_leg_ptr(), stream->get_leg_len());
1394
58
    int index = 0;
1395
1396
    // Match "last" case-insensitively for compatibility with existing JSONB
1397
    // paths such as [Last] and [LAST].
1398
58
    if (stream->get_leg_len() >= 4 &&
1399
58
        std::equal(LAST, LAST + 4, stream->get_leg_ptr(),
1400
0
                   [](char c1, char c2) { return std::tolower(c1) == std::tolower(c2); })) {
1401
0
        auto pos = idx_string.find(MINUS);
1402
1403
0
        if (pos != std::string::npos) {
1404
0
            for (size_t i = 4; i < pos; ++i) {
1405
0
                if (std::isspace(idx_string[i])) {
1406
0
                    continue;
1407
0
                } else {
1408
                    // leading zeroes are not allowed
1409
0
                    LOG(WARNING) << "Non-space char in idx_string: '" << idx_string << "'";
1410
0
                    return false;
1411
0
                }
1412
0
            }
1413
0
            idx_string = idx_string.substr(pos + 1);
1414
0
            idx_string = trim(idx_string);
1415
1416
            // Keep numeric-prefix parsing for last-N offsets as existing JSONB
1417
            // path behavior.
1418
0
            auto result = std::from_chars(idx_string.data(), idx_string.data() + idx_string.size(),
1419
0
                                          index);
1420
0
            if (result.ec != std::errc()) {
1421
0
                LOG(WARNING) << "Invalid index in JSON path: '" << idx_string << "'";
1422
0
                return false;
1423
0
            }
1424
1425
0
        } else if (stream->get_leg_len() > 4) {
1426
0
            return false;
1427
0
        }
1428
1429
0
        std::unique_ptr<leg_info> leg(new leg_info(nullptr, 0, -index - 1, ARRAY_CODE));
1430
0
        path->add_leg_to_leg_vector(std::move(leg));
1431
1432
0
        return true;
1433
0
    }
1434
1435
    // Preserve legacy numeric-prefix parsing for array indexes. std::from_chars
1436
    // may stop before the end (for example [1.5] is parsed as index 1), and
1437
    // current JSONB path semantics treat that as supported behavior.
1438
58
    auto result = std::from_chars(idx_string.data(), idx_string.data() + idx_string.size(), index);
1439
1440
58
    if (result.ec != std::errc()) {
1441
0
        return false;
1442
0
    }
1443
1444
58
    std::unique_ptr<leg_info> leg(new leg_info(nullptr, 0, index, ARRAY_CODE));
1445
58
    path->add_leg_to_leg_vector(std::move(leg));
1446
1447
58
    return true;
1448
58
}
1449
1450
36
inline bool JsonbPath::parse_member(Stream* stream, JsonbPath* path) {
1451
36
    if (stream->exhausted()) {
1452
0
        return false;
1453
0
    }
1454
1455
36
    if (stream->peek() == WILDCARD) {
1456
        // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1457
        // using const_cast is acceptable.
1458
0
        stream->set_leg_ptr(const_cast<char*>(stream->position()));
1459
0
        stream->add_leg_len();
1460
0
        stream->skip(1);
1461
0
        std::unique_ptr<leg_info> leg(
1462
0
                new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, MEMBER_CODE));
1463
0
        path->add_leg_to_leg_vector(std::move(leg));
1464
0
        path->_is_wildcard = true;
1465
0
        return true;
1466
0
    }
1467
1468
    // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1469
    // using const_cast is acceptable.
1470
36
    stream->set_leg_ptr(const_cast<char*>(stream->position()));
1471
1472
36
    const char* left_quotation_marks = nullptr;
1473
36
    const char* right_quotation_marks = nullptr;
1474
1475
104
    for (; !stream->exhausted(); stream->advance()) {
1476
        // Only accept space characters quoted by double quotes.
1477
68
        if (std::isspace(stream->peek()) && left_quotation_marks == nullptr) {
1478
0
            return false;
1479
68
        } else if (stream->peek() == ESCAPE) {
1480
0
            stream->add_leg_len();
1481
0
            stream->skip(1);
1482
0
            stream->add_leg_len();
1483
0
            stream->set_has_escapes(true);
1484
0
            if (stream->exhausted()) {
1485
0
                return false;
1486
0
            }
1487
0
            continue;
1488
68
        } else if (stream->peek() == DOUBLE_QUOTE) {
1489
0
            if (left_quotation_marks == nullptr) {
1490
0
                left_quotation_marks = stream->position();
1491
                // Called by function_jsonb.cpp, the variables passed in originate from a mutable block;
1492
                // using const_cast is acceptable.
1493
0
                stream->set_leg_ptr(const_cast<char*>(++left_quotation_marks));
1494
0
                continue;
1495
0
            } else {
1496
0
                right_quotation_marks = stream->position();
1497
0
                stream->skip(1);
1498
0
                break;
1499
0
            }
1500
68
        } else if (stream->peek() == BEGIN_MEMBER || stream->peek() == BEGIN_ARRAY) {
1501
0
            if (left_quotation_marks == nullptr) {
1502
0
                break;
1503
0
            }
1504
0
        }
1505
1506
68
        stream->add_leg_len();
1507
68
    }
1508
1509
36
    if ((left_quotation_marks != nullptr && right_quotation_marks == nullptr) ||
1510
36
        stream->get_leg_ptr() == nullptr || stream->get_leg_len() == 0) {
1511
0
        return false; //invalid json path
1512
0
    }
1513
1514
36
    if (stream->get_has_escapes()) {
1515
0
        stream->remove_escapes();
1516
0
    }
1517
1518
36
    std::unique_ptr<leg_info> leg(
1519
36
            new leg_info(stream->get_leg_ptr(), stream->get_leg_len(), 0, MEMBER_CODE));
1520
36
    path->add_leg_to_leg_vector(std::move(leg));
1521
1522
36
    return true;
1523
36
}
1524
1525
static_assert(is_pod_v<JsonbDocument>, "JsonbDocument must be standard layout and trivial");
1526
static_assert(is_pod_v<JsonbValue>, "JsonbValue must be standard layout and trivial");
1527
static_assert(is_pod_v<JsonbDecimal32>, "JsonbDecimal32 must be standard layout and trivial");
1528
static_assert(is_pod_v<JsonbDecimal64>, "JsonbDecimal64 must be standard layout and trivial");
1529
static_assert(is_pod_v<JsonbDecimal128>, "JsonbDecimal128 must be standard layout and trivial");
1530
static_assert(is_pod_v<JsonbDecimal256>, "JsonbDecimal256 must be standard layout and trivial");
1531
static_assert(is_pod_v<JsonbInt8Val>, "JsonbInt8Val must be standard layout and trivial");
1532
static_assert(is_pod_v<JsonbInt32Val>, "JsonbInt32Val must be standard layout and trivial");
1533
static_assert(is_pod_v<JsonbInt64Val>, "JsonbInt64Val must be standard layout and trivial");
1534
static_assert(is_pod_v<JsonbInt128Val>, "JsonbInt128Val must be standard layout and trivial");
1535
static_assert(is_pod_v<JsonbDoubleVal>, "JsonbDoubleVal must be standard layout and trivial");
1536
static_assert(is_pod_v<JsonbFloatVal>, "JsonbFloatVal must be standard layout and trivial");
1537
static_assert(is_pod_v<JsonbBinaryVal>, "JsonbBinaryVal must be standard layout and trivial");
1538
static_assert(is_pod_v<ContainerVal>, "ContainerVal must be standard layout and trivial");
1539
1540
#define ASSERT_DECIMAL_LAYOUT(type)                \
1541
    static_assert(offsetof(type, precision) == 0); \
1542
    static_assert(offsetof(type, scale) == 4);     \
1543
    static_assert(offsetof(type, value) == 8);
1544
1545
ASSERT_DECIMAL_LAYOUT(JsonbDecimal32)
1546
ASSERT_DECIMAL_LAYOUT(JsonbDecimal64)
1547
ASSERT_DECIMAL_LAYOUT(JsonbDecimal128)
1548
ASSERT_DECIMAL_LAYOUT(JsonbDecimal256)
1549
1550
#define ASSERT_NUMERIC_LAYOUT(type) static_assert(offsetof(type, num) == 0);
1551
1552
ASSERT_NUMERIC_LAYOUT(JsonbInt8Val)
1553
ASSERT_NUMERIC_LAYOUT(JsonbInt32Val)
1554
ASSERT_NUMERIC_LAYOUT(JsonbInt64Val)
1555
ASSERT_NUMERIC_LAYOUT(JsonbInt128Val)
1556
ASSERT_NUMERIC_LAYOUT(JsonbDoubleVal)
1557
1558
static_assert(offsetof(JsonbBinaryVal, size) == 0);
1559
static_assert(offsetof(JsonbBinaryVal, payload) == 4);
1560
1561
static_assert(offsetof(ContainerVal, size) == 0);
1562
static_assert(offsetof(ContainerVal, payload) == 4);
1563
1564
#pragma pack(pop)
1565
#if defined(__clang__)
1566
#pragma clang diagnostic pop
1567
#endif
1568
} // namespace doris
1569
1570
#endif // JSONB_JSONBDOCUMENT_H