Commit 4bca34d8 authored by Alexey Botchkov's avatar Alexey Botchkov

MDEV-12789 JSON_KEYS returns duplicate keys twice.

        Check for duplicating keys added.
parent 01a4eb8f
...@@ -356,6 +356,12 @@ json_keys('foo') ...@@ -356,6 +356,12 @@ json_keys('foo')
NULL NULL
Warnings: Warnings:
Warning 4038 Syntax error in JSON text in argument 1 to function 'json_keys' at position 1 Warning 4038 Syntax error in JSON text in argument 1 to function 'json_keys' at position 1
select json_keys('{"a":{"c":1, "d":2}, "b":2, "c":1, "a":3, "b":1, "c":2}');
json_keys('{"a":{"c":1, "d":2}, "b":2, "c":1, "a":3, "b":1, "c":2}')
["a", "b", "c"]
select json_keys('{"c1": "value 1", "c1": "value 2"}');
json_keys('{"c1": "value 1", "c1": "value 2"}')
["c1"]
SET @j = '["abc", [{"k": "10"}, "def"], {"x":"abc"}, {"y":"bcd"}]'; SET @j = '["abc", [{"k": "10"}, "def"], {"x":"abc"}, {"y":"bcd"}]';
select json_search(@j, 'one', 'abc'); select json_search(@j, 'one', 'abc');
json_search(@j, 'one', 'abc') json_search(@j, 'one', 'abc')
......
...@@ -138,6 +138,11 @@ select json_keys('{"a":{"c":1, "d":2}, "b":2}'); ...@@ -138,6 +138,11 @@ select json_keys('{"a":{"c":1, "d":2}, "b":2}');
select json_keys('{"a":{"c":1, "d":2}, "b":2}', "$.a"); select json_keys('{"a":{"c":1, "d":2}, "b":2}', "$.a");
select json_keys('{"a":{"c":1, "d":2}, "b":2}', "$.b"); select json_keys('{"a":{"c":1, "d":2}, "b":2}', "$.b");
select json_keys('foo'); select json_keys('foo');
#
# mdev-12789 JSON_KEYS returns duplicate keys twice
#
select json_keys('{"a":{"c":1, "d":2}, "b":2, "c":1, "a":3, "b":1, "c":2}');
select json_keys('{"c1": "value 1", "c1": "value 2"}');
SET @j = '["abc", [{"k": "10"}, "def"], {"x":"abc"}, {"y":"bcd"}]'; SET @j = '["abc", [{"k": "10"}, "def"], {"x":"abc"}, {"y":"bcd"}]';
select json_search(@j, 'one', 'abc'); select json_search(@j, 'one', 'abc');
......
...@@ -2779,6 +2779,41 @@ void Item_func_json_keys::fix_length_and_dec() ...@@ -2779,6 +2779,41 @@ void Item_func_json_keys::fix_length_and_dec()
} }
/*
That function is for Item_func_json_keys::val_str exclusively.
It utilizes the fact the resulting string is in specific format:
["key1", "key2"...]
*/
static int check_key_in_list(String *res,
const uchar *key, int key_len)
{
const uchar *c= (const uchar *) res->ptr() + 2; /* beginning '["' */
const uchar *end= (const uchar *) res->end() - 1; /* ending '"' */
while (c < end)
{
int n_char;
for (n_char=0; c[n_char] != '"' && n_char < key_len; n_char++)
{
if (c[n_char] != key[n_char])
break;
}
if (c[n_char] == '"')
{
if (n_char == key_len)
return 1;
}
else
{
while (c[n_char] != '"')
n_char++;
}
c+= n_char + 4; /* skip ', "' */
}
return 0;
}
String *Item_func_json_keys::val_str(String *str) String *Item_func_json_keys::val_str(String *str)
{ {
json_engine_t je; json_engine_t je;
...@@ -2835,6 +2870,7 @@ String *Item_func_json_keys::val_str(String *str) ...@@ -2835,6 +2870,7 @@ String *Item_func_json_keys::val_str(String *str)
while (json_scan_next(&je) == 0 && je.state != JST_OBJ_END) while (json_scan_next(&je) == 0 && je.state != JST_OBJ_END)
{ {
const uchar *key_start, *key_end; const uchar *key_start, *key_end;
int key_len;
switch (je.state) switch (je.state)
{ {
...@@ -2844,13 +2880,19 @@ String *Item_func_json_keys::val_str(String *str) ...@@ -2844,13 +2880,19 @@ String *Item_func_json_keys::val_str(String *str)
{ {
key_end= je.s.c_str; key_end= je.s.c_str;
} while (json_read_keyname_chr(&je) == 0); } while (json_read_keyname_chr(&je) == 0);
if (je.s.error || if (je.s.error)
(n_keys > 0 && str->append(", ", 2)) || goto err_return;
key_len= key_end - key_start;
if (!check_key_in_list(str, key_start, key_len))
{
if ((n_keys > 0 && str->append(", ", 2)) ||
str->append("\"", 1) || str->append("\"", 1) ||
append_simple(str, key_start, key_end - key_start) || append_simple(str, key_start, key_len) ||
str->append("\"", 1)) str->append("\"", 1))
goto err_return; goto err_return;
n_keys++; n_keys++;
}
break; break;
case JST_OBJ_START: case JST_OBJ_START:
case JST_ARRAY_START: case JST_ARRAY_START:
......
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