Coverage Report

Created: 2025-07-27 00:54

/root/doris/be/src/util/jsonb_writer.h
Line
Count
Source (jump to first uncovered line)
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 <limits>
40
#include <stack>
41
#include <string>
42
43
#include "jsonb_document.h"
44
#include "jsonb_stream.h"
45
46
namespace doris {
47
48
using int128_t = __int128;
49
50
template <class OS_TYPE>
51
class JsonbWriterT {
52
public:
53
1.99k
    JsonbWriterT() : alloc_(true), hasHdr_(false), kvState_(WS_Value), str_pos_(0) {
54
1.99k
        os_ = new OS_TYPE();
55
1.99k
    }
56
57
    explicit JsonbWriterT(OS_TYPE& os)
58
            : os_(&os), alloc_(false), hasHdr_(false), kvState_(WS_Value), str_pos_(0) {}
59
60
1.99k
    ~JsonbWriterT() {
61
1.99k
        if (alloc_) {
62
1.99k
            delete os_;
63
1.99k
        }
64
1.99k
    }
65
66
1.18k
    void reset() {
67
1.18k
        os_->clear();
68
1.18k
        os_->seekp(0);
69
1.18k
        hasHdr_ = false;
70
1.18k
        kvState_ = WS_Value;
71
1.18k
        first_ = true;
72
1.19k
        for (; !stack_.empty(); stack_.pop())
73
11
            ;
74
1.18k
    }
75
76
    uint32_t writeKey(const char* key, hDictInsert handler = nullptr) {
77
        return writeKey(key, strlen(key), handler);
78
    }
79
80
    // write a key string (or key id if an external dict is provided)
81
395
    uint32_t writeKey(const char* key, uint8_t len, hDictInsert handler = nullptr) {
82
395
        if (!stack_.empty() && verifyKeyState()) {
83
395
            int key_id = -1;
84
395
            if (handler) {
85
0
                key_id = handler(key, len);
86
0
            }
87
88
395
            uint32_t size = sizeof(uint8_t);
89
395
            if (key_id < 0) {
90
395
                os_->put(len);
91
395
                if (len == 0) {
92
                    // NOTE: we use sMaxKeyId to represent an empty key
93
1
                    JsonbKeyValue::keyid_type idx = JsonbKeyValue::sMaxKeyId;
94
1
                    os_->write((char*)&idx, sizeof(JsonbKeyValue::keyid_type));
95
1
                    size += sizeof(JsonbKeyValue::keyid_type);
96
394
                } else {
97
394
                    os_->write(key, len);
98
394
                    size += len;
99
394
                }
100
395
            } else if (key_id < JsonbKeyValue::sMaxKeyId) {
101
0
                JsonbKeyValue::keyid_type idx = key_id;
102
0
                os_->put(0);
103
0
                os_->write((char*)&idx, sizeof(JsonbKeyValue::keyid_type));
104
0
                size += sizeof(JsonbKeyValue::keyid_type);
105
0
            } else { // key id overflow
106
0
                assert(0);
107
0
                return 0;
108
0
            }
109
110
395
            kvState_ = WS_Key;
111
395
            return size;
112
395
        }
113
114
0
        return 0;
115
395
    }
116
117
35
    uint32_t writeValue(const JsonbValue* value) {
118
35
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
119
35
            if (!writeFirstHeader()) return 0;
120
35
            os_->write((char*)value, value->numPackedBytes());
121
35
            kvState_ = WS_Value;
122
35
            return value->size();
123
35
        }
124
0
        return 0;
125
35
    }
126
127
    // write a key id
128
10.2k
    uint32_t writeKey(JsonbKeyValue::keyid_type idx) {
129
10.2k
        if (!stack_.empty() && verifyKeyState()) {
130
9.23k
            os_->put(0);
131
9.23k
            os_->write((char*)&idx, sizeof(JsonbKeyValue::keyid_type));
132
9.23k
            kvState_ = WS_Key;
133
9.23k
            return sizeof(uint8_t) + sizeof(JsonbKeyValue::keyid_type);
134
9.23k
        }
135
136
1.02k
        return 0;
137
10.2k
    }
138
139
11.3k
    bool writeFirstHeader() {
140
11.3k
        if (first_ && stack_.empty()) {
141
569
            first_ = false;
142
            // if this is a new JSONB, write the header
143
569
            if (!hasHdr_) {
144
569
                writeHeader();
145
569
                return true;
146
569
            } else {
147
0
                return false;
148
0
            }
149
10.7k
        } else {
150
10.7k
            return true;
151
10.7k
        }
152
11.3k
    }
153
154
2.21k
    uint32_t writeNull() {
155
2.21k
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
156
2.21k
            if (!writeFirstHeader()) return 0;
157
2.21k
            os_->put((JsonbTypeUnder)JsonbType::T_Null);
158
2.21k
            kvState_ = WS_Value;
159
2.21k
            return sizeof(JsonbValue);
160
2.21k
        }
161
162
0
        return 0;
163
2.21k
    }
164
165
329
    uint32_t writeBool(bool b) {
166
329
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
167
329
            if (!writeFirstHeader()) return 0;
168
329
            if (b) {
169
166
                os_->put((JsonbTypeUnder)JsonbType::T_True);
170
166
            } else {
171
163
                os_->put((JsonbTypeUnder)JsonbType::T_False);
172
163
            }
173
174
329
            kvState_ = WS_Value;
175
329
            return sizeof(JsonbValue);
176
329
        }
177
178
0
        return 0;
179
329
    }
180
181
    // This function is a helper. It will make use of smallest space to
182
    // write an int
183
    uint32_t writeInt(int64_t val) {
184
        if (val >= std::numeric_limits<int8_t>::min() &&
185
            val <= std::numeric_limits<int8_t>::max()) {
186
            return writeInt8((int8_t)val);
187
        } else if (val >= std::numeric_limits<int16_t>::min() &&
188
                   val <= std::numeric_limits<int16_t>::max()) {
189
            return writeInt16((int16_t)val);
190
        } else if (val >= std::numeric_limits<int32_t>::min() &&
191
                   val <= std::numeric_limits<int32_t>::max()) {
192
            return writeInt32((int32_t)val);
193
        } else {
194
            return writeInt64(val);
195
        }
196
    }
197
198
364
    uint32_t writeInt8(int8_t v) {
199
364
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
200
364
            if (!writeFirstHeader()) return 0;
201
364
            os_->put((JsonbTypeUnder)JsonbType::T_Int8);
202
364
            os_->put(v);
203
364
            kvState_ = WS_Value;
204
364
            return sizeof(JsonbInt8Val);
205
364
        }
206
207
0
        return 0;
208
364
    }
209
210
271
    uint32_t writeInt16(int16_t v) {
211
271
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
212
271
            if (!writeFirstHeader()) return 0;
213
271
            os_->put((JsonbTypeUnder)JsonbType::T_Int16);
214
271
            os_->write((char*)&v, sizeof(int16_t));
215
271
            kvState_ = WS_Value;
216
271
            return sizeof(JsonbInt16Val);
217
271
        }
218
219
0
        return 0;
220
271
    }
221
222
3.13k
    uint32_t writeInt32(int32_t v) {
223
3.13k
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
224
3.13k
            if (!writeFirstHeader()) return 0;
225
3.13k
            os_->put((JsonbTypeUnder)JsonbType::T_Int32);
226
3.13k
            os_->write((char*)&v, sizeof(int32_t));
227
3.13k
            kvState_ = WS_Value;
228
3.13k
            return sizeof(JsonbInt32Val);
229
3.13k
        }
230
231
0
        return 0;
232
3.13k
    }
233
234
61
    uint32_t writeInt64(int64_t v) {
235
61
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
236
61
            if (!writeFirstHeader()) return 0;
237
61
            os_->put((JsonbTypeUnder)JsonbType::T_Int64);
238
61
            os_->write((char*)&v, sizeof(int64_t));
239
61
            kvState_ = WS_Value;
240
61
            return sizeof(JsonbInt64Val);
241
61
        }
242
243
0
        return 0;
244
61
    }
245
246
1.02k
    uint32_t writeInt128(int128_t v) {
247
1.02k
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
248
1.02k
            if (!writeFirstHeader()) return 0;
249
1.02k
            os_->put((JsonbTypeUnder)JsonbType::T_Int128);
250
1.02k
            os_->write((char*)&v, sizeof(int128_t));
251
1.02k
            kvState_ = WS_Value;
252
1.02k
            return sizeof(JsonbInt128Val);
253
1.02k
        }
254
255
0
        return 0;
256
1.02k
    }
257
258
277
    uint32_t writeDouble(double v) {
259
277
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
260
277
            if (!writeFirstHeader()) return 0;
261
277
            os_->put((JsonbTypeUnder)JsonbType::T_Double);
262
277
            os_->write((char*)&v, sizeof(double));
263
277
            kvState_ = WS_Value;
264
277
            return sizeof(JsonbDoubleVal);
265
277
        }
266
267
0
        return 0;
268
277
    }
269
270
0
    uint32_t writeFloat(float v) {
271
0
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
272
0
            if (!writeFirstHeader()) return 0;
273
0
            os_->put((JsonbTypeUnder)JsonbType::T_Float);
274
0
            os_->write((char*)&v, sizeof(float));
275
0
            kvState_ = WS_Value;
276
0
            return sizeof(JsonbFloatVal);
277
0
        }
278
279
0
        return 0;
280
0
    }
281
282
    // must call writeStartString before writing a string val
283
564
    bool writeStartString() {
284
564
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
285
564
            if (!writeFirstHeader()) return 0;
286
564
            os_->put((JsonbTypeUnder)JsonbType::T_String);
287
564
            str_pos_ = os_->tellp();
288
289
            // fill the size bytes with 0 for now
290
564
            uint32_t size = 0;
291
564
            os_->write((char*)&size, sizeof(uint32_t));
292
293
564
            kvState_ = WS_String;
294
564
            return true;
295
564
        }
296
297
0
        return false;
298
564
    }
299
300
    // finish writing a string val
301
564
    bool writeEndString() {
302
564
        if (kvState_ == WS_String) {
303
564
            std::streampos cur_pos = os_->tellp();
304
564
            int32_t size = (int32_t)(cur_pos - str_pos_ - sizeof(uint32_t));
305
564
            assert(size >= 0);
306
307
0
            os_->seekp(str_pos_);
308
564
            os_->write((char*)&size, sizeof(uint32_t));
309
564
            os_->seekp(cur_pos);
310
311
564
            kvState_ = WS_Value;
312
564
            return true;
313
564
        }
314
315
0
        return false;
316
564
    }
317
318
564
    uint32_t writeString(const char* str, uint32_t len) {
319
564
        if (kvState_ == WS_String) {
320
564
            os_->write(str, len);
321
564
            return len;
322
564
        }
323
324
0
        return 0;
325
564
    }
326
327
2
    uint32_t writeString(const std::string& str) {
328
2
        return writeString(str.c_str(), (uint32_t)str.size());
329
2
    }
330
    uint32_t writeString(char ch) {
331
        if (kvState_ == WS_String) {
332
            os_->put(ch);
333
            return 1;
334
        }
335
336
        return 0;
337
    }
338
339
    // must call writeStartBinary before writing a binary val
340
3.08k
    bool writeStartBinary() {
341
3.08k
        if ((first_ && stack_.empty()) || (!stack_.empty() && verifyValueState())) {
342
3.08k
            if (!writeFirstHeader()) return 0;
343
3.08k
            os_->put((JsonbTypeUnder)JsonbType::T_Binary);
344
3.08k
            str_pos_ = os_->tellp();
345
346
            // fill the size bytes with 0 for now
347
3.08k
            uint32_t size = 0;
348
3.08k
            os_->write((char*)&size, sizeof(uint32_t));
349
350
3.08k
            kvState_ = WS_Binary;
351
3.08k
            return true;
352
3.08k
        }
353
354
0
        return false;
355
3.08k
    }
356
357
    // finish writing a binary val
358
3.08k
    bool writeEndBinary() {
359
3.08k
        if (kvState_ == WS_Binary) {
360
3.08k
            std::streampos cur_pos = os_->tellp();
361
3.08k
            int32_t size = (int32_t)(cur_pos - str_pos_ - sizeof(uint32_t));
362
3.08k
            assert(size >= 0);
363
364
0
            os_->seekp(str_pos_);
365
3.08k
            os_->write((char*)&size, sizeof(uint32_t));
366
3.08k
            os_->seekp(cur_pos);
367
368
3.08k
            kvState_ = WS_Value;
369
3.08k
            return true;
370
3.08k
        }
371
372
0
        return false;
373
3.08k
    }
374
375
3.08k
    uint32_t writeBinary(const char* bin, uint32_t len) {
376
3.08k
        if (kvState_ == WS_Binary) {
377
3.08k
            os_->write(bin, len);
378
3.08k
            return len;
379
3.08k
        }
380
381
0
        return 0;
382
3.08k
    }
383
384
    // must call writeStartObject before writing an object val
385
1.32k
    bool writeStartObject() {
386
1.32k
        if (stack_.empty() || verifyValueState()) {
387
1.32k
            if (stack_.empty()) {
388
                // if this is a new JSONB, write the header
389
1.20k
                if (!hasHdr_) {
390
1.20k
                    writeHeader();
391
1.20k
                } else
392
0
                    return false;
393
1.20k
            }
394
395
            // check if the object exceeds the maximum nesting level
396
1.32k
            if (stack_.size() >= MaxNestingLevel) return false;
397
398
1.32k
            os_->put((JsonbTypeUnder)JsonbType::T_Object);
399
            // save the size position
400
1.32k
            stack_.push(WriteInfo({WS_Object, os_->tellp()}));
401
402
            // fill the size bytes with 0 for now
403
1.32k
            uint32_t size = 0;
404
1.32k
            os_->write((char*)&size, sizeof(uint32_t));
405
406
1.32k
            kvState_ = WS_Value;
407
1.32k
            return true;
408
1.32k
        }
409
410
0
        return false;
411
1.32k
    }
412
413
    // finish writing an object val
414
1.30k
    bool writeEndObject() {
415
1.30k
        if (!stack_.empty() && stack_.top().state == WS_Object && kvState_ == WS_Value) {
416
1.30k
            WriteInfo& ci = stack_.top();
417
1.30k
            std::streampos cur_pos = os_->tellp();
418
1.30k
            int32_t size = (int32_t)(cur_pos - ci.sz_pos - sizeof(uint32_t));
419
1.30k
            assert(size >= 0);
420
421
0
            os_->seekp(ci.sz_pos);
422
1.30k
            os_->write((char*)&size, sizeof(uint32_t));
423
1.30k
            os_->seekp(cur_pos);
424
1.30k
            stack_.pop();
425
426
1.30k
            return true;
427
1.30k
        }
428
429
0
        return false;
430
1.30k
    }
431
432
    // must call writeStartArray before writing an array val
433
454
    bool writeStartArray() {
434
454
        if (stack_.empty() || verifyValueState()) {
435
454
            if (stack_.empty()) {
436
                // if this is a new JSONB, write the header
437
437
                if (!hasHdr_) {
438
437
                    writeHeader();
439
437
                } else
440
0
                    return false;
441
437
            }
442
443
            // check if the array exceeds the maximum nesting level
444
454
            if (stack_.size() >= MaxNestingLevel) return false;
445
446
454
            os_->put((JsonbTypeUnder)JsonbType::T_Array);
447
            // save the size position
448
454
            stack_.push(WriteInfo({WS_Array, os_->tellp()}));
449
450
            // fill the size bytes with 0 for now
451
454
            uint32_t size = 0;
452
454
            os_->write((char*)&size, sizeof(uint32_t));
453
454
454
            kvState_ = WS_Value;
455
454
            return true;
456
454
        }
457
458
0
        return false;
459
454
    }
460
461
    // finish writing an array val
462
442
    bool writeEndArray() {
463
442
        if (!stack_.empty() && stack_.top().state == WS_Array && kvState_ == WS_Value) {
464
442
            WriteInfo& ci = stack_.top();
465
442
            std::streampos cur_pos = os_->tellp();
466
442
            int32_t size = (int32_t)(cur_pos - ci.sz_pos - sizeof(uint32_t));
467
442
            assert(size >= 0);
468
469
0
            os_->seekp(ci.sz_pos);
470
442
            os_->write((char*)&size, sizeof(uint32_t));
471
442
            os_->seekp(cur_pos);
472
442
            stack_.pop();
473
474
442
            return true;
475
442
        }
476
477
0
        return false;
478
442
    }
479
480
4.27k
    OS_TYPE* getOutput() { return os_; }
481
    JsonbDocument* getDocument() {
482
        return JsonbDocument::createDocument(getOutput()->getBuffer(), getOutput()->getSize());
483
    }
484
485
    JsonbValue* getValue() {
486
        return JsonbDocument::createValue(getOutput()->getBuffer(),
487
                                          (uint32_t)getOutput()->getSize());
488
    }
489
490
    bool writeEnd() {
491
        while (!stack_.empty()) {
492
            bool ok = false;
493
            switch (stack_.top().state) {
494
            case WS_Array:
495
                ok = writeEndArray();
496
                break;
497
            case WS_Object:
498
                ok = writeEndObject();
499
                break;
500
            case WS_String:
501
                ok = writeEndString();
502
                break;
503
            case WS_Binary:
504
                ok = writeEndBinary();
505
                break;
506
            default:
507
                ok = false;
508
                break;
509
            }
510
            if (ok == false) return false;
511
        }
512
        return true;
513
    }
514
515
private:
516
    // verify we are in the right state before writing a value
517
10.9k
    bool verifyValueState() {
518
10.9k
        assert(!stack_.empty());
519
        // The document can only be an Object or an Array which follows
520
        // the standard.
521
10.9k
        return (stack_.top().state == WS_Object && kvState_ == WS_Key) ||
522
10.9k
               (stack_.top().state == WS_Array && kvState_ == WS_Value);
523
10.9k
    }
524
525
    // verify we are in the right state before writing a key
526
10.6k
    bool verifyKeyState() {
527
10.6k
        assert(!stack_.empty());
528
10.6k
        return stack_.top().state == WS_Object && kvState_ == WS_Value;
529
10.6k
    }
530
531
2.21k
    void writeHeader() {
532
2.21k
        os_->put(JSONB_VER);
533
2.21k
        hasHdr_ = true;
534
2.21k
    }
535
536
private:
537
    enum WriteState {
538
        WS_NONE,
539
        WS_Array,
540
        WS_Object,
541
        WS_Key,
542
        WS_Value,
543
        WS_String,
544
        WS_Binary,
545
    };
546
547
    struct WriteInfo {
548
        WriteState state;
549
        std::streampos sz_pos;
550
    };
551
552
private:
553
    OS_TYPE* os_ = nullptr;
554
    bool alloc_;
555
    bool hasHdr_;
556
    WriteState kvState_; // key or value state
557
    std::streampos str_pos_;
558
    std::stack<WriteInfo> stack_;
559
    bool first_ = true;
560
};
561
562
typedef JsonbWriterT<JsonbOutStream> JsonbWriter;
563
564
} // namespace doris
565
566
#endif // JSONB_JSONBWRITER_H