Skip to content

Commit 25aaecb

Browse files
author
Alexey Botchkov
committed
MDEV-11858 json_merge() concatenates instead of merging.
Fix json_merge implementation.
1 parent 3ae038b commit 25aaecb

File tree

5 files changed

+236
-71
lines changed

5 files changed

+236
-71
lines changed

mysql-test/r/func_json.result

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,3 +555,15 @@ json_set('[]', '$[0][0][0]', 100)
555555
SELECT JSON_search( '{"": "a"}', "one", 'a');
556556
JSON_search( '{"": "a"}', "one", 'a')
557557
"$."
558+
select json_merge('{"a":"b"}', '{"a":"c"}') ;
559+
json_merge('{"a":"b"}', '{"a":"c"}')
560+
{"a": ["b", "c"]}
561+
select json_merge('{"a":{"x":"b"}}', '{"a":"c"}') ;
562+
json_merge('{"a":{"x":"b"}}', '{"a":"c"}')
563+
{"a": [{"x": "b"}, "c"]}
564+
select json_merge('{"a":{"u":12, "x":"b"}}', '{"a":{"x":"c"}}') ;
565+
json_merge('{"a":{"u":12, "x":"b"}}', '{"a":{"x":"c"}}')
566+
{"a": {"u": 12, "x": ["b", "c"]}}
567+
select json_merge('{"a":{"u":12, "x":"b", "r":1}}', '{"a":{"x":"c", "r":2}}') ;
568+
json_merge('{"a":{"u":12, "x":"b", "r":1}}', '{"a":{"x":"c", "r":2}}')
569+
{"a": {"u": 12, "x": ["b", "c"], "r": [1, 2]}}

mysql-test/suite/json/r/json_no_table.result

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -819,7 +819,7 @@ select json_merge( '[1, 2]', '[3, 4' );
819819
json_merge( '[1, 2]', '[3, 4' )
820820
NULL
821821
Warnings:
822-
Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_merge'
822+
Warning 4037 Unexpected end of JSON text in argument 2 to function 'json_merge'
823823
error ER_INVALID_JSON_TEXT_IN_PARAM
824824
select json_merge( '[1, 2', '[3, 4]' );
825825
json_merge( '[1, 2', '[3, 4]' )
@@ -855,31 +855,31 @@ json_merge( '{ "a": 2 }', '[1, 2]' )
855855
[{"a": 2}, 1, 2]
856856
select json_merge( '{"a": 1, "b": 2 }', '{"b": 3, "d": 4 }' );
857857
json_merge( '{"a": 1, "b": 2 }', '{"b": 3, "d": 4 }' )
858-
{"a": 1, "b": 2, "b": 3, "d": 4}
858+
{"a": 1, "b": [2, 3], "d": 4}
859859
select json_merge( '{"a": 1, "b": 2 }', '{"b": [3, 4], "d": 4 }' );
860860
json_merge( '{"a": 1, "b": 2 }', '{"b": [3, 4], "d": 4 }' )
861-
{"a": 1, "b": 2, "b": [3, 4], "d": 4}
861+
{"a": 1, "b": [2, 3, 4], "d": 4}
862862
select json_merge( '{"a": 1, "b": [2, 3] }', '{"b": 4, "d": 4 }' );
863863
json_merge( '{"a": 1, "b": [2, 3] }', '{"b": 4, "d": 4 }' )
864-
{"a": 1, "b": [2, 3], "b": 4, "d": 4}
864+
{"a": 1, "b": [2, 3, 4], "d": 4}
865865
select json_merge( '{"a": 1, "b": 2 }', '{"b": {"e": 7, "f": 8}, "d": 4 }' );
866866
json_merge( '{"a": 1, "b": 2 }', '{"b": {"e": 7, "f": 8}, "d": 4 }' )
867-
{"a": 1, "b": 2, "b": {"e": 7, "f": 8}, "d": 4}
867+
{"a": 1, "b": [2, {"e": 7, "f": 8}], "d": 4}
868868
select json_merge( '{"b": {"e": 7, "f": 8}, "d": 4 }', '{"a": 1, "b": 2 }' );
869869
json_merge( '{"b": {"e": 7, "f": 8}, "d": 4 }', '{"a": 1, "b": 2 }' )
870-
{"b": {"e": 7, "f": 8}, "d": 4, "a": 1, "b": 2}
870+
{"b": [{"e": 7, "f": 8}, 2], "d": 4, "a": 1}
871871
select json_merge( '{"a": 1, "b": [2, 9] }', '{"b": [10, 11], "d": 4 }' );
872872
json_merge( '{"a": 1, "b": [2, 9] }', '{"b": [10, 11], "d": 4 }' )
873-
{"a": 1, "b": [2, 9], "b": [10, 11], "d": 4}
873+
{"a": 1, "b": [2, 9, 10, 11], "d": 4}
874874
select json_merge( '{"a": 1, "b": [2, 9] }', '{"b": {"e": 7, "f": 8}, "d": 4 }' );
875875
json_merge( '{"a": 1, "b": [2, 9] }', '{"b": {"e": 7, "f": 8}, "d": 4 }' )
876-
{"a": 1, "b": [2, 9], "b": {"e": 7, "f": 8}, "d": 4}
876+
{"a": 1, "b": [2, 9, {"e": 7, "f": 8}], "d": 4}
877877
select json_merge( '{"b": {"e": 7, "f": 8}, "d": 4 }', '{"a": 1, "b": [2, 9] }' );
878878
json_merge( '{"b": {"e": 7, "f": 8}, "d": 4 }', '{"a": 1, "b": [2, 9] }' )
879-
{"b": {"e": 7, "f": 8}, "d": 4, "a": 1, "b": [2, 9]}
879+
{"b": [{"e": 7, "f": 8}, 2, 9], "d": 4, "a": 1}
880880
select json_merge( '{"b": {"e": 7, "f": 8}, "d": 4 }', '{ "a": 1, "b": {"e": 20, "g": 21 } }' );
881881
json_merge( '{"b": {"e": 7, "f": 8}, "d": 4 }', '{ "a": 1, "b": {"e": 20, "g": 21 } }' )
882-
{"b": {"e": 7, "f": 8}, "d": 4, "a": 1, "b": {"e": 20, "g": 21}}
882+
{"b": {"e": [7, 20], "f": 8, "g": 21}, "d": 4, "a": 1}
883883
select json_merge( '1', '2', '3' );
884884
json_merge( '1', '2', '3' )
885885
[1, 2, 3]
@@ -898,7 +898,7 @@ json_merge
898898
'{ "d": false, "b": { "g": 3, "d": 5 }, "f": [ 1, 2 ] }',
899899
'{ "m": true, "b": { "h": 8, "d": 4 }, "e": [ 3, 4 ] }'
900900
)
901-
{"a": true, "b": {"c": 3, "d": 4}, "e": [1, 2], "d": false, "b": {"g": 3, "d": 5}, "f": [1, 2], "m": true, "b": {"h": 8, "d": 4}, "e": [3, 4]}
901+
{"a": true, "b": {"c": 3, "d": [4, 5, 4], "g": 3, "h": 8}, "e": [1, 2, 3, 4], "d": false, "f": [1, 2], "m": true}
902902
SELECT JSON_MERGE
903903
(
904904
'{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }',
@@ -920,7 +920,7 @@ JSON_MERGE
920920
'{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }',
921921
'{ "b": [ false, 34 ] }'
922922
)
923-
{"a": "foo", "b": [true, {"c": 123}], "b": [false, 34]}
923+
{"a": "foo", "b": [true, {"c": 123}, false, 34]}
924924
SELECT JSON_MERGE
925925
(
926926
'{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }',
@@ -931,7 +931,7 @@ JSON_MERGE
931931
'{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }',
932932
'{ "b": "bar" }'
933933
)
934-
{"a": "foo", "b": [true, {"c": 123}], "b": "bar"}
934+
{"a": "foo", "b": [true, {"c": 123}, "bar"]}
935935
SELECT JSON_MERGE
936936
(
937937
'{ "a" : { "b" : 1 } }',
@@ -942,7 +942,7 @@ JSON_MERGE
942942
'{ "a" : { "b" : 1 } }',
943943
'{ "a" : { "c" : 1 } }'
944944
)
945-
{"a": {"b": 1}, "a": {"c": 1}}
945+
{"a": {"b": 1, "c": 1}}
946946
# ----------------------------------------------------------------------
947947
# Test of JSON_TYPE function.
948948
# ----------------------------------------------------------------------

mysql-test/t/func_json.test

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,3 +225,12 @@ SELECT json_set('[]', '$[0][0][0]', 100);
225225
# MDEV-11857 json_search() shows "Out of memory" with empty key.
226226
#
227227
SELECT JSON_search( '{"": "a"}', "one", 'a');
228+
229+
#
230+
# MDEV-11858 json_merge() concatenates instead of merging.
231+
#
232+
233+
select json_merge('{"a":"b"}', '{"a":"c"}') ;
234+
select json_merge('{"a":{"x":"b"}}', '{"a":"c"}') ;
235+
select json_merge('{"a":{"u":12, "x":"b"}}', '{"a":{"x":"c"}}') ;
236+
select json_merge('{"a":{"u":12, "x":"b", "r":1}}', '{"a":{"x":"c", "r":2}}') ;

sql/item_jsonfunc.cc

Lines changed: 201 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,6 +1721,203 @@ String *Item_func_json_object::val_str(String *str)
17211721
}
17221722

17231723

1724+
static int do_merge(String *str, json_engine_t *je1, json_engine_t *je2)
1725+
{
1726+
if (json_read_value(je1) || json_read_value(je2))
1727+
return 1;
1728+
1729+
if (je1->value_type == JSON_VALUE_OBJECT &&
1730+
je2->value_type == JSON_VALUE_OBJECT)
1731+
{
1732+
json_engine_t sav_je1= *je1;
1733+
json_engine_t sav_je2= *je2;
1734+
1735+
int first_key= 1;
1736+
json_string_t key_name;
1737+
1738+
json_string_set_cs(&key_name, je1->s.cs);
1739+
1740+
if (str->append("{", 1))
1741+
return 3;
1742+
while (json_scan_next(je1) == 0 &&
1743+
je1->state != JST_OBJ_END)
1744+
{
1745+
const uchar *key_start, *key_end;
1746+
/* Loop through the Json_1 keys and compare with the Json_2 keys. */
1747+
DBUG_ASSERT(je1->state == JST_KEY);
1748+
key_start= je1->s.c_str;
1749+
do
1750+
{
1751+
key_end= je1->s.c_str;
1752+
} while (json_read_keyname_chr(je1) == 0);
1753+
1754+
if (je1->s.error)
1755+
return 1;
1756+
1757+
if (first_key)
1758+
first_key= 0;
1759+
else
1760+
{
1761+
if (str->append(", ", 2))
1762+
return 3;
1763+
*je2= sav_je2;
1764+
}
1765+
1766+
if (str->append("\"", 1) ||
1767+
append_simple(str, key_start, key_end - key_start) ||
1768+
str->append("\":", 2))
1769+
return 3;
1770+
1771+
while (json_scan_next(je2) == 0 &&
1772+
je2->state != JST_OBJ_END)
1773+
{
1774+
int ires;
1775+
DBUG_ASSERT(je2->state == JST_KEY);
1776+
json_string_set_str(&key_name, key_start, key_end);
1777+
if (!json_key_matches(je2, &key_name))
1778+
{
1779+
if (je2->s.error || json_skip_key(je2))
1780+
return 2;
1781+
continue;
1782+
}
1783+
1784+
/* Json_2 has same key as Json_1. Merge them. */
1785+
if ((ires= do_merge(str, je1, je2)))
1786+
return ires;
1787+
goto merged_j1;
1788+
}
1789+
if (je2->s.error)
1790+
return 2;
1791+
1792+
key_start= je1->s.c_str;
1793+
/* Just append the Json_1 key value. */
1794+
if (json_skip_key(je1))
1795+
return 1;
1796+
if (append_simple(str, key_start, je1->s.c_str - key_start))
1797+
return 3;
1798+
1799+
merged_j1:
1800+
continue;
1801+
}
1802+
1803+
*je2= sav_je2;
1804+
/*
1805+
Now loop through the Json_2 keys.
1806+
Skip if there is same key in Json_1
1807+
*/
1808+
while (json_scan_next(je2) == 0 &&
1809+
je2->state != JST_OBJ_END)
1810+
{
1811+
const uchar *key_start, *key_end;
1812+
DBUG_ASSERT(je2->state == JST_KEY);
1813+
key_start= je2->s.c_str;
1814+
do
1815+
{
1816+
key_end= je2->s.c_str;
1817+
} while (json_read_keyname_chr(je2) == 0);
1818+
1819+
if (je2->s.error)
1820+
return 1;
1821+
1822+
*je1= sav_je1;
1823+
while (json_scan_next(je1) == 0 &&
1824+
je1->state != JST_OBJ_END)
1825+
{
1826+
DBUG_ASSERT(je1->state == JST_KEY);
1827+
json_string_set_str(&key_name, key_start, key_end);
1828+
if (!json_key_matches(je1, &key_name))
1829+
{
1830+
if (je1->s.error || json_skip_key(je1))
1831+
return 2;
1832+
continue;
1833+
}
1834+
if (json_skip_key(je2) ||
1835+
json_skip_level(je1))
1836+
return 1;
1837+
goto continue_j2;
1838+
}
1839+
1840+
if (je1->s.error)
1841+
return 2;
1842+
1843+
if (first_key)
1844+
first_key= 0;
1845+
else if (str->append(", ", 2))
1846+
return 3;
1847+
1848+
if (json_skip_key(je2))
1849+
return 1;
1850+
1851+
if (str->append("\"", 1) ||
1852+
append_simple(str, key_start, je2->s.c_str - key_start))
1853+
return 3;
1854+
1855+
continue_j2:
1856+
continue;
1857+
}
1858+
1859+
if (str->append("}", 1))
1860+
return 3;
1861+
}
1862+
else
1863+
{
1864+
const uchar *end1, *beg1, *end2, *beg2;
1865+
1866+
beg1= je1->value_begin;
1867+
1868+
/* Merge as a single array. */
1869+
if (je1->value_type == JSON_VALUE_ARRAY)
1870+
{
1871+
if (json_skip_level(je1))
1872+
return 1;
1873+
end1= je1->s.c_str - je1->sav_c_len;
1874+
}
1875+
else
1876+
{
1877+
if (str->append("[", 1))
1878+
return 3;
1879+
if (je1->value_type == JSON_VALUE_OBJECT)
1880+
{
1881+
if (json_skip_level(je1))
1882+
return 1;
1883+
end1= je1->s.c_str;
1884+
}
1885+
else
1886+
end1= je1->value_end;
1887+
}
1888+
1889+
if (str->append((const char*) beg1, end1 - beg1),
1890+
str->append(", ", 2))
1891+
return 3;
1892+
1893+
if (json_value_scalar(je2))
1894+
{
1895+
beg2= je2->value_begin;
1896+
end2= je2->value_end;
1897+
}
1898+
else
1899+
{
1900+
if (je2->value_type == JSON_VALUE_OBJECT)
1901+
beg2= je2->value_begin;
1902+
else
1903+
beg2= je2->s.c_str;
1904+
if (json_skip_level(je2))
1905+
return 2;
1906+
end2= je2->s.c_str;
1907+
}
1908+
1909+
if (str->append((const char*) beg2, end2 - beg2))
1910+
return 3;
1911+
1912+
if (je2->value_type != JSON_VALUE_ARRAY &&
1913+
str->append("]", 1))
1914+
return 3;
1915+
}
1916+
1917+
return 0;
1918+
}
1919+
1920+
17241921
String *Item_func_json_merge::val_str(String *str)
17251922
{
17261923
DBUG_ASSERT(fixed == 1);
@@ -1733,6 +1930,9 @@ String *Item_func_json_merge::val_str(String *str)
17331930

17341931
for (n_arg=1; n_arg < arg_count; n_arg++)
17351932
{
1933+
str->set_charset(js1->charset());
1934+
str->length(0);
1935+
17361936
js2= args[n_arg]->val_str(&tmp_js2);
17371937
if (args[n_arg]->null_value)
17381938
goto null_return;
@@ -1743,58 +1943,9 @@ String *Item_func_json_merge::val_str(String *str)
17431943
json_scan_start(&je2, js2->charset(),(const uchar *) js2->ptr(),
17441944
(const uchar *) js2->ptr() + js2->length());
17451945

1746-
if (json_read_value(&je1) || json_read_value(&je2))
1946+
if (do_merge(str, &je1, &je2))
17471947
goto error_return;
17481948

1749-
str->length(0);
1750-
if (je1.value_type == JSON_VALUE_OBJECT &&
1751-
je2.value_type == JSON_VALUE_OBJECT)
1752-
{
1753-
/* Wrap as a single objects. */
1754-
if (json_skip_level(&je1))
1755-
goto error_return;
1756-
if (str->append(js1->ptr(),
1757-
((const char *)je1.s.c_str - js1->ptr()) - je1.sav_c_len) ||
1758-
str->append(", ", 2) ||
1759-
str->append((const char *)je2.s.c_str,
1760-
js2->length() - ((const char *)je2.s.c_str - js2->ptr())))
1761-
goto error_return;
1762-
}
1763-
else
1764-
{
1765-
const char *end1, *beg2;
1766-
1767-
/* Merge as a single array. */
1768-
if (je1.value_type == JSON_VALUE_ARRAY)
1769-
{
1770-
if (json_skip_level(&je1))
1771-
goto error_return;
1772-
end1= (const char *) (je1.s.c_str - je1.sav_c_len);
1773-
}
1774-
else
1775-
{
1776-
if (str->append("[", 1))
1777-
goto error_return;
1778-
end1= js1->end();
1779-
}
1780-
1781-
if (str->append(js1->ptr(), end1 - js1->ptr()),
1782-
str->append(", ", 2))
1783-
goto error_return;
1784-
1785-
if (je2.value_type == JSON_VALUE_ARRAY)
1786-
beg2= (const char *) je2.s.c_str;
1787-
else
1788-
beg2= js2->ptr();
1789-
1790-
if (str->append(beg2, js2->end() - beg2))
1791-
goto error_return;
1792-
1793-
if (je2.value_type != JSON_VALUE_ARRAY &&
1794-
str->append("]", 1))
1795-
goto error_return;
1796-
}
1797-
17981949
{
17991950
/* Swap str and js1. */
18001951
if (str == &tmp_js1)

0 commit comments

Comments
 (0)