summaryrefslogtreecommitdiff
path: root/strings
diff options
context:
space:
mode:
authorAlexey Botchkov <holyfoot@askmonty.org>2016-12-09 12:26:32 +0400
committerAlexey Botchkov <holyfoot@askmonty.org>2016-12-09 12:26:32 +0400
commit04aa31c70bf90d6a89833791547a082d82cb2365 (patch)
treea0b155cb5b2828c87786298778768c41744fe17c /strings
parent0f7864a9b8ac04ea3e3b8e0637cc3a59520d7dfa (diff)
downloadmariadb-git-04aa31c70bf90d6a89833791547a082d82cb2365.tar.gz
MDEV-11469 JSON_SEARCH returns incorrect results.
Support for '**' in json path expressions added.
Diffstat (limited to 'strings')
-rw-r--r--strings/json_lib.c68
1 files changed, 42 insertions, 26 deletions
diff --git a/strings/json_lib.c b/strings/json_lib.c
index 976fab7e7f6..a9498070195 100644
--- a/strings/json_lib.c
+++ b/strings/json_lib.c
@@ -1006,6 +1006,8 @@ enum json_path_states {
PS_KEY, /* Key. */
PS_KNM, /* Parse key name. */
PS_KWD, /* Key wildcard. */
+ PS_AST, /* Asterisk. */
+ PS_DWD, /* Double wildcard. */
N_PATH_STATES, /* Below are states that aren't in the transitions table. */
PS_SCT, /* Parse the 'strict' keyword. */
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,
JE_SYN, PS_LAX, JE_SYN, PS_GO, JE_SYN, JE_SYN, JE_NOT_JSON_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_BAD_CHR},
/* 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,
PS_KNM, PS_KNM, PS_KNM, PS_KNM, JE_SYN, PS_KNM, JE_NOT_JSON_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,
JE_BAD_CHR},
/* 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_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}
};
@@ -1063,11 +1071,11 @@ int json_path_setup(json_path_t *p,
CHARSET_INFO *i_cs, const uchar *str, const uchar *end)
{
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);
- p->steps[0].type= JSON_PATH_ARRAY;
- p->steps[0].wild= 1;
+ p->steps[0].type= JSON_PATH_ARRAY_WILD;
p->last_step= p->steps;
p->mode_strict= FALSE;
@@ -1096,8 +1104,11 @@ int json_path_setup(json_path_t *p,
p->mode_strict= TRUE;
state= PS_LAX;
continue;
+ case PS_KWD:
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;
case PS_INT:
p->last_step->n_item*= 10;
@@ -1109,8 +1120,10 @@ int json_path_setup(json_path_t *p,
/* Note no 'continue' here. */
case PS_KEY:
p->last_step++;
- p->last_step->type= JSON_PATH_KEY;
- p->last_step->wild= 0;
+ if (p->last_step - p->steps >= JSON_DEPTH_LIMIT)
+ 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;
continue;
case PS_EAR:
@@ -1119,13 +1132,12 @@ int json_path_setup(json_path_t *p,
/* Note no 'continue' here. */
case PS_AR:
p->last_step++;
- p->last_step->type= JSON_PATH_ARRAY;
- p->last_step->wild= 0;
+ if (p->last_step - p->steps >= JSON_DEPTH_LIMIT)
+ 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;
continue;
- case PS_KWD:
- p->last_step->wild= 1;
- continue;
case PS_ESC:
if (json_handle_esc(&p->s))
return 1;
@@ -1133,11 +1145,14 @@ int json_path_setup(json_path_t *p,
case PS_KOK:
p->last_step->key_end= p->s.c_str - c_len;
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);
- 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)++;
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)--;
return json_skip_level(je);
@@ -1240,8 +1256,8 @@ int json_find_path(json_engine_t *je,
switch (je->state)
{
case JST_KEY:
- DBUG_ASSERT(cur_step->type == JSON_PATH_KEY);
- if (!cur_step->wild)
+ DBUG_ASSERT(cur_step->type & JSON_PATH_KEY);
+ if (!(cur_step->type & JSON_PATH_WILD))
{
json_string_set_str(&key_name, cur_step->key, cur_step->key_end);
if (!json_key_matches(je, &key_name))
@@ -1256,8 +1272,8 @@ int json_find_path(json_engine_t *je,
goto exit;
break;
case JST_VALUE:
- DBUG_ASSERT(cur_step->type == JSON_PATH_ARRAY);
- if (cur_step->wild ||
+ DBUG_ASSERT(cur_step->type & JSON_PATH_ARRAY);
+ if (cur_step->type & JSON_PATH_WILD ||
cur_step->n_item == array_counters[cur_step - p->steps])
{
/* 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;
if (state->path_depths[p_c] <
state->cur_depth /* Path already failed. */ ||
- (cur_step= state->paths[p_c].steps + state->cur_depth)->type !=
- JSON_PATH_KEY)
+ !((cur_step= state->paths[p_c].steps + state->cur_depth)->type &
+ JSON_PATH_KEY))
continue;
- if (!cur_step->wild)
+ if (!(cur_step->type & JSON_PATH_WILD))
{
json_string_t key_name;
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;
if (state->path_depths[p_c]< state->cur_depth /* Path already failed. */ ||
- (cur_step= state->paths[p_c].steps + state->cur_depth)->type !=
- JSON_PATH_ARRAY)
+ !((cur_step= state->paths[p_c].steps + state->cur_depth)->type &
+ JSON_PATH_ARRAY))
continue;
- if (cur_step->wild ||
+ if (cur_step->type & JSON_PATH_WILD ||
cur_step->n_item == state->array_counters[state->cur_depth])
{
/* 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)
/* Path already failed. */
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)
state->path_depths[p_c]++;
}