diff --git a/mysql-test/main/func_json.result b/mysql-test/main/func_json.result index ab35822a6ce..4d0bb7b840c 100644 --- a/mysql-test/main/func_json.result +++ b/mysql-test/main/func_json.result @@ -5126,5 +5126,19 @@ SELECT JSON_OBJECT_TO_ARRAY(@arr1); JSON_OBJECT_TO_ARRAY(@arr1) NULL # +# MDEV-31411: JSON_ARRAY_INTERSECT/JSON_OBJECT_FILTER_KEYS should fetch +# data from a table similar to other JSON functions +# +CREATE TABLE t1 ( +c1 longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(c1)), +c2 longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`c2`)) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; +INSERT INTO t1 VALUES('[1,2,3]', '[2, 3, 4]'), ('[2 ,3, 4]', '[4, 5, 6]'); +SELECT JSON_ARRAY_INTERSECT(c1, c2) FROM t1; +JSON_ARRAY_INTERSECT(c1, c2) +[2, 3] +[4] +DROP TABLE t1; +# # End of 11.2 Test # diff --git a/mysql-test/main/func_json.test b/mysql-test/main/func_json.test index 494a681243a..8f672fb8725 100644 --- a/mysql-test/main/func_json.test +++ b/mysql-test/main/func_json.test @@ -1,3 +1,5 @@ +--source include/have_innodb.inc + select json_valid('[1, 2]'); select json_valid('"string"}'); select json_valid('{"key1":1, "key2":[2,3]}'); @@ -3947,6 +3949,24 @@ SELECT JSON_OBJECT_TO_ARRAY(@obj1); SET @arr1= '[1, 2, 3]'; SELECT JSON_OBJECT_TO_ARRAY(@arr1); + +--echo # +--echo # MDEV-31411: JSON_ARRAY_INTERSECT/JSON_OBJECT_FILTER_KEYS should fetch +--echo # data from a table similar to other JSON functions +--echo # + +CREATE TABLE t1 ( + c1 longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(c1)), + c2 longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`c2`)) + ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; + +INSERT INTO t1 VALUES('[1,2,3]', '[2, 3, 4]'), ('[2 ,3, 4]', '[4, 5, 6]'); + +SELECT JSON_ARRAY_INTERSECT(c1, c2) FROM t1; + +DROP TABLE t1; + + --echo # --echo # End of 11.2 Test --echo # diff --git a/mysql-test/main/temp.test b/mysql-test/main/temp.test new file mode 100644 index 00000000000..7e29df49b71 --- /dev/null +++ b/mysql-test/main/temp.test @@ -0,0 +1,7 @@ +CREATE TABLE t1 ( c1 longtext , c2 longtext ); + +INSERT INTO t1 VALUES('[1,2,3]', '[2, 3, 4]'), ('[1,2,3]', '[2, 3, 4]'); + +SELECT JSON_ARRAY_INTERSECT(c1, c2) FROM t1; + +DROP TABLE t1; diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 508ea9f644e..7a8a62034af 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -2081,7 +2081,7 @@ return_null: String *Item_func_json_array_insert::val_str(String *str) { json_engine_t je; - String *js= args[0]->val_json(&tmp_js); + String *js= args[0]->val_str(&tmp_js); uint n_arg, n_path; THD *thd= current_thd; @@ -5155,8 +5155,21 @@ String* Item_func_json_array_intersect::val_str(String *str) { DBUG_ASSERT(fixed()); - json_engine_t je2, res_je; - String *js2= args[1]->val_json(&tmp_js2); + json_engine_t je2, res_je, je1; + String *js2= args[1]->val_json(&tmp_js2), *js1= args[0]->val_json(&tmp_js1); + + if (parse_for_each_row) + { + if (args[0]->null_value) + goto null_return; + if (hash_inited) + my_hash_free(&items); + if (root_inited) + free_root(&hash_root, MYF(0)); + root_inited= false; + hash_inited= false; + prepare_json_and_create_hash(&je1, js1); + } if (null_value || args[1]->null_value) goto null_return; @@ -5197,18 +5210,10 @@ null_return: return NULL; } -bool Item_func_json_array_intersect::fix_length_and_dec(THD *thd) +void Item_func_json_array_intersect::prepare_json_and_create_hash(json_engine_t *je1, String *js) { - json_engine_t je1; - String *js1= args[0]->val_json(&tmp_js1); - - if (args[0]->null_value) - { - null_value= true; - return FALSE; - } - json_scan_start(&je1, js1->charset(), (const uchar *) js1->ptr(), - (const uchar *) js1->ptr() + js1->length()); + json_scan_start(je1, js->charset(), (const uchar *) js->ptr(), + (const uchar *) js->ptr() + js->length()); /* Scan value uses the hash table to get the intersection of two arrays. */ @@ -5217,18 +5222,40 @@ bool Item_func_json_array_intersect::fix_length_and_dec(THD *thd) init_alloc_root(PSI_NOT_INSTRUMENTED, &hash_root, 1024, 0, MYF(0)); root_inited= true; - if (json_read_value(&je1) || je1.value_type != JSON_VALUE_ARRAY || - create_hash(&je1, &items, hash_inited, &hash_root)) + if (json_read_value(je1) || je1->value_type != JSON_VALUE_ARRAY || + create_hash(je1, &items, hash_inited, &hash_root)) + { + if (je1->s.error) + report_json_error(js, je1, 0); + null_value= 1; + } + + max_length= (args[0]->max_length < args[1]->max_length) ? + args[0]->max_length : args[1]->max_length; +} + +bool Item_func_json_array_intersect::fix_length_and_dec(THD *thd) +{ + json_engine_t je1; + String *js1; + + if (!args[0]->const_item()) { - if (je1.s.error) - report_json_error(js1, &je1, 0); - null_value= 1; - return FALSE; + if (args[1]->const_item()) + { + std::swap(args[0], args[1]); + } + else + { + parse_for_each_row= true; + goto end; + } } - max_length= (args[0]->max_length < args[1]->max_length) ? - args[0]->max_length : args[1]->max_length; + js1= args[0]->val_json(&tmp_js1); + prepare_json_and_create_hash(&je1, js1); +end: set_maybe_null(); return FALSE; } diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index 42255d8d6f6..6a643e72554 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -869,9 +869,10 @@ protected: bool hash_inited, root_inited; HASH items; MEM_ROOT hash_root; + bool parse_for_each_row; public: Item_func_json_array_intersect(THD *thd, Item *a, Item *b): - Item_str_func(thd, a, b) { hash_inited= root_inited= false; } + Item_str_func(thd, a, b) { hash_inited= root_inited= parse_for_each_row= false; } String *val_str(String *) override; bool fix_length_and_dec(THD *thd) override; LEX_CSTRING func_name_cstring() const override @@ -889,6 +890,7 @@ public: if (root_inited) free_root(&hash_root, MYF(0)); } + void prepare_json_and_create_hash(json_engine_t *je1, String *js); }; class Item_func_json_object_filter_keys: public Item_str_func