1 /* Copyright (C) 2014 SkySQL Ab, MariaDB Corporation Ab
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
15
16 #include "mariadb.h"
17 #include "sql_priv.h"
18 #include "sql_string.h"
19
20 #include "my_json_writer.h"
21
append_indent()22 void Json_writer::append_indent()
23 {
24 if (!document_start)
25 output.append('\n');
26 for (int i=0; i< indent_level; i++)
27 output.append(' ');
28 }
29
start_object()30 void Json_writer::start_object()
31 {
32 fmt_helper.on_start_object();
33
34 if (!element_started)
35 start_element();
36
37 output.append("{");
38 indent_level+=INDENT_SIZE;
39 first_child=true;
40 element_started= false;
41 document_start= false;
42 }
43
start_array()44 void Json_writer::start_array()
45 {
46 if (fmt_helper.on_start_array())
47 return;
48
49 if (!element_started)
50 start_element();
51
52 output.append("[");
53 indent_level+=INDENT_SIZE;
54 first_child=true;
55 element_started= false;
56 document_start= false;
57 }
58
59
end_object()60 void Json_writer::end_object()
61 {
62 indent_level-=INDENT_SIZE;
63 if (!first_child)
64 append_indent();
65 output.append("}");
66 }
67
68
end_array()69 void Json_writer::end_array()
70 {
71 if (fmt_helper.on_end_array())
72 return;
73 indent_level-=INDENT_SIZE;
74 if (!first_child)
75 append_indent();
76 output.append("]");
77 }
78
79
add_member(const char * name)80 Json_writer& Json_writer::add_member(const char *name)
81 {
82 if (fmt_helper.on_add_member(name))
83 return *this; // handled
84
85 // assert that we are in an object
86 DBUG_ASSERT(!element_started);
87 start_element();
88
89 output.append('"');
90 output.append(name);
91 output.append("\": ");
92 return *this;
93 }
94
95
96 /*
97 Used by formatting helper to print something that is formatted by the helper.
98 We should only separate it from the previous element.
99 */
100
start_sub_element()101 void Json_writer::start_sub_element()
102 {
103 //element_started= true;
104 if (first_child)
105 first_child= false;
106 else
107 output.append(',');
108
109 append_indent();
110 }
111
112
start_element()113 void Json_writer::start_element()
114 {
115 element_started= true;
116
117 if (first_child)
118 first_child= false;
119 else
120 output.append(',');
121
122 append_indent();
123 }
124
add_ll(longlong val)125 void Json_writer::add_ll(longlong val)
126 {
127 char buf[64];
128 my_snprintf(buf, sizeof(buf), "%lld", val);
129 add_unquoted_str(buf);
130 }
131
add_ull(ulonglong val)132 void Json_writer::add_ull(ulonglong val)
133 {
134 char buf[64];
135 my_snprintf(buf, sizeof(buf), "%llu", val);
136 add_unquoted_str(buf);
137 }
138
139
140 /* Add a memory size, printing in Kb, Kb, Gb if necessary */
add_size(longlong val)141 void Json_writer::add_size(longlong val)
142 {
143 char buf[64];
144 if (val < 1024)
145 my_snprintf(buf, sizeof(buf), "%lld", val);
146 else if (val < 1024*1024*16)
147 {
148 /* Values less than 16MB are specified in KB for precision */
149 size_t len= my_snprintf(buf, sizeof(buf), "%lld", val/1024);
150 strcpy(buf + len, "Kb");
151 }
152 else
153 {
154 size_t len= my_snprintf(buf, sizeof(buf), "%lld", val/(1024*1024));
155 strcpy(buf + len, "Mb");
156 }
157 add_str(buf);
158 }
159
160
add_double(double val)161 void Json_writer::add_double(double val)
162 {
163 char buf[64];
164 my_snprintf(buf, sizeof(buf), "%lg", val);
165 add_unquoted_str(buf);
166 }
167
168
add_bool(bool val)169 void Json_writer::add_bool(bool val)
170 {
171 add_unquoted_str(val? "true" : "false");
172 }
173
174
add_null()175 void Json_writer::add_null()
176 {
177 add_unquoted_str("null");
178 }
179
180
add_unquoted_str(const char * str)181 void Json_writer::add_unquoted_str(const char* str)
182 {
183 if (fmt_helper.on_add_str(str))
184 return;
185
186 if (!element_started)
187 start_element();
188
189 output.append(str);
190 element_started= false;
191 }
192
193
add_str(const char * str)194 void Json_writer::add_str(const char *str)
195 {
196 if (fmt_helper.on_add_str(str))
197 return;
198
199 if (!element_started)
200 start_element();
201
202 output.append('"');
203 output.append(str);
204 output.append('"');
205 element_started= false;
206 }
207
208
add_str(const String & str)209 void Json_writer::add_str(const String &str)
210 {
211 add_str(str.ptr());
212 }
213
214
on_add_member(const char * name)215 bool Single_line_formatting_helper::on_add_member(const char *name)
216 {
217 DBUG_ASSERT(state== INACTIVE || state == DISABLED);
218 if (state != DISABLED)
219 {
220 // remove everything from the array
221 buf_ptr= buffer;
222
223 //append member name to the array
224 size_t len= strlen(name);
225 if (len < MAX_LINE_LEN)
226 {
227 memcpy(buf_ptr, name, len);
228 buf_ptr+=len;
229 *(buf_ptr++)= 0;
230
231 line_len= owner->indent_level + (uint)len + 1;
232 state= ADD_MEMBER;
233 return true; // handled
234 }
235 }
236 return false; // not handled
237 }
238
239
on_start_array()240 bool Single_line_formatting_helper::on_start_array()
241 {
242 if (state == ADD_MEMBER)
243 {
244 state= IN_ARRAY;
245 return true; // handled
246 }
247 else
248 {
249 if (state != DISABLED)
250 state= INACTIVE;
251 // TODO: what if we have accumulated some stuff already? shouldn't we
252 // flush it?
253 return false; // not handled
254 }
255 }
256
257
on_end_array()258 bool Single_line_formatting_helper::on_end_array()
259 {
260 if (state == IN_ARRAY)
261 {
262 flush_on_one_line();
263 state= INACTIVE;
264 return true; // handled
265 }
266 return false; // not handled
267 }
268
269
on_start_object()270 void Single_line_formatting_helper::on_start_object()
271 {
272 // Nested objects will not be printed on one line
273 disable_and_flush();
274 }
275
276
on_add_str(const char * str)277 bool Single_line_formatting_helper::on_add_str(const char *str)
278 {
279 if (state == IN_ARRAY)
280 {
281 size_t len= strlen(str);
282
283 // New length will be:
284 // "$string",
285 // quote + quote + comma + space = 4
286 if (line_len + len + 4 > MAX_LINE_LEN)
287 {
288 disable_and_flush();
289 return false; // didn't handle the last element
290 }
291
292 //append string to array
293 memcpy(buf_ptr, str, len);
294 buf_ptr+=len;
295 *(buf_ptr++)= 0;
296 line_len += (uint)len + 4;
297 return true; // handled
298 }
299
300 disable_and_flush();
301 return false; // not handled
302 }
303
304
305 /*
306 Append everything accumulated to the output on one line
307 */
308
flush_on_one_line()309 void Single_line_formatting_helper::flush_on_one_line()
310 {
311 owner->start_sub_element();
312 char *ptr= buffer;
313 int nr= 0;
314 while (ptr < buf_ptr)
315 {
316 char *str= ptr;
317
318 if (nr == 0)
319 {
320 owner->output.append('"');
321 owner->output.append(str);
322 owner->output.append("\": ");
323 owner->output.append('[');
324 }
325 else
326 {
327 if (nr != 1)
328 owner->output.append(", ");
329 owner->output.append('"');
330 owner->output.append(str);
331 owner->output.append('"');
332 }
333 nr++;
334
335 while (*ptr!=0)
336 ptr++;
337 ptr++;
338 }
339 owner->output.append(']');
340 /* We've printed out the contents of the buffer, mark it as empty */
341 buf_ptr= buffer;
342 }
343
344
disable_and_flush()345 void Single_line_formatting_helper::disable_and_flush()
346 {
347 if (state == DISABLED)
348 return;
349
350 bool start_array= (state == IN_ARRAY);
351 state= DISABLED;
352 // deactivate ourselves and flush all accumulated calls.
353 char *ptr= buffer;
354 int nr= 0;
355 while (ptr < buf_ptr)
356 {
357 char *str= ptr;
358 if (nr == 0)
359 {
360 owner->add_member(str);
361 if (start_array)
362 owner->start_array();
363 }
364 else
365 {
366 //if (nr == 1)
367 // owner->start_array();
368 owner->add_str(str);
369 }
370
371 nr++;
372 while (*ptr!=0)
373 ptr++;
374 ptr++;
375 }
376 buf_ptr= buffer;
377 state= INACTIVE;
378 }
379
380