/root/doris/be/src/util/jsonb_utils.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 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 <sstream> |
25 | | |
26 | | #include "common/exception.h" |
27 | | #include "jsonb_document.h" |
28 | | #include "jsonb_stream.h" |
29 | | #include "jsonb_writer.h" |
30 | | |
31 | | namespace doris { |
32 | | |
33 | | #define OUT_BUF_SIZE 1024 |
34 | | |
35 | | /* |
36 | | * JsonbToJson converts an JsonbValue object to a JSON string. |
37 | | */ |
38 | | class JsonbToJson { |
39 | | public: |
40 | 304 | JsonbToJson() : os_(buffer_, OUT_BUF_SIZE) {} |
41 | | |
42 | | // get json string |
43 | 300 | const std::string to_json_string(const char* data, size_t size) { |
44 | 300 | JsonbDocument* pdoc = doris::JsonbDocument::checkAndCreateDocument(data, size); |
45 | 300 | if (!pdoc) { |
46 | 0 | throw Exception(Status::FatalError("invalid json binary value: {}", |
47 | 0 | std::string_view(data, size))); |
48 | 0 | } |
49 | 300 | return to_json_string(pdoc->getValue()); |
50 | 300 | } |
51 | | |
52 | 326 | const std::string to_json_string(const JsonbValue* val) { |
53 | 326 | os_.clear(); |
54 | 326 | os_.seekp(0); |
55 | | |
56 | 326 | if (val) { |
57 | 326 | intern_json(val); |
58 | 326 | } |
59 | | |
60 | 326 | os_.put(0); |
61 | | |
62 | 326 | std::string json_string {os_.getBuffer()}; |
63 | 326 | return json_string; |
64 | 326 | } |
65 | | |
66 | 300 | static const std::string jsonb_to_json_string(const char* data, size_t size) { |
67 | 300 | JsonbToJson jsonb_to_json; |
68 | 300 | return jsonb_to_json.to_json_string(data, size); |
69 | 300 | } |
70 | | |
71 | | private: |
72 | | // recursively convert JsonbValue |
73 | 743 | void intern_json(const JsonbValue* val) { |
74 | 743 | switch (val->type()) { |
75 | 33 | case JsonbType::T_Null: { |
76 | 33 | os_.write("null", 4); |
77 | 33 | break; |
78 | 0 | } |
79 | 35 | case JsonbType::T_True: { |
80 | 35 | os_.write("true", 4); |
81 | 35 | break; |
82 | 0 | } |
83 | 32 | case JsonbType::T_False: { |
84 | 32 | os_.write("false", 5); |
85 | 32 | break; |
86 | 0 | } |
87 | 99 | case JsonbType::T_Int8: { |
88 | 99 | os_.write(((JsonbInt8Val*)val)->val()); |
89 | 99 | break; |
90 | 0 | } |
91 | 70 | case JsonbType::T_Int16: { |
92 | 70 | os_.write(((JsonbInt16Val*)val)->val()); |
93 | 70 | break; |
94 | 0 | } |
95 | 18 | case JsonbType::T_Int32: { |
96 | 18 | os_.write(((JsonbInt32Val*)val)->val()); |
97 | 18 | break; |
98 | 0 | } |
99 | 18 | case JsonbType::T_Int64: { |
100 | 18 | os_.write(((JsonbInt64Val*)val)->val()); |
101 | 18 | break; |
102 | 0 | } |
103 | 81 | case JsonbType::T_Double: { |
104 | 81 | os_.write(((JsonbDoubleVal*)val)->val()); |
105 | 81 | break; |
106 | 0 | } |
107 | 0 | case JsonbType::T_Float: { |
108 | 0 | os_.write(((JsonbFloatVal*)val)->val()); |
109 | 0 | break; |
110 | 0 | } |
111 | 0 | case JsonbType::T_Int128: { |
112 | 0 | os_.write(((JsonbInt128Val*)val)->val()); |
113 | 0 | break; |
114 | 0 | } |
115 | 149 | case JsonbType::T_String: { |
116 | 149 | string_to_json(((JsonbStringVal*)val)->getBlob(), ((JsonbStringVal*)val)->length()); |
117 | 149 | break; |
118 | 0 | } |
119 | 0 | case JsonbType::T_Binary: { |
120 | 0 | os_.write("\"<BINARY>", 9); |
121 | 0 | os_.write(((JsonbBinaryVal*)val)->getBlob(), ((JsonbBinaryVal*)val)->getBlobLen()); |
122 | 0 | os_.write("<BINARY>\"", 9); |
123 | 0 | break; |
124 | 0 | } |
125 | 115 | case JsonbType::T_Object: { |
126 | 115 | object_to_json((ObjectVal*)val); |
127 | 115 | break; |
128 | 0 | } |
129 | 93 | case JsonbType::T_Array: { |
130 | 93 | array_to_json((ArrayVal*)val); |
131 | 93 | break; |
132 | 0 | } |
133 | 0 | default: |
134 | 0 | break; |
135 | 743 | } |
136 | 743 | } |
137 | | |
138 | 301 | void string_to_json(const char* str, size_t len) { |
139 | 301 | os_.put('"'); |
140 | 301 | if (nullptr == str) { |
141 | 1 | os_.put('"'); |
142 | 1 | return; |
143 | 1 | } |
144 | 300 | char char_buffer[16]; |
145 | 1.00M | for (const char* ptr = str; ptr != str + len && *ptr; ++ptr) { |
146 | 1.00M | if ((unsigned char)*ptr > 31 && *ptr != '\"' && *ptr != '\\') |
147 | 1.00M | os_.put(*ptr); |
148 | 6 | else { |
149 | 6 | os_.put('\\'); |
150 | 6 | unsigned char token; |
151 | 6 | switch (token = *ptr) { |
152 | 0 | case '\\': |
153 | 0 | os_.put('\\'); |
154 | 0 | break; |
155 | 1 | case '\"': |
156 | 1 | os_.put('\"'); |
157 | 1 | break; |
158 | 1 | case '\b': |
159 | 1 | os_.put('b'); |
160 | 1 | break; |
161 | 1 | case '\f': |
162 | 1 | os_.put('f'); |
163 | 1 | break; |
164 | 1 | case '\n': |
165 | 1 | os_.put('n'); |
166 | 1 | break; |
167 | 1 | case '\r': |
168 | 1 | os_.put('r'); |
169 | 1 | break; |
170 | 1 | case '\t': |
171 | 1 | os_.put('t'); |
172 | 1 | break; |
173 | 0 | default: { |
174 | 0 | int char_num = snprintf(char_buffer, sizeof(char_buffer), "u%04x", token); |
175 | 0 | os_.write(char_buffer, char_num); |
176 | 0 | break; |
177 | 0 | } |
178 | 6 | } |
179 | 6 | } |
180 | 1.00M | } |
181 | 300 | os_.put('"'); |
182 | 300 | } |
183 | | |
184 | | // convert object |
185 | 115 | void object_to_json(const ObjectVal* val) { |
186 | 115 | os_.put('{'); |
187 | | |
188 | 115 | auto iter = val->begin(); |
189 | 115 | auto iter_fence = val->end(); |
190 | | |
191 | 267 | while (iter < iter_fence) { |
192 | | // write key |
193 | 152 | if (iter->klen()) { |
194 | 151 | string_to_json(iter->getKeyStr(), iter->klen()); |
195 | 151 | } else { |
196 | | // NOTE: we use sMaxKeyId to represent an empty key. see jsonb_writer.h |
197 | 1 | if (iter->getKeyId() == JsonbKeyValue::sMaxKeyId) { |
198 | 1 | string_to_json(nullptr, 0); |
199 | 1 | } else { |
200 | 0 | os_.write(iter->getKeyId()); |
201 | 0 | } |
202 | 1 | } |
203 | 152 | os_.put(':'); |
204 | | |
205 | | // convert value |
206 | 152 | intern_json(iter->value()); |
207 | | |
208 | 152 | ++iter; |
209 | 152 | if (iter != iter_fence) { |
210 | 59 | os_.put(','); |
211 | 59 | } |
212 | 152 | } |
213 | | |
214 | 115 | assert(iter == iter_fence); |
215 | | |
216 | 0 | os_.put('}'); |
217 | 115 | } |
218 | | |
219 | | // convert array to json |
220 | 93 | void array_to_json(const ArrayVal* val) { |
221 | 93 | os_.put('['); |
222 | | |
223 | 93 | auto iter = val->begin(); |
224 | 93 | auto iter_fence = val->end(); |
225 | | |
226 | 358 | while (iter != iter_fence) { |
227 | | // convert value |
228 | 265 | intern_json((const JsonbValue*)iter); |
229 | 265 | ++iter; |
230 | 265 | if (iter != iter_fence) { |
231 | 187 | os_.put(','); |
232 | 187 | } |
233 | 265 | } |
234 | | |
235 | 93 | assert(iter == iter_fence); |
236 | | |
237 | 0 | os_.put(']'); |
238 | 93 | } |
239 | | |
240 | | private: |
241 | | JsonbOutStream os_; |
242 | | char buffer_[OUT_BUF_SIZE]; |
243 | | }; |
244 | | |
245 | | // This class is a utility to create a JsonbValue. |
246 | | template <class OS_TYPE> |
247 | | class JsonbValueCreaterT { |
248 | | public: |
249 | | JsonbValue* operator()(int32_t val) { return operator()((int64_t)val); } |
250 | | |
251 | | JsonbValue* operator()(int64_t val) { |
252 | | writer_.reset(); |
253 | | writer_.writeStartArray(); |
254 | | writer_.writeInt(val); |
255 | | writer_.writeEndArray(); |
256 | | return extractValue(); |
257 | | } |
258 | | JsonbValue* operator()(double val) { |
259 | | writer_.reset(); |
260 | | writer_.writeStartArray(); |
261 | | writer_.writeDouble(val); |
262 | | writer_.writeEndArray(); |
263 | | return extractValue(); |
264 | | } |
265 | | JsonbValue* operator()(const char* str) { return operator()(str, (unsigned int)strlen(str)); } |
266 | | JsonbValue* operator()(const char* str, unsigned int str_len) { |
267 | | writer_.reset(); |
268 | | writer_.writeStartArray(); |
269 | | writer_.writeStartString(); |
270 | | writer_.writeString(str, str_len); |
271 | | writer_.writeEndString(); |
272 | | writer_.writeEndArray(); |
273 | | return extractValue(); |
274 | | } |
275 | | JsonbValue* operator()(bool val) { |
276 | | writer_.reset(); |
277 | | writer_.writeStartArray(); |
278 | | writer_.writeBool(val); |
279 | | writer_.writeEndArray(); |
280 | | return extractValue(); |
281 | | } |
282 | | JsonbValue* operator()() { |
283 | | writer_.reset(); |
284 | | writer_.writeStartArray(); |
285 | | writer_.writeNull(); |
286 | | writer_.writeEndArray(); |
287 | | return extractValue(); |
288 | | } |
289 | | |
290 | | private: |
291 | | JsonbValue* extractValue() { |
292 | | return static_cast<ArrayVal*>( |
293 | | JsonbDocument::createValue(writer_.getOutput()->getBuffer(), |
294 | | (int)writer_.getOutput()->getSize())) |
295 | | ->get(0); |
296 | | } |
297 | | JsonbWriterT<OS_TYPE> writer_; |
298 | | }; |
299 | | typedef JsonbValueCreaterT<JsonbOutStream> JsonbValueCreater; |
300 | | } // namespace doris |
301 | | |
302 | | #endif // JSONB_JSONBUTIL_H |