diff --git a/mysql-test/r/func_json.result b/mysql-test/r/func_json.result index cace2f985ac..6c1987cc3e7 100644 --- a/mysql-test/r/func_json.result +++ b/mysql-test/r/func_json.result @@ -425,6 +425,12 @@ json_length('{}') select json_length('[1, 2, {"a": 3}]'); json_length('[1, 2, {"a": 3}]') 3 +select json_length('{"a": 1, "b": {"c": 30}}', '$.b'); +json_length('{"a": 1, "b": {"c": 30}}', '$.b') +1 +select json_length('{"a": 1, "b": {"c": 30}}'); +json_length('{"a": 1, "b": {"c": 30}}') +2 create table json (j INT); show create table json; Table Create Table diff --git a/mysql-test/t/func_json.test b/mysql-test/t/func_json.test index 7e10a4fb203..7ab136f177c 100644 --- a/mysql-test/t/func_json.test +++ b/mysql-test/t/func_json.test @@ -170,6 +170,8 @@ select json_depth('[10, {"a": 20}]'); select json_length(''); select json_length('{}'); select json_length('[1, 2, {"a": 3}]'); +select json_length('{"a": 1, "b": {"c": 30}}', '$.b'); +select json_length('{"a": 1, "b": {"c": 30}}'); create table json (j INT); show create table json; diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 4d87aec669f..9b9490a0cbc 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -1599,29 +1599,85 @@ null_return: } +void Item_func_json_length::fix_length_and_dec() +{ + if (arg_count > 1) + path.set_constant_flag(args[1]->const_item()); +} + + longlong Item_func_json_length::val_int() { String *js= args[0]->val_str(&tmp_js); json_engine_t je; uint length= 0; + uint array_counters[JSON_DEPTH_LIMIT]; 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()); - do + if (arg_count > 1) { - if (je.state == JST_VALUE) + /* Path specified - let's apply it. */ + if (!path.parsed) + { + 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())) + { + report_path_error(s_p, &path.p, 2); + goto null_return; + } + path.parsed= path.constant; + } + if (args[1]->null_value) + goto null_return; + + path.cur_step= path.p.steps; + if (json_find_path(&je, &path.p, &path.cur_step, array_counters)) + { + if (je.s.error) + goto err_return; + goto null_return; + } + } + + + if (json_read_value(&je)) + goto err_return; + + if (json_value_scalar(&je)) + return 1; + + while (json_scan_next(&je) == 0 && + je.state != JST_OBJ_END && je.state != JST_ARRAY_END) + { + switch (je.state) + { + case JST_VALUE: + case JST_KEY: length++; - } while (json_scan_next(&je) == 0); + break; + case JST_OBJ_START: + case JST_ARRAY_START: + if (json_skip_level(&je)) + goto err_return; + break; + default: + break; + }; + } if (!je.s.error) - return length - 1; + return length; +err_return: report_json_error(js, &je, 0); +null_return: null_value= 1; return 0; } diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index e6f26d95b13..07741536f55 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -67,8 +67,8 @@ protected: String tmp_js, tmp_path; public: - Item_func_json_exists(THD *thd, Item *js, Item *path): - Item_int_func(thd, js, path) {} + Item_func_json_exists(THD *thd, Item *js, Item *i_path): + Item_int_func(thd, js, i_path) {} const char *func_name() const { return "json_exists"; } bool is_bool_type() { return true; } void fix_length_and_dec(); @@ -85,8 +85,8 @@ protected: String tmp_js, tmp_path; public: - Item_func_json_value(THD *thd, Item *js, Item *path): - Item_str_func(thd, js, path) {} + Item_func_json_value(THD *thd, Item *js, Item *i_path): + Item_str_func(thd, js, i_path) {} const char *func_name() const { return "json_value"; } void fix_length_and_dec(); String *val_str(String *); @@ -99,8 +99,8 @@ public: class Item_func_json_query: public Item_func_json_value { public: - Item_func_json_query(THD *thd, Item *js, Item *path): - Item_func_json_value(thd, js, path) {} + Item_func_json_query(THD *thd, Item *js, Item *i_path): + Item_func_json_value(thd, js, i_path) {} const char *func_name() const { return "json_query"; } bool check_and_get_value(json_engine_t *je, String *res, int *error); Item *get_copy(THD *thd, MEM_ROOT *mem_root) @@ -291,12 +291,14 @@ public: class Item_func_json_length: public Item_int_func { protected: + json_path_with_flags path; String tmp_js; String tmp_path; public: Item_func_json_length(THD *thd, List &list): Item_int_func(thd, list) {} const char *func_name() const { return "json_length"; } + void fix_length_and_dec(); longlong val_int(); Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); }