diff options
author | Alexey Botchkov <holyfoot@askmonty.org> | 2017-01-24 17:34:44 +0400 |
---|---|---|
committer | Alexey Botchkov <holyfoot@askmonty.org> | 2017-01-24 17:34:44 +0400 |
commit | 50831b0f197fd1edb98aa56085e391e5033e2a54 (patch) | |
tree | ee2ce1697dc7a8b8f3478c47b14cbfd0eb3cb1ba /sql/item_jsonfunc.cc | |
parent | e5398aca766536bc6151270a6dcd57260dada713 (diff) | |
download | mariadb-git-50831b0f197fd1edb98aa56085e391e5033e2a54.tar.gz |
MDEV-11557 port MySQL-5.7 JSON tests to MariaDB.
json_no_table.test ported.
Diffstat (limited to 'sql/item_jsonfunc.cc')
-rw-r--r-- | sql/item_jsonfunc.cc | 366 |
1 files changed, 191 insertions, 175 deletions
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index b0576fbdaba..e97f00dae8e 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -168,6 +168,7 @@ void report_json_error_ex(String *js, json_engine_t *je, #define NO_WILDCARD_ALLOWED 1 #define SHOULD_END_WITH_ARRAY 2 +#define TRIVIAL_PATH_NOT_ALLOWED 3 #define report_path_error(js, je, n_param) \ report_path_error_ex(js, je, func_name(), n_param,\ @@ -205,6 +206,11 @@ static void report_path_error_ex(String *ps, json_path_t *p, code= ER_JSON_PATH_NO_WILDCARD; break; + case TRIVIAL_PATH_NOT_ALLOWED: + code= ER_JSON_PATH_EMPTY; + break; + + default: return; } @@ -547,22 +553,43 @@ 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) +{ + for (; n_paths > 0; n_paths--, paths_list++) + { + if (json_path_compare(&paths_list->p, p) == 0) + return TRUE; + } + return FALSE; +} + + +static bool path_ok(const json_path_with_flags *paths_list, int n_paths, + const json_path_t *p) +{ + for (; n_paths > 0; n_paths--, paths_list++) + { + if (json_path_compare(&paths_list->p, p) >= 0) + return TRUE; + } + return FALSE; +} + + String *Item_func_json_extract::val_str(String *str) { String *js= args[0]->val_str(&tmp_js); - json_engine_t je; - bool multiple_values_found= FALSE; + json_engine_t je, sav_je; + json_path_t p; const uchar *value; - const char *first_value= NULL; - uint n_arg, v_len, first_len; - uint array_counters[JSON_DEPTH_LIMIT]; + int not_first_value= 0; + uint n_arg, v_len; + int possible_multiple_values; if ((null_value= args[0]->null_value)) return 0; - str->set_charset(js->charset()); - str->length(0); - for (n_arg=1; n_arg < arg_count; n_arg++) { json_path_with_flags *c_path= paths + n_arg - 1; @@ -572,76 +599,66 @@ String *Item_func_json_extract::val_str(String *str) if (s_p && json_path_setup(&c_path->p,s_p->charset(),(const uchar *) s_p->ptr(), (const uchar *) s_p->ptr() + s_p->length())) + { + report_path_error(s_p, &c_path->p, n_arg); goto return_null; + } c_path->parsed= c_path->constant; } + } - if (args[n_arg]->null_value) - goto return_null; + possible_multiple_values= arg_count > 2 || + (paths[0].p.types_used & (JSON_PATH_WILD | JSON_PATH_DOUBLE_WILD)); - json_scan_start(&je, js->charset(),(const uchar *) js->ptr(), - (const uchar *) js->ptr() + js->length()); + str->set_charset(js->charset()); + str->length(0); - c_path->cur_step= c_path->p.steps; + if (possible_multiple_values && str->append("[", 1)) + goto error; - while (!json_find_path(&je, &c_path->p, &c_path->cur_step, array_counters)) - { - if (json_read_value(&je)) - goto error; + json_get_path_start(&je, js->charset(),(const uchar *) js->ptr(), + (const uchar *) js->ptr() + js->length(), &p); - value= je.value_begin; - if (json_value_scalar(&je)) - v_len= je.value_end - value; - else - { - if (json_skip_level(&je)) - goto error; - v_len= je.s.c_str - value; - } + while (json_get_path_next(&je, &p) == 0) + { + if (!path_exact(paths, arg_count-1, &p)) + continue; - if (!multiple_values_found) - { - if (first_value == NULL) - { - /* - Just remember the first value as we don't know yet - if we need to create an array out of it or not. - */ - first_value= (const char *) value; - first_len= v_len; - } - else - { - multiple_values_found= TRUE; /* We have to make an JSON array. */ - if (str->append("[", 1) || - str->append(first_value, first_len)) - goto error; /* Out of memory. */ - } + value= je.value_begin; - } - if (multiple_values_found && - (str->append(", ", 2) || - str->append((const char *) value, v_len))) - goto error; /* Out of memory. */ + if (json_value_scalar(&je)) + v_len= je.value_end - value; + else + { + if (possible_multiple_values) + sav_je= je; + if (json_skip_level(&je)) + goto error; + v_len= je.s.c_str - value; + if (possible_multiple_values) + je= sav_je; + } - if (json_scan_next(&je)) - break; + if ((not_first_value && str->append(", ", 2)) || + str->append((const char *) value, v_len)) + goto error; /* Out of memory. */ - } + not_first_value= 1; + + if (!possible_multiple_values) + break; } if (je.s.error) goto error; - if (first_value == NULL) + if (!not_first_value) { /* Nothing was found. */ goto return_null; } - if (multiple_values_found ? - str->append("]") : - str->append(first_value, first_len)) + if (possible_multiple_values && str->append("]")) goto error; /* Out of memory. */ return str; @@ -796,12 +813,14 @@ static int check_contains(json_engine_t *js, json_engine_t *value) { while (json_scan_next(js) == 0 && js->state != JST_ARRAY_END) { - json_level_t c_level; + int c_level, v_scalar; DBUG_ASSERT(js->state == JST_VALUE); if (json_read_value(js)) return FALSE; - c_level= json_value_scalar(js) ? NULL : json_get_level(js); + if (!(v_scalar= json_value_scalar(js))) + c_level= json_get_level(js); + if (check_contains(js, value)) { if (json_skip_level(js)) @@ -809,7 +828,7 @@ static int check_contains(json_engine_t *js, json_engine_t *value) return TRUE; } if (value->s.error || js->s.error || - (c_level && json_skip_to_level(js, c_level))) + (!v_scalar && json_skip_to_level(js, c_level))) return FALSE; } return FALSE; @@ -955,6 +974,8 @@ return_null: bool Item_func_json_contains_path::fix_fields(THD *thd, Item **ref) { return alloc_tmp_paths(thd, arg_count-2, &paths, &tmp_paths) || + (p_found= (bool *) alloc_root(thd->mem_root, + (arg_count-2)*sizeof(bool))) == NULL || Item_int_func::fix_fields(thd, ref); } @@ -1010,6 +1031,7 @@ static int parse_one_or_all(const Item_func *f, Item *ooa_arg, } +#ifdef DUMMY longlong Item_func_json_contains_path::val_int() { String *js= args[0]->val_str(&tmp_js); @@ -1076,6 +1098,87 @@ return_null: null_value= 1; return 0; } +#endif /*DUMMY*/ + +longlong Item_func_json_contains_path::val_int() +{ + String *js= args[0]->val_str(&tmp_js); + json_engine_t je; + uint n_arg; + longlong result; + json_path_t p; + int n_found; + + if ((null_value= args[0]->null_value)) + return 0; + + if (parse_one_or_all(this, args[1], &ooa_parsed, ooa_constant, &mode_one)) + goto null_return;; + + for (n_arg=2; n_arg < arg_count; n_arg++) + { + json_path_with_flags *c_path= paths + n_arg - 2; + if (!c_path->parsed) + { + String *s_p= args[n_arg]->val_str(tmp_paths + (n_arg-2)); + if (s_p && + json_path_setup(&c_path->p,s_p->charset(),(const uchar *) s_p->ptr(), + (const uchar *) s_p->ptr() + s_p->length())) + { + report_path_error(s_p, &c_path->p, n_arg); + goto null_return; + } + c_path->parsed= c_path->constant; + } + if (args[n_arg]->null_value) + goto null_return; + } + + json_get_path_start(&je, js->charset(),(const uchar *) js->ptr(), + (const uchar *) js->ptr() + js->length(), &p); + + + if (!mode_one) + { + bzero(p_found, (arg_count-2) * sizeof(bool)); + n_found= arg_count - 2; + } + + result= 0; + while (json_get_path_next(&je, &p) == 0) + { + int n_path= arg_count - 2; + 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 (mode_one) + { + result= 1; + break; + } + /* mode_all */ + if (p_found[n_path-1]) + continue; /* already found */ + if (--n_found == 0) + { + result= 1; + break; + } + p_found[n_path-1]= TRUE; + } + } + } + + if (je.s.error == 0) + return result; + + report_json_error(js, &je, 0); +null_return: + null_value= 1; + return 0; +} static int append_json_value(String *str, Item *item, String *tmp_val) @@ -1626,10 +1729,10 @@ longlong Item_func_json_length::val_int() { String *s_p= args[1]->val_str(&tmp_path); if (s_p && - json_path_setup(&path.p, s_p->charset(), (const uchar *) s_p->ptr(), - (const uchar *) s_p->ptr() + s_p->length())) + path_setup_nwc(&path.p, s_p->charset(), (const uchar *) s_p->ptr(), + (const uchar *) s_p->ptr() + s_p->length())) { - report_path_error(s_p, &path.p, 2); + report_path_error(s_p, &path.p, 1); goto null_return; } path.parsed= path.constant; @@ -2040,7 +2143,7 @@ String *Item_func_json_remove::val_str(String *str) str->set_charset(js->charset()); json_string_set_cs(&key_name, js->charset()); - for (n_arg=1, n_path=0; n_arg < arg_count; n_arg+=2, n_path++) + for (n_arg=1, n_path=0; n_arg < arg_count; n_arg++, n_path++) { uint array_counters[JSON_DEPTH_LIMIT]; json_path_with_flags *c_path= paths + n_path; @@ -2064,7 +2167,11 @@ String *Item_func_json_remove::val_str(String *str) /* We search to the last step. */ c_path->p.last_step--; if (c_path->p.last_step < c_path->p.steps) + { + c_path->p.s.error= TRIVIAL_PATH_NOT_ALLOWED; + report_path_error(s_p, &c_path->p, n_arg); goto null_return; + } } c_path->parsed= c_path->constant; } @@ -2371,60 +2478,6 @@ static int append_json_path(String *str, const json_path_t *p) } -static int json_path_compare(const json_path_t *a, const json_path_t *b) -{ - const json_path_step_t *sa= a->steps + 1; - const json_path_step_t *sb= b->steps + 1; - - if (a->last_step - sa > b->last_step - sb) - return -2; - - while (sa <= a->last_step) - { - if (sb > b->last_step) - return -2; - - if (!((sa->type & sb->type) & JSON_PATH_KEY_OR_ARRAY)) - goto step_failed; - - if (sa->type & JSON_PATH_ARRAY) - { - if (!(sa->type & JSON_PATH_WILD) && sa->n_item != sb->n_item) - goto step_failed; - } - else /* JSON_PATH_KEY */ - { - if (!(sa->type & JSON_PATH_WILD) && - (sa->key_end - sa->key != sb->key_end - sb->key || - memcmp(sa->key, sb->key, sa->key_end - sa->key) != 0)) - goto step_failed; - } - sb++; - sa++; - continue; - -step_failed: - if (!(sa->type & JSON_PATH_DOUBLE_WILD)) - return -1; - sb++; - } - - return sb <= b->last_step; -} - - -static bool path_ok(const json_path_with_flags *paths_list, int n_paths, - const json_path_t *p) -{ - for (; n_paths > 0; n_paths--, paths_list++) - { - if (json_path_compare(&paths_list->p, p) >= 0) - return TRUE; - } - return FALSE; -} - - String *Item_func_json_search::val_str(String *str) { String *js= args[0]->val_str(&tmp_js); @@ -2462,75 +2515,38 @@ String *Item_func_json_search::val_str(String *str) goto null_return; } - json_scan_start(&je, js->charset(),(const uchar *) js->ptr(), - (const uchar *) js->ptr() + js->length()); - - p.last_step= p.steps; - p.steps[0].type= JSON_PATH_ARRAY_WILD; - p.steps[0].n_item= 0; + json_get_path_start(&je, js->charset(),(const uchar *) js->ptr(), + (const uchar *) js->ptr() + js->length(), &p); - do + while (json_get_path_next(&je, &p) == 0) { - switch (je.state) + if (json_value_scalar(&je)) { - case JST_KEY: - p.last_step->key= je.s.c_str; - while (json_read_keyname_chr(&je) == 0) - p.last_step->key_end= je.s.c_str; - if (je.s.error) - goto js_error; - /* Now we have je.state == JST_VALUE, so let's handle it. */ - - case JST_VALUE: - if (json_read_value(&je)) - goto js_error; - if (json_value_scalar(&je)) + if ((arg_count < 5 || path_ok(paths, arg_count - 4, &p)) && + compare_json_value_wild(&je, s_str) != 0) { - if ((arg_count < 5 || path_ok(paths, n_arg - 4, &p)) && - compare_json_value_wild(&je, s_str) != 0) + ++n_path_found; + if (n_path_found == 1) { - ++n_path_found; - if (n_path_found == 1) - { - sav_path= p; - sav_path.last_step= sav_path.steps + (p.last_step - p.steps); - } - else + sav_path= p; + sav_path.last_step= sav_path.steps + (p.last_step - p.steps); + } + else + { + if (n_path_found == 2) { - if (n_path_found == 2) - { - if (str->append("[", 1) || - append_json_path(str, &sav_path)) + if (str->append("[", 1) || + append_json_path(str, &sav_path)) goto js_error; - } - if (str->append(", ", 2) || append_json_path(str, &p)) - goto js_error; } - - if (mode_one) - goto end; + if (str->append(", ", 2) || append_json_path(str, &p)) + goto js_error; } - if (p.last_step->type & JSON_PATH_ARRAY) - p.last_step->n_item++; - + if (mode_one) + goto end; } - else - { - p.last_step++; - p.last_step->type= (enum json_path_step_types) je.value_type; - p.last_step->n_item= 0; - } - break; - case JST_OBJ_END: - case JST_ARRAY_END: - p.last_step--; - if (p.last_step->type & JSON_PATH_ARRAY) - p.last_step->n_item++; - break; - default: - break; } - } while (json_scan_next(&je) == 0); + } if (je.s.error) goto js_error; |