mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-11469 JSON_SEARCH returns incorrect results.
Support for '**' in json path expressions added.
This commit is contained in:
@@ -69,17 +69,26 @@ int json_read_string_const_chr(json_string_t *js);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Path step types - actually bitmasks to let '&' or '|' operations. */
|
||||||
enum json_path_step_types
|
enum json_path_step_types
|
||||||
{
|
{
|
||||||
JSON_PATH_KEY=0,
|
JSON_PATH_KEY_NULL=0,
|
||||||
JSON_PATH_ARRAY=1
|
JSON_PATH_KEY=1, /* Must be equal to JSON_VALUE_OBJECT. */
|
||||||
|
JSON_PATH_ARRAY=2, /* Must be equal to JSON_VALUE_ARRAY. */
|
||||||
|
JSON_PATH_KEY_OR_ARRAY=3,
|
||||||
|
JSON_PATH_WILD=4, /* Step like .* or [*] */
|
||||||
|
JSON_PATH_DOUBLE_WILD=8, /* Step like **.k or **[1] */
|
||||||
|
JSON_PATH_KEY_WILD= 1+4,
|
||||||
|
JSON_PATH_KEY_DOUBLEWILD= 1+8,
|
||||||
|
JSON_PATH_ARRAY_WILD= 2+4,
|
||||||
|
JSON_PATH_ARRAY_DOUBLEWILD= 2+8
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef struct st_json_path_step_t
|
typedef struct st_json_path_step_t
|
||||||
{
|
{
|
||||||
enum json_path_step_types type; /* The type of the step - KEY or ARRAY */
|
enum json_path_step_types type; /* The type of the step - */
|
||||||
int wild; /* If the step is a wildcard */
|
/* see json_path_step_types */
|
||||||
const uchar *key; /* Pointer to the beginning of the key. */
|
const uchar *key; /* Pointer to the beginning of the key. */
|
||||||
const uchar *key_end; /* Pointer to the end of the key. */
|
const uchar *key_end; /* Pointer to the end of the key. */
|
||||||
uint n_item; /* Item number in an array. No meaning for the key step. */
|
uint n_item; /* Item number in an array. No meaning for the key step. */
|
||||||
@@ -162,8 +171,8 @@ enum json_states {
|
|||||||
|
|
||||||
enum json_value_types
|
enum json_value_types
|
||||||
{
|
{
|
||||||
JSON_VALUE_OBJECT=0,
|
JSON_VALUE_OBJECT=1,
|
||||||
JSON_VALUE_ARRAY=1,
|
JSON_VALUE_ARRAY=2,
|
||||||
JSON_VALUE_STRING,
|
JSON_VALUE_STRING,
|
||||||
JSON_VALUE_NUMBER,
|
JSON_VALUE_NUMBER,
|
||||||
JSON_VALUE_TRUE,
|
JSON_VALUE_TRUE,
|
||||||
|
@@ -40,6 +40,9 @@ NULL
|
|||||||
select json_query('{"key1":123, "key1": [1,2,3]}', '$.key1');
|
select json_query('{"key1":123, "key1": [1,2,3]}', '$.key1');
|
||||||
json_query('{"key1":123, "key1": [1,2,3]}', '$.key1')
|
json_query('{"key1":123, "key1": [1,2,3]}', '$.key1')
|
||||||
[1,2,3]
|
[1,2,3]
|
||||||
|
select json_query('{"key1":123, "key1": [1,2,3]}', concat('$', repeat('.k', 1000)));
|
||||||
|
json_query('{"key1":123, "key1": [1,2,3]}', concat('$', repeat('.k', 1000)))
|
||||||
|
NULL
|
||||||
select json_array();
|
select json_array();
|
||||||
json_array()
|
json_array()
|
||||||
[]
|
[]
|
||||||
@@ -289,6 +292,9 @@ json_search(@j, 'all', '10', NULL, '$[*]')
|
|||||||
select json_search(@j, 'all', '10', NULL, '$[*][0].k');
|
select json_search(@j, 'all', '10', NULL, '$[*][0].k');
|
||||||
json_search(@j, 'all', '10', NULL, '$[*][0].k')
|
json_search(@j, 'all', '10', NULL, '$[*][0].k')
|
||||||
"$[1][0].k"
|
"$[1][0].k"
|
||||||
|
select json_search(@j, 'all', '10', NULL, '$**.k');
|
||||||
|
json_search(@j, 'all', '10', NULL, '$**.k')
|
||||||
|
"$[1][0].k"
|
||||||
create table t1( json_col text );
|
create table t1( json_col text );
|
||||||
insert into t1 values
|
insert into t1 values
|
||||||
('{ "a": "foobar" }'),
|
('{ "a": "foobar" }'),
|
||||||
|
@@ -14,6 +14,7 @@ select json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key2');
|
|||||||
select json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key1');
|
select json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key1');
|
||||||
select json_query('{"key1": 1}', '$.key1');
|
select json_query('{"key1": 1}', '$.key1');
|
||||||
select json_query('{"key1":123, "key1": [1,2,3]}', '$.key1');
|
select json_query('{"key1":123, "key1": [1,2,3]}', '$.key1');
|
||||||
|
select json_query('{"key1":123, "key1": [1,2,3]}', concat('$', repeat('.k', 1000)));
|
||||||
|
|
||||||
select json_array();
|
select json_array();
|
||||||
select json_array(1);
|
select json_array(1);
|
||||||
@@ -120,6 +121,7 @@ select json_search(@j, 'all', 'abc', NULL, '$');
|
|||||||
select json_search(@j, 'all', '10', NULL, '$');
|
select json_search(@j, 'all', '10', NULL, '$');
|
||||||
select json_search(@j, 'all', '10', NULL, '$[*]');
|
select json_search(@j, 'all', '10', NULL, '$[*]');
|
||||||
select json_search(@j, 'all', '10', NULL, '$[*][0].k');
|
select json_search(@j, 'all', '10', NULL, '$[*][0].k');
|
||||||
|
select json_search(@j, 'all', '10', NULL, '$**.k');
|
||||||
create table t1( json_col text );
|
create table t1( json_col text );
|
||||||
insert into t1 values
|
insert into t1 values
|
||||||
('{ "a": "foobar" }'),
|
('{ "a": "foobar" }'),
|
||||||
|
@@ -1506,7 +1506,7 @@ String *Item_func_json_insert::val_str(String *str)
|
|||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
lp= c_path->p.last_step+1;
|
lp= c_path->p.last_step+1;
|
||||||
if (lp->type == JSON_PATH_ARRAY)
|
if (lp->type & JSON_PATH_ARRAY)
|
||||||
{
|
{
|
||||||
uint n_item= 0;
|
uint n_item= 0;
|
||||||
|
|
||||||
@@ -1722,7 +1722,7 @@ String *Item_func_json_remove::val_str(String *str)
|
|||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
lp= c_path->p.last_step+1;
|
lp= c_path->p.last_step+1;
|
||||||
if (lp->type == JSON_PATH_ARRAY)
|
if (lp->type & JSON_PATH_ARRAY)
|
||||||
{
|
{
|
||||||
if (je.value_type != JSON_VALUE_ARRAY)
|
if (je.value_type != JSON_VALUE_ARRAY)
|
||||||
continue;
|
continue;
|
||||||
@@ -1982,7 +1982,7 @@ static int append_json_path(String *str, const json_path_t *p)
|
|||||||
|
|
||||||
for (c= p->steps+1; c <= p->last_step; c++)
|
for (c= p->steps+1; c <= p->last_step; c++)
|
||||||
{
|
{
|
||||||
if (c->type == JSON_PATH_KEY)
|
if (c->type & JSON_PATH_KEY)
|
||||||
{
|
{
|
||||||
if (str->append(".", 1) ||
|
if (str->append(".", 1) ||
|
||||||
append_simple(str, c->key, c->key_end-c->key))
|
append_simple(str, c->key, c->key_end-c->key))
|
||||||
@@ -2002,6 +2002,7 @@ static int append_json_path(String *str, const json_path_t *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef DUMMY
|
||||||
static int json_path_compare(const json_path_t *a, const json_path_t *b)
|
static int json_path_compare(const json_path_t *a, const json_path_t *b)
|
||||||
{
|
{
|
||||||
uint i, a_len= a->last_step - a->steps, b_len= b->last_step - b->steps;
|
uint i, a_len= a->last_step - a->steps, b_len= b->last_step - b->steps;
|
||||||
@@ -2014,17 +2015,17 @@ static int json_path_compare(const json_path_t *a, const json_path_t *b)
|
|||||||
const json_path_step_t *sa= a->steps + i;
|
const json_path_step_t *sa= a->steps + i;
|
||||||
const json_path_step_t *sb= b->steps + i;
|
const json_path_step_t *sb= b->steps + i;
|
||||||
|
|
||||||
if (sa->type != sb->type)
|
if (!((sa->type & sb->type) & JSON_PATH_KEY_OR_ARRAY))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (sa->type == JSON_PATH_ARRAY)
|
if (sa->type & JSON_PATH_ARRAY)
|
||||||
{
|
{
|
||||||
if (!sa->wild && sa->n_item != sb->n_item)
|
if (!(sa->type & JSON_PATH_WILD) && sa->n_item != sb->n_item)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else /* JSON_PATH_KEY */
|
else /* JSON_PATH_KEY */
|
||||||
{
|
{
|
||||||
if (!sa->wild &&
|
if (!(sa->type & JSON_PATH_WILD) &&
|
||||||
(sa->key_end - sa->key != sb->key_end - sb->key ||
|
(sa->key_end - sa->key != sb->key_end - sb->key ||
|
||||||
memcmp(sa->key, sb->key, sa->key_end - sa->key) != 0))
|
memcmp(sa->key, sb->key, sa->key_end - sa->key) != 0))
|
||||||
return -1;
|
return -1;
|
||||||
@@ -2033,6 +2034,49 @@ static int json_path_compare(const json_path_t *a, const json_path_t *b)
|
|||||||
|
|
||||||
return b_len > a_len;
|
return b_len > a_len;
|
||||||
}
|
}
|
||||||
|
#endif /*DUMMY*/
|
||||||
|
|
||||||
|
|
||||||
|
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,
|
static bool path_ok(const json_path_with_flags *paths_list, int n_paths,
|
||||||
@@ -2088,8 +2132,7 @@ String *Item_func_json_search::val_str(String *str)
|
|||||||
(const uchar *) js->ptr() + js->length());
|
(const uchar *) js->ptr() + js->length());
|
||||||
|
|
||||||
p.last_step= p.steps;
|
p.last_step= p.steps;
|
||||||
p.steps[0].wild= 0;
|
p.steps[0].type= JSON_PATH_ARRAY_WILD;
|
||||||
p.steps[0].type= JSON_PATH_ARRAY;
|
|
||||||
p.steps[0].n_item= 0;
|
p.steps[0].n_item= 0;
|
||||||
|
|
||||||
do
|
do
|
||||||
@@ -2133,27 +2176,21 @@ String *Item_func_json_search::val_str(String *str)
|
|||||||
if (mode_one)
|
if (mode_one)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
if (p.last_step->type == JSON_PATH_ARRAY)
|
if (p.last_step->type & JSON_PATH_ARRAY)
|
||||||
p.last_step->n_item++;
|
p.last_step->n_item++;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p.last_step++;
|
p.last_step++;
|
||||||
if (je.value_type == JSON_VALUE_ARRAY)
|
p.last_step->type= (enum json_path_step_types) je.value_type;
|
||||||
{
|
p.last_step->n_item= 0;
|
||||||
p.last_step->type= JSON_PATH_ARRAY;
|
|
||||||
p.last_step->n_item= 0;
|
|
||||||
}
|
|
||||||
else /*JSON_VALUE_OBJECT*/
|
|
||||||
p.last_step->type= JSON_PATH_KEY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case JST_OBJ_END:
|
case JST_OBJ_END:
|
||||||
case JST_ARRAY_END:
|
case JST_ARRAY_END:
|
||||||
p.last_step--;
|
p.last_step--;
|
||||||
if (p.last_step->type == JSON_PATH_ARRAY)
|
if (p.last_step->type & JSON_PATH_ARRAY)
|
||||||
p.last_step->n_item++;
|
p.last_step->n_item++;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@@ -1006,6 +1006,8 @@ enum json_path_states {
|
|||||||
PS_KEY, /* Key. */
|
PS_KEY, /* Key. */
|
||||||
PS_KNM, /* Parse key name. */
|
PS_KNM, /* Parse key name. */
|
||||||
PS_KWD, /* Key wildcard. */
|
PS_KWD, /* Key wildcard. */
|
||||||
|
PS_AST, /* Asterisk. */
|
||||||
|
PS_DWD, /* Double wildcard. */
|
||||||
N_PATH_STATES, /* Below are states that aren't in the transitions table. */
|
N_PATH_STATES, /* Below are states that aren't in the transitions table. */
|
||||||
PS_SCT, /* Parse the 'strict' keyword. */
|
PS_SCT, /* Parse the 'strict' keyword. */
|
||||||
PS_EKY, /* '.' after the keyname so next step is the key. */
|
PS_EKY, /* '.' after the keyname so next step is the key. */
|
||||||
@@ -1029,7 +1031,7 @@ static int json_path_transitions[N_PATH_STATES][N_PATH_CLASSES]=
|
|||||||
/* LAX */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN,
|
/* LAX */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN,
|
||||||
JE_SYN, PS_LAX, JE_SYN, PS_GO, JE_SYN, JE_SYN, JE_NOT_JSON_CHR,
|
JE_SYN, PS_LAX, JE_SYN, PS_GO, JE_SYN, JE_SYN, JE_NOT_JSON_CHR,
|
||||||
JE_BAD_CHR},
|
JE_BAD_CHR},
|
||||||
/* PT */ { PS_OK, JE_SYN, JE_SYN, PS_AR, JE_SYN, PS_KEY, JE_SYN, JE_SYN,
|
/* PT */ { PS_OK, JE_SYN, PS_AST, PS_AR, JE_SYN, PS_KEY, JE_SYN, JE_SYN,
|
||||||
JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_NOT_JSON_CHR,
|
JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_NOT_JSON_CHR,
|
||||||
JE_BAD_CHR},
|
JE_BAD_CHR},
|
||||||
/* AR */ { JE_EOS, JE_SYN, PS_AWD, JE_SYN, PS_PT, JE_SYN, PS_Z,
|
/* AR */ { JE_EOS, JE_SYN, PS_AWD, JE_SYN, PS_PT, JE_SYN, PS_Z,
|
||||||
@@ -1050,11 +1052,17 @@ static int json_path_transitions[N_PATH_STATES][N_PATH_CLASSES]=
|
|||||||
/* KEY */ { JE_EOS, PS_KNM, PS_KWD, JE_SYN, PS_KNM, JE_SYN, PS_KNM,
|
/* KEY */ { JE_EOS, PS_KNM, PS_KWD, JE_SYN, PS_KNM, JE_SYN, PS_KNM,
|
||||||
PS_KNM, PS_KNM, PS_KNM, PS_KNM, JE_SYN, PS_KNM, JE_NOT_JSON_CHR,
|
PS_KNM, PS_KNM, PS_KNM, PS_KNM, JE_SYN, PS_KNM, JE_NOT_JSON_CHR,
|
||||||
JE_BAD_CHR},
|
JE_BAD_CHR},
|
||||||
/* KNM */ { PS_KOK, PS_KNM, PS_KNM, PS_EAR, PS_KNM, PS_EKY, PS_KNM,
|
/* KNM */ { PS_KOK, PS_KNM, PS_AST, PS_EAR, PS_KNM, PS_EKY, PS_KNM,
|
||||||
PS_KNM, PS_KNM, PS_KNM, PS_KNM, PS_ESC, PS_KNM, JE_NOT_JSON_CHR,
|
PS_KNM, PS_KNM, PS_KNM, PS_KNM, PS_ESC, PS_KNM, JE_NOT_JSON_CHR,
|
||||||
JE_BAD_CHR},
|
JE_BAD_CHR},
|
||||||
/* KWD */ { PS_OK, JE_SYN, JE_SYN, PS_AR, JE_SYN, PS_EKY, JE_SYN,
|
/* KWD */ { PS_OK, JE_SYN, JE_SYN, PS_AR, JE_SYN, PS_EKY, JE_SYN,
|
||||||
JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_NOT_JSON_CHR,
|
JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_NOT_JSON_CHR,
|
||||||
|
JE_BAD_CHR},
|
||||||
|
/* AST */ { JE_SYN, JE_SYN, PS_DWD, JE_SYN, JE_SYN, JE_SYN, JE_SYN,
|
||||||
|
JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_NOT_JSON_CHR,
|
||||||
|
JE_BAD_CHR},
|
||||||
|
/* DWD */ { JE_SYN, JE_SYN, PS_AST, PS_AR, JE_SYN, PS_KEY, JE_SYN, JE_SYN,
|
||||||
|
JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_NOT_JSON_CHR,
|
||||||
JE_BAD_CHR}
|
JE_BAD_CHR}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1063,11 +1071,11 @@ int json_path_setup(json_path_t *p,
|
|||||||
CHARSET_INFO *i_cs, const uchar *str, const uchar *end)
|
CHARSET_INFO *i_cs, const uchar *str, const uchar *end)
|
||||||
{
|
{
|
||||||
int c_len, t_next, state= PS_GO;
|
int c_len, t_next, state= PS_GO;
|
||||||
|
enum json_path_step_types double_wildcard= JSON_PATH_KEY_NULL;
|
||||||
|
|
||||||
json_string_setup(&p->s, i_cs, str, end);
|
json_string_setup(&p->s, i_cs, str, end);
|
||||||
|
|
||||||
p->steps[0].type= JSON_PATH_ARRAY;
|
p->steps[0].type= JSON_PATH_ARRAY_WILD;
|
||||||
p->steps[0].wild= 1;
|
|
||||||
p->last_step= p->steps;
|
p->last_step= p->steps;
|
||||||
p->mode_strict= FALSE;
|
p->mode_strict= FALSE;
|
||||||
|
|
||||||
@@ -1096,8 +1104,11 @@ int json_path_setup(json_path_t *p,
|
|||||||
p->mode_strict= TRUE;
|
p->mode_strict= TRUE;
|
||||||
state= PS_LAX;
|
state= PS_LAX;
|
||||||
continue;
|
continue;
|
||||||
|
case PS_KWD:
|
||||||
case PS_AWD:
|
case PS_AWD:
|
||||||
p->last_step->wild= 1;
|
if (p->last_step->type & JSON_PATH_DOUBLE_WILD)
|
||||||
|
return p->s.error= JE_SYN;
|
||||||
|
p->last_step->type|= JSON_PATH_WILD;
|
||||||
continue;
|
continue;
|
||||||
case PS_INT:
|
case PS_INT:
|
||||||
p->last_step->n_item*= 10;
|
p->last_step->n_item*= 10;
|
||||||
@@ -1109,8 +1120,10 @@ int json_path_setup(json_path_t *p,
|
|||||||
/* Note no 'continue' here. */
|
/* Note no 'continue' here. */
|
||||||
case PS_KEY:
|
case PS_KEY:
|
||||||
p->last_step++;
|
p->last_step++;
|
||||||
p->last_step->type= JSON_PATH_KEY;
|
if (p->last_step - p->steps >= JSON_DEPTH_LIMIT)
|
||||||
p->last_step->wild= 0;
|
return p->s.error= JE_DEPTH;
|
||||||
|
p->last_step->type= JSON_PATH_KEY | double_wildcard;
|
||||||
|
double_wildcard= JSON_PATH_KEY_NULL;
|
||||||
p->last_step->key= p->s.c_str;
|
p->last_step->key= p->s.c_str;
|
||||||
continue;
|
continue;
|
||||||
case PS_EAR:
|
case PS_EAR:
|
||||||
@@ -1119,13 +1132,12 @@ int json_path_setup(json_path_t *p,
|
|||||||
/* Note no 'continue' here. */
|
/* Note no 'continue' here. */
|
||||||
case PS_AR:
|
case PS_AR:
|
||||||
p->last_step++;
|
p->last_step++;
|
||||||
p->last_step->type= JSON_PATH_ARRAY;
|
if (p->last_step - p->steps >= JSON_DEPTH_LIMIT)
|
||||||
p->last_step->wild= 0;
|
return p->s.error= JE_DEPTH;
|
||||||
|
p->last_step->type= JSON_PATH_ARRAY | double_wildcard;
|
||||||
|
double_wildcard= JSON_PATH_KEY_NULL;
|
||||||
p->last_step->n_item= 0;
|
p->last_step->n_item= 0;
|
||||||
continue;
|
continue;
|
||||||
case PS_KWD:
|
|
||||||
p->last_step->wild= 1;
|
|
||||||
continue;
|
|
||||||
case PS_ESC:
|
case PS_ESC:
|
||||||
if (json_handle_esc(&p->s))
|
if (json_handle_esc(&p->s))
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1133,11 +1145,14 @@ int json_path_setup(json_path_t *p,
|
|||||||
case PS_KOK:
|
case PS_KOK:
|
||||||
p->last_step->key_end= p->s.c_str - c_len;
|
p->last_step->key_end= p->s.c_str - c_len;
|
||||||
state= PS_OK;
|
state= PS_OK;
|
||||||
break;
|
break; /* 'break' as the loop supposed to end after that. */
|
||||||
|
case PS_DWD:
|
||||||
|
double_wildcard= JSON_PATH_DOUBLE_WILD;
|
||||||
|
continue;
|
||||||
};
|
};
|
||||||
} while (state != PS_OK);
|
} while (state != PS_OK);
|
||||||
|
|
||||||
return 0;
|
return double_wildcard ? (p->s.error= JE_SYN) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1196,7 +1211,8 @@ static int handle_match(json_engine_t *je, json_path_t *p,
|
|||||||
(*p_cur_step)++;
|
(*p_cur_step)++;
|
||||||
array_counters[*p_cur_step - p->steps]= 0;
|
array_counters[*p_cur_step - p->steps]= 0;
|
||||||
|
|
||||||
if ((int) je->value_type != (int) (*p_cur_step)->type)
|
if ((int) je->value_type !=
|
||||||
|
(int) ((*p_cur_step)->type & JSON_PATH_KEY_OR_ARRAY))
|
||||||
{
|
{
|
||||||
(*p_cur_step)--;
|
(*p_cur_step)--;
|
||||||
return json_skip_level(je);
|
return json_skip_level(je);
|
||||||
@@ -1240,8 +1256,8 @@ int json_find_path(json_engine_t *je,
|
|||||||
switch (je->state)
|
switch (je->state)
|
||||||
{
|
{
|
||||||
case JST_KEY:
|
case JST_KEY:
|
||||||
DBUG_ASSERT(cur_step->type == JSON_PATH_KEY);
|
DBUG_ASSERT(cur_step->type & JSON_PATH_KEY);
|
||||||
if (!cur_step->wild)
|
if (!(cur_step->type & JSON_PATH_WILD))
|
||||||
{
|
{
|
||||||
json_string_set_str(&key_name, cur_step->key, cur_step->key_end);
|
json_string_set_str(&key_name, cur_step->key, cur_step->key_end);
|
||||||
if (!json_key_matches(je, &key_name))
|
if (!json_key_matches(je, &key_name))
|
||||||
@@ -1256,8 +1272,8 @@ int json_find_path(json_engine_t *je,
|
|||||||
goto exit;
|
goto exit;
|
||||||
break;
|
break;
|
||||||
case JST_VALUE:
|
case JST_VALUE:
|
||||||
DBUG_ASSERT(cur_step->type == JSON_PATH_ARRAY);
|
DBUG_ASSERT(cur_step->type & JSON_PATH_ARRAY);
|
||||||
if (cur_step->wild ||
|
if (cur_step->type & JSON_PATH_WILD ||
|
||||||
cur_step->n_item == array_counters[cur_step - p->steps])
|
cur_step->n_item == array_counters[cur_step - p->steps])
|
||||||
{
|
{
|
||||||
/* Array item matches. */
|
/* Array item matches. */
|
||||||
@@ -1316,11 +1332,11 @@ int json_find_paths_next(json_engine_t *je, json_find_paths_t *state)
|
|||||||
json_path_step_t *cur_step;
|
json_path_step_t *cur_step;
|
||||||
if (state->path_depths[p_c] <
|
if (state->path_depths[p_c] <
|
||||||
state->cur_depth /* Path already failed. */ ||
|
state->cur_depth /* Path already failed. */ ||
|
||||||
(cur_step= state->paths[p_c].steps + state->cur_depth)->type !=
|
!((cur_step= state->paths[p_c].steps + state->cur_depth)->type &
|
||||||
JSON_PATH_KEY)
|
JSON_PATH_KEY))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!cur_step->wild)
|
if (!(cur_step->type & JSON_PATH_WILD))
|
||||||
{
|
{
|
||||||
json_string_t key_name;
|
json_string_t key_name;
|
||||||
json_string_setup(&key_name, state->paths[p_c].s.cs,
|
json_string_setup(&key_name, state->paths[p_c].s.cs,
|
||||||
@@ -1354,10 +1370,10 @@ int json_find_paths_next(json_engine_t *je, json_find_paths_t *state)
|
|||||||
{
|
{
|
||||||
json_path_step_t *cur_step;
|
json_path_step_t *cur_step;
|
||||||
if (state->path_depths[p_c]< state->cur_depth /* Path already failed. */ ||
|
if (state->path_depths[p_c]< state->cur_depth /* Path already failed. */ ||
|
||||||
(cur_step= state->paths[p_c].steps + state->cur_depth)->type !=
|
!((cur_step= state->paths[p_c].steps + state->cur_depth)->type &
|
||||||
JSON_PATH_ARRAY)
|
JSON_PATH_ARRAY))
|
||||||
continue;
|
continue;
|
||||||
if (cur_step->wild ||
|
if (cur_step->type & JSON_PATH_WILD ||
|
||||||
cur_step->n_item == state->array_counters[state->cur_depth])
|
cur_step->n_item == state->array_counters[state->cur_depth])
|
||||||
{
|
{
|
||||||
/* Array item matches. */
|
/* Array item matches. */
|
||||||
@@ -1386,7 +1402,7 @@ int json_find_paths_next(json_engine_t *je, json_find_paths_t *state)
|
|||||||
if (state->path_depths[p_c] < state->cur_depth)
|
if (state->path_depths[p_c] < state->cur_depth)
|
||||||
/* Path already failed. */
|
/* Path already failed. */
|
||||||
continue;
|
continue;
|
||||||
if (state->paths[p_c].steps[state->cur_depth].type ==
|
if (state->paths[p_c].steps[state->cur_depth].type &
|
||||||
(je->state == JST_OBJ_START) ? JSON_PATH_KEY : JSON_PATH_ARRAY)
|
(je->state == JST_OBJ_START) ? JSON_PATH_KEY : JSON_PATH_ARRAY)
|
||||||
state->path_depths[p_c]++;
|
state->path_depths[p_c]++;
|
||||||
}
|
}
|
||||||
|
@@ -117,11 +117,11 @@ test_path_parsing()
|
|||||||
if (json_path_setup(&p, ci, s_e(p0)))
|
if (json_path_setup(&p, ci, s_e(p0)))
|
||||||
return;
|
return;
|
||||||
ok(p.last_step - p.steps == 4 &&
|
ok(p.last_step - p.steps == 4 &&
|
||||||
p.steps[0].type == JSON_PATH_ARRAY && p.steps[0].wild == 1 &&
|
p.steps[0].type == JSON_PATH_ARRAY_WILD &&
|
||||||
p.steps[1].type == JSON_PATH_KEY && p.steps[1].wild == 0 &&
|
p.steps[1].type == JSON_PATH_KEY &&
|
||||||
p.steps[2].type == JSON_PATH_ARRAY && p.steps[2].n_item == 12 &&
|
p.steps[2].type == JSON_PATH_ARRAY && p.steps[2].n_item == 12 &&
|
||||||
p.steps[3].type == JSON_PATH_KEY && p.steps[3].wild == 1 &&
|
p.steps[3].type == JSON_PATH_KEY_WILD &&
|
||||||
p.steps[4].type == JSON_PATH_ARRAY && p.steps[4].wild == 1,
|
p.steps[4].type == JSON_PATH_ARRAY_WILD,
|
||||||
"path");
|
"path");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user