diff options
author | Alexey Botchkov <holyfoot@askmonty.org> | 2017-02-06 06:47:48 +0400 |
---|---|---|
committer | Alexey Botchkov <holyfoot@askmonty.org> | 2017-02-06 06:47:48 +0400 |
commit | abf7582112645ef8decc549eb662a07072b5cd32 (patch) | |
tree | 1082c1f2c8e32120cee647e0cd0374bd67c37b37 /sql/item_jsonfunc.cc | |
parent | e51b015fc354ec40c8430d4f4ea6346bc9a8e07b (diff) | |
download | mariadb-git-abf7582112645ef8decc549eb662a07072b5cd32.tar.gz |
MDEV-11557 port MySQL-5.7 JSON tests to MariaDB.
Fixes for issues found.
Diffstat (limited to 'sql/item_jsonfunc.cc')
-rw-r--r-- | sql/item_jsonfunc.cc | 226 |
1 files changed, 211 insertions, 15 deletions
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index d1f82bc94da..73b0e6b0870 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -113,6 +113,100 @@ static int st_append_escaped(String *s, const String *a) } +static int json_nice(json_engine_t *je, String *nice_js, + Item_func_json_format::formats mode) +{ + int depth= 0; + const char *comma, *colon; + uint comma_len, colon_len; + int first_value= 1; + + DBUG_ASSERT(je->s.cs == nice_js->charset()); + + if (mode == Item_func_json_format::LOOSE) + { + comma= ", "; + comma_len= 2; + colon= "\": "; + colon_len= 3; + } + else + { + comma= ","; + comma_len= 1; + colon= "\":"; + colon_len= 2; + } + + do + { + switch (je->state) + { + case JST_KEY: + { + const uchar *key_start= je->s.c_str; + const uchar *key_end; + + while (json_read_keyname_chr(je) == 0) + key_end= je->s.c_str; + + if (je->s.error) + goto error; + + if (!first_value) + nice_js->append(comma, comma_len); + + nice_js->append("\"", 1); + append_simple(nice_js, key_start, key_end - key_start); + nice_js->append(colon, colon_len); + } + /* now we have key value to handle, so no 'break'. */ + DBUG_ASSERT(je->state == JST_VALUE); + goto handle_value; + + case JST_VALUE: + if (!first_value) + nice_js->append(comma, comma_len); + +handle_value: + if (json_read_value(je)) + goto error; + if (json_value_scalar(je)) + { + if (append_simple(nice_js, je->value_begin, + je->value_end - je->value_begin)) + goto error; + + first_value= 0; + } + else + { + nice_js->append((je->value_type == JSON_VALUE_OBJECT) ? "{" : "[", 1); + first_value= 1; + depth++; + } + + break; + + case JST_OBJ_END: + case JST_ARRAY_END: + depth--; + nice_js->append((je->state == JST_OBJ_END) ? "}": "]", 1); + first_value= 0; + break; + + default: + break; + }; + } while (json_scan_next(je) == 0); + + return je->s.error; + +error: + return 1; +} + + #define report_json_error(js, je, n_param) \ report_json_error_ex(js, je, func_name(), n_param, \ Sql_condition::WARN_LEVEL_WARN) @@ -554,11 +648,11 @@ void Item_func_json_extract::fix_length_and_dec() static bool path_exact(const json_path_with_flags *paths_list, int n_paths, - const json_path_t *p) + const json_path_t *p, enum json_value_types vt) { for (; n_paths > 0; n_paths--, paths_list++) { - if (json_path_compare(&paths_list->p, p) == 0) + if (json_path_compare(&paths_list->p, p, vt) == 0) return TRUE; } return FALSE; @@ -566,11 +660,11 @@ static bool path_exact(const json_path_with_flags *paths_list, int n_paths, static bool path_ok(const json_path_with_flags *paths_list, int n_paths, - const json_path_t *p) + const json_path_t *p, enum json_value_types vt) { for (; n_paths > 0; n_paths--, paths_list++) { - if (json_path_compare(&paths_list->p, p) >= 0) + if (json_path_compare(&paths_list->p, p, vt) >= 0) return TRUE; } return FALSE; @@ -624,7 +718,7 @@ String *Item_func_json_extract::val_str(String *str) while (json_get_path_next(&je, &p) == 0) { - if (!path_exact(paths, arg_count-1, &p)) + if (!path_exact(paths, arg_count-1, &p, je.value_type)) continue; value= je.value_begin; @@ -661,10 +755,18 @@ String *Item_func_json_extract::val_str(String *str) goto return_null; } - if (possible_multiple_values && str->append("]")) + if (possible_multiple_values && str->append("]", 1)) goto error; /* Out of memory. */ - return str; + js= str; + json_scan_start(&je, js->charset(),(const uchar *) js->ptr(), + (const uchar *) js->ptr() + js->length()); + tmp_js.length(0); + tmp_js.set_charset(js->charset()); + if (json_nice(&je, &tmp_js, Item_func_json_format::LOOSE)) + goto error; + + return &tmp_js; error: report_json_error(js, &je, 0); @@ -1153,7 +1255,7 @@ longlong Item_func_json_contains_path::val_int() json_path_with_flags *c_path= paths; for (; n_path > 0; n_path--, c_path++) { - if (json_path_compare(&c_path->p, &p) >= 0) + if (json_path_compare(&c_path->p, &p, je.value_type) >= 0) { if (mode_one) { @@ -1424,7 +1526,14 @@ String *Item_func_json_array_append::val_str(String *str) } } - return js; + json_scan_start(&je, js->charset(),(const uchar *) js->ptr(), + (const uchar *) js->ptr() + js->length()); + str->length(0); + str->set_charset(js->charset()); + if (json_nice(&je, str, Item_func_json_format::LOOSE)) + goto js_error; + + return str; js_error: report_json_error(js, &je, 0); @@ -1558,7 +1667,14 @@ String *Item_func_json_array_insert::val_str(String *str) } } - return js; + json_scan_start(&je, js->charset(),(const uchar *) js->ptr(), + (const uchar *) js->ptr() + js->length()); + str->length(0); + str->set_charset(js->charset()); + if (json_nice(&je, str, Item_func_json_format::LOOSE)) + goto js_error; + + return str; js_error: report_json_error(js, &je, 0); @@ -1690,8 +1806,15 @@ String *Item_func_json_merge::val_str(String *str) } } + json_scan_start(&je1, js1->charset(),(const uchar *) js1->ptr(), + (const uchar *) js1->ptr() + js1->length()); + str->length(0); + str->set_charset(js1->charset()); + if (json_nice(&je1, str, Item_func_json_format::LOOSE)) + goto error_return; + null_value= 0; - return js1; + return str; error_return: if (je1.s.error) @@ -1970,6 +2093,7 @@ String *Item_func_json_insert::val_str(String *str) { if (je.s.error) goto js_error; + continue; } if (json_read_value(&je)) @@ -1986,7 +2110,16 @@ String *Item_func_json_insert::val_str(String *str) int do_array_autowrap; if (mode_insert) - do_array_autowrap= !mode_replace || lp->n_item; + { + if (mode_replace) + do_array_autowrap= lp->n_item > 0; + else + { + if (lp->n_item == 0) + continue; + do_array_autowrap= 1; + } + } else { if (lp->n_item) @@ -2124,7 +2257,14 @@ continue_point: } } - return js; + json_scan_start(&je, js->charset(),(const uchar *) js->ptr(), + (const uchar *) js->ptr() + js->length()); + str->length(0); + str->set_charset(js->charset()); + if (json_nice(&je, str, Item_func_json_format::LOOSE)) + goto js_error; + + return str; js_error: report_json_error(js, &je, 0); @@ -2300,7 +2440,14 @@ v_found: } } - return js; + json_scan_start(&je, js->charset(),(const uchar *) js->ptr(), + (const uchar *) js->ptr() + js->length()); + str->length(0); + str->set_charset(js->charset()); + if (json_nice(&je, str, Item_func_json_format::LOOSE)) + goto js_error; + + return str; js_error: report_json_error(js, &je, 0); @@ -2540,7 +2687,7 @@ String *Item_func_json_search::val_str(String *str) { if (json_value_scalar(&je)) { - if ((arg_count < 5 || path_ok(paths, arg_count - 4, &p)) && + if ((arg_count < 5 || path_ok(paths, arg_count - 4, &p, je.value_type)) && compare_json_value_wild(&je, s_str) != 0) { ++n_path_found; @@ -2609,3 +2756,52 @@ String *Item_json_typecast::val_str(String *str) return vs; } + +const char *Item_func_json_format::func_name() const +{ + switch (fmt) + { + case COMPACT: + return "json_compact"; + case LOOSE: + return "json_loose"; + case DETAILED: + return "json_detailed"; + default: + DBUG_ASSERT(0); + }; + + return ""; +} + + +void Item_func_json_format::fix_length_and_dec() +{ + decimals= 0; + max_length= args[0]->max_length; +} + + +String *Item_func_json_format::val_str(String *str) +{ + String *js= args[0]->val_str(&tmp_js); + json_engine_t je; + if ((null_value= args[0]->null_value)) + return 0; + + json_scan_start(&je, js->charset(), (const uchar *) js->ptr(), + (const uchar *) js->ptr()+js->length()); + + str->length(0); + str->set_charset(js->charset()); + if (json_nice(&je, str, fmt)) + { + null_value= 1; + report_json_error(js, &je, 0); + return 0; + } + + return str; +} + + |