summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Botchkov <holyfoot@askmonty.org>2017-08-11 00:50:29 +0400
committerAlexey Botchkov <holyfoot@askmonty.org>2017-08-11 00:50:29 +0400
commit79d28533549d15e848b342cf518ae4b409ba3e64 (patch)
treedefca6f922ea782facd0b36f5cec20e2fb4d0cc7
parentbfffe571accb93c80066b070688e6712d4cb5643 (diff)
downloadmariadb-git-79d28533549d15e848b342cf518ae4b409ba3e64.tar.gz
MDEV-12604 Comparison of JSON_EXTRACT result differs with Mysql.
JSON_EXTRACT behaves specifically in the comparison, so we have to implement specific method for that in Arg_comparator.
-rw-r--r--sql/item_cmpfunc.cc48
-rw-r--r--sql/item_cmpfunc.h6
-rw-r--r--sql/item_func.h2
-rw-r--r--sql/item_jsonfunc.cc280
-rw-r--r--sql/item_jsonfunc.h6
5 files changed, 199 insertions, 143 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index efab3da4ac1..16452a0de84 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -627,6 +627,21 @@ int Arg_comparator::set_cmp_func(Item_func_or_sum *owner_arg,
*/
if (owner->agg_arg_charsets_for_comparison(&m_compare_collation, a, b))
return 1;
+
+ if ((*a)->type() == Item::FUNC_ITEM &&
+ ((Item_func *) (*a))->functype() == Item_func::JSON_EXTRACT_FUNC)
+ {
+ func= is_owner_equal_func() ? &Arg_comparator::compare_e_json_str:
+ &Arg_comparator::compare_json_str;
+ return 0;
+ }
+ else if ((*b)->type() == Item::FUNC_ITEM &&
+ ((Item_func *) (*b))->functype() == Item_func::JSON_EXTRACT_FUNC)
+ {
+ func= is_owner_equal_func() ? &Arg_comparator::compare_e_json_str:
+ &Arg_comparator::compare_str_json;
+ return 0;
+ }
}
if (m_compare_type == TIME_RESULT)
@@ -670,15 +685,6 @@ 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);
@@ -1169,6 +1175,30 @@ int Arg_comparator::compare_e_row()
}
+int Arg_comparator::compare_json_str()
+{
+ return compare_json_str_basic(*a, *b);
+}
+
+
+int Arg_comparator::compare_str_json()
+{
+ return -compare_json_str_basic(*b, *a);
+}
+
+
+int Arg_comparator::compare_e_json_str()
+{
+ return compare_e_json_str_basic(*a, *b);
+}
+
+
+int Arg_comparator::compare_e_str_json()
+{
+ return compare_e_json_str_basic(*b, *a);
+}
+
+
void Item_func_truth::fix_length_and_dec()
{
maybe_null= 0;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 8ff789d983a..131062dab36 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -106,6 +106,12 @@ public:
int compare_e_datetime() { return compare_e_temporal(MYSQL_TYPE_DATETIME); }
int compare_time() { return compare_temporal(MYSQL_TYPE_TIME); }
int compare_e_time() { return compare_e_temporal(MYSQL_TYPE_TIME); }
+ int compare_json_str_basic(Item *j, Item *s);
+ int compare_json_str();
+ int compare_str_json();
+ int compare_e_json_str_basic(Item *j, Item *s);
+ int compare_e_json_str();
+ int compare_e_str_json();
Item** cache_converted_constant(THD *thd, Item **value, Item **cache,
Item_result type);
diff --git a/sql/item_func.h b/sql/item_func.h
index 585b981ba05..9aa9b09db1d 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -67,7 +67,7 @@ public:
NOW_FUNC, NOW_UTC_FUNC, SYSDATE_FUNC, TRIG_COND_FUNC,
SUSERVAR_FUNC, GUSERVAR_FUNC, COLLATE_FUNC,
EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC,
- NEG_FUNC, GSYSVAR_FUNC, DYNCOL_FUNC };
+ NEG_FUNC, GSYSVAR_FUNC, DYNCOL_FUNC, JSON_EXTRACT_FUNC };
enum Type type() const { return FUNC_ITEM; }
virtual enum Functype functype() const { return UNKNOWN_FUNC; }
Item_func(THD *thd): Item_func_or_sum(thd), allowed_arg_cols(1)
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc
index d871175a3ba..88165c09426 100644
--- a/sql/item_jsonfunc.cc
+++ b/sql/item_jsonfunc.cc
@@ -642,81 +642,6 @@ error:
}
-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)
{
@@ -779,7 +704,7 @@ void Item_func_json_extract::fix_length_and_dec()
static bool path_exact(const json_path_with_flags *paths_list, int n_paths,
- const json_path_t *p, enum json_value_types vt)
+ const json_path_t *p, json_value_types vt)
{
for (; n_paths > 0; n_paths--, paths_list++)
{
@@ -791,7 +716,7 @@ static bool path_exact(const json_path_with_flags *paths_list, int n_paths,
static bool path_ok(const json_path_with_flags *paths_list, int n_paths,
- const json_path_t *p, enum json_value_types vt)
+ const json_path_t *p, json_value_types vt)
{
for (; n_paths > 0; n_paths--, paths_list++)
{
@@ -802,7 +727,9 @@ static bool path_ok(const json_path_with_flags *paths_list, int n_paths,
}
-String *Item_func_json_extract::val_str(String *str)
+String *Item_func_json_extract::read_json(String *str,
+ json_value_types *type,
+ char **out_val, int *value_len)
{
String *js= args[0]->val_json(&tmp_js);
json_engine_t je, sav_je;
@@ -838,8 +765,13 @@ String *Item_func_json_extract::val_str(String *str)
possible_multiple_values= arg_count > 2 ||
(paths[0].p.types_used & (JSON_PATH_WILD | JSON_PATH_DOUBLE_WILD));
- str->set_charset(js->charset());
- str->length(0);
+ *type= possible_multiple_values ? JSON_VALUE_ARRAY : JSON_VALUE_NULL;
+
+ if (str)
+ {
+ str->set_charset(js->charset());
+ str->length(0);
+ }
if (possible_multiple_values && str->append("[", 1))
goto error;
@@ -854,6 +786,18 @@ String *Item_func_json_extract::val_str(String *str)
value= je.value_begin;
+ if (*type == JSON_VALUE_NULL)
+ {
+ *type= je.value_type;
+ *out_val= (char *) je.value;
+ *value_len= je.value_len;
+ }
+ if (!str)
+ {
+ /* If str is NULL, we only care about the first found value. */
+ goto return_ok;
+ }
+
if (json_value_scalar(&je))
v_len= je.value_end - value;
else
@@ -897,6 +841,7 @@ String *Item_func_json_extract::val_str(String *str)
if (json_nice(&je, &tmp_js, Item_func_json_format::LOOSE))
goto error;
+return_ok:
return &tmp_js;
error:
@@ -907,68 +852,74 @@ return_null:
}
-longlong Item_func_json_extract::val_int()
+String *Item_func_json_extract::val_str(String *str)
{
- String *js= args[0]->val_json(&tmp_js);
- json_engine_t je;
- uint n_arg;
- uint array_counters[JSON_DEPTH_LIMIT];
-
- if ((null_value= args[0]->null_value))
- return 0;
-
- for (n_arg=1; n_arg < arg_count; n_arg++)
- {
- json_path_with_flags *c_path= paths + n_arg - 1;
- if (!c_path->parsed)
- {
- String *s_p= args[n_arg]->val_str(tmp_paths+(n_arg-1));
- if (s_p &&
- json_path_setup(&c_path->p,s_p->charset(),(const uchar *) s_p->ptr(),
- (const uchar *) s_p->ptr() + s_p->length()))
- goto error;
- c_path->parsed= c_path->constant;
- }
-
- if (args[n_arg]->null_value)
- goto error;
+ json_value_types type;
+ char *value;
+ int value_len;
+ return read_json(str, &type, &value, &value_len);
+}
- json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
- (const uchar *) js->ptr() + js->length());
- c_path->cur_step= c_path->p.steps;
+longlong Item_func_json_extract::val_int()
+{
+ json_value_types type;
+ char *value;
+ int value_len;
+ longlong i;
- if (json_find_path(&je, &c_path->p, &c_path->cur_step, array_counters))
+ if (read_json(NULL, &type, &value, &value_len) != NULL)
+ {
+ switch (type)
{
- /* Path wasn't found. */
- if (je.s.error)
- goto error;
+ case JSON_VALUE_NUMBER:
+ case JSON_VALUE_STRING:
+ {
+ char *end;
+ int err;
+ i= my_strntoll(collation.collation, value, value_len, 10, &end, &err);
+ break;
+ }
+ case JSON_VALUE_TRUE:
+ i= 1;
+ break;
+ default:
+ i= 0;
+ break;
+ };
+ }
+ return i;
+}
- continue;
- }
- if (json_read_value(&je))
- goto error;
+double Item_func_json_extract::val_real()
+{
+ json_value_types type;
+ char *value;
+ int value_len;
+ double d= 0.0;
- if (json_value_scalar(&je))
+ if (read_json(NULL, &type, &value, &value_len) != NULL)
+ {
+ switch (type)
{
- int err;
- char *v_end= (char *) je.value_end;
- return (je.s.cs->cset->strtoll10)(je.s.cs, (const char *) je.value_begin,
- &v_end, &err);
- }
- else
- break;
+ case JSON_VALUE_STRING:
+ case JSON_VALUE_NUMBER:
+ {
+ char *end;
+ int err;
+ d= my_strntod(collation.collation, value, value_len, &end, &err);
+ break;
+ }
+ case JSON_VALUE_TRUE:
+ d= 1.0;
+ break;
+ default:
+ break;
+ };
}
- /* Nothing was found. */
- null_value= 1;
- return 0;
-
-error:
- /* TODO: launch error messages. */
- null_value= 1;
- return 0;
+ return d;
}
@@ -3193,4 +3144,71 @@ String *Item_func_json_format::val_json(String *str)
return js;
}
+int Arg_comparator::compare_json_str_basic(Item *j, Item *s)
+{
+ String *res1,*res2;
+ json_value_types type;
+ char *value;
+ int value_len, c_len;
+ Item_func_json_extract *e= (Item_func_json_extract *) j;
+
+ if ((res1= e->read_json(&value1, &type, &value, &value_len)))
+ {
+ if ((res2= s->val_str(&value2)))
+ {
+ if (type == JSON_VALUE_STRING)
+ {
+ if (value1.realloc_with_extra_if_needed(value_len) ||
+ (c_len= json_unescape(value1.charset(), (uchar *) value,
+ (uchar *) value+value_len,
+ &my_charset_utf8_general_ci,
+ (uchar *) value1.ptr(),
+ (uchar *) (value1.ptr() + value_len))) < 0)
+ goto error;
+ value1.length(c_len);
+ res1= &value1;
+ }
+
+ if (set_null)
+ owner->null_value= 0;
+ return sortcmp(res1, res2, compare_collation());
+ }
+ }
+error:
+ if (set_null)
+ owner->null_value= 1;
+ return -1;
+}
+
+
+int Arg_comparator::compare_e_json_str_basic(Item *j, Item *s)
+{
+ String *res1,*res2;
+ json_value_types type;
+ char *value;
+ int value_len, c_len;
+ Item_func_json_extract *e= (Item_func_json_extract *) j;
+
+ res1= e->read_json(&value1, &type, &value, &value_len);
+ res2= s->val_str(&value2);
+
+ if (!res1 || !res2)
+ return MY_TEST(res1 == res2);
+
+ if (type == JSON_VALUE_STRING)
+ {
+ if (value1.realloc_with_extra_if_needed(value_len) ||
+ (c_len= json_unescape(value1.charset(), (uchar *) value,
+ (uchar *) value+value_len,
+ &my_charset_utf8_general_ci,
+ (uchar *) value1.ptr(),
+ (uchar *) (value1.ptr() + value_len))) < 0)
+ return 1;
+ value1.length(c_len);
+ res1= &value1;
+ }
+
+ return MY_TEST(sortcmp(res1, res2, compare_collation()) == 0);
+}
+
diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h
index cc089129556..b5c35ff551f 100644
--- a/sql/item_jsonfunc.h
+++ b/sql/item_jsonfunc.h
@@ -133,8 +133,6 @@ public:
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); }
};
@@ -160,12 +158,16 @@ class Item_func_json_extract: public Item_json_str_multipath
protected:
String tmp_js;
public:
+ String *read_json(String *str, json_value_types *type,
+ char **out_val, int *value_len);
Item_func_json_extract(THD *thd, List<Item> &list):
Item_json_str_multipath(thd, list) {}
const char *func_name() const { return "json_extract"; }
+ enum Functype functype() const { return JSON_EXTRACT_FUNC; }
void fix_length_and_dec();
String *val_str(String *);
longlong val_int();
+ double val_real();
uint get_n_paths() const { return arg_count - 1; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_json_extract>(thd, mem_root, this); }