Commit abf75821 authored by Alexey Botchkov's avatar Alexey Botchkov

MDEV-11557 port MySQL-5.7 JSON tests to MariaDB.

        Fixes for issues found.
parent e51b015f
......@@ -409,7 +409,12 @@ int json_get_path_start(json_engine_t *je, CHARSET_INFO *i_cs,
int json_get_path_next(json_engine_t *je, json_path_t *p);
int json_path_compare(const json_path_t *a, const json_path_t *b);
int json_path_parts_compare(
const json_path_step_t *a, const json_path_step_t *a_end,
const json_path_step_t *b, const json_path_step_t *b_end,
enum json_value_types vt);
int json_path_compare(const json_path_t *a, const json_path_t *b,
enum json_value_types vt);
#ifdef __cplusplus
......
......@@ -57,7 +57,7 @@ json_array_append('["a", "b"]', '$', FALSE)
["a", "b", false]
select json_array_append('{"k1":1, "k2":["a", "b"]}', '$.k2', 2);
json_array_append('{"k1":1, "k2":["a", "b"]}', '$.k2', 2)
{"k1":1, "k2":["a", "b", 2]}
{"k1": 1, "k2": ["a", "b", 2]}
select json_array_append('["a", ["b", "c"], "d"]', '$[0]', 2);
json_array_append('["a", ["b", "c"], "d"]', '$[0]', 2)
[["a", 2], ["b", "c"], "d"]
......@@ -190,10 +190,10 @@ json_extract('{"key1":"asd", "key2":[2,3]}', "$.keyX", "$.keyY")
NULL
select json_extract('{"key1":"asd", "key2":[2,3]}', "$.key1", "$.key2");
json_extract('{"key1":"asd", "key2":[2,3]}', "$.key1", "$.key2")
["asd", [2,3]]
["asd", [2, 3]]
select json_extract('{"key1":5, "key2":[2,3]}', "$.key1", "$.key2");
json_extract('{"key1":5, "key2":[2,3]}', "$.key1", "$.key2")
[5, [2,3]]
[5, [2, 3]]
select json_extract('{"key0":true, "key1":"qwe"}', "$.key1");
json_extract('{"key0":true, "key1":"qwe"}', "$.key1")
"qwe"
......@@ -205,7 +205,7 @@ json_extract('[10, 20, [30, 40]]', '$[2][*]')
[30, 40]
select json_extract('[10, 20, [{"a":3}, 30, 40]]', '$[2][*]');
json_extract('[10, 20, [{"a":3}, 30, 40]]', '$[2][*]')
[{"a":3}, 30, 40]
[{"a": 3}, 30, 40]
select json_extract('1', '$');
json_extract('1', '$')
1
......@@ -220,29 +220,29 @@ json_extract( '[{"a": [3, 4]}, {"b": 2}]', '$[0].a', '$[1].a')
[[3, 4]]
select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.k1', 'word');
json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.k1', 'word')
{"a":1, "b":{"c":1, "k1":"word"}, "d":[1, 2]}
{"a": 1, "b": {"c": 1, "k1": "word"}, "d": [1, 2]}
select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.d[3]', 3);
json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.d[3]', 3)
{"a":1, "b":{"c":1}, "d":[1, 2, 3]}
{"a": 1, "b": {"c": 1}, "d": [1, 2, 3]}
select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.a[2]', 2);
json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.a[2]', 2)
{"a":[1, 2], "b":{"c":1}, "d":[1, 2]}
{"a": [1, 2], "b": {"c": 1}, "d": [1, 2]}
select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.c', 'word');
json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.c', 'word')
{"a":1, "b":{"c":1}, "d":[1, 2]}
{"a": 1, "b": {"c": 1}, "d": [1, 2]}
select json_set('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]');
json_set('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]')
{ "a": 10, "b": [2, 3], "c":"[true, false]"}
{"a": 10, "b": [2, 3], "c": "[true, false]"}
select json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]');
json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]')
{ "a": 10, "b": [2, 3]}
{"a": 10, "b": [2, 3]}
select json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.b', '[true, false]');
json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.b', '[true, false]')
{ "a": 10, "b": "[true, false]"}
{"a": 10, "b": "[true, false]"}
set @j = '["a", ["b", "c"], "d"]';
select json_remove(@j, '$[0]');
json_remove(@j, '$[0]')
[ ["b", "c"], "d"]
[["b", "c"], "d"]
select json_remove(@j, '$[1]');
json_remove(@j, '$[1]')
["a", "d"]
......@@ -323,7 +323,7 @@ Warnings:
Warning 4038 Syntax error in JSON text in argument 1 to function 'json_merge' at position 1
select json_merge('{"a":"b"}','{"c":"d"}');
json_merge('{"a":"b"}','{"c":"d"}')
{"a":"b", "c":"d"}
{"a": "b", "c": "d"}
SELECT JSON_MERGE('[1, 2]', '{"id": 47}');
JSON_MERGE('[1, 2]', '{"id": 47}')
[1, 2, {"id": 47}]
......@@ -485,15 +485,13 @@ json_set('{"a":12}', '$[0]', 100)
100
select json_set('{"a":12}', '$[0].a', 100);
json_set('{"a":12}', '$[0].a', 100)
{"a":100}
{"a": 100}
select json_set('{"a":12}', '$[0][0].a', 100);
json_set('{"a":12}', '$[0][0].a', 100)
{"a":100}
{"a": 100}
select json_set('{"a":12}', '$[0][1].a', 100);
json_set('{"a":12}', '$[0][1].a', 100)
NULL
Warnings:
Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_set'
{"a": 12}
select json_value('{"\\"key1":123}', '$."\\"key1"');
json_value('{"\\"key1":123}', '$."\\"key1"')
123
......@@ -503,3 +501,54 @@ json_value('{"\\"key1\\"":123}', '$."\\"key1\\""')
select json_value('{"key 1":123}', '$."key 1"');
json_value('{"key 1":123}', '$."key 1"')
123
select json_contains_path('{"a":[{"c":[1,{"a":[0,1,2]},3]}], "b":[1,2,3]}', 'one', "$**.a[2]");
json_contains_path('{"a":[{"c":[1,{"a":[0,1,2]},3]}], "b":[1,2,3]}', 'one', "$**.a[2]")
1
select json_contains_path('{"a":[{"c":[1,{"a":[0,1,2]},3]}], "b":[1,2,3]}', 'one', "$**.a[3]");
json_contains_path('{"a":[{"c":[1,{"a":[0,1,2]},3]}], "b":[1,2,3]}', 'one', "$**.a[3]")
0
select json_extract( '[1]', '$[0][0]' );
json_extract( '[1]', '$[0][0]' )
1
select json_extract( '[1]', '$[1][0]' );
json_extract( '[1]', '$[1][0]' )
NULL
select json_extract( '[1]', '$**[0]' );
json_extract( '[1]', '$**[0]' )
[1]
select json_extract( '[1]', '$**[0][0]' );
json_extract( '[1]', '$**[0][0]' )
[1]
select json_insert('1', '$[0]', 4);
json_insert('1', '$[0]', 4)
1
select json_replace('1', '$[0]', 4);
json_replace('1', '$[0]', 4)
4
select json_set('1', '$[0]', 4);
json_set('1', '$[0]', 4)
4
select json_set('1', '$[1]', 4);
json_set('1', '$[1]', 4)
[1, 4]
select json_replace('1', '$[1]', 4);
json_replace('1', '$[1]', 4)
1
SELECT json_insert('[]', '$[0][0]', 100);
json_insert('[]', '$[0][0]', 100)
[]
SELECT json_insert('1', '$[0][0]', 100);
json_insert('1', '$[0][0]', 100)
1
SELECT json_replace('1', '$[0][0]', 100);
json_replace('1', '$[0][0]', 100)
100
SELECT json_replace('[]', '$[0][0]', 100);
json_replace('[]', '$[0][0]', 100)
[]
SELECT json_set('[]', '$[0][0]', 100);
json_set('[]', '$[0][0]', 100)
[]
SELECT json_set('[]', '$[0][0][0]', 100);
json_set('[]', '$[0][0][0]', 100)
[]
......@@ -200,3 +200,23 @@ select json_set('{"a":12}', '$[0][1].a', 100);
select json_value('{"\\"key1":123}', '$."\\"key1"');
select json_value('{"\\"key1\\"":123}', '$."\\"key1\\""');
select json_value('{"key 1":123}', '$."key 1"');
select json_contains_path('{"a":[{"c":[1,{"a":[0,1,2]},3]}], "b":[1,2,3]}', 'one', "$**.a[2]");
select json_contains_path('{"a":[{"c":[1,{"a":[0,1,2]},3]}], "b":[1,2,3]}', 'one', "$**.a[3]");
select json_extract( '[1]', '$[0][0]' );
select json_extract( '[1]', '$[1][0]' );
select json_extract( '[1]', '$**[0]' );
select json_extract( '[1]', '$**[0][0]' );
select json_insert('1', '$[0]', 4);
select json_replace('1', '$[0]', 4);
select json_set('1', '$[0]', 4);
select json_set('1', '$[1]', 4);
select json_replace('1', '$[1]', 4);
SELECT json_insert('[]', '$[0][0]', 100);
SELECT json_insert('1', '$[0][0]', 100);
SELECT json_replace('1', '$[0][0]', 100);
SELECT json_replace('[]', '$[0][0]', 100);
SELECT json_set('[]', '$[0][0]', 100);
SELECT json_set('[]', '$[0][0][0]', 100);
......@@ -1762,6 +1762,46 @@ class Create_func_json_valid : public Create_func_arg1
};
class Create_func_json_compact : public Create_func_arg1
{
public:
virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_json_compact s_singleton;
protected:
Create_func_json_compact() {}
virtual ~Create_func_json_compact() {}
};
class Create_func_json_loose : public Create_func_arg1
{
public:
virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_json_loose s_singleton;
protected:
Create_func_json_loose() {}
virtual ~Create_func_json_loose() {}
};
class Create_func_json_detailed : public Create_func_arg2
{
public:
virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_json_detailed s_singleton;
protected:
Create_func_json_detailed() {}
virtual ~Create_func_json_detailed() {}
};
class Create_func_json_type : public Create_func_arg1
{
public:
......@@ -5003,6 +5043,35 @@ Create_func_json_exists::create_2_arg(THD *thd, Item *arg1, Item *arg2)
}
Create_func_json_detailed Create_func_json_detailed::s_singleton;
Item*
Create_func_json_detailed::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_json_format(thd, arg1, arg2);
}
Create_func_json_loose Create_func_json_loose::s_singleton;
Item*
Create_func_json_loose::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_json_format(thd, arg1,
Item_func_json_format::LOOSE);
}
Create_func_json_compact Create_func_json_compact::s_singleton;
Item*
Create_func_json_compact::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_json_format(thd, arg1,
Item_func_json_format::COMPACT);
}
Create_func_json_valid Create_func_json_valid::s_singleton;
Item*
......@@ -6728,14 +6797,17 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("JSON_ARRAY") }, BUILDER(Create_func_json_array)},
{ { C_STRING_WITH_LEN("JSON_ARRAY_APPEND") }, BUILDER(Create_func_json_array_append)},
{ { C_STRING_WITH_LEN("JSON_ARRAY_INSERT") }, BUILDER(Create_func_json_array_insert)},
{ { C_STRING_WITH_LEN("JSON_COMPACT") }, BUILDER(Create_func_json_compact)},
{ { C_STRING_WITH_LEN("JSON_CONTAINS") }, BUILDER(Create_func_json_contains)},
{ { C_STRING_WITH_LEN("JSON_CONTAINS_PATH") }, BUILDER(Create_func_json_contains_path)},
{ { C_STRING_WITH_LEN("JSON_DEPTH") }, BUILDER(Create_func_json_depth)},
{ { C_STRING_WITH_LEN("JSON_DETAILED") }, BUILDER(Create_func_json_detailed)},
{ { C_STRING_WITH_LEN("JSON_EXISTS") }, BUILDER(Create_func_json_exists)},
{ { C_STRING_WITH_LEN("JSON_EXTRACT") }, BUILDER(Create_func_json_extract)},
{ { C_STRING_WITH_LEN("JSON_INSERT") }, BUILDER(Create_func_json_insert)},
{ { C_STRING_WITH_LEN("JSON_KEYS") }, BUILDER(Create_func_json_keys)},
{ { C_STRING_WITH_LEN("JSON_LENGTH") }, BUILDER(Create_func_json_length)},
{ { C_STRING_WITH_LEN("JSON_LOOSE") }, BUILDER(Create_func_json_loose)},
{ { C_STRING_WITH_LEN("JSON_MERGE") }, BUILDER(Create_func_json_merge)},
{ { C_STRING_WITH_LEN("JSON_QUERY") }, BUILDER(Create_func_json_query)},
{ { C_STRING_WITH_LEN("JSON_QUOTE") }, BUILDER(Create_func_json_quote)},
......
......@@ -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 @@ String *Item_func_json_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);
......@@ -2300,7 +2440,14 @@ String *Item_func_json_remove::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);
......@@ -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;
}
......@@ -427,4 +427,30 @@ class Item_json_typecast: public Item_str_func
};
class Item_func_json_format: public Item_str_func
{
public:
enum formats
{
NONE,
COMPACT,
LOOSE,
DETAILED
};
protected:
formats fmt;
String tmp_js;
public:
Item_func_json_format(THD *thd, Item *js, formats format):
Item_str_func(thd, js), fmt(format) {}
Item_func_json_format(THD *thd, Item *js, Item *tabsize):
Item_str_func(thd, js, tabsize), fmt(DETAILED) {}
const char *func_name() const;
void fix_length_and_dec();
String *val_str(String *str);
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_json_format>(thd, mem_root, this); }
};
#endif /* ITEM_JSONFUNC_INCLUDED */
......@@ -1001,6 +1001,7 @@ enum json_path_states {
PS_LAX, /* Parse the 'lax' keyword. */
PS_PT, /* New path's step begins. */
PS_AR, /* Parse array step. */
PS_SAR, /* space after the '['. */
PS_AWD, /* Array wildcard. */
PS_Z, /* '0' (as an array item number). */
PS_INT, /* Parse integer (as an array item number). */
......@@ -1041,7 +1042,10 @@ static int json_path_transitions[N_PATH_STATES][N_PATH_CLASSES]=
JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN,
JE_NOT_JSON_CHR, JE_BAD_CHR},
/* AR */ { JE_EOS, JE_SYN, PS_AWD, JE_SYN, PS_PT, JE_SYN, PS_Z,
PS_INT, JE_SYN, JE_SYN, PS_AR, JE_SYN, JE_SYN, JE_SYN,
PS_INT, JE_SYN, JE_SYN, PS_SAR, JE_SYN, JE_SYN, JE_SYN,
JE_NOT_JSON_CHR, JE_BAD_CHR},
/* SAR */ { JE_EOS, JE_SYN, PS_AWD, JE_SYN, PS_PT, JE_SYN, PS_Z,
PS_INT, JE_SYN, JE_SYN, PS_SAR, JE_SYN, JE_SYN, JE_SYN,
JE_NOT_JSON_CHR, JE_BAD_CHR},
/* AWD */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, PS_PT, JE_SYN, JE_SYN,
JE_SYN, JE_SYN, JE_SYN, PS_AS, JE_SYN, JE_SYN, JE_SYN,
......@@ -1722,45 +1726,103 @@ int json_get_path_next(json_engine_t *je, json_path_t *p)
}
int json_path_compare(const json_path_t *a, const json_path_t *b)
int json_path_parts_compare(
const json_path_step_t *a, const json_path_step_t *a_end,
const json_path_step_t *b, const json_path_step_t *b_end,
enum json_value_types vt)
{
const json_path_step_t *sa= a->steps + 1;
const json_path_step_t *sb= b->steps + 1;
if (a->last_step - sa > b->last_step - sb)
return -2;
int res, res2;
while (sa <= a->last_step)
while (a <= a_end)
{
if (sb > b->last_step)
if (b > b_end)
{
while (vt != JSON_VALUE_ARRAY &&
(a->type & JSON_PATH_ARRAY_WILD) == JSON_PATH_ARRAY &&
a->n_item == 0)
{
if (++a > a_end)
return 0;
}
return -2;
}
DBUG_ASSERT((b->type & (JSON_PATH_WILD | JSON_PATH_DOUBLE_WILD)) == 0);
if (!((sa->type & sb->type) & JSON_PATH_KEY_OR_ARRAY))
goto step_failed;
if (sa->type & JSON_PATH_ARRAY)
if (a->type & JSON_PATH_ARRAY)
{
if (!(sa->type & JSON_PATH_WILD) && sa->n_item != sb->n_item)
if (b->type & JSON_PATH_ARRAY)
{
if ((a->type & JSON_PATH_WILD) || a->n_item == b->n_item)
goto step_fits;
goto step_failed;
}
if (a->n_item == 0)
goto step_fits_autowrap;
goto step_failed;
}
else /* JSON_PATH_KEY */
{
if (!(sa->type & JSON_PATH_WILD) &&
(sa->key_end - sa->key != sb->key_end - sb->key ||
memcmp(sa->key, sb->key, sa->key_end - sa->key) != 0))
if (!(b->type & JSON_PATH_KEY))
goto step_failed;
if (!(a->type & JSON_PATH_WILD) &&
(a->key_end - a->key != b->key_end - b->key ||
memcmp(a->key, b->key, a->key_end - a->key) != 0))
goto step_failed;
}
sb++;
sa++;
continue;
goto step_fits;
}
step_failed:
if (!(sa->type & JSON_PATH_DOUBLE_WILD))
if (!(a->type & JSON_PATH_DOUBLE_WILD))
return -1;
sb++;
b++;
continue;
step_fits:
b++;
if (!(a->type & JSON_PATH_DOUBLE_WILD))
{
a++;
continue;
}
/* Double wild handling needs recursions. */
res= json_path_parts_compare(a+1, a_end, b, b_end, vt);
if (res == 0)
return 0;
res2= json_path_parts_compare(a, a_end, b, b_end, vt);
return (res2 >= 0) ? res2 : res;
step_fits_autowrap:
if (!(a->type & JSON_PATH_DOUBLE_WILD))
{
a++;
continue;
}
/* Double wild handling needs recursions. */
res= json_path_parts_compare(a+1, a_end, b+1, b_end, vt);
if (res == 0)
return 0;
res2= json_path_parts_compare(a, a_end, b+1, b_end, vt);
return (res2 >= 0) ? res2 : res;
}
return sb <= b->last_step;
return b <= b_end;
}
int json_path_compare(const json_path_t *a, const json_path_t *b,
enum json_value_types vt)
{
return json_path_parts_compare(a->steps+1, a->last_step,
b->steps+1, b->last_step, vt);
}
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