Coverage Report

Created: 2026-09-23 18:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/util/jsonb_utils.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 file defines miscellaneous utility classes.
13
 *
14
 * @author Tian Xia <tianx@fb.com>
15
 *
16
 *  this file is copied from 
17
 * https://github.com/facebook/mysql-5.6/blob/fb-mysql-5.6.35/fbson/FbsonUtil.h
18
 * and modified by Doris
19
 */
20
21
#ifndef JSONB_JSONBUTIL_H
22
#define JSONB_JSONBUTIL_H
23
24
#include "common/status.h"
25
#include "util/jsonb_document.h"
26
#include "util/jsonb_stream.h"
27
28
namespace doris {
29
30
676
#define OUT_BUF_SIZE 1024
31
32
/*
33
 * JsonbToJson converts an JsonbValue object to a JSON string.
34
 */
35
class JsonbToJson {
36
public:
37
676
    JsonbToJson() : os_(buffer_, OUT_BUF_SIZE) {}
38
39
    // get json string
40
644
    std::string to_json_string(const char* data, size_t size) {
41
644
        const JsonbDocument* pdoc;
42
644
        THROW_IF_ERROR(doris::JsonbDocument::checkAndCreateDocument(data, size, &pdoc));
43
644
        return to_json_string(pdoc->getValue());
44
644
    }
45
46
676
    std::string to_json_string(const JsonbValue* val) {
47
676
        os_.clear();
48
676
        os_.seekp(0);
49
50
676
        if (val) {
51
676
            intern_json(val);
52
676
        }
53
54
676
        os_.put(0);
55
56
676
        std::string json_string {os_.getBuffer()};
57
676
        return json_string;
58
676
    }
59
60
644
    static std::string jsonb_to_json_string(const char* data, size_t size) {
61
644
        JsonbToJson jsonb_to_json;
62
644
        return jsonb_to_json.to_json_string(data, size);
63
644
    }
64
65
private:
66
    // recursively convert JsonbValue
67
2.89k
    void intern_json(const JsonbValue* val) {
68
2.89k
        switch (val->type) {
69
49
        case JsonbType::T_Null: {
70
49
            os_.write("null", 4);
71
49
            break;
72
0
        }
73
51
        case JsonbType::T_True: {
74
51
            os_.write("true", 4);
75
51
            break;
76
0
        }
77
16
        case JsonbType::T_False: {
78
16
            os_.write("false", 5);
79
16
            break;
80
0
        }
81
963
        case JsonbType::T_Int8: {
82
963
            os_.write(val->unpack<JsonbInt8Val>()->val());
83
963
            break;
84
0
        }
85
266
        case JsonbType::T_Int16: {
86
266
            os_.write(val->unpack<JsonbInt16Val>()->val());
87
266
            break;
88
0
        }
89
13
        case JsonbType::T_Int32: {
90
13
            os_.write(val->unpack<JsonbInt32Val>()->val());
91
13
            break;
92
0
        }
93
16
        case JsonbType::T_Int64: {
94
16
            os_.write(val->unpack<JsonbInt64Val>()->val());
95
16
            break;
96
0
        }
97
40
        case JsonbType::T_Double: {
98
40
            os_.write(val->unpack<JsonbDoubleVal>()->val());
99
40
            break;
100
0
        }
101
2
        case JsonbType::T_Float: {
102
2
            os_.write(val->unpack<JsonbFloatVal>()->val());
103
2
            break;
104
0
        }
105
3
        case JsonbType::T_Int128: {
106
3
            os_.write(val->unpack<JsonbInt128Val>()->val());
107
3
            break;
108
0
        }
109
226
        case JsonbType::T_String: {
110
            // getBlobLen() is the stored payload length. length() would drop a
111
            // trailing NUL that belongs to the value, so it cannot be used here;
112
            // the writer stores strings by their exact length and never pads.
113
226
            string_to_json(val->unpack<JsonbStringVal>()->getBlob(),
114
226
                           val->unpack<JsonbStringVal>()->getBlobLen());
115
226
            break;
116
0
        }
117
0
        case JsonbType::T_Binary: {
118
0
            os_.write("\"<BINARY>", 9);
119
0
            os_.write(val->unpack<JsonbBinaryVal>()->getBlob(),
120
0
                      val->unpack<JsonbBinaryVal>()->getBlobLen());
121
0
            os_.write("<BINARY>\"", 9);
122
0
            break;
123
0
        }
124
1.13k
        case JsonbType::T_Object: {
125
1.13k
            object_to_json(val->unpack<ObjectVal>());
126
1.13k
            break;
127
0
        }
128
109
        case JsonbType::T_Array: {
129
109
            array_to_json(val->unpack<ArrayVal>());
130
109
            break;
131
0
        }
132
1
        case JsonbType::T_Decimal32: {
133
1
            const auto* decimal_val = val->unpack<JsonbDecimal32>();
134
1
            decimal_to_json(Decimal32 {decimal_val->val()}, decimal_val->precision,
135
1
                            decimal_val->scale);
136
1
            break;
137
0
        }
138
1
        case JsonbType::T_Decimal64: {
139
1
            const auto* decimal_val = val->unpack<JsonbDecimal64>();
140
1
            decimal_to_json(Decimal64 {decimal_val->val()}, decimal_val->precision,
141
1
                            decimal_val->scale);
142
1
            break;
143
0
        }
144
8
        case JsonbType::T_Decimal128: {
145
8
            const auto* decimal_val = val->unpack<JsonbDecimal128>();
146
8
            decimal_to_json(Decimal128V3 {decimal_val->val()}, decimal_val->precision,
147
8
                            decimal_val->scale);
148
8
            break;
149
0
        }
150
1
        case JsonbType::T_Decimal256: {
151
1
            const auto* decimal_val = val->unpack<JsonbDecimal256>();
152
1
            decimal_to_json(Decimal256 {decimal_val->val()}, decimal_val->precision,
153
1
                            decimal_val->scale);
154
1
            break;
155
0
        }
156
0
        default:
157
0
            break;
158
2.89k
        }
159
2.89k
    }
160
161
1.78k
    void string_to_json(const char* str, size_t len) {
162
1.78k
        os_.put('"');
163
1.78k
        if (nullptr == str) {
164
3
            os_.put('"');
165
3
            return;
166
3
        }
167
1.77k
        char char_buffer[16];
168
        // A JSON string may legally contain U+0000, so the loop must be bounded by
169
        // the length only; the NUL itself is escaped as \u0000 by the default branch.
170
2.05M
        for (const char* ptr = str; ptr != str + len; ++ptr) {
171
2.05M
            if ((unsigned char)*ptr > 31 && *ptr != '\"' && *ptr != '\\') {
172
2.05M
                os_.put(*ptr);
173
2.05M
            } else {
174
13
                os_.put('\\');
175
13
                unsigned char token;
176
13
                switch (token = *ptr) {
177
0
                case '\\':
178
0
                    os_.put('\\');
179
0
                    break;
180
1
                case '\"':
181
1
                    os_.put('\"');
182
1
                    break;
183
1
                case '\b':
184
1
                    os_.put('b');
185
1
                    break;
186
1
                case '\f':
187
1
                    os_.put('f');
188
1
                    break;
189
1
                case '\n':
190
1
                    os_.put('n');
191
1
                    break;
192
1
                case '\r':
193
1
                    os_.put('r');
194
1
                    break;
195
1
                case '\t':
196
1
                    os_.put('t');
197
1
                    break;
198
7
                default: {
199
7
                    int char_num = snprintf(char_buffer, sizeof(char_buffer), "u%04x", token);
200
7
                    os_.write(char_buffer, char_num);
201
7
                    break;
202
0
                }
203
13
                }
204
13
            }
205
2.05M
        }
206
1.77k
        os_.put('"');
207
1.77k
    }
208
209
    // convert object
210
1.13k
    void object_to_json(const ObjectVal* val) {
211
1.13k
        os_.put('{');
212
213
1.13k
        auto iter = val->begin();
214
1.13k
        auto iter_fence = val->end();
215
216
2.68k
        while (iter < iter_fence) {
217
            // write key
218
1.55k
            if (iter->klen()) {
219
1.55k
                string_to_json(iter->getKeyStr(), iter->klen());
220
1.55k
            } else {
221
                // NOTE: we use sMaxKeyId to represent an empty key. see jsonb_writer.h
222
3
                if (iter->getKeyId() == JsonbKeyValue::sMaxKeyId) {
223
3
                    string_to_json(nullptr, 0);
224
3
                } else {
225
0
                    os_.write(iter->getKeyId());
226
0
                }
227
3
            }
228
1.55k
            os_.put(':');
229
230
            // convert value
231
1.55k
            intern_json(iter->value());
232
233
1.55k
            ++iter;
234
1.55k
            if (iter != iter_fence) {
235
455
                os_.put(',');
236
455
            }
237
1.55k
        }
238
239
1.13k
        assert(iter == iter_fence);
240
241
1.13k
        os_.put('}');
242
1.13k
    }
243
244
    // convert array to json
245
109
    void array_to_json(const ArrayVal* val) {
246
109
        os_.put('[');
247
248
109
        auto iter = val->begin();
249
109
        auto iter_fence = val->end();
250
251
777
        while (iter != iter_fence) {
252
            // convert value
253
668
            intern_json((const JsonbValue*)iter);
254
668
            ++iter;
255
668
            if (iter != iter_fence) {
256
572
                os_.put(',');
257
572
            }
258
668
        }
259
260
109
        assert(iter == iter_fence);
261
262
109
        os_.put(']');
263
109
    }
264
265
    template <JsonbDecimalType T>
266
    void decimal_to_json(const T& value, const uint32_t precision, const uint32_t scale);
267
268
    JsonbOutStream os_;
269
    char buffer_[OUT_BUF_SIZE];
270
};
271
272
} // namespace doris
273
274
#endif // JSONB_JSONBUTIL_H