summaryrefslogtreecommitdiff
path: root/sql/item_jsonfunc.cc
diff options
context:
space:
mode:
authorAlexey Botchkov <holyfoot@askmonty.org>2017-02-06 06:47:48 +0400
committerAlexey Botchkov <holyfoot@askmonty.org>2017-02-06 06:47:48 +0400
commitabf7582112645ef8decc549eb662a07072b5cd32 (patch)
tree1082c1f2c8e32120cee647e0cd0374bd67c37b37 /sql/item_jsonfunc.cc
parente51b015fc354ec40c8430d4f4ea6346bc9a8e07b (diff)
downloadmariadb-git-abf7582112645ef8decc549eb662a07072b5cd32.tar.gz
MDEV-11557 port MySQL-5.7 JSON tests to MariaDB.
Fixes for issues found.
Diffstat (limited to 'sql/item_jsonfunc.cc')
-rw-r--r--sql/item_jsonfunc.cc226
1 files changed, 211 insertions, 15 deletions
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc
index d1f82bc94da..73b0e6b0870 100644
--- a/sql/item_jsonfunc.cc
+++ b/sql/item_jsonfunc.cc
@@ -113,6 +113,100 @@ static int st_append_escaped(String *s, const String *a)
}
+static int json_nice(json_engine_t *je, String *nice_js,
+ Item_func_json_format::formats mode)
+{
+ int depth= 0;
+ const char *comma, *colon;
+ uint comma_len, colon_len;
+ int first_value= 1;
+
+ DBUG_ASSERT(je->s.cs == nice_js->charset());
+
+ if (mode == Item_func_json_format::LOOSE)
+ {
+ comma= ", ";
+ comma_len= 2;
+ colon= "\": ";
+ colon_len= 3;
+ }
+ else
+ {
+ comma= ",";
+ comma_len= 1;
+ colon= "\":";
+ colon_len= 2;
+ }
+
+ do
+ {
+ switch (je->state)
+ {
+ case JST_KEY:
+ {
+ const uchar *key_start= je->s.c_str;
+ const uchar *key_end;
+
+ while (json_read_keyname_chr(je) == 0)
+ key_end= je->s.c_str;
+
+ if (je->s.error)
+ goto error;
+
+ if (!first_value)
+ nice_js->append(comma, comma_len);
+
+ nice_js->append("\"", 1);
+ append_simple(nice_js, key_start, key_end - key_start);
+ nice_js->append(colon, colon_len);
+ }
+ /* now we have key value to handle, so no 'break'. */
+ DBUG_ASSERT(je->state == JST_VALUE);
+ goto handle_value;
+
+ case JST_VALUE:
+ if (!first_value)
+ nice_js->append(comma, comma_len);
+
+handle_value:
+ if (json_read_value(je))
+ goto error;
+ if (json_value_scalar(je))
+ {
+ if (append_simple(nice_js, je->value_begin,
+ je->value_end - je->value_begin))
+ goto error;
+
+ first_value= 0;
+ }
+ else
+ {
+ nice_js->append((je->value_type == JSON_VALUE_OBJECT) ? "{" : "[", 1);
+ first_value= 1;
+ depth++;
+ }
+
+ break;
+
+ case JST_OBJ_END:
+ case JST_ARRAY_END:
+ depth--;
+ nice_js->append((je->state == JST_OBJ_END) ? "}": "]", 1);
+ first_value= 0;
+ break;
+
+ default:
+ break;
+ };
+ } while (json_scan_next(je) == 0);
+
+ return je->s.error;
+
+error:
+ return 1;
+}
+
+
#define report_json_error(js, je, n_param) \
report_json_error_ex(js, je, func_name(), n_param, \
Sql_condition::WARN_LEVEL_WARN)
@@ -554,11 +648,11 @@ 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)
+ const json_path_t *p, enum json_value_types vt)
{
for (; n_paths > 0; n_paths--, paths_list++)
{
- if (json_path_compare(&paths_list->p, p) == 0)
+ if (json_path_compare(&paths_list->p, p, vt) == 0)
return TRUE;
}
return FALSE;
@@ -566,11 +660,11 @@ 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)
+ const json_path_t *p, enum json_value_types vt)
{
for (; n_paths > 0; n_paths--, paths_list++)
{
- if (json_path_compare(&paths_list->p, p) >= 0)
+ if (json_path_compare(&paths_list->p, p, vt) >= 0)
return TRUE;
}
return FALSE;
@@ -624,7 +718,7 @@ String *Item_func_json_extract::val_str(String *str)
while (json_get_path_next(&je, &p) == 0)
{
- if (!path_exact(paths, arg_count-1, &p))
+ if (!path_exact(paths, arg_count-1, &p, je.value_type))
continue;
value= je.value_begin;
@@ -661,10 +755,18 @@ String *Item_func_json_extract::val_str(String *str)
goto return_null;
}
- if (possible_multiple_values && str->append("]"))
+ if (possible_multiple_values && str->append("]", 1))
goto error; /* Out of memory. */
- return str;
+ js= str;
+ json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
+ (const uchar *) js->ptr() + js->length());
+ tmp_js.length(0);
+ tmp_js.set_charset(js->charset());
+ if (json_nice(&je, &tmp_js, Item_func_json_format::LOOSE))
+ goto error;
+
+ return &tmp_js;
error:
report_json_error(js, &je, 0);
@@ -1153,7 +1255,7 @@ longlong Item_func_json_contains_path::val_int()
json_path_with_flags *c_path= paths;
for (; n_path > 0; n_path--, c_path++)
{
- if (json_path_compare(&c_path->p, &p) >= 0)
+ if (json_path_compare(&c_path->p, &p, je.value_type) >= 0)
{
if (mode_one)
{
@@ -1424,7 +1526,14 @@ String *Item_func_json_array_append::val_str(String *str)
}
}
- return js;
+ json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
+ (const uchar *) js->ptr() + js->length());
+ str->length(0);
+ str->set_charset(js->charset());
+ if (json_nice(&je, str, Item_func_json_format::LOOSE))
+ goto js_error;
+
+ return str;
js_error:
report_json_error(js, &je, 0);
@@ -1558,7 +1667,14 @@ String *Item_func_json_array_insert::val_str(String *str)
}
}
- return js;
+ json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
+ (const uchar *) js->ptr() + js->length());
+ str->length(0);
+ str->set_charset(js->charset());
+ if (json_nice(&je, str, Item_func_json_format::LOOSE))
+ goto js_error;
+
+ return str;
js_error:
report_json_error(js, &je, 0);
@@ -1690,8 +1806,15 @@ String *Item_func_json_merge::val_str(String *str)
}
}
+ json_scan_start(&je1, js1->charset(),(const uchar *) js1->ptr(),
+ (const uchar *) js1->ptr() + js1->length());
+ str->length(0);
+ str->set_charset(js1->charset());
+ if (json_nice(&je1, str, Item_func_json_format::LOOSE))
+ goto error_return;
+
null_value= 0;
- return js1;
+ return str;
error_return:
if (je1.s.error)
@@ -1970,6 +2093,7 @@ String *Item_func_json_insert::val_str(String *str)
{
if (je.s.error)
goto js_error;
+ continue;
}
if (json_read_value(&je))
@@ -1986,7 +2110,16 @@ String *Item_func_json_insert::val_str(String *str)
int do_array_autowrap;
if (mode_insert)
- do_array_autowrap= !mode_replace || lp->n_item;
+ {
+ if (mode_replace)
+ do_array_autowrap= lp->n_item > 0;
+ else
+ {
+ if (lp->n_item == 0)
+ continue;
+ do_array_autowrap= 1;
+ }
+ }
else
{
if (lp->n_item)
@@ -2124,7 +2257,14 @@ continue_point:
}
}
- return js;
+ json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
+ (const uchar *) js->ptr() + js->length());
+ str->length(0);
+ str->set_charset(js->charset());
+ if (json_nice(&je, str, Item_func_json_format::LOOSE))
+ goto js_error;
+
+ return str;
js_error:
report_json_error(js, &je, 0);
@@ -2300,7 +2440,14 @@ v_found:
}
}
- return js;
+ json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
+ (const uchar *) js->ptr() + js->length());
+ str->length(0);
+ str->set_charset(js->charset());
+ if (json_nice(&je, str, Item_func_json_format::LOOSE))
+ goto js_error;
+
+ return str;
js_error:
report_json_error(js, &je, 0);
@@ -2540,7 +2687,7 @@ String *Item_func_json_search::val_str(String *str)
{
if (json_value_scalar(&je))
{
- if ((arg_count < 5 || path_ok(paths, arg_count - 4, &p)) &&
+ if ((arg_count < 5 || path_ok(paths, arg_count - 4, &p, je.value_type)) &&
compare_json_value_wild(&je, s_str) != 0)
{
++n_path_found;
@@ -2609,3 +2756,52 @@ String *Item_json_typecast::val_str(String *str)
return vs;
}
+
+const char *Item_func_json_format::func_name() const
+{
+ switch (fmt)
+ {
+ case COMPACT:
+ return "json_compact";
+ case LOOSE:
+ return "json_loose";
+ case DETAILED:
+ return "json_detailed";
+ default:
+ DBUG_ASSERT(0);
+ };
+
+ return "";
+}
+
+
+void Item_func_json_format::fix_length_and_dec()
+{
+ decimals= 0;
+ max_length= args[0]->max_length;
+}
+
+
+String *Item_func_json_format::val_str(String *str)
+{
+ String *js= args[0]->val_str(&tmp_js);
+ json_engine_t je;
+ if ((null_value= args[0]->null_value))
+ return 0;
+
+ json_scan_start(&je, js->charset(), (const uchar *) js->ptr(),
+ (const uchar *) js->ptr()+js->length());
+
+ str->length(0);
+ str->set_charset(js->charset());
+ if (json_nice(&je, str, fmt))
+ {
+ null_value= 1;
+ report_json_error(js, &je, 0);
+ return 0;
+ }
+
+ return str;
+}
+
+