Commit 25aaecb2 authored by Alexey Botchkov's avatar Alexey Botchkov

MDEV-11858 json_merge() concatenates instead of merging.

        Fix json_merge implementation.
parent 3ae038b7
...@@ -555,3 +555,15 @@ json_set('[]', '$[0][0][0]', 100) ...@@ -555,3 +555,15 @@ json_set('[]', '$[0][0][0]', 100)
SELECT JSON_search( '{"": "a"}', "one", 'a'); SELECT JSON_search( '{"": "a"}', "one", 'a');
JSON_search( '{"": "a"}', "one", 'a') JSON_search( '{"": "a"}', "one", 'a')
"$." "$."
select json_merge('{"a":"b"}', '{"a":"c"}') ;
json_merge('{"a":"b"}', '{"a":"c"}')
{"a": ["b", "c"]}
select json_merge('{"a":{"x":"b"}}', '{"a":"c"}') ;
json_merge('{"a":{"x":"b"}}', '{"a":"c"}')
{"a": [{"x": "b"}, "c"]}
select json_merge('{"a":{"u":12, "x":"b"}}', '{"a":{"x":"c"}}') ;
json_merge('{"a":{"u":12, "x":"b"}}', '{"a":{"x":"c"}}')
{"a": {"u": 12, "x": ["b", "c"]}}
select json_merge('{"a":{"u":12, "x":"b", "r":1}}', '{"a":{"x":"c", "r":2}}') ;
json_merge('{"a":{"u":12, "x":"b", "r":1}}', '{"a":{"x":"c", "r":2}}')
{"a": {"u": 12, "x": ["b", "c"], "r": [1, 2]}}
...@@ -225,3 +225,12 @@ SELECT json_set('[]', '$[0][0][0]', 100); ...@@ -225,3 +225,12 @@ SELECT json_set('[]', '$[0][0][0]', 100);
# MDEV-11857 json_search() shows "Out of memory" with empty key. # MDEV-11857 json_search() shows "Out of memory" with empty key.
# #
SELECT JSON_search( '{"": "a"}', "one", 'a'); SELECT JSON_search( '{"": "a"}', "one", 'a');
#
# MDEV-11858 json_merge() concatenates instead of merging.
#
select json_merge('{"a":"b"}', '{"a":"c"}') ;
select json_merge('{"a":{"x":"b"}}', '{"a":"c"}') ;
select json_merge('{"a":{"u":12, "x":"b"}}', '{"a":{"x":"c"}}') ;
select json_merge('{"a":{"u":12, "x":"b", "r":1}}', '{"a":{"x":"c", "r":2}}') ;
...@@ -1721,80 +1721,231 @@ String *Item_func_json_object::val_str(String *str) ...@@ -1721,80 +1721,231 @@ String *Item_func_json_object::val_str(String *str)
} }
String *Item_func_json_merge::val_str(String *str) static int do_merge(String *str, json_engine_t *je1, json_engine_t *je2)
{ {
DBUG_ASSERT(fixed == 1); if (json_read_value(je1) || json_read_value(je2))
json_engine_t je1, je2; return 1;
String *js1= args[0]->val_str(&tmp_js1), *js2;
uint n_arg;
if (args[0]->null_value) if (je1->value_type == JSON_VALUE_OBJECT &&
goto null_return; je2->value_type == JSON_VALUE_OBJECT)
{
json_engine_t sav_je1= *je1;
json_engine_t sav_je2= *je2;
for (n_arg=1; n_arg < arg_count; n_arg++) int first_key= 1;
json_string_t key_name;
json_string_set_cs(&key_name, je1->s.cs);
if (str->append("{", 1))
return 3;
while (json_scan_next(je1) == 0 &&
je1->state != JST_OBJ_END)
{ {
js2= args[n_arg]->val_str(&tmp_js2); const uchar *key_start, *key_end;
if (args[n_arg]->null_value) /* Loop through the Json_1 keys and compare with the Json_2 keys. */
goto null_return; DBUG_ASSERT(je1->state == JST_KEY);
key_start= je1->s.c_str;
do
{
key_end= je1->s.c_str;
} while (json_read_keyname_chr(je1) == 0);
json_scan_start(&je1, js1->charset(),(const uchar *) js1->ptr(), if (je1->s.error)
(const uchar *) js1->ptr() + js1->length()); return 1;
json_scan_start(&je2, js2->charset(),(const uchar *) js2->ptr(), if (first_key)
(const uchar *) js2->ptr() + js2->length()); first_key= 0;
else
{
if (str->append(", ", 2))
return 3;
*je2= sav_je2;
}
if (json_read_value(&je1) || json_read_value(&je2)) if (str->append("\"", 1) ||
goto error_return; append_simple(str, key_start, key_end - key_start) ||
str->append("\":", 2))
return 3;
str->length(0); while (json_scan_next(je2) == 0 &&
if (je1.value_type == JSON_VALUE_OBJECT && je2->state != JST_OBJ_END)
je2.value_type == JSON_VALUE_OBJECT)
{ {
/* Wrap as a single objects. */ int ires;
if (json_skip_level(&je1)) DBUG_ASSERT(je2->state == JST_KEY);
goto error_return; json_string_set_str(&key_name, key_start, key_end);
if (str->append(js1->ptr(), if (!json_key_matches(je2, &key_name))
((const char *)je1.s.c_str - js1->ptr()) - je1.sav_c_len) || {
str->append(", ", 2) || if (je2->s.error || json_skip_key(je2))
str->append((const char *)je2.s.c_str, return 2;
js2->length() - ((const char *)je2.s.c_str - js2->ptr()))) continue;
goto error_return; }
/* Json_2 has same key as Json_1. Merge them. */
if ((ires= do_merge(str, je1, je2)))
return ires;
goto merged_j1;
}
if (je2->s.error)
return 2;
key_start= je1->s.c_str;
/* Just append the Json_1 key value. */
if (json_skip_key(je1))
return 1;
if (append_simple(str, key_start, je1->s.c_str - key_start))
return 3;
merged_j1:
continue;
}
*je2= sav_je2;
/*
Now loop through the Json_2 keys.
Skip if there is same key in Json_1
*/
while (json_scan_next(je2) == 0 &&
je2->state != JST_OBJ_END)
{
const uchar *key_start, *key_end;
DBUG_ASSERT(je2->state == JST_KEY);
key_start= je2->s.c_str;
do
{
key_end= je2->s.c_str;
} while (json_read_keyname_chr(je2) == 0);
if (je2->s.error)
return 1;
*je1= sav_je1;
while (json_scan_next(je1) == 0 &&
je1->state != JST_OBJ_END)
{
DBUG_ASSERT(je1->state == JST_KEY);
json_string_set_str(&key_name, key_start, key_end);
if (!json_key_matches(je1, &key_name))
{
if (je1->s.error || json_skip_key(je1))
return 2;
continue;
}
if (json_skip_key(je2) ||
json_skip_level(je1))
return 1;
goto continue_j2;
}
if (je1->s.error)
return 2;
if (first_key)
first_key= 0;
else if (str->append(", ", 2))
return 3;
if (json_skip_key(je2))
return 1;
if (str->append("\"", 1) ||
append_simple(str, key_start, je2->s.c_str - key_start))
return 3;
continue_j2:
continue;
}
if (str->append("}", 1))
return 3;
} }
else else
{ {
const char *end1, *beg2; const uchar *end1, *beg1, *end2, *beg2;
beg1= je1->value_begin;
/* Merge as a single array. */ /* Merge as a single array. */
if (je1.value_type == JSON_VALUE_ARRAY) if (je1->value_type == JSON_VALUE_ARRAY)
{ {
if (json_skip_level(&je1)) if (json_skip_level(je1))
goto error_return; return 1;
end1= (const char *) (je1.s.c_str - je1.sav_c_len); end1= je1->s.c_str - je1->sav_c_len;
} }
else else
{ {
if (str->append("[", 1)) if (str->append("[", 1))
goto error_return; return 3;
end1= js1->end(); if (je1->value_type == JSON_VALUE_OBJECT)
{
if (json_skip_level(je1))
return 1;
end1= je1->s.c_str;
}
else
end1= je1->value_end;
} }
if (str->append(js1->ptr(), end1 - js1->ptr()), if (str->append((const char*) beg1, end1 - beg1),
str->append(", ", 2)) str->append(", ", 2))
goto error_return; return 3;
if (je2.value_type == JSON_VALUE_ARRAY) if (json_value_scalar(je2))
beg2= (const char *) je2.s.c_str; {
beg2= je2->value_begin;
end2= je2->value_end;
}
else else
beg2= js2->ptr(); {
if (je2->value_type == JSON_VALUE_OBJECT)
beg2= je2->value_begin;
else
beg2= je2->s.c_str;
if (json_skip_level(je2))
return 2;
end2= je2->s.c_str;
}
if (str->append(beg2, js2->end() - beg2)) if (str->append((const char*) beg2, end2 - beg2))
goto error_return; return 3;
if (je2.value_type != JSON_VALUE_ARRAY && if (je2->value_type != JSON_VALUE_ARRAY &&
str->append("]", 1)) str->append("]", 1))
goto error_return; return 3;
} }
return 0;
}
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), *js2;
uint n_arg;
if (args[0]->null_value)
goto null_return;
for (n_arg=1; n_arg < arg_count; n_arg++)
{
str->set_charset(js1->charset());
str->length(0);
js2= args[n_arg]->val_str(&tmp_js2);
if (args[n_arg]->null_value)
goto null_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 (do_merge(str, &je1, &je2))
goto error_return;
{ {
/* Swap str and js1. */ /* Swap str and js1. */
if (str == &tmp_js1) if (str == &tmp_js1)
......
...@@ -1197,13 +1197,6 @@ int json_skip_to_level(json_engine_t *j, int level) ...@@ -1197,13 +1197,6 @@ int json_skip_to_level(json_engine_t *j, int level)
int json_skip_key(json_engine_t *j) int json_skip_key(json_engine_t *j)
{ {
if (j->state == JST_KEY)
{
while (json_read_keyname_chr(j) == 0);
if (j->s.error)
return 1;
}
if (json_read_value(j)) if (json_read_value(j))
return 1; return 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment