[Commits] 4bca34d: MDEV-12789 JSON_KEYS returns duplicate keys twice.

Alexey Botchkov holyfoot at askmonty.org
Tue Aug 8 14:41:18 EEST 2017


revision-id: 4bca34d8a4d6e307ea9ee1d19c0aaf1e54df8837 (mariadb-10.2.7-53-g4bca34d)
parent(s): 01a4eb8f761eb669fe2ae5139c73a7434b141a8f
committer: Alexey Botchkov
timestamp: 2017-08-08 15:40:11 +0400
message:

MDEV-12789 JSON_KEYS returns duplicate keys twice.

        Check for duplicating keys added.

---
 mysql-test/r/func_json.result |  6 ++++++
 mysql-test/t/func_json.test   |  5 +++++
 sql/item_jsonfunc.cc          | 50 +++++++++++++++++++++++++++++++++++++++----
 3 files changed, 57 insertions(+), 4 deletions(-)

diff --git a/mysql-test/r/func_json.result b/mysql-test/r/func_json.result
index d004ebd..aa8a285 100644
--- a/mysql-test/r/func_json.result
+++ b/mysql-test/r/func_json.result
@@ -356,6 +356,12 @@ json_keys('foo')
 NULL
 Warnings:
 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"}]';
 select json_search(@j, 'one', 'abc');
 json_search(@j, 'one', 'abc')
diff --git a/mysql-test/t/func_json.test b/mysql-test/t/func_json.test
index 3bcdc6a..3bbda0d 100644
--- a/mysql-test/t/func_json.test
+++ b/mysql-test/t/func_json.test
@@ -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}', "$.b");
 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"}]';
 select json_search(@j, 'one', 'abc');
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc
index 315443f..d871175 100644
--- a/sql/item_jsonfunc.cc
+++ b/sql/item_jsonfunc.cc
@@ -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)
 {
   json_engine_t je;
@@ -2835,6 +2870,7 @@ String *Item_func_json_keys::val_str(String *str)
   while (json_scan_next(&je) == 0 && je.state != JST_OBJ_END)
   {
     const uchar *key_start, *key_end;
+    int key_len;
 
     switch (je.state)
     {
@@ -2844,13 +2880,19 @@ String *Item_func_json_keys::val_str(String *str)
       {
         key_end= je.s.c_str;
       } while (json_read_keyname_chr(&je) == 0);
-      if (je.s.error ||
-          (n_keys > 0 && str->append(", ", 2)) ||
+      if (je.s.error)
+        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) ||
-          append_simple(str, key_start, key_end - key_start) ||
+          append_simple(str, key_start, key_len) ||
           str->append("\"", 1))
         goto err_return;
-      n_keys++;
+        n_keys++;
+      }
       break;
     case JST_OBJ_START:
     case JST_ARRAY_START:


More information about the commits mailing list