Commit c781cefd authored by Rucha Deodhar's avatar Rucha Deodhar

MDEV-27911: Implement range notation for json path

Range can be thought about in similar manner as wildcard (*) where
more than one elements are processed. To implement range notation, extended
json parser to parse the 'to' keyword and added JSON_PATH_ARRAY_RANGE for
path type. If there is 'to' keyword then use JSON_PATH_ARRAY range for
path type along with existing type.
This new integer to store the end index of range is n_item_end.
When there is 'to' keyword, store the integer in n_item_end else store in
n_item.
parent abe97121
...@@ -84,7 +84,8 @@ enum json_path_step_types ...@@ -84,7 +84,8 @@ enum json_path_step_types
JSON_PATH_KEY_DOUBLEWILD= 1+8, JSON_PATH_KEY_DOUBLEWILD= 1+8,
JSON_PATH_ARRAY_WILD= 2+4, JSON_PATH_ARRAY_WILD= 2+4,
JSON_PATH_ARRAY_DOUBLEWILD= 2+8, JSON_PATH_ARRAY_DOUBLEWILD= 2+8,
JSON_PATH_NEGATIVE_INDEX= 16 JSON_PATH_NEGATIVE_INDEX= 16,
JSON_PATH_ARRAY_RANGE= 32
}; };
...@@ -95,6 +96,7 @@ typedef struct st_json_path_step_t ...@@ -95,6 +96,7 @@ typedef struct st_json_path_step_t
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. */
int n_item; /* Item number in an array. No meaning for the key step. */ int n_item; /* Item number in an array. No meaning for the key step. */
int n_item_end; /* Last index of the range. */
} json_path_step_t; } json_path_step_t;
......
...@@ -2029,5 +2029,194 @@ SELECT JSON_VALUE(@json,'$.x[0]'); ...@@ -2029,5 +2029,194 @@ SELECT JSON_VALUE(@json,'$.x[0]');
JSON_VALUE(@json,'$.x[0]') JSON_VALUE(@json,'$.x[0]')
0 0
# #
# MDEV-27911: Implement range notation for json path
#
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[15, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20],
21, 22
]';
SELECT JSON_EXISTS(@json, '$[3][3][-2 to last]');
JSON_EXISTS(@json, '$[3][3][-2 to last]')
1
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[15, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20],
21, 22
]';
SELECT JSON_SEARCH(@json, 'one', '12', NULL, '$[3][0 to 3]');
JSON_SEARCH(@json, 'one', '12', NULL, '$[3][0 to 3]')
NULL
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[12, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20]
]';
SELECT JSON_VALUE(@json, '$[0][1 to 2].key1');
JSON_VALUE(@json, '$[0][1 to 2].key1')
value1
SET @json='{
"A": [0,
[1, 2, 3],
[4, 5, 6],
"seven",
0.8,
true,
false,
"eleven",
[12, [13, 14], {"key1":"value1"},[15]],
true],
"B": {"C": 1},
"D": 2
}';
SELECT JSON_QUERY(@json, '$.A[-2][-3 to -1]');
JSON_QUERY(@json, '$.A[-2][-3 to -1]')
[13, 14]
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[15, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20],
21, 22
]';
SELECT JSON_EXTRACT(@json, '$[0 to 3][2]');
JSON_EXTRACT(@json, '$[0 to 3][2]')
[3, 6, [9, {"key2": 2}, 11], [14]]
SELECT JSON_EXTRACT(@json, '$[3][3][last-1 to last]');
JSON_EXTRACT(@json, '$[3][3][last-1 to last]')
["string1", [16, {"key1": [1, 2, 3, [4, 5, 6]]}, 18]]
SELECT JSON_EXTRACT(@json, '$[3][3][-2 to -1]');
JSON_EXTRACT(@json, '$[3][3][-2 to -1]')
["string1", [16, {"key1": [1, 2, 3, [4, 5, 6]]}, 18]]
# Checking errors
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[15, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20],
21, 22
]';
SELECT JSON_CONTAINS_PATH(@json,'one', '$[3][0 to 3]');
JSON_CONTAINS_PATH(@json,'one', '$[3][0 to 3]')
1
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[15, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20],
21, 22
]';
SELECT JSON_CONTAINS(@json, '$[3][0 to 3]');
JSON_CONTAINS(@json, '$[3][0 to 3]')
NULL
Warnings:
Warning 4038 Syntax error in JSON text in argument 2 to function 'json_contains' at position 1
SET @json='{
"A": [0,
[1, 2, 3],
[4, 5, 6],
"seven",
0.8,
true,
false,
"eleven",
[12, 13, {"key1":"value1"},[15]],
true],
"B": {"C": 1},
"D": 2
}';
SELECT JSON_ARRAY_INSERT(@json, '$.A[0 to last-1]', 5);
JSON_ARRAY_INSERT(@json, '$.A[0 to last-1]', 5)
NULL
Warnings:
Warning 4044 Wildcards or range in JSON path not allowed in argument 2 to function 'json_array_insert'
SET @json='{
"A": [0,
[1, 2, 3],
[4, 5, 6],
"seven",
0.8,
true,
false,
"eleven",
[12, 13, {"key1":"value1"},[15]],
true],
"B": {"C": 1},
"D": 2
}';
SELECT JSON_ARRAY_APPEND(@json, '$.A[*]', 7);
JSON_ARRAY_APPEND(@json, '$.A[*]', 7)
NULL
Warnings:
Warning 4044 Wildcards or range in JSON path not allowed in argument 2 to function 'json_array_append'
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[12, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20]
]';
SELECT JSON_SET(@json, '$[0][1 to 2].key1', 1);
JSON_SET(@json, '$[0][1 to 2].key1', 1)
NULL
Warnings:
Warning 4044 Wildcards or range in JSON path not allowed in argument 2 to function 'json_set'
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[15, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20],
21, 22
]';
SELECT JSON_REPLACE(@json, '$[1][last-2 to last]', 4);
JSON_REPLACE(@json, '$[1][last-2 to last]', 4)
NULL
Warnings:
Warning 4044 Wildcards or range in JSON path not allowed in argument 2 to function 'json_replace'
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[15, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20],
21, 22
]';
SELECT JSON_REMOVE(@json, '$[1][-6 to last-2]');
JSON_REMOVE(@json, '$[1][-6 to last-2]')
NULL
Warnings:
Warning 4044 Wildcards or range in JSON path not allowed in argument 2 to function 'json_remove'
SET @json='{
"A": [0,
[1, 2, 3],
[4, 5, 6],
"seven",
0.8,
true,
false,
"eleven",
[12, [13, 14], {"key1":"value1"},[15]],
true],
"B": {"C": 1},
"D": 2
}';
SELECT JSON_KEYS(@json, '$.A[8][1 to 3]');
JSON_KEYS(@json, '$.A[8][1 to 3]')
NULL
Warnings:
Warning 4044 Wildcards or range in JSON path not allowed in argument 2 to function 'json_keys'
#
# End of 10.9 Test # End of 10.9 Test
# #
...@@ -1316,6 +1316,167 @@ SELECT JSON_VALUE(@json,'$.x[last-0]'); ...@@ -1316,6 +1316,167 @@ SELECT JSON_VALUE(@json,'$.x[last-0]');
SELECT JSON_VALUE(@json,'$.x[-0]'); SELECT JSON_VALUE(@json,'$.x[-0]');
SELECT JSON_VALUE(@json,'$.x[0]'); SELECT JSON_VALUE(@json,'$.x[0]');
--echo #
--echo # MDEV-27911: Implement range notation for json path
--echo #
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[15, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20],
21, 22
]';
SELECT JSON_EXISTS(@json, '$[3][3][-2 to last]');
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[15, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20],
21, 22
]';
SELECT JSON_SEARCH(@json, 'one', '12', NULL, '$[3][0 to 3]');
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[12, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20]
]';
SELECT JSON_VALUE(@json, '$[0][1 to 2].key1');
SET @json='{
"A": [0,
[1, 2, 3],
[4, 5, 6],
"seven",
0.8,
true,
false,
"eleven",
[12, [13, 14], {"key1":"value1"},[15]],
true],
"B": {"C": 1},
"D": 2
}';
SELECT JSON_QUERY(@json, '$.A[-2][-3 to -1]');
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[15, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20],
21, 22
]';
SELECT JSON_EXTRACT(@json, '$[0 to 3][2]');
SELECT JSON_EXTRACT(@json, '$[3][3][last-1 to last]');
SELECT JSON_EXTRACT(@json, '$[3][3][-2 to -1]');
--echo # Checking errors
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[15, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20],
21, 22
]';
SELECT JSON_CONTAINS_PATH(@json,'one', '$[3][0 to 3]');
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[15, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20],
21, 22
]';
SELECT JSON_CONTAINS(@json, '$[3][0 to 3]');
SET @json='{
"A": [0,
[1, 2, 3],
[4, 5, 6],
"seven",
0.8,
true,
false,
"eleven",
[12, 13, {"key1":"value1"},[15]],
true],
"B": {"C": 1},
"D": 2
}';
SELECT JSON_ARRAY_INSERT(@json, '$.A[0 to last-1]', 5);
SET @json='{
"A": [0,
[1, 2, 3],
[4, 5, 6],
"seven",
0.8,
true,
false,
"eleven",
[12, 13, {"key1":"value1"},[15]],
true],
"B": {"C": 1},
"D": 2
}';
SELECT JSON_ARRAY_APPEND(@json, '$.A[*]', 7);
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[12, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20]
]';
SELECT JSON_SET(@json, '$[0][1 to 2].key1', 1);
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[15, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20],
21, 22
]';
SELECT JSON_REPLACE(@json, '$[1][last-2 to last]', 4);
SET @json= '[
[1, {"key1": "value1"}, 3],
[false, 5, 6],
[7, 8, [9, {"key2": 2}, 11]],
[15, 1.34, [14], ["string1", [16, {"key1":[1,2,3,[4,5,6]]}, 18]]],
[19, 20],
21, 22
]';
SELECT JSON_REMOVE(@json, '$[1][-6 to last-2]');
SET @json='{
"A": [0,
[1, 2, 3],
[4, 5, 6],
"seven",
0.8,
true,
false,
"eleven",
[12, [13, 14], {"key1":"value1"},[15]],
true],
"B": {"C": 1},
"D": 2
}';
SELECT JSON_KEYS(@json, '$.A[8][1 to 3]');
--echo # --echo #
--echo # End of 10.9 Test --echo # End of 10.9 Test
--echo # --echo #
...@@ -374,7 +374,8 @@ static int path_setup_nwc(json_path_t *p, CHARSET_INFO *i_cs, ...@@ -374,7 +374,8 @@ static int path_setup_nwc(json_path_t *p, CHARSET_INFO *i_cs,
{ {
if (!json_path_setup(p, i_cs, str, end)) if (!json_path_setup(p, i_cs, str, end))
{ {
if ((p->types_used & (JSON_PATH_WILD | JSON_PATH_DOUBLE_WILD)) == 0) if ((p->types_used & (JSON_PATH_WILD | JSON_PATH_DOUBLE_WILD |
JSON_PATH_ARRAY_RANGE)) == 0)
return 0; return 0;
p->s.error= NO_WILDCARD_ALLOWED; p->s.error= NO_WILDCARD_ALLOWED;
} }
...@@ -862,7 +863,8 @@ String *Item_func_json_extract::read_json(String *str, ...@@ -862,7 +863,8 @@ String *Item_func_json_extract::read_json(String *str,
} }
possible_multiple_values= arg_count > 2 || possible_multiple_values= arg_count > 2 ||
(paths[0].p.types_used & (JSON_PATH_WILD | JSON_PATH_DOUBLE_WILD)); (paths[0].p.types_used & (JSON_PATH_WILD | JSON_PATH_DOUBLE_WILD |
JSON_PATH_ARRAY_RANGE));
*type= possible_multiple_values ? JSON_VALUE_ARRAY : JSON_VALUE_NULL; *type= possible_multiple_values ? JSON_VALUE_ARRAY : JSON_VALUE_NULL;
......
...@@ -561,7 +561,8 @@ int ha_json_table::fill_column_values(THD *thd, uchar * buf, uchar *pos) ...@@ -561,7 +561,8 @@ int ha_json_table::fill_column_values(THD *thd, uchar * buf, uchar *pos)
more matches for it in json and report an error if so. more matches for it in json and report an error if so.
*/ */
if (jc->m_path.types_used & if (jc->m_path.types_used &
(JSON_PATH_WILD | JSON_PATH_DOUBLE_WILD) && (JSON_PATH_WILD | JSON_PATH_DOUBLE_WILD |
JSON_PATH_ARRAY_RANGE) &&
(json_scan_next(&je) || (json_scan_next(&je) ||
!json_find_path(&je, &jc->m_path, &cur_step, !json_find_path(&je, &jc->m_path, &cur_step,
array_counters))) array_counters)))
......
...@@ -8420,7 +8420,7 @@ ER_JSON_PATH_DEPTH ...@@ -8420,7 +8420,7 @@ ER_JSON_PATH_DEPTH
eng "Limit of %d on JSON path depth is reached in argument %d to function '%s' at position %d" eng "Limit of %d on JSON path depth is reached in argument %d to function '%s' at position %d"
spa "El límite de %d en profundidad de ruta JSON se ha alcanzado en argumento %d a función '%s' en la posición %d" spa "El límite de %d en profundidad de ruta JSON se ha alcanzado en argumento %d a función '%s' en la posición %d"
ER_JSON_PATH_NO_WILDCARD ER_JSON_PATH_NO_WILDCARD
eng "Wildcards in JSON path not allowed in argument %d to function '%s'" eng "Wildcards or range in JSON path not allowed in argument %d to function '%s'"
spa "Comodines en ruta JSON no permitidos en argumento %d a función '%s'" spa "Comodines en ruta JSON no permitidos en argumento %d a función '%s'"
ER_JSON_PATH_ARRAY ER_JSON_PATH_ARRAY
eng "JSON path should end with an array identifier in argument %d to function '%s'" eng "JSON path should end with an array identifier in argument %d to function '%s'"
......
...@@ -983,6 +983,7 @@ enum json_path_chr_classes { ...@@ -983,6 +983,7 @@ enum json_path_chr_classes {
P_USD, /* $ */ P_USD, /* $ */
P_ASTER, /* * */ P_ASTER, /* * */
P_LSQRB, /* [ */ P_LSQRB, /* [ */
P_T, /* t (for to) */
P_RSQRB, /* ] */ P_RSQRB, /* ] */
P_POINT, /* . */ P_POINT, /* . */
P_NEG, /* hyphen (for negative index in path) */ P_NEG, /* hyphen (for negative index in path) */
...@@ -1013,12 +1014,12 @@ static enum json_path_chr_classes json_path_chr_map[128] = { ...@@ -1013,12 +1014,12 @@ static enum json_path_chr_classes json_path_chr_map[128] = {
P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC,
P_ETC, P_ETC, P_ETC, P_ETC, P_L, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_L, P_ETC, P_ETC, P_ETC,
P_ETC, P_ETC, P_S, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_S, P_ETC, P_T, P_ETC, P_ETC, P_ETC,
P_ETC, P_ETC, P_ETC, P_LSQRB, P_BKSL, P_RSQRB, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_LSQRB, P_BKSL, P_RSQRB, P_ETC, P_ETC,
P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC,
P_ETC, P_ETC, P_ETC, P_ETC, P_L, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_L, P_ETC, P_ETC, P_ETC,
P_ETC, P_ETC, P_S, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_S, P_ETC, P_T, P_ETC, P_ETC, P_ETC,
P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC
}; };
...@@ -1042,6 +1043,7 @@ enum json_path_states { ...@@ -1042,6 +1043,7 @@ enum json_path_states {
PS_KEYX, /* Key started with quote ("). */ PS_KEYX, /* Key started with quote ("). */
PS_KNMX, /* Parse quoted key name. */ PS_KNMX, /* Parse quoted key name. */
PS_LAST, /* Parse 'last' keyword */ PS_LAST, /* Parse 'last' keyword */
PS_T, /* Parse 'to' keyword. */
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. */
...@@ -1057,71 +1059,75 @@ enum json_path_states { ...@@ -1057,71 +1059,75 @@ enum json_path_states {
static int json_path_transitions[N_PATH_STATES][N_PATH_CLASSES]= static int json_path_transitions[N_PATH_STATES][N_PATH_CLASSES]=
{ {
/* /*
EOS $, * [ ] . - 0 EOS $, * [ to ] . -
1..9 L S SPACE \ " ETC 0 1..9 L S SPACE \ " ETC
ERR BAD ERR BAD
*/ */
/* GO */ { JE_EOS, PS_PT, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, /* GO */ { JE_EOS, PS_PT, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN,
JE_SYN, PS_LAX, PS_SCT, PS_GO, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, PS_LAX, PS_SCT, PS_GO, JE_SYN, JE_SYN, JE_SYN,
JE_NOT_JSON_CHR, JE_BAD_CHR}, JE_NOT_JSON_CHR, JE_BAD_CHR},
/* LAX */ { JE_EOS, JE_SYN, 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,
JE_SYN, PS_LAX, JE_SYN, PS_GO, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, PS_LAX, JE_SYN, PS_GO, JE_SYN, JE_SYN, JE_SYN,
JE_NOT_JSON_CHR, JE_BAD_CHR}, JE_NOT_JSON_CHR, JE_BAD_CHR},
/* PT */ { PS_OK, JE_SYN, PS_AST, PS_AR, JE_SYN, PS_KEY, JE_SYN, JE_SYN, JE_SYN, /* PT */ { PS_OK, JE_SYN, PS_AST, PS_AR, JE_SYN, JE_SYN, PS_KEY, JE_SYN,
JE_SYN, JE_SYN, JE_SYN, JE_SYN, 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}, JE_NOT_JSON_CHR, JE_BAD_CHR},
/* AR */ { JE_EOS, JE_SYN, PS_AWD, JE_SYN, JE_SYN, JE_SYN, PS_NEG,PS_Z, /* AR */ { JE_EOS, JE_SYN, PS_AWD, JE_SYN, JE_SYN, JE_SYN, JE_SYN, PS_NEG,
PS_INT, PS_LAST, JE_SYN, PS_SAR, JE_SYN, JE_SYN, JE_SYN, PS_Z, PS_INT, PS_LAST, JE_SYN, PS_SAR, JE_SYN, JE_SYN, JE_SYN,
JE_NOT_JSON_CHR, JE_BAD_CHR}, JE_NOT_JSON_CHR, JE_BAD_CHR},
/* SAR */ { JE_EOS, JE_SYN, PS_AWD, JE_SYN, PS_PT, JE_SYN,JE_SYN, PS_Z, /* SAR */ { JE_EOS, JE_SYN, PS_AWD, JE_SYN, JE_SYN, PS_PT, JE_SYN, JE_SYN,
PS_INT, PS_LAST, JE_SYN, PS_SAR, JE_SYN, JE_SYN, JE_SYN, PS_Z, PS_INT, PS_LAST, JE_SYN, PS_SAR, JE_SYN, JE_SYN, JE_SYN,
JE_NOT_JSON_CHR, JE_BAD_CHR}, JE_NOT_JSON_CHR, JE_BAD_CHR},
/* AWD */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, PS_PT, JE_SYN,JE_SYN, JE_SYN, /* AWD */ { JE_EOS, JE_SYN, 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, JE_SYN, JE_SYN, JE_SYN, JE_SYN, PS_AS, JE_SYN, JE_SYN, JE_SYN,
JE_NOT_JSON_CHR, JE_BAD_CHR}, JE_NOT_JSON_CHR, JE_BAD_CHR},
/* NEG */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, PS_INT, /* NEG */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN,
PS_INT, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, PS_INT, PS_INT, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN,
JE_NOT_JSON_CHR, JE_BAD_CHR}, JE_NOT_JSON_CHR, JE_BAD_CHR},
/* Z */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, PS_PT, JE_SYN,JE_SYN, JE_SYN, /* Z */ { JE_EOS, JE_SYN, 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, JE_SYN, JE_SYN, JE_SYN, JE_SYN, PS_AS, JE_SYN, JE_SYN, JE_SYN,
JE_NOT_JSON_CHR, JE_BAD_CHR}, JE_NOT_JSON_CHR, JE_BAD_CHR},
/* INT */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, PS_PT, JE_SYN,JE_SYN, PS_INT, /* INT */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, JE_SYN, PS_PT, JE_SYN, JE_SYN,
PS_INT, JE_SYN, JE_SYN, PS_AS, JE_SYN, JE_SYN, JE_SYN, PS_INT, PS_INT, JE_SYN, JE_SYN, PS_AS, JE_SYN, JE_SYN, JE_SYN,
JE_NOT_JSON_CHR, JE_BAD_CHR}, JE_NOT_JSON_CHR, JE_BAD_CHR},
/* AS */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, PS_PT, JE_SYN, JE_SYN, JE_SYN, /* AS */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, PS_T, PS_PT, JE_SYN, PS_NEG,
JE_SYN, JE_SYN, PS_AS, JE_SYN, JE_SYN, JE_SYN, JE_SYN, PS_INT, PS_LAST, PS_AS, JE_SYN, JE_SYN, JE_SYN,
JE_NOT_JSON_CHR, JE_BAD_CHR}, JE_NOT_JSON_CHR, JE_BAD_CHR},
/* KEY */ { JE_EOS, PS_KNM, PS_KWD, JE_SYN, PS_KNM, JE_SYN,JE_SYN, PS_KNM, /* KEY */ { JE_EOS, PS_KNM, PS_KWD, JE_SYN, PS_KNM, PS_KNM, JE_SYN, JE_SYN,
PS_KNM, PS_KNM, PS_KNM, PS_KNM, JE_SYN, PS_KEYX, PS_KNM, PS_KNM, PS_KNM, PS_KNM, PS_KNM, PS_KNM, JE_SYN, PS_KEYX, PS_KNM,
JE_NOT_JSON_CHR, JE_BAD_CHR}, JE_NOT_JSON_CHR, JE_BAD_CHR},
/* KNM */ { PS_KOK, PS_KNM, PS_AST, PS_EAR, PS_KNM, PS_EKY, JE_SYN,PS_KNM, /* KNM */ { PS_KOK, PS_KNM, PS_AST, PS_EAR, PS_KNM, PS_KNM, PS_EKY, JE_SYN,
PS_KNM, PS_KNM, PS_KNM, PS_KNM, PS_ESC, PS_KNM, PS_KNM, PS_KNM, PS_KNM, PS_KNM, PS_KNM, PS_KNM, PS_ESC, PS_KNM, PS_KNM,
JE_NOT_JSON_CHR, JE_BAD_CHR}, JE_NOT_JSON_CHR, JE_BAD_CHR},
/* KWD */ { PS_OK, JE_SYN, JE_SYN, PS_AR, JE_SYN, PS_EKY, JE_SYN,JE_SYN, /* KWD */ { PS_OK, JE_SYN, JE_SYN, PS_AR, JE_SYN, JE_SYN, PS_EKY, JE_SYN,
JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, 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}, JE_NOT_JSON_CHR, JE_BAD_CHR},
/* AST */ { JE_SYN, JE_SYN, PS_DWD, JE_SYN, JE_SYN, JE_SYN, JE_SYN,JE_SYN, /* 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_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}, 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, /* DWD */ { JE_SYN, JE_SYN, PS_AST, PS_AR, JE_SYN, JE_SYN, PS_KEY, JE_SYN,
JE_SYN, JE_SYN, JE_SYN, JE_SYN, 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}, JE_NOT_JSON_CHR, JE_BAD_CHR},
/* KEYX*/ { JE_EOS, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, JE_SYN,PS_KNMX, /* KEYX*/ { JE_EOS, PS_KNMX, PS_KNMX, PS_KNMX, JE_SYN, PS_KNMX, PS_KNMX, JE_SYN,
PS_KNMX,PS_KNMX, PS_KNMX, PS_KNMX, PS_ESCX, PS_EKYX, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, PS_ESCX, PS_EKYX, PS_KNMX,
JE_NOT_JSON_CHR, JE_BAD_CHR}, JE_NOT_JSON_CHR, JE_BAD_CHR},
/* KNMX */{ JE_EOS, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, JE_SYN,PS_KNMX, /* KNMX */{ JE_EOS, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, JE_SYN,
PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX,PS_ESCX, PS_EKYX, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, PS_ESCX, PS_EKYX, PS_KNMX,
JE_NOT_JSON_CHR, JE_BAD_CHR}, JE_NOT_JSON_CHR, JE_BAD_CHR},
/* LAST */{ JE_SYN, JE_SYN, JE_SYN, JE_SYN, PS_PT, JE_SYN, PS_NEG, JE_SYN, /* LAST */{ JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, PS_PT, JE_SYN, PS_NEG,
JE_SYN, JE_SYN, JE_SYN, PS_AS, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, PS_AS, JE_SYN, JE_SYN, JE_SYN,
JE_SYN, JE_BAD_CHR} JE_SYN, JE_BAD_CHR},
/* T */ { JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, PS_PT, JE_SYN, PS_NEG,
JE_SYN, JE_SYN, JE_SYN, JE_SYN, PS_AS, JE_SYN, JE_SYN, JE_SYN,
JE_SYN, JE_BAD_CHR},
}; };
int json_path_setup(json_path_t *p, 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, is_negative_index= 0, is_last= 0, prev_value=0; int c_len, t_next, state= PS_GO, is_negative_index= 0, is_last= 0,
prev_value=0, is_to= 0, *cur_val;
enum json_path_step_types double_wildcard= JSON_PATH_KEY_NULL; 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);
...@@ -1161,19 +1167,21 @@ int json_path_setup(json_path_t *p, ...@@ -1161,19 +1167,21 @@ int json_path_setup(json_path_t *p,
p->types_used|= JSON_PATH_WILD; p->types_used|= JSON_PATH_WILD;
continue; continue;
case PS_INT: case PS_INT:
cur_val= is_to ? &(p->last_step->n_item_end) :
&(p->last_step->n_item);
if (is_last) if (is_last)
{ {
prev_value*= 10; prev_value*= 10;
prev_value-= p->s.c_next - '0'; prev_value-= p->s.c_next - '0';
p->last_step->n_item= -1 + prev_value; *cur_val= -1 + prev_value;
} }
else else
{ {
p->last_step->n_item*= 10; (*cur_val)*= 10;
if (is_negative_index) if (is_negative_index)
p->last_step->n_item-= p->s.c_next - '0'; *cur_val-= p->s.c_next - '0';
else else
p->last_step->n_item+= p->s.c_next - '0'; *cur_val+= p->s.c_next - '0';
} }
continue; continue;
case PS_EKYX: case PS_EKYX:
...@@ -1186,7 +1194,10 @@ int json_path_setup(json_path_t *p, ...@@ -1186,7 +1194,10 @@ int json_path_setup(json_path_t *p,
/* fall through */ /* fall through */
case PS_KEY: case PS_KEY:
p->last_step++; p->last_step++;
is_to= 0;
prev_value= 0;
is_negative_index= 0; is_negative_index= 0;
is_last= 0;
if (p->last_step - p->steps >= JSON_DEPTH_LIMIT) if (p->last_step - p->steps >= JSON_DEPTH_LIMIT)
return p->s.error= JE_DEPTH; return p->s.error= JE_DEPTH;
p->types_used|= p->last_step->type= JSON_PATH_KEY | double_wildcard; p->types_used|= p->last_step->type= JSON_PATH_KEY | double_wildcard;
...@@ -1202,13 +1213,14 @@ int json_path_setup(json_path_t *p, ...@@ -1202,13 +1213,14 @@ int json_path_setup(json_path_t *p,
case PS_AR: case PS_AR:
p->last_step++; p->last_step++;
is_last= 0; is_last= 0;
is_to= 0;
prev_value= 0;
is_negative_index= 0;
if (p->last_step - p->steps >= JSON_DEPTH_LIMIT) if (p->last_step - p->steps >= JSON_DEPTH_LIMIT)
return p->s.error= JE_DEPTH; return p->s.error= JE_DEPTH;
p->types_used|= p->last_step->type= JSON_PATH_ARRAY | double_wildcard; p->types_used|= p->last_step->type= JSON_PATH_ARRAY | double_wildcard;
double_wildcard= JSON_PATH_KEY_NULL; double_wildcard= JSON_PATH_KEY_NULL;
p->last_step->n_item= 0; p->last_step->n_item= 0;
prev_value= 0;
is_negative_index= 0;
continue; continue;
case PS_ESC: case PS_ESC:
if (json_handle_esc(&p->s)) if (json_handle_esc(&p->s))
...@@ -1230,16 +1242,28 @@ int json_path_setup(json_path_t *p, ...@@ -1230,16 +1242,28 @@ int json_path_setup(json_path_t *p,
case PS_NEG: case PS_NEG:
p->types_used|= JSON_PATH_NEGATIVE_INDEX; p->types_used|= JSON_PATH_NEGATIVE_INDEX;
is_negative_index= 1; is_negative_index= 1;
if (is_last)
p->last_step->n_item= 0;
continue; continue;
case PS_LAST: case PS_LAST:
if ((p->s.error= skip_string_verbatim(&p->s, "ast"))) if ((p->s.error= skip_string_verbatim(&p->s, "ast")))
return 1; return 1;
p->types_used|= JSON_PATH_NEGATIVE_INDEX; p->types_used|= JSON_PATH_NEGATIVE_INDEX;
is_last= 1; is_last= 1;
if (is_to)
p->last_step->n_item_end= -1;
else
p->last_step->n_item= -1; p->last_step->n_item= -1;
continue; continue;
case PS_T:
if ((p->s.error= skip_string_verbatim(&p->s, "o")))
return 1;
is_to= 1;
is_negative_index= 0;
is_last= 0;
prev_value= 0;
p->last_step->n_item_end= 0;
p->last_step->type|= JSON_PATH_ARRAY_RANGE;
p->types_used|= JSON_PATH_ARRAY_RANGE;
continue;
}; };
} while (state != PS_OK); } while (state != PS_OK);
...@@ -1420,7 +1444,7 @@ int json_find_path(json_engine_t *je, ...@@ -1420,7 +1444,7 @@ int json_find_path(json_engine_t *je,
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->type & JSON_PATH_WILD || if (cur_step->type & (JSON_PATH_WILD | JSON_PATH_ARRAY_RANGE) ||
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. */
...@@ -1855,14 +1879,27 @@ int json_path_parts_compare( ...@@ -1855,14 +1879,27 @@ int json_path_parts_compare(
DBUG_ASSERT((b->type & (JSON_PATH_WILD | JSON_PATH_DOUBLE_WILD)) == 0); DBUG_ASSERT((b->type & (JSON_PATH_WILD | JSON_PATH_DOUBLE_WILD)) == 0);
if (a->type & JSON_PATH_ARRAY) if (a->type & JSON_PATH_ARRAY)
{ {
if (b->type & JSON_PATH_ARRAY) if (b->type & JSON_PATH_ARRAY)
{ {
if ((a->type & JSON_PATH_WILD) || int res= 0, corrected_n_item_a= 0, corrected_n_item_end_a= 0;
(a->n_item >= 0 ? a->n_item == b->n_item : if (array_sizes)
a->n_item == b->n_item - array_sizes[b-temp_b])) {
corrected_n_item_a= a->n_item < 0 ? array_sizes[b-temp_b] +
a->n_item :
a->n_item;
corrected_n_item_end_a= a->n_item_end < 0 ? array_sizes[b-temp_b] +
a->n_item_end :
a->n_item_end;
}
if (a->type & JSON_PATH_ARRAY_RANGE)
res= b->n_item >= corrected_n_item_a &&
b->n_item <= corrected_n_item_end_a;
else
res= corrected_n_item_a == b->n_item;
if ((a->type & JSON_PATH_WILD) || res)
goto step_fits; goto step_fits;
goto step_failed; goto step_failed;
} }
......
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