From 3bae5328ea55d40ea7a748ac7b07cf9ec82111bf Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 6 Dec 2016 01:32:13 +0400 Subject: [PATCH] MDEV-11433 JSON_MERGE returns a non-NULL result with a NULL argument. Item_func_json_merge fixed. --- mysql-test/r/func_json.result | 15 +++++++ mysql-test/t/func_json.test | 5 +++ sql/item_jsonfunc.cc | 74 ++++++++++++++++++++++++++++------- sql/item_jsonfunc.h | 2 +- 4 files changed, 81 insertions(+), 15 deletions(-) diff --git a/mysql-test/r/func_json.result b/mysql-test/r/func_json.result index 516be85b7be..46e56b7ec16 100644 --- a/mysql-test/r/func_json.result +++ b/mysql-test/r/func_json.result @@ -218,7 +218,22 @@ select json_merge('string'); ERROR 42000: Incorrect parameter count in the call to native function 'json_merge' select json_merge('string', 123); json_merge('string', 123) +NULL +select json_merge('"string"', 123); +json_merge('"string"', 123) ["string", 123] +select json_merge('[1, 2]', '[true, false]'); +json_merge('[1, 2]', '[true, false]') +[1, 2, true, false] +select json_merge('{"1": 2}', '{"true": false}'); +json_merge('{"1": 2}', '{"true": false}') +{"1": 2, "true": false} +select json_merge('{"1": 2}', '{"true": false}', '{"3": 4}'); +json_merge('{"1": 2}', '{"true": false}', '{"3": 4}') +{"1": 2, "true": false, "3": 4} +select json_merge(NULL,json_object('foo', 1)); +json_merge(NULL,json_object('foo', 1)) +NULL select json_type('{"k1":123, "k2":345}'); json_type('{"k1":123, "k2":345}') OBJECT diff --git a/mysql-test/t/func_json.test b/mysql-test/t/func_json.test index 73b91efab87..7bb1c9a9e1f 100644 --- a/mysql-test/t/func_json.test +++ b/mysql-test/t/func_json.test @@ -93,6 +93,11 @@ drop table t1; --error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT select json_merge('string'); select json_merge('string', 123); +select json_merge('"string"', 123); +select json_merge('[1, 2]', '[true, false]'); +select json_merge('{"1": 2}', '{"true": false}'); +select json_merge('{"1": 2}', '{"true": false}', '{"3": 4}'); +select json_merge(NULL,json_object('foo', 1)); select json_type('{"k1":123, "k2":345}'); select json_type('[123, "k2", 345]'); diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index c3b4bc7b8b5..829a547bb07 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -1219,28 +1219,74 @@ err_return: String *Item_func_json_merge::val_str(String *str) { DBUG_ASSERT(fixed == 1); + json_engine_t je1, je2; + String *js1= args[0]->val_str(&tmp_js1); uint n_arg; - str->length(0); - - if (str->append("[", 1) || - ((arg_count > 0) && append_json_value(str, args[0], &tmp_val))) - goto err_return; + if (args[0]->null_value) + goto error_return; for (n_arg=1; n_arg < arg_count; n_arg++) { - if (str->append(", ", 2) || - append_json_value(str, args[n_arg], &tmp_val)) - goto err_return; + String *js2= args[n_arg]->val_str(&tmp_js2); + if (args[n_arg]->null_value) + goto error_return; + + json_scan_start(&je1, js1->charset(),(const uchar *) js1->ptr(), + (const uchar *) js1->ptr() + js1->length()); + + json_scan_start(&je2, js2->charset(),(const uchar *) js2->ptr(), + (const uchar *) js2->ptr() + js2->length()); + + if (json_read_value(&je1) || json_read_value(&je2)) + goto error_return; + + str->length(0); + if ((je1.value_type == JSON_VALUE_ARRAY && + je2.value_type == JSON_VALUE_ARRAY) || + (je1.value_type == JSON_VALUE_OBJECT && + je2.value_type == JSON_VALUE_OBJECT)) + { + /* Merge the adjancent arrays or objects. */ + if (json_skip_level(&je1)) + goto error_return; + if (str->append(js1->ptr(), + ((const char *)je1.s.c_str - js1->ptr()) - je1.sav_c_len) || + str->append(", ", 2) || + str->append((const char *)je2.s.c_str, + js2->length() - ((const char *)je2.s.c_str - js2->ptr()))) + goto error_return; + } + else + { + /* Wrap as an array. */ + if (str->append("[", 1) || + str->append(js1->ptr(), js1->length()) || + str->append(", ", 2) || + str->append(js2->ptr(), js2->length()) || + str->append("]", 1)) + goto error_return; + } + + { + /* Swap str and js1. */ + if (str == &tmp_js1) + { + str= js1; + js1= &tmp_js1; + } + else + { + js1= str; + str= &tmp_js1; + } + } } - if (str->append("]", 1)) - goto err_return; + null_value= 0; + return js1; - return str; - -err_return: - /*TODO: Launch out of memory error. */ +error_return: null_value= 1; return NULL; } diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index e8d677158ed..da9baf47648 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -278,7 +278,7 @@ public: class Item_func_json_merge: public Item_func_json_array { protected: - String tmp_val; + String tmp_js1, tmp_js2; public: Item_func_json_merge(THD *thd, List &list): Item_func_json_array(thd, list) {}