[Commits] 9b6def0: MDEV-12604 Comparison of JSON_EXTRACT result differs with Mysql.

Alexey Botchkov holyfoot at askmonty.org
Tue Aug 8 09:25:16 EEST 2017


revision-id: 9b6def064bb8f303f957c55349484a7a638f5d13 (mariadb-10.2.7-48-g9b6def0)
parent(s): 34eef269eb93ee42c0e5e1894781c61f66cb6f14
committer: Alexey Botchkov
timestamp: 2017-08-08 10:23:41 +0400
message:

MDEV-12604 Comparison of JSON_EXTRACT result differs with Mysql.

        Comparison fixed to take the actual type of JSON value into
        account. Bug in escaping handling fixed.

---
 mysql-test/r/func_json.result |  15 ++++++
 mysql-test/t/func_json.test   |  10 ++++
 sql/item_cmpfunc.cc           |   9 ++++
 sql/item_jsonfunc.cc          | 111 +++++++++++++++++++++++++++++++++++++-----
 sql/item_jsonfunc.h           |   4 +-
 strings/json_lib.c            |   2 +-
 6 files changed, 138 insertions(+), 13 deletions(-)

diff --git a/mysql-test/r/func_json.result b/mysql-test/r/func_json.result
index 894e460..d004ebd 100644
--- a/mysql-test/r/func_json.result
+++ b/mysql-test/r/func_json.result
@@ -648,3 +648,18 @@ NULL
 SELECT JSON_EXTRACT( '{"foo":"bar"}', '$[*]' );
 JSON_EXTRACT( '{"foo":"bar"}', '$[*]' )
 NULL
+select JSON_EXTRACT('{"name":"value"}', '$.name') = 'value';
+JSON_EXTRACT('{"name":"value"}', '$.name') = 'value'
+1
+select JSON_EXTRACT('{\"asdf\":true}', "$.\"asdf\"") = true;
+JSON_EXTRACT('{\"asdf\":true}', "$.\"asdf\"") = true
+1
+select JSON_EXTRACT('{\"asdf\":true}', "$.\"asdf\"") = false;
+JSON_EXTRACT('{\"asdf\":true}', "$.\"asdf\"") = false
+0
+select JSON_EXTRACT('{\"asdf\":true}', "$.\"asdf\"") = 1;
+JSON_EXTRACT('{\"asdf\":true}', "$.\"asdf\"") = 1
+1
+select JSON_EXTRACT('{\"input1\":\"\\u00f6\"}', '$.\"input1\"');
+JSON_EXTRACT('{\"input1\":\"\\u00f6\"}', '$.\"input1\"')
+"\u00f6"
diff --git a/mysql-test/t/func_json.test b/mysql-test/t/func_json.test
index 0ce742a..3bcdc6a 100644
--- a/mysql-test/t/func_json.test
+++ b/mysql-test/t/func_json.test
@@ -302,3 +302,13 @@ DROP TABLE t1;
 SELECT JSON_EXTRACT( '{"foo":"bar"}', '$[*].*' );
 SELECT JSON_EXTRACT( '{"foo":"bar"}', '$[*]' );
 
+#
+# MDEV-12604 Comparison of JSON_EXTRACT result differs with Mysql.
+#
+
+select JSON_EXTRACT('{"name":"value"}', '$.name') = 'value';
+select JSON_EXTRACT('{\"asdf\":true}', "$.\"asdf\"") = true;
+select JSON_EXTRACT('{\"asdf\":true}', "$.\"asdf\"") = false;
+select JSON_EXTRACT('{\"asdf\":true}', "$.\"asdf\"") = 1;
+select JSON_EXTRACT('{\"input1\":\"\\u00f6\"}', '$.\"input1\"');
+
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index d203efa..efab3da 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -670,6 +670,15 @@ int Arg_comparator::set_cmp_func(Item_func_or_sum *owner_arg,
                                   &Arg_comparator::compare_datetime;
   }
 
+  if ((*a)->is_json_type() ^ (*b)->is_json_type())
+  {
+    Item **j_item= (*a)->is_json_type() ? a : b;
+    Item *uf= new(thd->mem_root) Item_func_json_unquote(thd, *j_item);
+    if (!uf || uf->fix_fields(thd, &uf))
+      return 1;
+    *j_item= uf;
+  }
+
   a= cache_converted_constant(thd, a, &a_cache, m_compare_type);
   b= cache_converted_constant(thd, b, &b_cache, m_compare_type);
   return set_compare_func(owner_arg, m_compare_type);
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc
index c7639bc..3f00177 100644
--- a/sql/item_jsonfunc.cc
+++ b/sql/item_jsonfunc.cc
@@ -587,24 +587,40 @@ void Item_func_json_unquote::fix_length_and_dec()
 }
 
 
-String *Item_func_json_unquote::val_str(String *str)
+String *Item_func_json_unquote::read_json(json_engine_t *je)
 {
   String *js= args[0]->val_json(&tmp_s);
-  json_engine_t je;
-  int c_len;
 
   if ((null_value= args[0]->null_value))
-    return NULL;
+    return 0;
 
-  json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
+  json_scan_start(je, js->charset(),(const uchar *) js->ptr(),
                   (const uchar *) js->ptr() + js->length());
 
-  je.value_type= (enum json_value_types) -1; /* To report errors right. */
+  je->value_type= (enum json_value_types) -1; /* To report errors right. */
 
-  if (json_read_value(&je))
+  if (json_read_value(je))
     goto error;
 
-  if (je.value_type != JSON_VALUE_STRING)
+  return js;
+
+error:
+  if (je->value_type == JSON_VALUE_STRING)
+    report_json_error(js, je, 0);
+  return js;
+}
+
+
+String *Item_func_json_unquote::val_str(String *str)
+{
+  json_engine_t je;
+  int c_len;
+  String *js;
+
+  if (!(js= read_json(&je)))
+    return NULL;
+
+  if (je.s.error || je.value_type != JSON_VALUE_STRING)
     return js;
 
   str->length(0);
@@ -621,13 +637,86 @@ String *Item_func_json_unquote::val_str(String *str)
   return str;
 
 error:
-  if (je.value_type == JSON_VALUE_STRING)
-    report_json_error(js, &je, 0);
-  /* We just return the argument's value in the case of error. */
+  report_json_error(js, &je, 0);
   return js;
 }
 
 
+double Item_func_json_unquote::val_real()
+{
+  json_engine_t je;
+  double d= 0.0;
+  String *js;
+
+  if ((js= read_json(&je)) != NULL)
+  {
+    switch (je.value_type)
+    {
+      case JSON_VALUE_NUMBER:
+      {
+        char *end;
+        int err;
+        d= my_strntod(je.s.cs, (char *) je.value, je.value_len, &end, &err);
+        break;
+      }
+      case JSON_VALUE_TRUE:
+        d= 1.0;
+        break;
+      case JSON_VALUE_STRING:
+      {
+        char *end;
+        int err;
+        d= my_strntod(js->charset(), (char *) js->ptr(), js->length(),
+                      &end, &err);
+        break;
+      }
+      default:
+        break;
+    };
+  }
+
+  return d;
+}
+
+
+longlong Item_func_json_unquote::val_int()
+{
+  json_engine_t je;
+  longlong i= 0;
+  String *js;
+
+  if ((js= read_json(&je)) != NULL)
+  {
+    switch (je.value_type)
+    {
+      case JSON_VALUE_NUMBER:
+      {
+        char *end;
+        int err;
+        i= my_strntoll(je.s.cs, (char *) je.value, je.value_len, 10,
+                       &end, &err);
+        break;
+      }
+      case JSON_VALUE_TRUE:
+        i= 1;
+        break;
+      case JSON_VALUE_STRING:
+      {
+        char *end;
+        int err;
+        i= my_strntoll(js->charset(), (char *) js->ptr(), js->length(), 10,
+                       &end, &err);
+        break;
+      }
+      default:
+        break;
+    };
+  }
+
+  return i;
+}
+
+
 static int alloc_tmp_paths(THD *thd, uint n_paths,
                            json_path_with_flags **paths,String **tmp_paths)
 {
diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h
index 394ed5f..cc08912 100644
--- a/sql/item_jsonfunc.h
+++ b/sql/item_jsonfunc.h
@@ -127,12 +127,14 @@ class Item_func_json_unquote: public Item_str_func
 {
 protected:
   String tmp_s;
-
+  String *read_json(json_engine_t *je);
 public:
   Item_func_json_unquote(THD *thd, Item *s): Item_str_func(thd, s) {}
   const char *func_name() const { return "json_unquote"; }
   void fix_length_and_dec();
   String *val_str(String *);
+  double val_real();
+  longlong val_int();
   Item *get_copy(THD *thd, MEM_ROOT *mem_root)
   { return get_item_copy<Item_func_json_unquote>(thd, mem_root, this); }
 };
diff --git a/strings/json_lib.c b/strings/json_lib.c
index 7167b6a..b0c843c 100644
--- a/strings/json_lib.c
+++ b/strings/json_lib.c
@@ -253,7 +253,7 @@ static int read_4_hexdigits(json_string_t *s, uchar *dest)
     if ((c_len= json_next_char(s)) <= 0)
       return s->error= json_eos(s) ? JE_EOS : JE_BAD_CHR;
 
-    if (s->c_next >= 128 || (t= json_instr_chr_map[s->c_next]) >= S_F)
+    if (s->c_next >= 128 || (t= json_instr_chr_map[s->c_next]) > S_F)
       return s->error= JE_SYN;
 
     s->c_str+= c_len;


More information about the commits mailing list