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 |