You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

372 lines
6.9 KiB

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