Coverage Report

Created: 2026-05-22 01:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/util/jsonb_writer.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 file defines JsonbWriterT (template) and JsonbWriter.
13
 *
14
 * JsonbWriterT is a template class which implements an JSONB serializer.
15
 * Users call various write functions of JsonbWriterT object to write values
16
 * directly to JSONB packed bytes. All write functions of value or key return
17
 * the number of bytes written to JSONB, or 0 if there is an error. To write an
18
 * object, an array, or a string, you must call writeStart[..] before writing
19
 * values or key, and call writeEnd[..] after finishing at the end.
20
 *
21
 * By default, an JsonbWriterT object creates an output stream buffer.
22
 * Alternatively, you can also pass any output stream object to a writer, as
23
 * long as the stream object implements some basic functions of std::ostream
24
 * (such as JsonbOutStream, see JsonbStream.h).
25
 *
26
 * JsonbWriter specializes JsonbWriterT with JsonbOutStream type (see
27
 * JsonbStream.h). So unless you want to provide own a different output stream
28
 * type, use JsonbParser object.
29
 *
30
 * @author Tian Xia <tianx@fb.com>
31
 * this file is copied from 
32
 * https://github.com/facebook/mysql-5.6/blob/fb-mysql-5.6.35/fbson/FbsonWriter.h
33
 * and modified by Doris
34
 */
35
36
#ifndef JSONB_JSONBWRITER_H
37
#define JSONB_JSONBWRITER_H
38
39
#include <glog/logging.h>
40
41
#include <cstdint>
42
#include <limits>
43
#include <stack>
44
#include <string>
45
46
#include "common/status.h"
47
#include "core/types.h"
48
#include "util/jsonb_document.h"
49
#include "util/jsonb_stream.h"
50
51
namespace doris {
52
53
using int128_t = __int128;
54
55
template <class OS_TYPE>
56
class JsonbWriterT {
57
    /// TODO: maybe we should not use a template class here
58
    static_assert(std::is_same_v<OS_TYPE, JsonbOutStream>);
59
60
public:
61
1.17M
    JsonbWriterT() : alloc_(true), hasHdr_(false), kvState_(WS_Value), str_pos_(0) {
62
1.17M
        os_ = new OS_TYPE();
63
1.17M
    }
64
65
    explicit JsonbWriterT(OS_TYPE& os)
66
            : os_(&os), alloc_(false), hasHdr_(false), kvState_(WS_Value), str_pos_(0) {}
67
68
1.17M
    ~JsonbWriterT() {
69
1.17M
        if (alloc_) {
70
1.17M
            delete os_;
71
1.17M
        }
72
1.17M
    }
73
74
    JsonbWriterT<OS_TYPE>& operator=(JsonbWriterT<OS_TYPE>&& other) {
75
        if (this != &other) {
76
            if (alloc_) {
77
                delete os_;
78
            }
79
            os_ = other.os_;
80
            other.os_ = nullptr;
81
            alloc_ = other.alloc_;
82
            other.alloc_ = false;
83
            hasHdr_ = other.hasHdr_;
84
            kvState_ = other.kvState_;
85
            str_pos_ = other.str_pos_;
86
            first_ = other.first_;
87
            stack_ = std::move(other.stack_);
88
        }
89
        return *this;
90
    }
91
92
58.3k
    void reset() {
93
58.3k
        os_->clear();
94
58.3k
        os_->seekp(0);
95
58.3k
        hasHdr_ = false;
96
58.3k
        kvState_ = WS_Value;
97
58.3k
        first_ = true;
98
58.3k
        for (; !stack_.empty(); stack_.pop()) {
99
0
            ;
100
0
        }
101
58.3k
    }
102
103
    // write a key string (or key id if an external dict is provided)
104
9.42k
    bool writeKey(const char* key, uint8_t len) {
105
9.42k
        if (!stack_.empty() && verifyKeyState()) {
106
9.42k
            os_->put(len);
107
9.42k
            if (len == 0) {
108
                // NOTE: we use sMaxKeyId to represent an empty key
109
431
                JsonbKeyValue::keyid_type idx = JsonbKeyValue::sMaxKeyId;
110
431
                os_->write((char*)&idx, sizeof(JsonbKeyValue::keyid_type));
111
8.99k
            } else {
112
8.99k
                os_->write(key, len);
113
8.99k
            }
114
9.42k
            kvState_ = WS_Key;
115
9.42k
            return true;
116
9.42k
        }
117
118
1
        return false;
119
9.42k
    }
120
121
25.6k
    bool writeValue(const JsonbValue* value) {
122
25.6k
        if (!value) {
123
0
            return writeNull();
124
0
        }
125
126
25.6k
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
127
25.6k
            if (!writeFirstHeader()) {
128
0
                return false;
129
0
            }
130
25.6k
            os_->write((char*)value, value->numPackedBytes());
131
25.6k
            kvState_ = WS_Value;
132
25.6k
            return true;
133
25.6k
        }
134
0
        return false;
135
25.6k
    }
136
137
44
    bool writeValueSimple(const JsonbValue* value) {
138
44
        DCHECK(value) << "value should not be nullptr";
139
44
        DCHECK(first_) << "only called at the beginning";
140
44
        DCHECK(stack_.empty()) << "only called at the beginning";
141
44
        DCHECK(!hasHdr_) << "only called at the beginning";
142
44
        first_ = false;
143
44
        writeHeader();
144
44
        os_->write((char*)value, value->numPackedBytes());
145
44
        kvState_ = WS_Value;
146
44
        return true;
147
44
    }
148
149
    // write a key id
150
18.2k
    bool writeKey(JsonbKeyValue::keyid_type idx) {
151
18.2k
        if (!stack_.empty() && verifyKeyState()) {
152
16.8k
            os_->put(0);
153
16.8k
            os_->write((char*)&idx, sizeof(JsonbKeyValue::keyid_type));
154
16.8k
            kvState_ = WS_Key;
155
16.8k
            return true;
156
16.8k
        }
157
158
1.42k
        return false;
159
18.2k
    }
160
161
2.30M
    bool writeFirstHeader() {
162
2.30M
        if (first_ && stack_.empty()) {
163
1.10M
            first_ = false;
164
            // if this is a new JSONB, write the header
165
1.10M
            if (!hasHdr_) {
166
1.10M
                writeHeader();
167
1.10M
                return true;
168
1.10M
            } else {
169
0
                return false;
170
0
            }
171
1.19M
        } else {
172
1.19M
            return true;
173
1.19M
        }
174
2.30M
    }
175
176
26.0k
    bool writeNull() {
177
26.0k
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
178
26.0k
            if (!writeFirstHeader()) {
179
0
                return false;
180
0
            }
181
26.0k
            os_->put((JsonbTypeUnder)JsonbType::T_Null);
182
26.0k
            kvState_ = WS_Value;
183
26.0k
            return true;
184
26.0k
        }
185
186
0
        return false;
187
26.0k
    }
188
189
89.9k
    bool writeBool(bool b) {
190
89.9k
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
191
89.9k
            if (!writeFirstHeader()) {
192
0
                return false;
193
0
            }
194
89.9k
            if (b) {
195
57.0k
                os_->put((JsonbTypeUnder)JsonbType::T_True);
196
57.0k
            } else {
197
32.9k
                os_->put((JsonbTypeUnder)JsonbType::T_False);
198
32.9k
            }
199
200
89.9k
            kvState_ = WS_Value;
201
89.9k
            return true;
202
89.9k
        }
203
204
0
        return false;
205
89.9k
    }
206
207
    // This function is a helper. It will make use of smallest space to
208
    // write an int
209
5
    bool writeInt(int64_t val) {
210
5
        if (val >= std::numeric_limits<int8_t>::min() &&
211
5
            val <= std::numeric_limits<int8_t>::max()) {
212
3
            return writeInt8((int8_t)val);
213
3
        } else if (val >= std::numeric_limits<int16_t>::min() &&
214
2
                   val <= std::numeric_limits<int16_t>::max()) {
215
2
            return writeInt16((int16_t)val);
216
2
        } else if (val >= std::numeric_limits<int32_t>::min() &&
217
0
                   val <= std::numeric_limits<int32_t>::max()) {
218
0
            return writeInt32((int32_t)val);
219
0
        } else {
220
0
            return writeInt64(val);
221
0
        }
222
5
    }
223
224
48.1k
    bool writeInt8(int8_t v) {
225
48.1k
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
226
48.1k
            if (!writeFirstHeader()) {
227
0
                return false;
228
0
            }
229
48.1k
            os_->put((JsonbTypeUnder)JsonbType::T_Int8);
230
48.1k
            os_->put(v);
231
48.1k
            kvState_ = WS_Value;
232
48.1k
            return true;
233
48.1k
        }
234
235
0
        return false;
236
48.1k
    }
237
238
189
    bool writeInt16(int16_t v) {
239
189
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
240
189
            if (!writeFirstHeader()) {
241
0
                return false;
242
0
            }
243
189
            os_->put((JsonbTypeUnder)JsonbType::T_Int16);
244
189
            os_->write((char*)&v, sizeof(int16_t));
245
189
            kvState_ = WS_Value;
246
189
            return true;
247
189
        }
248
249
0
        return false;
250
189
    }
251
252
3.67k
    bool writeInt32(int32_t v) {
253
3.67k
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
254
3.67k
            if (!writeFirstHeader()) {
255
0
                return false;
256
0
            }
257
3.67k
            os_->put((JsonbTypeUnder)JsonbType::T_Int32);
258
3.67k
            os_->write((char*)&v, sizeof(int32_t));
259
3.67k
            kvState_ = WS_Value;
260
3.67k
            return true;
261
3.67k
        }
262
263
0
        return false;
264
3.67k
    }
265
266
722k
    bool writeInt64(int64_t v) {
267
722k
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
268
722k
            if (!writeFirstHeader()) {
269
0
                return false;
270
0
            }
271
722k
            os_->put((JsonbTypeUnder)JsonbType::T_Int64);
272
722k
            os_->write((char*)&v, sizeof(int64_t));
273
722k
            kvState_ = WS_Value;
274
722k
            return true;
275
722k
        }
276
277
0
        return false;
278
722k
    }
279
280
45.5k
    bool writeInt128(int128_t v) {
281
45.5k
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
282
45.5k
            if (!writeFirstHeader()) {
283
0
                return false;
284
0
            }
285
45.5k
            os_->put((JsonbTypeUnder)JsonbType::T_Int128);
286
45.5k
            os_->write((char*)&v, sizeof(int128_t));
287
45.5k
            kvState_ = WS_Value;
288
45.5k
            return true;
289
45.5k
        }
290
291
0
        return false;
292
45.5k
    }
293
294
280k
    bool writeDouble(double v) {
295
280k
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
296
280k
            if (!writeFirstHeader()) {
297
0
                return false;
298
0
            }
299
280k
            os_->put((JsonbTypeUnder)JsonbType::T_Double);
300
280k
            os_->write((char*)&v, sizeof(double));
301
280k
            kvState_ = WS_Value;
302
280k
            return true;
303
280k
        }
304
305
0
        return false;
306
280k
    }
307
308
23
    bool writeFloat(float v) {
309
23
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
310
23
            if (!writeFirstHeader()) {
311
0
                return false;
312
0
            }
313
23
            os_->put((JsonbTypeUnder)JsonbType::T_Float);
314
23
            os_->write((char*)&v, sizeof(float));
315
23
            kvState_ = WS_Value;
316
23
            return true;
317
23
        }
318
319
0
        return false;
320
23
    }
321
322
    template <JsonbDecimalType T>
323
31
    bool writeDecimal(const T& v, const uint32_t precision, const uint32_t scale) {
324
31
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
325
31
            if (!writeFirstHeader()) {
326
0
                return false;
327
0
            }
328
329
31
            if constexpr (std::same_as<T, Decimal256>) {
330
6
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal256);
331
9
            } else if constexpr (std::same_as<T, Decimal128V3>) {
332
9
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal128);
333
9
            } else if constexpr (std::same_as<T, Decimal64>) {
334
7
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal64);
335
9
            } else {
336
9
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal32);
337
9
            }
338
339
31
            os_->write(reinterpret_cast<const char*>(&precision), sizeof(uint32_t));
340
31
            os_->write(reinterpret_cast<const char*>(&scale), sizeof(uint32_t));
341
31
            os_->write((char*)(&(v.value)), sizeof(v.value));
342
31
            kvState_ = WS_Value;
343
31
            return true;
344
31
        }
345
346
0
        return false;
347
31
    }
_ZN5doris12JsonbWriterTINS_14JsonbOutStreamEE12writeDecimalITk16JsonbDecimalTypeNS_7DecimalIiEEEEbRKT_jj
Line
Count
Source
323
9
    bool writeDecimal(const T& v, const uint32_t precision, const uint32_t scale) {
324
9
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
325
9
            if (!writeFirstHeader()) {
326
0
                return false;
327
0
            }
328
329
            if constexpr (std::same_as<T, Decimal256>) {
330
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal256);
331
            } else if constexpr (std::same_as<T, Decimal128V3>) {
332
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal128);
333
            } else if constexpr (std::same_as<T, Decimal64>) {
334
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal64);
335
9
            } else {
336
9
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal32);
337
9
            }
338
339
9
            os_->write(reinterpret_cast<const char*>(&precision), sizeof(uint32_t));
340
9
            os_->write(reinterpret_cast<const char*>(&scale), sizeof(uint32_t));
341
9
            os_->write((char*)(&(v.value)), sizeof(v.value));
342
9
            kvState_ = WS_Value;
343
9
            return true;
344
9
        }
345
346
0
        return false;
347
9
    }
_ZN5doris12JsonbWriterTINS_14JsonbOutStreamEE12writeDecimalITk16JsonbDecimalTypeNS_7DecimalIlEEEEbRKT_jj
Line
Count
Source
323
7
    bool writeDecimal(const T& v, const uint32_t precision, const uint32_t scale) {
324
7
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
325
7
            if (!writeFirstHeader()) {
326
0
                return false;
327
0
            }
328
329
            if constexpr (std::same_as<T, Decimal256>) {
330
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal256);
331
            } else if constexpr (std::same_as<T, Decimal128V3>) {
332
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal128);
333
7
            } else if constexpr (std::same_as<T, Decimal64>) {
334
7
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal64);
335
            } else {
336
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal32);
337
            }
338
339
7
            os_->write(reinterpret_cast<const char*>(&precision), sizeof(uint32_t));
340
7
            os_->write(reinterpret_cast<const char*>(&scale), sizeof(uint32_t));
341
7
            os_->write((char*)(&(v.value)), sizeof(v.value));
342
7
            kvState_ = WS_Value;
343
7
            return true;
344
7
        }
345
346
0
        return false;
347
7
    }
_ZN5doris12JsonbWriterTINS_14JsonbOutStreamEE12writeDecimalITk16JsonbDecimalTypeNS_12Decimal128V3EEEbRKT_jj
Line
Count
Source
323
9
    bool writeDecimal(const T& v, const uint32_t precision, const uint32_t scale) {
324
9
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
325
9
            if (!writeFirstHeader()) {
326
0
                return false;
327
0
            }
328
329
            if constexpr (std::same_as<T, Decimal256>) {
330
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal256);
331
9
            } else if constexpr (std::same_as<T, Decimal128V3>) {
332
9
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal128);
333
            } else if constexpr (std::same_as<T, Decimal64>) {
334
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal64);
335
            } else {
336
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal32);
337
            }
338
339
9
            os_->write(reinterpret_cast<const char*>(&precision), sizeof(uint32_t));
340
9
            os_->write(reinterpret_cast<const char*>(&scale), sizeof(uint32_t));
341
9
            os_->write((char*)(&(v.value)), sizeof(v.value));
342
9
            kvState_ = WS_Value;
343
9
            return true;
344
9
        }
345
346
0
        return false;
347
9
    }
_ZN5doris12JsonbWriterTINS_14JsonbOutStreamEE12writeDecimalITk16JsonbDecimalTypeNS_7DecimalIN4wide7integerILm256EiEEEEEEbRKT_jj
Line
Count
Source
323
6
    bool writeDecimal(const T& v, const uint32_t precision, const uint32_t scale) {
324
6
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
325
6
            if (!writeFirstHeader()) {
326
0
                return false;
327
0
            }
328
329
6
            if constexpr (std::same_as<T, Decimal256>) {
330
6
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal256);
331
            } else if constexpr (std::same_as<T, Decimal128V3>) {
332
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal128);
333
            } else if constexpr (std::same_as<T, Decimal64>) {
334
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal64);
335
            } else {
336
                os_->put((JsonbTypeUnder)JsonbType::T_Decimal32);
337
            }
338
339
6
            os_->write(reinterpret_cast<const char*>(&precision), sizeof(uint32_t));
340
6
            os_->write(reinterpret_cast<const char*>(&scale), sizeof(uint32_t));
341
6
            os_->write((char*)(&(v.value)), sizeof(v.value));
342
6
            kvState_ = WS_Value;
343
6
            return true;
344
6
        }
345
346
0
        return false;
347
6
    }
348
349
    // must call writeStartString before writing a string val
350
1.06M
    bool writeStartString() {
351
1.06M
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
352
1.06M
            if (!writeFirstHeader()) return 0;
353
1.06M
            os_->put((JsonbTypeUnder)JsonbType::T_String);
354
1.06M
            str_pos_ = os_->tellp();
355
356
            // fill the size bytes with 0 for now
357
1.06M
            uint32_t size = 0;
358
1.06M
            os_->write((char*)&size, sizeof(uint32_t));
359
360
1.06M
            kvState_ = WS_String;
361
1.06M
            return true;
362
1.06M
        }
363
364
0
        return false;
365
1.06M
    }
366
367
    // finish writing a string val
368
1.06M
    bool writeEndString() {
369
1.06M
        if (kvState_ == WS_String) {
370
1.06M
            std::streampos cur_pos = os_->tellp();
371
1.06M
            int32_t size = (int32_t)(cur_pos - str_pos_ - sizeof(uint32_t));
372
1.06M
            assert(size >= 0);
373
374
1.06M
            os_->seekp(str_pos_);
375
1.06M
            os_->write((char*)&size, sizeof(uint32_t));
376
1.06M
            os_->seekp(cur_pos);
377
378
1.06M
            kvState_ = WS_Value;
379
1.06M
            return true;
380
1.06M
        }
381
382
0
        return false;
383
1.06M
    }
384
385
    // TODO: here changed length to uint64_t, as some api also need changed, But the thirdparty api is uint_32t
386
    // need consider a better way to handle case.
387
1.04M
    bool writeString(const char* str, uint64_t len) {
388
1.04M
        if (kvState_ == WS_String) {
389
1.04M
            os_->write(str, len);
390
1.04M
            return true;
391
1.04M
        }
392
393
5
        return false;
394
1.04M
    }
395
396
793k
    bool writeString(const std::string& str) { return writeString(str.c_str(), str.size()); }
397
    bool writeString(char ch) {
398
        if (kvState_ == WS_String) {
399
            os_->put(ch);
400
            return true;
401
        }
402
403
        return false;
404
    }
405
406
    // must call writeStartBinary before writing a binary val
407
4.36k
    bool writeStartBinary() {
408
4.36k
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
409
4.36k
            if (!writeFirstHeader()) return 0;
410
4.36k
            os_->put((JsonbTypeUnder)JsonbType::T_Binary);
411
4.36k
            str_pos_ = os_->tellp();
412
413
            // fill the size bytes with 0 for now
414
4.36k
            uint32_t size = 0;
415
4.36k
            os_->write((char*)&size, sizeof(uint32_t));
416
417
4.36k
            kvState_ = WS_Binary;
418
4.36k
            return true;
419
4.36k
        }
420
421
0
        return false;
422
4.36k
    }
423
424
    // finish writing a binary val
425
4.36k
    bool writeEndBinary() {
426
4.36k
        if (kvState_ == WS_Binary) {
427
4.36k
            std::streampos cur_pos = os_->tellp();
428
4.36k
            int32_t size = (int32_t)(cur_pos - str_pos_ - sizeof(uint32_t));
429
4.36k
            assert(size >= 0);
430
431
4.36k
            os_->seekp(str_pos_);
432
4.36k
            os_->write((char*)&size, sizeof(uint32_t));
433
4.36k
            os_->seekp(cur_pos);
434
435
4.36k
            kvState_ = WS_Value;
436
4.36k
            return true;
437
4.36k
        }
438
439
0
        return false;
440
4.36k
    }
441
442
4.36k
    bool writeBinary(const char* bin, uint64_t len) {
443
4.36k
        if (kvState_ == WS_Binary) {
444
4.36k
            os_->write(bin, len);
445
4.36k
            return true;
446
4.36k
        }
447
448
0
        return false;
449
4.36k
    }
450
451
    // must call writeStartObject before writing an object val
452
5.31k
    bool writeStartObject() {
453
5.31k
        if (stack_.empty() || verifyValueState()) {
454
5.31k
            if (stack_.empty()) {
455
                // if this is a new JSONB, write the header
456
1.56k
                if (!hasHdr_) {
457
1.56k
                    writeHeader();
458
1.56k
                } else
459
0
                    return false;
460
1.56k
            }
461
462
            // check if the object exceeds the maximum nesting level
463
5.31k
            if (stack_.size() >= MaxNestingLevel) return false;
464
465
5.31k
            os_->put((JsonbTypeUnder)JsonbType::T_Object);
466
            // save the size position
467
5.31k
            stack_.push(WriteInfo({WS_Object, os_->tellp()}));
468
469
            // fill the size bytes with 0 for now
470
5.31k
            uint32_t size = 0;
471
5.31k
            os_->write((char*)&size, sizeof(uint32_t));
472
473
5.31k
            kvState_ = WS_Value;
474
5.31k
            return true;
475
5.31k
        }
476
477
0
        return false;
478
5.31k
    }
479
480
    // finish writing an object val
481
4.75k
    bool writeEndObject() {
482
4.75k
        if (!stack_.empty() && stack_.top().state == WS_Object && kvState_ == WS_Value) {
483
4.75k
            WriteInfo& ci = stack_.top();
484
4.75k
            std::streampos cur_pos = os_->tellp();
485
4.75k
            auto size = (int32_t)(cur_pos - ci.sz_pos - sizeof(uint32_t));
486
4.75k
            assert(size >= 0);
487
488
4.75k
            os_->seekp(ci.sz_pos);
489
4.75k
            os_->write((char*)&size, sizeof(uint32_t));
490
4.75k
            os_->seekp(cur_pos);
491
4.75k
            stack_.pop();
492
493
4.75k
            return true;
494
4.75k
        }
495
496
1
        return false;
497
4.75k
    }
498
499
    // must call writeStartArray before writing an array val
500
173k
    bool writeStartArray() {
501
173k
        if (stack_.empty() || verifyValueState()) {
502
173k
            if (stack_.empty()) {
503
                // if this is a new JSONB, write the header
504
73.1k
                if (!hasHdr_) {
505
73.1k
                    writeHeader();
506
73.1k
                } else {
507
0
                    return false;
508
0
                }
509
73.1k
            }
510
511
            // check if the array exceeds the maximum nesting level
512
173k
            if (stack_.size() >= MaxNestingLevel) {
513
0
                return false;
514
0
            }
515
516
173k
            os_->put((JsonbTypeUnder)JsonbType::T_Array);
517
            // save the size position
518
173k
            stack_.push(WriteInfo({WS_Array, os_->tellp()}));
519
520
            // fill the size bytes with 0 for now
521
173k
            uint32_t size = 0;
522
173k
            os_->write((char*)&size, sizeof(uint32_t));
523
524
173k
            kvState_ = WS_Value;
525
173k
            return true;
526
173k
        }
527
528
0
        return false;
529
173k
    }
530
531
    // finish writing an array val
532
173k
    bool writeEndArray() {
533
173k
        if (!stack_.empty() && stack_.top().state == WS_Array && kvState_ == WS_Value) {
534
173k
            WriteInfo& ci = stack_.top();
535
173k
            std::streampos cur_pos = os_->tellp();
536
173k
            auto size = (int32_t)(cur_pos - ci.sz_pos - sizeof(uint32_t));
537
173k
            assert(size >= 0);
538
539
173k
            os_->seekp(ci.sz_pos);
540
173k
            os_->write((char*)&size, sizeof(uint32_t));
541
173k
            os_->seekp(cur_pos);
542
173k
            stack_.pop();
543
544
173k
            return true;
545
173k
        }
546
547
0
        return false;
548
173k
    }
549
550
2.36M
    OS_TYPE* getOutput() { return os_; }
551
552
#ifdef BE_TEST
553
42
    const JsonbDocument* getDocument() {
554
42
        const JsonbDocument* doc = nullptr;
555
42
        THROW_IF_ERROR(JsonbDocument::checkAndCreateDocument(getOutput()->getBuffer(),
556
42
                                                             getOutput()->getSize(), &doc));
557
42
        return doc;
558
42
    }
559
560
12
    const JsonbValue* getValue() {
561
12
        return JsonbDocument::createValue(getOutput()->getBuffer(), getOutput()->getSize());
562
12
    }
563
#endif
564
565
    bool writeEnd() {
566
        while (!stack_.empty()) {
567
            bool ok = false;
568
            switch (stack_.top().state) {
569
            case WS_Array:
570
                ok = writeEndArray();
571
                break;
572
            case WS_Object:
573
                ok = writeEndObject();
574
                break;
575
            case WS_String:
576
                ok = writeEndString();
577
                break;
578
            case WS_Binary:
579
                ok = writeEndBinary();
580
                break;
581
            default:
582
                ok = false;
583
                break;
584
            }
585
            if (!ok) {
586
                return false;
587
            }
588
        }
589
        return true;
590
    }
591
592
private:
593
    // verify we are in the right state before writing a value
594
1.30M
    bool verifyValueState() {
595
1.30M
        assert(!stack_.empty());
596
        // The document can only be an Object or an Array which follows
597
        // the standard.
598
1.30M
        return (stack_.top().state == WS_Object && kvState_ == WS_Key) ||
599
1.30M
               (stack_.top().state == WS_Array && kvState_ == WS_Value);
600
1.30M
    }
601
602
    // verify we are in the right state before writing a key
603
27.6k
    bool verifyKeyState() {
604
27.6k
        assert(!stack_.empty());
605
27.6k
        return stack_.top().state == WS_Object && kvState_ == WS_Value;
606
27.6k
    }
607
608
1.18M
    void writeHeader() {
609
1.18M
        os_->put(JSONB_VER);
610
1.18M
        hasHdr_ = true;
611
1.18M
    }
612
613
    enum WriteState {
614
        WS_NONE,
615
        WS_Array,
616
        WS_Object,
617
        WS_Key,
618
        WS_Value,
619
        WS_String,
620
        WS_Binary,
621
    };
622
623
    struct WriteInfo {
624
        WriteState state;
625
        std::streampos sz_pos;
626
    };
627
628
    OS_TYPE* os_ = nullptr;
629
    bool alloc_;
630
    bool hasHdr_;
631
    WriteState kvState_; // key or value state
632
    std::streampos str_pos_;
633
    std::stack<WriteInfo> stack_;
634
    bool first_ = true;
635
};
636
637
using JsonbWriter = JsonbWriterT<JsonbOutStream>;
638
639
} // namespace doris
640
641
#endif // JSONB_JSONBWRITER_H