mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-11557 port MySQL-5.7 JSON tests to MariaDB.
json_no_table.test ported.
This commit is contained in:
@ -219,7 +219,7 @@ typedef struct st_json_engine_t
|
|||||||
/* string constants. */
|
/* string constants. */
|
||||||
|
|
||||||
int stack[JSON_DEPTH_LIMIT]; /* Keeps the stack of nested JSON structures. */
|
int stack[JSON_DEPTH_LIMIT]; /* Keeps the stack of nested JSON structures. */
|
||||||
int *stack_p; /* The 'stack' pointer. */
|
int stack_p; /* The 'stack' pointer. */
|
||||||
} json_engine_t;
|
} json_engine_t;
|
||||||
|
|
||||||
|
|
||||||
@ -308,7 +308,7 @@ typedef const int *json_level_t;
|
|||||||
*/
|
*/
|
||||||
#define json_get_level(j) (j->stack_p)
|
#define json_get_level(j) (j->stack_p)
|
||||||
|
|
||||||
int json_skip_to_level(json_engine_t *j, json_level_t level);
|
int json_skip_to_level(json_engine_t *j, int level);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
json_skip_level() works as above with just current structre.
|
json_skip_level() works as above with just current structre.
|
||||||
@ -391,6 +391,27 @@ int json_append_ascii(CHARSET_INFO *json_cs,
|
|||||||
uchar *json, uchar *json_end,
|
uchar *json, uchar *json_end,
|
||||||
const uchar *ascii, const uchar *ascii_end);
|
const uchar *ascii, const uchar *ascii_end);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Scan the JSON and return paths met one-by-one.
|
||||||
|
json_get_path_start(&p)
|
||||||
|
while (json_get_path_next(&p))
|
||||||
|
{
|
||||||
|
handle_the_next_path();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
int json_get_path_start(json_engine_t *je, CHARSET_INFO *i_cs,
|
||||||
|
const uchar *str, const uchar *end,
|
||||||
|
json_path_t *p);
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -182,6 +182,7 @@ my @DEFAULT_SUITES= qw(
|
|||||||
innodb_fts-
|
innodb_fts-
|
||||||
innodb_gis-
|
innodb_gis-
|
||||||
innodb_zip-
|
innodb_zip-
|
||||||
|
json-
|
||||||
maria-
|
maria-
|
||||||
multi_source-
|
multi_source-
|
||||||
optimizer_unfixed_bugs-
|
optimizer_unfixed_bugs-
|
||||||
|
@ -212,6 +212,12 @@ json_extract('1', '$')
|
|||||||
select json_extract('[10, 20, [30, 40], 1, 10]', '$[1]');
|
select json_extract('[10, 20, [30, 40], 1, 10]', '$[1]');
|
||||||
json_extract('[10, 20, [30, 40], 1, 10]', '$[1]')
|
json_extract('[10, 20, [30, 40], 1, 10]', '$[1]')
|
||||||
20
|
20
|
||||||
|
select json_extract('[10, 20, [30, 40], 1, 10]', '$[1]', '$[25]');
|
||||||
|
json_extract('[10, 20, [30, 40], 1, 10]', '$[1]', '$[25]')
|
||||||
|
[20]
|
||||||
|
select json_extract( '[{"a": [3, 4]}, {"b": 2}]', '$[0].a', '$[1].a');
|
||||||
|
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');
|
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')
|
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]}
|
||||||
|
3634
mysql-test/suite/json/r/json_no_table.result
Normal file
3634
mysql-test/suite/json/r/json_no_table.result
Normal file
File diff suppressed because one or more lines are too long
2288
mysql-test/suite/json/t/json_no_table.test
Normal file
2288
mysql-test/suite/json/t/json_no_table.test
Normal file
File diff suppressed because it is too large
Load Diff
@ -78,6 +78,8 @@ select json_extract('[10, 20, [30, 40]]', '$[2][*]');
|
|||||||
select json_extract('[10, 20, [{"a":3}, 30, 40]]', '$[2][*]');
|
select json_extract('[10, 20, [{"a":3}, 30, 40]]', '$[2][*]');
|
||||||
select json_extract('1', '$');
|
select json_extract('1', '$');
|
||||||
select json_extract('[10, 20, [30, 40], 1, 10]', '$[1]');
|
select json_extract('[10, 20, [30, 40], 1, 10]', '$[1]');
|
||||||
|
select json_extract('[10, 20, [30, 40], 1, 10]', '$[1]', '$[25]');
|
||||||
|
select json_extract( '[{"a": [3, 4]}, {"b": 2}]', '$[0].a', '$[1].a');
|
||||||
|
|
||||||
select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.k1', 'word');
|
select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.k1', 'word');
|
||||||
select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.d[3]', 3);
|
select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.d[3]', 3);
|
||||||
|
@ -168,6 +168,7 @@ void report_json_error_ex(String *js, json_engine_t *je,
|
|||||||
|
|
||||||
#define NO_WILDCARD_ALLOWED 1
|
#define NO_WILDCARD_ALLOWED 1
|
||||||
#define SHOULD_END_WITH_ARRAY 2
|
#define SHOULD_END_WITH_ARRAY 2
|
||||||
|
#define TRIVIAL_PATH_NOT_ALLOWED 3
|
||||||
|
|
||||||
#define report_path_error(js, je, n_param) \
|
#define report_path_error(js, je, n_param) \
|
||||||
report_path_error_ex(js, je, func_name(), n_param,\
|
report_path_error_ex(js, je, func_name(), n_param,\
|
||||||
@ -205,6 +206,11 @@ static void report_path_error_ex(String *ps, json_path_t *p,
|
|||||||
code= ER_JSON_PATH_NO_WILDCARD;
|
code= ER_JSON_PATH_NO_WILDCARD;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TRIVIAL_PATH_NOT_ALLOWED:
|
||||||
|
code= ER_JSON_PATH_EMPTY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -547,22 +553,43 @@ 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)
|
||||||
|
{
|
||||||
|
for (; n_paths > 0; n_paths--, paths_list++)
|
||||||
|
{
|
||||||
|
if (json_path_compare(&paths_list->p, p) == 0)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool path_ok(const json_path_with_flags *paths_list, int n_paths,
|
||||||
|
const json_path_t *p)
|
||||||
|
{
|
||||||
|
for (; n_paths > 0; n_paths--, paths_list++)
|
||||||
|
{
|
||||||
|
if (json_path_compare(&paths_list->p, p) >= 0)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
String *Item_func_json_extract::val_str(String *str)
|
String *Item_func_json_extract::val_str(String *str)
|
||||||
{
|
{
|
||||||
String *js= args[0]->val_str(&tmp_js);
|
String *js= args[0]->val_str(&tmp_js);
|
||||||
json_engine_t je;
|
json_engine_t je, sav_je;
|
||||||
bool multiple_values_found= FALSE;
|
json_path_t p;
|
||||||
const uchar *value;
|
const uchar *value;
|
||||||
const char *first_value= NULL;
|
int not_first_value= 0;
|
||||||
uint n_arg, v_len, first_len;
|
uint n_arg, v_len;
|
||||||
uint array_counters[JSON_DEPTH_LIMIT];
|
int possible_multiple_values;
|
||||||
|
|
||||||
if ((null_value= args[0]->null_value))
|
if ((null_value= args[0]->null_value))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
str->set_charset(js->charset());
|
|
||||||
str->length(0);
|
|
||||||
|
|
||||||
for (n_arg=1; n_arg < arg_count; n_arg++)
|
for (n_arg=1; n_arg < arg_count; n_arg++)
|
||||||
{
|
{
|
||||||
json_path_with_flags *c_path= paths + n_arg - 1;
|
json_path_with_flags *c_path= paths + n_arg - 1;
|
||||||
@ -572,76 +599,66 @@ String *Item_func_json_extract::val_str(String *str)
|
|||||||
if (s_p &&
|
if (s_p &&
|
||||||
json_path_setup(&c_path->p,s_p->charset(),(const uchar *) s_p->ptr(),
|
json_path_setup(&c_path->p,s_p->charset(),(const uchar *) s_p->ptr(),
|
||||||
(const uchar *) s_p->ptr() + s_p->length()))
|
(const uchar *) s_p->ptr() + s_p->length()))
|
||||||
|
{
|
||||||
|
report_path_error(s_p, &c_path->p, n_arg);
|
||||||
goto return_null;
|
goto return_null;
|
||||||
|
}
|
||||||
c_path->parsed= c_path->constant;
|
c_path->parsed= c_path->constant;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (args[n_arg]->null_value)
|
possible_multiple_values= arg_count > 2 ||
|
||||||
goto return_null;
|
(paths[0].p.types_used & (JSON_PATH_WILD | JSON_PATH_DOUBLE_WILD));
|
||||||
|
|
||||||
json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
|
str->set_charset(js->charset());
|
||||||
(const uchar *) js->ptr() + js->length());
|
str->length(0);
|
||||||
|
|
||||||
c_path->cur_step= c_path->p.steps;
|
if (possible_multiple_values && str->append("[", 1))
|
||||||
|
goto error;
|
||||||
|
|
||||||
while (!json_find_path(&je, &c_path->p, &c_path->cur_step, array_counters))
|
json_get_path_start(&je, js->charset(),(const uchar *) js->ptr(),
|
||||||
|
(const uchar *) js->ptr() + js->length(), &p);
|
||||||
|
|
||||||
|
while (json_get_path_next(&je, &p) == 0)
|
||||||
|
{
|
||||||
|
if (!path_exact(paths, arg_count-1, &p))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
value= je.value_begin;
|
||||||
|
|
||||||
|
if (json_value_scalar(&je))
|
||||||
|
v_len= je.value_end - value;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (json_read_value(&je))
|
if (possible_multiple_values)
|
||||||
|
sav_je= je;
|
||||||
|
if (json_skip_level(&je))
|
||||||
goto error;
|
goto error;
|
||||||
|
v_len= je.s.c_str - value;
|
||||||
value= je.value_begin;
|
if (possible_multiple_values)
|
||||||
if (json_value_scalar(&je))
|
je= sav_je;
|
||||||
v_len= je.value_end - value;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (json_skip_level(&je))
|
|
||||||
goto error;
|
|
||||||
v_len= je.s.c_str - value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!multiple_values_found)
|
|
||||||
{
|
|
||||||
if (first_value == NULL)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Just remember the first value as we don't know yet
|
|
||||||
if we need to create an array out of it or not.
|
|
||||||
*/
|
|
||||||
first_value= (const char *) value;
|
|
||||||
first_len= v_len;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
multiple_values_found= TRUE; /* We have to make an JSON array. */
|
|
||||||
if (str->append("[", 1) ||
|
|
||||||
str->append(first_value, first_len))
|
|
||||||
goto error; /* Out of memory. */
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (multiple_values_found &&
|
|
||||||
(str->append(", ", 2) ||
|
|
||||||
str->append((const char *) value, v_len)))
|
|
||||||
goto error; /* Out of memory. */
|
|
||||||
|
|
||||||
if (json_scan_next(&je))
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((not_first_value && str->append(", ", 2)) ||
|
||||||
|
str->append((const char *) value, v_len))
|
||||||
|
goto error; /* Out of memory. */
|
||||||
|
|
||||||
|
not_first_value= 1;
|
||||||
|
|
||||||
|
if (!possible_multiple_values)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (je.s.error)
|
if (je.s.error)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (first_value == NULL)
|
if (!not_first_value)
|
||||||
{
|
{
|
||||||
/* Nothing was found. */
|
/* Nothing was found. */
|
||||||
goto return_null;
|
goto return_null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (multiple_values_found ?
|
if (possible_multiple_values && str->append("]"))
|
||||||
str->append("]") :
|
|
||||||
str->append(first_value, first_len))
|
|
||||||
goto error; /* Out of memory. */
|
goto error; /* Out of memory. */
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
@ -796,12 +813,14 @@ static int check_contains(json_engine_t *js, json_engine_t *value)
|
|||||||
{
|
{
|
||||||
while (json_scan_next(js) == 0 && js->state != JST_ARRAY_END)
|
while (json_scan_next(js) == 0 && js->state != JST_ARRAY_END)
|
||||||
{
|
{
|
||||||
json_level_t c_level;
|
int c_level, v_scalar;
|
||||||
DBUG_ASSERT(js->state == JST_VALUE);
|
DBUG_ASSERT(js->state == JST_VALUE);
|
||||||
if (json_read_value(js))
|
if (json_read_value(js))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
c_level= json_value_scalar(js) ? NULL : json_get_level(js);
|
if (!(v_scalar= json_value_scalar(js)))
|
||||||
|
c_level= json_get_level(js);
|
||||||
|
|
||||||
if (check_contains(js, value))
|
if (check_contains(js, value))
|
||||||
{
|
{
|
||||||
if (json_skip_level(js))
|
if (json_skip_level(js))
|
||||||
@ -809,7 +828,7 @@ static int check_contains(json_engine_t *js, json_engine_t *value)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
if (value->s.error || js->s.error ||
|
if (value->s.error || js->s.error ||
|
||||||
(c_level && json_skip_to_level(js, c_level)))
|
(!v_scalar && json_skip_to_level(js, c_level)))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -955,6 +974,8 @@ return_null:
|
|||||||
bool Item_func_json_contains_path::fix_fields(THD *thd, Item **ref)
|
bool Item_func_json_contains_path::fix_fields(THD *thd, Item **ref)
|
||||||
{
|
{
|
||||||
return alloc_tmp_paths(thd, arg_count-2, &paths, &tmp_paths) ||
|
return alloc_tmp_paths(thd, arg_count-2, &paths, &tmp_paths) ||
|
||||||
|
(p_found= (bool *) alloc_root(thd->mem_root,
|
||||||
|
(arg_count-2)*sizeof(bool))) == NULL ||
|
||||||
Item_int_func::fix_fields(thd, ref);
|
Item_int_func::fix_fields(thd, ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1010,6 +1031,7 @@ static int parse_one_or_all(const Item_func *f, Item *ooa_arg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef DUMMY
|
||||||
longlong Item_func_json_contains_path::val_int()
|
longlong Item_func_json_contains_path::val_int()
|
||||||
{
|
{
|
||||||
String *js= args[0]->val_str(&tmp_js);
|
String *js= args[0]->val_str(&tmp_js);
|
||||||
@ -1076,6 +1098,87 @@ return_null:
|
|||||||
null_value= 1;
|
null_value= 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif /*DUMMY*/
|
||||||
|
|
||||||
|
longlong Item_func_json_contains_path::val_int()
|
||||||
|
{
|
||||||
|
String *js= args[0]->val_str(&tmp_js);
|
||||||
|
json_engine_t je;
|
||||||
|
uint n_arg;
|
||||||
|
longlong result;
|
||||||
|
json_path_t p;
|
||||||
|
int n_found;
|
||||||
|
|
||||||
|
if ((null_value= args[0]->null_value))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (parse_one_or_all(this, args[1], &ooa_parsed, ooa_constant, &mode_one))
|
||||||
|
goto null_return;;
|
||||||
|
|
||||||
|
for (n_arg=2; n_arg < arg_count; n_arg++)
|
||||||
|
{
|
||||||
|
json_path_with_flags *c_path= paths + n_arg - 2;
|
||||||
|
if (!c_path->parsed)
|
||||||
|
{
|
||||||
|
String *s_p= args[n_arg]->val_str(tmp_paths + (n_arg-2));
|
||||||
|
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()))
|
||||||
|
{
|
||||||
|
report_path_error(s_p, &c_path->p, n_arg);
|
||||||
|
goto null_return;
|
||||||
|
}
|
||||||
|
c_path->parsed= c_path->constant;
|
||||||
|
}
|
||||||
|
if (args[n_arg]->null_value)
|
||||||
|
goto null_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_get_path_start(&je, js->charset(),(const uchar *) js->ptr(),
|
||||||
|
(const uchar *) js->ptr() + js->length(), &p);
|
||||||
|
|
||||||
|
|
||||||
|
if (!mode_one)
|
||||||
|
{
|
||||||
|
bzero(p_found, (arg_count-2) * sizeof(bool));
|
||||||
|
n_found= arg_count - 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
result= 0;
|
||||||
|
while (json_get_path_next(&je, &p) == 0)
|
||||||
|
{
|
||||||
|
int n_path= arg_count - 2;
|
||||||
|
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 (mode_one)
|
||||||
|
{
|
||||||
|
result= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* mode_all */
|
||||||
|
if (p_found[n_path-1])
|
||||||
|
continue; /* already found */
|
||||||
|
if (--n_found == 0)
|
||||||
|
{
|
||||||
|
result= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p_found[n_path-1]= TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (je.s.error == 0)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
report_json_error(js, &je, 0);
|
||||||
|
null_return:
|
||||||
|
null_value= 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int append_json_value(String *str, Item *item, String *tmp_val)
|
static int append_json_value(String *str, Item *item, String *tmp_val)
|
||||||
@ -1626,10 +1729,10 @@ longlong Item_func_json_length::val_int()
|
|||||||
{
|
{
|
||||||
String *s_p= args[1]->val_str(&tmp_path);
|
String *s_p= args[1]->val_str(&tmp_path);
|
||||||
if (s_p &&
|
if (s_p &&
|
||||||
json_path_setup(&path.p, s_p->charset(), (const uchar *) s_p->ptr(),
|
path_setup_nwc(&path.p, s_p->charset(), (const uchar *) s_p->ptr(),
|
||||||
(const uchar *) s_p->ptr() + s_p->length()))
|
(const uchar *) s_p->ptr() + s_p->length()))
|
||||||
{
|
{
|
||||||
report_path_error(s_p, &path.p, 2);
|
report_path_error(s_p, &path.p, 1);
|
||||||
goto null_return;
|
goto null_return;
|
||||||
}
|
}
|
||||||
path.parsed= path.constant;
|
path.parsed= path.constant;
|
||||||
@ -2040,7 +2143,7 @@ String *Item_func_json_remove::val_str(String *str)
|
|||||||
str->set_charset(js->charset());
|
str->set_charset(js->charset());
|
||||||
json_string_set_cs(&key_name, js->charset());
|
json_string_set_cs(&key_name, js->charset());
|
||||||
|
|
||||||
for (n_arg=1, n_path=0; n_arg < arg_count; n_arg+=2, n_path++)
|
for (n_arg=1, n_path=0; n_arg < arg_count; n_arg++, n_path++)
|
||||||
{
|
{
|
||||||
uint array_counters[JSON_DEPTH_LIMIT];
|
uint array_counters[JSON_DEPTH_LIMIT];
|
||||||
json_path_with_flags *c_path= paths + n_path;
|
json_path_with_flags *c_path= paths + n_path;
|
||||||
@ -2064,7 +2167,11 @@ String *Item_func_json_remove::val_str(String *str)
|
|||||||
/* We search to the last step. */
|
/* We search to the last step. */
|
||||||
c_path->p.last_step--;
|
c_path->p.last_step--;
|
||||||
if (c_path->p.last_step < c_path->p.steps)
|
if (c_path->p.last_step < c_path->p.steps)
|
||||||
|
{
|
||||||
|
c_path->p.s.error= TRIVIAL_PATH_NOT_ALLOWED;
|
||||||
|
report_path_error(s_p, &c_path->p, n_arg);
|
||||||
goto null_return;
|
goto null_return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
c_path->parsed= c_path->constant;
|
c_path->parsed= c_path->constant;
|
||||||
}
|
}
|
||||||
@ -2371,60 +2478,6 @@ static int append_json_path(String *str, const json_path_t *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int json_path_compare(const json_path_t *a, const json_path_t *b)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
while (sa <= a->last_step)
|
|
||||||
{
|
|
||||||
if (sb > b->last_step)
|
|
||||||
return -2;
|
|
||||||
|
|
||||||
if (!((sa->type & sb->type) & JSON_PATH_KEY_OR_ARRAY))
|
|
||||||
goto step_failed;
|
|
||||||
|
|
||||||
if (sa->type & JSON_PATH_ARRAY)
|
|
||||||
{
|
|
||||||
if (!(sa->type & JSON_PATH_WILD) && sa->n_item != sb->n_item)
|
|
||||||
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))
|
|
||||||
goto step_failed;
|
|
||||||
}
|
|
||||||
sb++;
|
|
||||||
sa++;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
step_failed:
|
|
||||||
if (!(sa->type & JSON_PATH_DOUBLE_WILD))
|
|
||||||
return -1;
|
|
||||||
sb++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb <= b->last_step;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool path_ok(const json_path_with_flags *paths_list, int n_paths,
|
|
||||||
const json_path_t *p)
|
|
||||||
{
|
|
||||||
for (; n_paths > 0; n_paths--, paths_list++)
|
|
||||||
{
|
|
||||||
if (json_path_compare(&paths_list->p, p) >= 0)
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
String *Item_func_json_search::val_str(String *str)
|
String *Item_func_json_search::val_str(String *str)
|
||||||
{
|
{
|
||||||
String *js= args[0]->val_str(&tmp_js);
|
String *js= args[0]->val_str(&tmp_js);
|
||||||
@ -2462,75 +2515,38 @@ String *Item_func_json_search::val_str(String *str)
|
|||||||
goto null_return;
|
goto null_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
|
json_get_path_start(&je, js->charset(),(const uchar *) js->ptr(),
|
||||||
(const uchar *) js->ptr() + js->length());
|
(const uchar *) js->ptr() + js->length(), &p);
|
||||||
|
|
||||||
p.last_step= p.steps;
|
while (json_get_path_next(&je, &p) == 0)
|
||||||
p.steps[0].type= JSON_PATH_ARRAY_WILD;
|
|
||||||
p.steps[0].n_item= 0;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
switch (je.state)
|
if (json_value_scalar(&je))
|
||||||
{
|
{
|
||||||
case JST_KEY:
|
if ((arg_count < 5 || path_ok(paths, arg_count - 4, &p)) &&
|
||||||
p.last_step->key= je.s.c_str;
|
compare_json_value_wild(&je, s_str) != 0)
|
||||||
while (json_read_keyname_chr(&je) == 0)
|
|
||||||
p.last_step->key_end= je.s.c_str;
|
|
||||||
if (je.s.error)
|
|
||||||
goto js_error;
|
|
||||||
/* Now we have je.state == JST_VALUE, so let's handle it. */
|
|
||||||
|
|
||||||
case JST_VALUE:
|
|
||||||
if (json_read_value(&je))
|
|
||||||
goto js_error;
|
|
||||||
if (json_value_scalar(&je))
|
|
||||||
{
|
{
|
||||||
if ((arg_count < 5 || path_ok(paths, n_arg - 4, &p)) &&
|
++n_path_found;
|
||||||
compare_json_value_wild(&je, s_str) != 0)
|
if (n_path_found == 1)
|
||||||
{
|
{
|
||||||
++n_path_found;
|
sav_path= p;
|
||||||
if (n_path_found == 1)
|
sav_path.last_step= sav_path.steps + (p.last_step - p.steps);
|
||||||
{
|
|
||||||
sav_path= p;
|
|
||||||
sav_path.last_step= sav_path.steps + (p.last_step - p.steps);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (n_path_found == 2)
|
|
||||||
{
|
|
||||||
if (str->append("[", 1) ||
|
|
||||||
append_json_path(str, &sav_path))
|
|
||||||
goto js_error;
|
|
||||||
}
|
|
||||||
if (str->append(", ", 2) || append_json_path(str, &p))
|
|
||||||
goto js_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode_one)
|
|
||||||
goto end;
|
|
||||||
}
|
}
|
||||||
if (p.last_step->type & JSON_PATH_ARRAY)
|
else
|
||||||
p.last_step->n_item++;
|
{
|
||||||
|
if (n_path_found == 2)
|
||||||
|
{
|
||||||
|
if (str->append("[", 1) ||
|
||||||
|
append_json_path(str, &sav_path))
|
||||||
|
goto js_error;
|
||||||
|
}
|
||||||
|
if (str->append(", ", 2) || append_json_path(str, &p))
|
||||||
|
goto js_error;
|
||||||
|
}
|
||||||
|
if (mode_one)
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
p.last_step++;
|
|
||||||
p.last_step->type= (enum json_path_step_types) je.value_type;
|
|
||||||
p.last_step->n_item= 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case JST_OBJ_END:
|
|
||||||
case JST_ARRAY_END:
|
|
||||||
p.last_step--;
|
|
||||||
if (p.last_step->type & JSON_PATH_ARRAY)
|
|
||||||
p.last_step->n_item++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} while (json_scan_next(&je) == 0);
|
}
|
||||||
|
|
||||||
if (je.s.error)
|
if (je.s.error)
|
||||||
goto js_error;
|
goto js_error;
|
||||||
|
@ -197,6 +197,7 @@ protected:
|
|||||||
String *tmp_paths;
|
String *tmp_paths;
|
||||||
bool mode_one;
|
bool mode_one;
|
||||||
bool ooa_constant, ooa_parsed;
|
bool ooa_constant, ooa_parsed;
|
||||||
|
bool *p_found;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Item_func_json_contains_path(THD *thd, List<Item> &list):
|
Item_func_json_contains_path(THD *thd, List<Item> &list):
|
||||||
|
@ -7446,3 +7446,5 @@ ER_GEOJSON_TOO_FEW_POINTS
|
|||||||
eng "Incorrect GeoJSON format - too few points for linestring specified."
|
eng "Incorrect GeoJSON format - too few points for linestring specified."
|
||||||
ER_GEOJSON_NOT_CLOSED
|
ER_GEOJSON_NOT_CLOSED
|
||||||
eng "Incorrect GeoJSON format - polygon not closed."
|
eng "Incorrect GeoJSON format - polygon not closed."
|
||||||
|
ER_JSON_PATH_EMPTY
|
||||||
|
eng "Path expression '$' is not allowed in argument %d to function '%s'."
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include <my_global.h>
|
#include <my_global.h>
|
||||||
|
#include <string.h>
|
||||||
#include <m_ctype.h>
|
#include <m_ctype.h>
|
||||||
|
|
||||||
|
|
||||||
@ -126,9 +127,9 @@ static int syntax_error(json_engine_t *j)
|
|||||||
static int mark_object(json_engine_t *j)
|
static int mark_object(json_engine_t *j)
|
||||||
{
|
{
|
||||||
j->state= JST_OBJ_START;
|
j->state= JST_OBJ_START;
|
||||||
if ((++j->stack_p) - j->stack < JSON_DEPTH_LIMIT)
|
if (++j->stack_p < JSON_DEPTH_LIMIT)
|
||||||
{
|
{
|
||||||
*j->stack_p= JST_OBJ_CONT;
|
j->stack[j->stack_p]= JST_OBJ_CONT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
j->s.error= JE_DEPTH;
|
j->s.error= JE_DEPTH;
|
||||||
@ -142,9 +143,9 @@ static int read_obj(json_engine_t *j)
|
|||||||
j->state= JST_OBJ_START;
|
j->state= JST_OBJ_START;
|
||||||
j->value_type= JSON_VALUE_OBJECT;
|
j->value_type= JSON_VALUE_OBJECT;
|
||||||
j->value= j->value_begin;
|
j->value= j->value_begin;
|
||||||
if ((++j->stack_p) - j->stack < JSON_DEPTH_LIMIT)
|
if (++j->stack_p < JSON_DEPTH_LIMIT)
|
||||||
{
|
{
|
||||||
*j->stack_p= JST_OBJ_CONT;
|
j->stack[j->stack_p]= JST_OBJ_CONT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
j->s.error= JE_DEPTH;
|
j->s.error= JE_DEPTH;
|
||||||
@ -156,9 +157,9 @@ static int read_obj(json_engine_t *j)
|
|||||||
static int mark_array(json_engine_t *j)
|
static int mark_array(json_engine_t *j)
|
||||||
{
|
{
|
||||||
j->state= JST_ARRAY_START;
|
j->state= JST_ARRAY_START;
|
||||||
if ((++j->stack_p) - j->stack < JSON_DEPTH_LIMIT)
|
if (++j->stack_p < JSON_DEPTH_LIMIT)
|
||||||
{
|
{
|
||||||
*j->stack_p= JST_ARRAY_CONT;
|
j->stack[j->stack_p]= JST_ARRAY_CONT;
|
||||||
j->value= j->value_begin;
|
j->value= j->value_begin;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -172,9 +173,9 @@ static int read_array(json_engine_t *j)
|
|||||||
j->state= JST_ARRAY_START;
|
j->state= JST_ARRAY_START;
|
||||||
j->value_type= JSON_VALUE_ARRAY;
|
j->value_type= JSON_VALUE_ARRAY;
|
||||||
j->value= j->value_begin;
|
j->value= j->value_begin;
|
||||||
if ((++j->stack_p) - j->stack < JSON_DEPTH_LIMIT)
|
if (++j->stack_p < JSON_DEPTH_LIMIT)
|
||||||
{
|
{
|
||||||
*j->stack_p= JST_ARRAY_CONT;
|
j->stack[j->stack_p]= JST_ARRAY_CONT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
j->s.error= JE_DEPTH;
|
j->s.error= JE_DEPTH;
|
||||||
@ -376,7 +377,7 @@ static int skip_str_constant(json_engine_t *j)
|
|||||||
return j->s.error= json_eos(&j->s) ? JE_EOS : JE_BAD_CHR;
|
return j->s.error= json_eos(&j->s) ? JE_EOS : JE_BAD_CHR;
|
||||||
}
|
}
|
||||||
|
|
||||||
j->state= *j->stack_p;
|
j->state= j->stack[j->stack_p];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,7 +398,7 @@ static int read_strn(json_engine_t *j)
|
|||||||
if (skip_str_constant(j))
|
if (skip_str_constant(j))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
j->state= *j->stack_p;
|
j->state= j->stack[j->stack_p];
|
||||||
j->value_len= (j->s.c_str - j->value) - 1;
|
j->value_len= (j->s.c_str - j->value) - 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -469,7 +470,7 @@ static int json_num_states[NS_NUM_STATES][N_NUM_CLASSES]=
|
|||||||
/*GO*/ { NS_GO1, JE_SYN, NS_Z, NS_INT, JE_SYN, JE_SYN, JE_SYN, JE_BAD_CHR },
|
/*GO*/ { NS_GO1, JE_SYN, NS_Z, NS_INT, JE_SYN, JE_SYN, JE_SYN, JE_BAD_CHR },
|
||||||
/*GO1*/ { JE_SYN, JE_SYN, NS_Z1, NS_INT, JE_SYN, JE_SYN, JE_SYN, JE_BAD_CHR },
|
/*GO1*/ { JE_SYN, JE_SYN, NS_Z1, NS_INT, JE_SYN, JE_SYN, JE_SYN, JE_BAD_CHR },
|
||||||
/*ZERO*/ { JE_SYN, JE_SYN, JE_SYN, JE_SYN, NS_FRAC, JE_SYN, NS_OK, JE_BAD_CHR },
|
/*ZERO*/ { JE_SYN, JE_SYN, JE_SYN, JE_SYN, NS_FRAC, JE_SYN, NS_OK, JE_BAD_CHR },
|
||||||
/*ZE1*/ { JE_SYN, JE_SYN, JE_SYN, JE_SYN, NS_FRAC, JE_SYN, JE_SYN, JE_BAD_CHR },
|
/*ZE1*/ { JE_SYN, JE_SYN, JE_SYN, JE_SYN, NS_FRAC, JE_SYN, NS_OK, JE_BAD_CHR },
|
||||||
/*INT*/ { JE_SYN, JE_SYN, NS_INT, NS_INT, NS_FRAC, NS_EX, NS_OK, JE_BAD_CHR },
|
/*INT*/ { JE_SYN, JE_SYN, NS_INT, NS_INT, NS_FRAC, NS_EX, NS_OK, JE_BAD_CHR },
|
||||||
/*FRAC*/ { JE_SYN, JE_SYN, NS_FRAC, NS_FRAC,JE_SYN, NS_EX, NS_OK, JE_BAD_CHR },
|
/*FRAC*/ { JE_SYN, JE_SYN, NS_FRAC, NS_FRAC,JE_SYN, NS_EX, NS_OK, JE_BAD_CHR },
|
||||||
/*EX*/ { NS_EX1, NS_EX1, NS_EX1, NS_EX1, JE_SYN, JE_SYN, JE_SYN, JE_BAD_CHR },
|
/*EX*/ { NS_EX1, NS_EX1, NS_EX1, NS_EX1, JE_SYN, JE_SYN, JE_SYN, JE_BAD_CHR },
|
||||||
@ -517,7 +518,7 @@ static int skip_num_constant(json_engine_t *j)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
j->state= *j->stack_p;
|
j->state= j->stack[j->stack_p];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -570,7 +571,7 @@ static int v_false(json_engine_t *j)
|
|||||||
{
|
{
|
||||||
if (skip_string_verbatim(&j->s, "alse"))
|
if (skip_string_verbatim(&j->s, "alse"))
|
||||||
return 1;
|
return 1;
|
||||||
j->state= *j->stack_p;
|
j->state= j->stack[j->stack_p];
|
||||||
return json_scan_next(j);
|
return json_scan_next(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -580,7 +581,7 @@ static int v_null(json_engine_t *j)
|
|||||||
{
|
{
|
||||||
if (skip_string_verbatim(&j->s, "ull"))
|
if (skip_string_verbatim(&j->s, "ull"))
|
||||||
return 1;
|
return 1;
|
||||||
j->state= *j->stack_p;
|
j->state= j->stack[j->stack_p];
|
||||||
return json_scan_next(j);
|
return json_scan_next(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -590,7 +591,7 @@ static int v_true(json_engine_t *j)
|
|||||||
{
|
{
|
||||||
if (skip_string_verbatim(&j->s, "rue"))
|
if (skip_string_verbatim(&j->s, "rue"))
|
||||||
return 1;
|
return 1;
|
||||||
j->state= *j->stack_p;
|
j->state= j->stack[j->stack_p];
|
||||||
return json_scan_next(j);
|
return json_scan_next(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,7 +601,7 @@ static int read_false(json_engine_t *j)
|
|||||||
{
|
{
|
||||||
j->value_type= JSON_VALUE_FALSE;
|
j->value_type= JSON_VALUE_FALSE;
|
||||||
j->value= j->value_begin;
|
j->value= j->value_begin;
|
||||||
j->state= *j->stack_p;
|
j->state= j->stack[j->stack_p];
|
||||||
j->value_len= 5;
|
j->value_len= 5;
|
||||||
return skip_string_verbatim(&j->s, "alse");
|
return skip_string_verbatim(&j->s, "alse");
|
||||||
}
|
}
|
||||||
@ -611,7 +612,7 @@ static int read_null(json_engine_t *j)
|
|||||||
{
|
{
|
||||||
j->value_type= JSON_VALUE_NULL;
|
j->value_type= JSON_VALUE_NULL;
|
||||||
j->value= j->value_begin;
|
j->value= j->value_begin;
|
||||||
j->state= *j->stack_p;
|
j->state= j->stack[j->stack_p];
|
||||||
j->value_len= 4;
|
j->value_len= 4;
|
||||||
return skip_string_verbatim(&j->s, "ull");
|
return skip_string_verbatim(&j->s, "ull");
|
||||||
}
|
}
|
||||||
@ -622,7 +623,7 @@ static int read_true(json_engine_t *j)
|
|||||||
{
|
{
|
||||||
j->value_type= JSON_VALUE_TRUE;
|
j->value_type= JSON_VALUE_TRUE;
|
||||||
j->value= j->value_begin;
|
j->value= j->value_begin;
|
||||||
j->state= *j->stack_p;
|
j->state= j->stack[j->stack_p];
|
||||||
j->value_len= 4;
|
j->value_len= 4;
|
||||||
return skip_string_verbatim(&j->s, "rue");
|
return skip_string_verbatim(&j->s, "rue");
|
||||||
}
|
}
|
||||||
@ -791,7 +792,7 @@ int json_scan_start(json_engine_t *je,
|
|||||||
{
|
{
|
||||||
json_string_setup(&je->s, i_cs, str, end);
|
json_string_setup(&je->s, i_cs, str, end);
|
||||||
je->stack[0]= JST_DONE;
|
je->stack[0]= JST_DONE;
|
||||||
je->stack_p= je->stack;
|
je->stack_p= 0;
|
||||||
je->state= JST_VALUE;
|
je->state= JST_VALUE;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -839,7 +840,7 @@ static int skip_key(json_engine_t *j)
|
|||||||
run our 'state machine' accordingly.
|
run our 'state machine' accordingly.
|
||||||
*/
|
*/
|
||||||
static int struct_end_eos(json_engine_t *j)
|
static int struct_end_eos(json_engine_t *j)
|
||||||
{ return json_actions[*j->stack_p][C_EOS](j); }
|
{ return json_actions[j->stack[j->stack_p]][C_EOS](j); }
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -849,7 +850,7 @@ static int struct_end_eos(json_engine_t *j)
|
|||||||
run our 'state machine' accordingly.
|
run our 'state machine' accordingly.
|
||||||
*/
|
*/
|
||||||
static int struct_end_cb(json_engine_t *j)
|
static int struct_end_cb(json_engine_t *j)
|
||||||
{ return json_actions[*j->stack_p][C_RCURB](j); }
|
{ return json_actions[j->stack[j->stack_p]][C_RCURB](j); }
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -859,7 +860,7 @@ static int struct_end_cb(json_engine_t *j)
|
|||||||
run our 'state machine' accordingly.
|
run our 'state machine' accordingly.
|
||||||
*/
|
*/
|
||||||
static int struct_end_qb(json_engine_t *j)
|
static int struct_end_qb(json_engine_t *j)
|
||||||
{ return json_actions[*j->stack_p][C_RSQRB](j); }
|
{ return json_actions[j->stack[j->stack_p]][C_RSQRB](j); }
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -869,7 +870,7 @@ static int struct_end_qb(json_engine_t *j)
|
|||||||
run our 'state machine' accordingly.
|
run our 'state machine' accordingly.
|
||||||
*/
|
*/
|
||||||
static int struct_end_cm(json_engine_t *j)
|
static int struct_end_cm(json_engine_t *j)
|
||||||
{ return json_actions[*j->stack_p][C_COMMA](j); }
|
{ return json_actions[j->stack[j->stack_p]][C_COMMA](j); }
|
||||||
|
|
||||||
|
|
||||||
int json_read_keyname_chr(json_engine_t *j)
|
int json_read_keyname_chr(json_engine_t *j)
|
||||||
@ -1107,8 +1108,6 @@ int json_path_setup(json_path_t *p,
|
|||||||
continue;
|
continue;
|
||||||
case PS_KWD:
|
case PS_KWD:
|
||||||
case PS_AWD:
|
case PS_AWD:
|
||||||
if (p->last_step->type & JSON_PATH_DOUBLE_WILD)
|
|
||||||
return p->s.error= JE_SYN;
|
|
||||||
p->last_step->type|= JSON_PATH_WILD;
|
p->last_step->type|= JSON_PATH_WILD;
|
||||||
p->types_used|= JSON_PATH_WILD;
|
p->types_used|= JSON_PATH_WILD;
|
||||||
continue;
|
continue;
|
||||||
@ -1158,7 +1157,7 @@ int json_path_setup(json_path_t *p,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int json_skip_to_level(json_engine_t *j, json_level_t level)
|
int json_skip_to_level(json_engine_t *j, int level)
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
if (j->stack_p < level)
|
if (j->stack_p < level)
|
||||||
@ -1595,3 +1594,118 @@ int json_escape(CHARSET_INFO *str_cs,
|
|||||||
|
|
||||||
return json - json_start;
|
return json - json_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int json_get_path_start(json_engine_t *je, CHARSET_INFO *i_cs,
|
||||||
|
const uchar *str, const uchar *end,
|
||||||
|
json_path_t *p)
|
||||||
|
{
|
||||||
|
json_scan_start(je, i_cs, str, end);
|
||||||
|
p->last_step= p->steps - 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int json_get_path_next(json_engine_t *je, json_path_t *p)
|
||||||
|
{
|
||||||
|
if (p->last_step < p->steps)
|
||||||
|
{
|
||||||
|
if (json_read_value(je))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
p->last_step= p->steps;
|
||||||
|
p->steps[0].type= JSON_PATH_ARRAY_WILD;
|
||||||
|
p->steps[0].n_item= 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (json_value_scalar(je))
|
||||||
|
{
|
||||||
|
if (p->last_step->type & JSON_PATH_ARRAY)
|
||||||
|
p->last_step->n_item++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p->last_step++;
|
||||||
|
p->last_step->type= (enum json_path_step_types) je->value_type;
|
||||||
|
p->last_step->n_item= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json_scan_next(je))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
switch (je->state)
|
||||||
|
{
|
||||||
|
case JST_KEY:
|
||||||
|
p->last_step->key= je->s.c_str;
|
||||||
|
while (json_read_keyname_chr(je) == 0)
|
||||||
|
p->last_step->key_end= je->s.c_str;
|
||||||
|
if (je->s.error)
|
||||||
|
return 1;
|
||||||
|
/* Now we have je.state == JST_VALUE, so let's handle it. */
|
||||||
|
|
||||||
|
case JST_VALUE:
|
||||||
|
if (json_read_value(je))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
case JST_OBJ_END:
|
||||||
|
case JST_ARRAY_END:
|
||||||
|
p->last_step--;
|
||||||
|
if (p->last_step->type & JSON_PATH_ARRAY)
|
||||||
|
p->last_step->n_item++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (json_scan_next(je) == 0);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int json_path_compare(const json_path_t *a, const json_path_t *b)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
while (sa <= a->last_step)
|
||||||
|
{
|
||||||
|
if (sb > b->last_step)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
if (!((sa->type & sb->type) & JSON_PATH_KEY_OR_ARRAY))
|
||||||
|
goto step_failed;
|
||||||
|
|
||||||
|
if (sa->type & JSON_PATH_ARRAY)
|
||||||
|
{
|
||||||
|
if (!(sa->type & JSON_PATH_WILD) && sa->n_item != sb->n_item)
|
||||||
|
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))
|
||||||
|
goto step_failed;
|
||||||
|
}
|
||||||
|
sb++;
|
||||||
|
sa++;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
step_failed:
|
||||||
|
if (!(sa->type & JSON_PATH_DOUBLE_WILD))
|
||||||
|
return -1;
|
||||||
|
sb++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb <= b->last_step;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user