MDEV-22224: Support JSON Path negative index
This patch can be viewed as combination of two parts: 1) Enabling '-' in the path so that the parser does not give out a warning. 2) Setting the negative index to a correct value and returning the appropriate value. 1) To enable using the negative index in the path: To make the parser not return warning when negative index is used in path '-' needs to be allowed in json path characters. P_NEG is added to enable this and is made recognizable by setting the 45th index of json_path_chr_map[] to P_NEG (instead of previous P_ETC) because 45 corresponds to '-' in unicode. When the path is being parsed and '-' is encountered, the parser should recognize it as parsing '-' sign, so a new json state PS_NEG is required. When the state is PS_NEG, it means that a negative integer is going to be parsed so set is_negative_index of current step to 1 and n_item is set accordingly when integer is encountered after '-'. Next proceed with parsing rest of the path and get the correct path. Next thing is parsing the json and returning correct value. 2) Setting the negative index to a correct value and returning the value: While parsing json if we encounter array and the path step for the array is a negative index (n_item < 0), then we can count the number of elements in the array and set n_item to correct corresponding value. This is done in json_skip_array_and_count.
This commit is contained in:
parent
e98013cb5c
commit
dfcbb30a92
@ -83,7 +83,8 @@ enum json_path_step_types
|
||||
JSON_PATH_KEY_WILD= 1+4,
|
||||
JSON_PATH_KEY_DOUBLEWILD= 1+8,
|
||||
JSON_PATH_ARRAY_WILD= 2+4,
|
||||
JSON_PATH_ARRAY_DOUBLEWILD= 2+8
|
||||
JSON_PATH_ARRAY_DOUBLEWILD= 2+8,
|
||||
JSON_PATH_NEGATIVE_INDEX= 16
|
||||
};
|
||||
|
||||
|
||||
@ -93,7 +94,7 @@ typedef struct st_json_path_step_t
|
||||
/* see json_path_step_types */
|
||||
const uchar *key; /* Pointer to the beginning 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. */
|
||||
int n_item; /* Item number in an array. No meaning for the key step. */
|
||||
} json_path_step_t;
|
||||
|
||||
|
||||
@ -356,7 +357,7 @@ int json_skip_level_and_count(json_engine_t *j, int *n_items_skipped);
|
||||
*/
|
||||
int json_find_path(json_engine_t *je,
|
||||
json_path_t *p, json_path_step_t **p_cur_step,
|
||||
uint *array_counters);
|
||||
int *array_counters);
|
||||
|
||||
|
||||
typedef struct st_json_find_paths_t
|
||||
@ -365,7 +366,7 @@ typedef struct st_json_find_paths_t
|
||||
json_path_t *paths;
|
||||
uint cur_depth;
|
||||
uint *path_depths;
|
||||
uint array_counters[JSON_DEPTH_LIMIT];
|
||||
int array_counters[JSON_DEPTH_LIMIT];
|
||||
} json_find_paths_t;
|
||||
|
||||
|
||||
@ -425,13 +426,8 @@ int json_get_path_start(json_engine_t *je, CHARSET_INFO *i_cs,
|
||||
|
||||
int json_get_path_next(json_engine_t *je, json_path_t *p);
|
||||
|
||||
|
||||
int json_path_parts_compare(
|
||||
const json_path_step_t *a, const json_path_step_t *a_end,
|
||||
const json_path_step_t *b, const json_path_step_t *b_end,
|
||||
enum json_value_types vt);
|
||||
int json_path_compare(const json_path_t *a, const json_path_t *b,
|
||||
enum json_value_types vt);
|
||||
enum json_value_types vt, const int* array_size_counter);
|
||||
|
||||
int json_valid(const char *js, size_t js_len, CHARSET_INFO *cs);
|
||||
|
||||
@ -443,6 +439,8 @@ int json_locate_key(const char *js, const char *js_end,
|
||||
int json_normalize(DYNAMIC_STRING *result,
|
||||
const char *s, size_t size, CHARSET_INFO *cs);
|
||||
|
||||
int json_skip_array_and_count(json_engine_t *j, int* n_item);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -1753,3 +1753,265 @@ Warning 4037 Unexpected end of JSON text in argument 2 to function 'json_overlap
|
||||
#
|
||||
# End of 10.9 test
|
||||
#
|
||||
#
|
||||
# Beginning of 10.9 Test
|
||||
#
|
||||
# MDEV-22224: Support JSON Path negative index
|
||||
#
|
||||
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[-2][-1]', 5);
|
||||
JSON_ARRAY_APPEND(@json, '$.A[-2][-1]', 5)
|
||||
{"A": [0, [1, 2, 3], [4, 5, 6], "seven", 0.8, true, false, "eleven", [12, 13, {"key1": "value1"}, [15, 5]], true], "B": {"C": 1}, "D": 2}
|
||||
SELECT JSON_ARRAY_APPEND(@json, '$.A[last-1][last]', 5);
|
||||
JSON_ARRAY_APPEND(@json, '$.A[last-1][last]', 5)
|
||||
{"A": [0, [1, 2, 3], [4, 5, 6], "seven", 0.8, true, false, "eleven", [12, 13, {"key1": "value1"}, [15, 5]], true], "B": {"C": 1}, "D": 2}
|
||||
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[-2][-2]', 5);
|
||||
JSON_ARRAY_INSERT(@json, '$.A[-2][-2]', 5)
|
||||
{"A": [0, [1, 2, 3], [4, 5, 6], "seven", 0.8, true, false, "eleven", [12, 13, {"key1": "value1"}, 5, [15]], true], "B": {"C": 1}, "D": 2}
|
||||
SELECT JSON_ARRAY_INSERT(@json, '$.A[last-1][last-1]', 5);
|
||||
JSON_ARRAY_INSERT(@json, '$.A[last-1][last-1]', 5)
|
||||
{"A": [0, [1, 2, 3], [4, 5, 6], "seven", 0.8, true, false, "eleven", [12, 13, {"key1": "value1"}, 5, [15]], true], "B": {"C": 1}, "D": 2}
|
||||
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_CONTAINS(@json, '15', '$.A[-2][-1]');
|
||||
JSON_CONTAINS(@json, '15', '$.A[-2][-1]')
|
||||
1
|
||||
SELECT JSON_CONTAINS(@json, '15', '$.A[last-1][last]');
|
||||
JSON_CONTAINS(@json, '15', '$.A[last-1][last]')
|
||||
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_CONTAINS_PATH(@json, 'one', '$.A[-2]');
|
||||
JSON_CONTAINS_PATH(@json, 'one', '$.A[-2]')
|
||||
1
|
||||
SELECT JSON_CONTAINS_PATH(@json, 'one', '$.A[last-1]');
|
||||
JSON_CONTAINS_PATH(@json, 'one', '$.A[last-1]')
|
||||
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_EXISTS(@json, '$.A[-2][-1]');
|
||||
JSON_EXISTS(@json, '$.A[-2][-1]')
|
||||
1
|
||||
SELECT JSON_EXISTS(@json, '$.A[last-1][last]');
|
||||
JSON_EXISTS(@json, '$.A[last-1][last]')
|
||||
1
|
||||
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_EXTRACT(@json, '$.A[-8][1]');
|
||||
JSON_EXTRACT(@json, '$.A[-8][1]')
|
||||
5
|
||||
SELECT JSON_EXTRACT(@json, '$.A[last-7][1]');
|
||||
JSON_EXTRACT(@json, '$.A[last-7][1]')
|
||||
5
|
||||
SET @json= '[{"A": 1, "B": 2, "C": {"D": 3}},{"A": 1, "B": 2, "C": {"D": 3}}]';
|
||||
SELECT JSON_KEYS(@json, '$[-1].C');
|
||||
JSON_KEYS(@json, '$[-1].C')
|
||||
["D"]
|
||||
SELECT JSON_KEYS(@json, '$[last].C');
|
||||
JSON_KEYS(@json, '$[last].C')
|
||||
["D"]
|
||||
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_LENGTH(@json, '$.A[-2][-3]');
|
||||
JSON_LENGTH(@json, '$.A[-2][-3]')
|
||||
2
|
||||
SELECT JSON_LENGTH(@json, '$.A[last-1][last-2]');
|
||||
JSON_LENGTH(@json, '$.A[last-1][last-2]')
|
||||
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_QUERY(@json, '$.A[-8]');
|
||||
JSON_QUERY(@json, '$.A[-8]')
|
||||
[4, 5, 6]
|
||||
SELECT JSON_QUERY(@json, '$.A[last-7]');
|
||||
JSON_QUERY(@json, '$.A[last-7]')
|
||||
[4, 5, 6]
|
||||
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_REMOVE(@json, '$.A[-10]');
|
||||
JSON_REMOVE(@json, '$.A[-10]')
|
||||
{"A": [[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_REMOVE(@json, '$.A[last-9]');
|
||||
JSON_REMOVE(@json, '$.A[last-9]')
|
||||
{"A": [[1, 2, 3], [4, 5, 6], "seven", 0.8, true, false, "eleven", [12, [13, 14], {"key1": "value1"}, [15]], true], "B": {"C": 1}, "D": 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_REPLACE(@json, '$.A[-1]', 4);
|
||||
JSON_REPLACE(@json, '$.A[-1]', 4)
|
||||
{"A": [0, [1, 2, 3], [4, 5, 6], "seven", 0.8, true, false, "eleven", [12, [13, 14], {"key1": "value1"}, [15]], 4], "B": {"C": 1}, "D": 2}
|
||||
SELECT JSON_REPLACE(@json, '$.A[last]', 4);
|
||||
JSON_REPLACE(@json, '$.A[last]', 4)
|
||||
{"A": [0, [1, 2, 3], [4, 5, 6], "seven", 0.8, true, false, "eleven", [12, [13, 14], {"key1": "value1"}, [15]], 4], "B": {"C": 1}, "D": 2}
|
||||
SET @json = '["abc", [{"k": "10"}, "def"], {"x":"abc"}, {"y":"bcd"}]';
|
||||
SELECT JSON_SEARCH(@json, 'all', 'abc', NULL, '$[-2]');
|
||||
JSON_SEARCH(@json, 'all', 'abc', NULL, '$[-2]')
|
||||
"$[2].x"
|
||||
SELECT JSON_SEARCH(@json, 'all', 'abc', NULL, '$[last-1]');
|
||||
JSON_SEARCH(@json, 'all', 'abc', NULL, '$[last-1]')
|
||||
"$[2].x"
|
||||
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_SET(@json, '$.A[-4]', 100);
|
||||
JSON_SET(@json, '$.A[-4]', 100)
|
||||
{"A": [0, [1, 2, 3], [4, 5, 6], "seven", 0.8, true, 100, "eleven", [12, [13, 14], {"key1": "value1"}, [15]], true], "B": {"C": 1}, "D": 2}
|
||||
SELECT JSON_SET(@json, '$.A[last-3]', 100);
|
||||
JSON_SET(@json, '$.A[last-3]', 100)
|
||||
{"A": [0, [1, 2, 3], [4, 5, 6], "seven", 0.8, true, 100, "eleven", [12, [13, 14], {"key1": "value1"}, [15]], true], "B": {"C": 1}, "D": 2}
|
||||
SET @json='{
|
||||
"A": [0,
|
||||
[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
"seven",
|
||||
0.8,
|
||||
true,
|
||||
false,
|
||||
"eleven",
|
||||
[12, [13, 14], {"key1":123},[15]],
|
||||
true],
|
||||
"B": {"C": 1},
|
||||
"D": 2
|
||||
}';
|
||||
SELECT JSON_VALUE(@json, '$.A[-2][-2].key1');
|
||||
JSON_VALUE(@json, '$.A[-2][-2].key1')
|
||||
123
|
||||
SELECT JSON_VALUE(@json, '$.A[last-1][last-1].key1');
|
||||
JSON_VALUE(@json, '$.A[last-1][last-1].key1')
|
||||
123
|
||||
#
|
||||
# End of 10.9 Test
|
||||
#
|
||||
|
@ -916,7 +916,6 @@ DROP TABLE t;
|
||||
--echo #
|
||||
--echo # End of 10.5 tests
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--echo # Beginning of 10.9 tests
|
||||
--echo #
|
||||
@ -1089,3 +1088,224 @@ SELECT JSON_OVERLAPS('true','tr');
|
||||
--echo #
|
||||
--echo # End of 10.9 test
|
||||
--echo #
|
||||
--echo #
|
||||
--echo # Beginning of 10.9 Test
|
||||
--echo #
|
||||
--echo # MDEV-22224: Support JSON Path negative index
|
||||
--echo #
|
||||
|
||||
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[-2][-1]', 5);
|
||||
SELECT JSON_ARRAY_APPEND(@json, '$.A[last-1][last]', 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_INSERT(@json, '$.A[-2][-2]', 5);
|
||||
SELECT JSON_ARRAY_INSERT(@json, '$.A[last-1][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_CONTAINS(@json, '15', '$.A[-2][-1]');
|
||||
SELECT JSON_CONTAINS(@json, '15', '$.A[last-1][last]');
|
||||
|
||||
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_CONTAINS_PATH(@json, 'one', '$.A[-2]');
|
||||
SELECT JSON_CONTAINS_PATH(@json, 'one', '$.A[last-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_EXISTS(@json, '$.A[-2][-1]');
|
||||
SELECT JSON_EXISTS(@json, '$.A[last-1][last]');
|
||||
|
||||
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_EXTRACT(@json, '$.A[-8][1]');
|
||||
SELECT JSON_EXTRACT(@json, '$.A[last-7][1]');
|
||||
|
||||
SET @json= '[{"A": 1, "B": 2, "C": {"D": 3}},{"A": 1, "B": 2, "C": {"D": 3}}]';
|
||||
SELECT JSON_KEYS(@json, '$[-1].C');
|
||||
SELECT JSON_KEYS(@json, '$[last].C');
|
||||
|
||||
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_LENGTH(@json, '$.A[-2][-3]');
|
||||
SELECT JSON_LENGTH(@json, '$.A[last-1][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_QUERY(@json, '$.A[-8]');
|
||||
SELECT JSON_QUERY(@json, '$.A[last-7]');
|
||||
|
||||
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_REMOVE(@json, '$.A[-10]');
|
||||
SELECT JSON_REMOVE(@json, '$.A[last-9]');
|
||||
|
||||
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_REPLACE(@json, '$.A[-1]', 4);
|
||||
SELECT JSON_REPLACE(@json, '$.A[last]', 4);
|
||||
|
||||
SET @json = '["abc", [{"k": "10"}, "def"], {"x":"abc"}, {"y":"bcd"}]';
|
||||
SELECT JSON_SEARCH(@json, 'all', 'abc', NULL, '$[-2]');
|
||||
SELECT JSON_SEARCH(@json, 'all', 'abc', NULL, '$[last-1]');
|
||||
|
||||
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_SET(@json, '$.A[-4]', 100);
|
||||
SELECT JSON_SET(@json, '$.A[last-3]', 100);
|
||||
|
||||
SET @json='{
|
||||
"A": [0,
|
||||
[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
"seven",
|
||||
0.8,
|
||||
true,
|
||||
false,
|
||||
"eleven",
|
||||
[12, [13, 14], {"key1":123},[15]],
|
||||
true],
|
||||
"B": {"C": 1},
|
||||
"D": 2
|
||||
}';
|
||||
SELECT JSON_VALUE(@json, '$.A[-2][-2].key1');
|
||||
SELECT JSON_VALUE(@json, '$.A[last-1][last-1].key1');
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.9 Test
|
||||
--echo #
|
||||
|
@ -467,7 +467,7 @@ bool Item_func_json_exists::fix_length_and_dec(THD *thd)
|
||||
longlong Item_func_json_exists::val_int()
|
||||
{
|
||||
json_engine_t je;
|
||||
uint array_counters[JSON_DEPTH_LIMIT];
|
||||
int array_counters[JSON_DEPTH_LIMIT];
|
||||
|
||||
String *js= args[0]->val_json(&tmp_js);
|
||||
|
||||
@ -536,7 +536,7 @@ bool Json_path_extractor::extract(String *str, Item *item_js, Item *item_jp,
|
||||
{
|
||||
String *js= item_js->val_json(&tmp_js);
|
||||
int error= 0;
|
||||
uint array_counters[JSON_DEPTH_LIMIT];
|
||||
int array_counters[JSON_DEPTH_LIMIT];
|
||||
|
||||
if (!parsed)
|
||||
{
|
||||
@ -797,11 +797,12 @@ bool Item_func_json_extract::fix_length_and_dec(THD *thd)
|
||||
|
||||
|
||||
static bool path_exact(const json_path_with_flags *paths_list, int n_paths,
|
||||
const json_path_t *p, json_value_types vt)
|
||||
const json_path_t *p, json_value_types vt,
|
||||
const int *array_size_counter)
|
||||
{
|
||||
for (; n_paths > 0; n_paths--, paths_list++)
|
||||
{
|
||||
if (json_path_compare(&paths_list->p, p, vt) == 0)
|
||||
if (json_path_compare(&paths_list->p, p, vt, array_size_counter) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
@ -809,11 +810,12 @@ static bool path_exact(const json_path_with_flags *paths_list, int n_paths,
|
||||
|
||||
|
||||
static bool path_ok(const json_path_with_flags *paths_list, int n_paths,
|
||||
const json_path_t *p, json_value_types vt)
|
||||
const json_path_t *p, json_value_types vt,
|
||||
const int *array_size_counter)
|
||||
{
|
||||
for (; n_paths > 0; n_paths--, paths_list++)
|
||||
{
|
||||
if (json_path_compare(&paths_list->p, p, vt) >= 0)
|
||||
if (json_path_compare(&paths_list->p, p, vt, array_size_counter) >= 0)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
@ -832,6 +834,8 @@ String *Item_func_json_extract::read_json(String *str,
|
||||
uint n_arg;
|
||||
size_t v_len;
|
||||
int possible_multiple_values;
|
||||
int array_size_counter[JSON_DEPTH_LIMIT];
|
||||
uint has_negative_path= 0;
|
||||
|
||||
if ((null_value= args[0]->null_value))
|
||||
return 0;
|
||||
@ -850,6 +854,7 @@ String *Item_func_json_extract::read_json(String *str,
|
||||
goto return_null;
|
||||
}
|
||||
c_path->parsed= c_path->constant;
|
||||
has_negative_path|= c_path->p.types_used & JSON_PATH_NEGATIVE_INDEX;
|
||||
}
|
||||
|
||||
if (args[n_arg]->null_value)
|
||||
@ -875,7 +880,12 @@ String *Item_func_json_extract::read_json(String *str,
|
||||
|
||||
while (json_get_path_next(&je, &p) == 0)
|
||||
{
|
||||
if (!path_exact(paths, arg_count-1, &p, je.value_type))
|
||||
if (has_negative_path && je.value_type == JSON_VALUE_ARRAY &&
|
||||
json_skip_array_and_count(&je,
|
||||
array_size_counter + (p.last_step - p.steps)))
|
||||
goto error;
|
||||
|
||||
if (!path_exact(paths, arg_count-1, &p, je.value_type, array_size_counter))
|
||||
continue;
|
||||
|
||||
value= je.value_begin;
|
||||
@ -1245,7 +1255,7 @@ longlong Item_func_json_contains::val_int()
|
||||
|
||||
if (arg_count>2) /* Path specified. */
|
||||
{
|
||||
uint array_counters[JSON_DEPTH_LIMIT];
|
||||
int array_counters[JSON_DEPTH_LIMIT];
|
||||
if (!path.parsed)
|
||||
{
|
||||
String *s_p= args[2]->val_str(&tmp_path);
|
||||
@ -1375,7 +1385,7 @@ longlong Item_func_json_contains_path::val_int()
|
||||
result= !mode_one;
|
||||
for (n_arg=2; n_arg < arg_count; n_arg++)
|
||||
{
|
||||
uint array_counters[JSON_DEPTH_LIMIT];
|
||||
int array_counters[JSON_DEPTH_LIMIT];
|
||||
json_path_with_flags *c_path= paths + n_arg - 2;
|
||||
if (!c_path->parsed)
|
||||
{
|
||||
@ -1436,6 +1446,8 @@ longlong Item_func_json_contains_path::val_int()
|
||||
json_path_t p;
|
||||
int n_found;
|
||||
LINT_INIT(n_found);
|
||||
int array_sizes[JSON_DEPTH_LIMIT];
|
||||
uint has_negative_path= 0;
|
||||
|
||||
if ((null_value= args[0]->null_value))
|
||||
return 0;
|
||||
@ -1457,6 +1469,7 @@ longlong Item_func_json_contains_path::val_int()
|
||||
goto null_return;
|
||||
}
|
||||
c_path->parsed= c_path->constant;
|
||||
has_negative_path|= c_path->p.types_used & JSON_PATH_NEGATIVE_INDEX;
|
||||
}
|
||||
if (args[n_arg]->null_value)
|
||||
goto null_return;
|
||||
@ -1478,10 +1491,17 @@ longlong Item_func_json_contains_path::val_int()
|
||||
while (json_get_path_next(&je, &p) == 0)
|
||||
{
|
||||
int n_path= arg_count - 2;
|
||||
if (has_negative_path && je.value_type == JSON_VALUE_ARRAY &&
|
||||
json_skip_array_and_count(&je, array_sizes + (p.last_step - p.steps)))
|
||||
{
|
||||
result= 1;
|
||||
break;
|
||||
}
|
||||
|
||||
json_path_with_flags *c_path= paths;
|
||||
for (; n_path > 0; n_path--, c_path++)
|
||||
{
|
||||
if (json_path_compare(&c_path->p, &p, je.value_type) >= 0)
|
||||
if (json_path_compare(&c_path->p, &p, je.value_type, array_sizes) >= 0)
|
||||
{
|
||||
if (mode_one)
|
||||
{
|
||||
@ -1748,7 +1768,7 @@ String *Item_func_json_array_append::val_str(String *str)
|
||||
|
||||
for (n_arg=1, n_path=0; n_arg < arg_count; n_arg+=2, n_path++)
|
||||
{
|
||||
uint array_counters[JSON_DEPTH_LIMIT];
|
||||
int array_counters[JSON_DEPTH_LIMIT];
|
||||
json_path_with_flags *c_path= paths + n_path;
|
||||
if (!c_path->parsed)
|
||||
{
|
||||
@ -1878,10 +1898,10 @@ String *Item_func_json_array_insert::val_str(String *str)
|
||||
|
||||
for (n_arg=1, n_path=0; n_arg < arg_count; n_arg+=2, n_path++)
|
||||
{
|
||||
uint array_counters[JSON_DEPTH_LIMIT];
|
||||
int array_counters[JSON_DEPTH_LIMIT];
|
||||
json_path_with_flags *c_path= paths + n_path;
|
||||
const char *item_pos;
|
||||
uint n_item;
|
||||
int n_item, corrected_n_item;
|
||||
|
||||
if (!c_path->parsed)
|
||||
{
|
||||
@ -1931,11 +1951,20 @@ String *Item_func_json_array_insert::val_str(String *str)
|
||||
|
||||
item_pos= 0;
|
||||
n_item= 0;
|
||||
corrected_n_item= c_path->p.last_step[1].n_item;
|
||||
if (corrected_n_item < 0)
|
||||
{
|
||||
int array_size;
|
||||
if (json_skip_array_and_count(&je, &array_size))
|
||||
goto js_error;
|
||||
corrected_n_item+= array_size + 1;
|
||||
}
|
||||
|
||||
while (json_scan_next(&je) == 0 && je.state != JST_ARRAY_END)
|
||||
{
|
||||
DBUG_ASSERT(je.state == JST_VALUE);
|
||||
if (n_item == c_path->p.last_step[1].n_item)
|
||||
|
||||
if (n_item == corrected_n_item)
|
||||
{
|
||||
item_pos= (const char *) je.s.c_str;
|
||||
break;
|
||||
@ -2666,7 +2695,7 @@ longlong Item_func_json_length::val_int()
|
||||
String *js= args[0]->val_json(&tmp_js);
|
||||
json_engine_t je;
|
||||
uint length= 0;
|
||||
uint array_counters[JSON_DEPTH_LIMIT];
|
||||
int array_counters[JSON_DEPTH_LIMIT];
|
||||
int err;
|
||||
|
||||
if ((null_value= args[0]->null_value))
|
||||
@ -2894,10 +2923,11 @@ String *Item_func_json_insert::val_str(String *str)
|
||||
|
||||
for (n_arg=1, n_path=0; n_arg < arg_count; n_arg+=2, n_path++)
|
||||
{
|
||||
uint array_counters[JSON_DEPTH_LIMIT];
|
||||
int array_counters[JSON_DEPTH_LIMIT];
|
||||
json_path_with_flags *c_path= paths + n_path;
|
||||
const char *v_to;
|
||||
const json_path_step_t *lp;
|
||||
json_path_step_t *lp;
|
||||
int corrected_n_item;
|
||||
|
||||
if (!c_path->parsed)
|
||||
{
|
||||
@ -2943,7 +2973,7 @@ String *Item_func_json_insert::val_str(String *str)
|
||||
lp= c_path->p.last_step+1;
|
||||
if (lp->type & JSON_PATH_ARRAY)
|
||||
{
|
||||
uint n_item= 0;
|
||||
int n_item= 0;
|
||||
|
||||
if (je.value_type != JSON_VALUE_ARRAY)
|
||||
{
|
||||
@ -2991,13 +3021,21 @@ String *Item_func_json_insert::val_str(String *str)
|
||||
|
||||
goto continue_point;
|
||||
}
|
||||
corrected_n_item= lp->n_item;
|
||||
if (corrected_n_item < 0)
|
||||
{
|
||||
int array_size;
|
||||
if (json_skip_array_and_count(&je, &array_size))
|
||||
goto js_error;
|
||||
corrected_n_item+= array_size;
|
||||
}
|
||||
|
||||
while (json_scan_next(&je) == 0 && je.state != JST_ARRAY_END)
|
||||
{
|
||||
switch (je.state)
|
||||
{
|
||||
case JST_VALUE:
|
||||
if (n_item == lp->n_item)
|
||||
if (n_item == corrected_n_item)
|
||||
goto v_found;
|
||||
n_item++;
|
||||
if (json_skip_array_item(&je))
|
||||
@ -3148,11 +3186,11 @@ String *Item_func_json_remove::val_str(String *str)
|
||||
|
||||
for (n_arg=1, n_path=0; n_arg < arg_count; n_arg++, n_path++)
|
||||
{
|
||||
uint array_counters[JSON_DEPTH_LIMIT];
|
||||
int array_counters[JSON_DEPTH_LIMIT];
|
||||
json_path_with_flags *c_path= paths + n_path;
|
||||
const char *rem_start= 0, *rem_end;
|
||||
const json_path_step_t *lp;
|
||||
uint n_item= 0;
|
||||
json_path_step_t *lp;
|
||||
int n_item= 0;
|
||||
|
||||
if (!c_path->parsed)
|
||||
{
|
||||
@ -3197,17 +3235,28 @@ String *Item_func_json_remove::val_str(String *str)
|
||||
goto js_error;
|
||||
|
||||
lp= c_path->p.last_step+1;
|
||||
|
||||
if (lp->type & JSON_PATH_ARRAY)
|
||||
{
|
||||
int corrected_n_item;
|
||||
if (je.value_type != JSON_VALUE_ARRAY)
|
||||
continue;
|
||||
|
||||
corrected_n_item= lp->n_item;
|
||||
if (corrected_n_item < 0)
|
||||
{
|
||||
int array_size;
|
||||
if (json_skip_array_and_count(&je, &array_size))
|
||||
goto js_error;
|
||||
corrected_n_item+= array_size;
|
||||
}
|
||||
|
||||
while (json_scan_next(&je) == 0 && je.state != JST_ARRAY_END)
|
||||
{
|
||||
switch (je.state)
|
||||
{
|
||||
case JST_VALUE:
|
||||
if (n_item == lp->n_item)
|
||||
if (n_item == corrected_n_item)
|
||||
{
|
||||
rem_start= (const char *) (je.s.c_str -
|
||||
(n_item ? je.sav_c_len : 0));
|
||||
@ -3359,7 +3408,7 @@ String *Item_func_json_keys::val_str(String *str)
|
||||
json_engine_t je;
|
||||
String *js= args[0]->val_json(&tmp_js);
|
||||
uint n_keys= 0;
|
||||
uint array_counters[JSON_DEPTH_LIMIT];
|
||||
int array_counters[JSON_DEPTH_LIMIT];
|
||||
|
||||
if ((args[0]->null_value))
|
||||
goto null_return;
|
||||
@ -3566,6 +3615,8 @@ String *Item_func_json_search::val_str(String *str)
|
||||
json_engine_t je;
|
||||
json_path_t p, sav_path;
|
||||
uint n_arg;
|
||||
int array_sizes[JSON_DEPTH_LIMIT];
|
||||
uint has_negative_path= 0;
|
||||
|
||||
if (args[0]->null_value || args[2]->null_value)
|
||||
goto null_return;
|
||||
@ -3591,6 +3642,7 @@ String *Item_func_json_search::val_str(String *str)
|
||||
goto null_return;
|
||||
}
|
||||
c_path->parsed= c_path->constant;
|
||||
has_negative_path|= c_path->p.types_used & JSON_PATH_NEGATIVE_INDEX;
|
||||
}
|
||||
if (args[n_arg]->null_value)
|
||||
goto null_return;
|
||||
@ -3601,9 +3653,14 @@ String *Item_func_json_search::val_str(String *str)
|
||||
|
||||
while (json_get_path_next(&je, &p) == 0)
|
||||
{
|
||||
if (has_negative_path && je.value_type == JSON_VALUE_ARRAY &&
|
||||
json_skip_array_and_count(&je, array_sizes + (p.last_step - p.steps)))
|
||||
goto js_error;
|
||||
|
||||
if (json_value_scalar(&je))
|
||||
{
|
||||
if ((arg_count < 5 || path_ok(paths, arg_count - 4, &p, je.value_type)) &&
|
||||
if ((arg_count < 5 ||
|
||||
path_ok(paths, arg_count - 4, &p, je.value_type, array_sizes)) &&
|
||||
compare_json_value_wild(&je, s_str) != 0)
|
||||
{
|
||||
++n_path_found;
|
||||
|
@ -312,7 +312,8 @@ handle_new_nested:
|
||||
|
||||
while (!json_get_path_next(&m_engine, &m_cur_path))
|
||||
{
|
||||
if (json_path_compare(&m_path, &m_cur_path, m_engine.value_type))
|
||||
if (json_path_compare(&m_path, &m_cur_path, m_engine.value_type,
|
||||
NULL))
|
||||
continue;
|
||||
/* path found. */
|
||||
++m_ordinality_counter;
|
||||
@ -501,7 +502,7 @@ int ha_json_table::fill_column_values(THD *thd, uchar * buf, uchar *pos)
|
||||
{
|
||||
json_engine_t je;
|
||||
json_path_step_t *cur_step;
|
||||
uint array_counters[JSON_DEPTH_LIMIT];
|
||||
int array_counters[JSON_DEPTH_LIMIT];
|
||||
int not_found;
|
||||
const uchar* node_start;
|
||||
const uchar* node_end;
|
||||
|
@ -985,6 +985,7 @@ enum json_path_chr_classes {
|
||||
P_LSQRB, /* [ */
|
||||
P_RSQRB, /* ] */
|
||||
P_POINT, /* . */
|
||||
P_NEG, /* hyphen (for negative index in path) */
|
||||
P_ZERO, /* 0 */
|
||||
P_DIGIT, /* 123456789 */
|
||||
P_L, /* l (for "lax") */
|
||||
@ -1006,7 +1007,7 @@ static enum json_path_chr_classes json_path_chr_map[128] = {
|
||||
P_ERR, P_ERR, P_ERR, P_ERR, P_ERR, P_ERR, P_ERR, P_ERR,
|
||||
|
||||
P_SPACE, P_ETC, P_QUOTE, P_ETC, P_USD, P_ETC, P_ETC, P_ETC,
|
||||
P_ETC, P_ETC, P_ASTER, P_ETC, P_ETC, P_ETC, P_POINT, P_ETC,
|
||||
P_ETC, P_ETC, P_ASTER, P_ETC, P_ETC, P_NEG, P_POINT, P_ETC,
|
||||
P_ZERO, P_DIGIT, P_DIGIT, P_DIGIT, P_DIGIT, P_DIGIT, P_DIGIT, P_DIGIT,
|
||||
P_DIGIT, P_DIGIT, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC, P_ETC,
|
||||
|
||||
@ -1029,6 +1030,7 @@ enum json_path_states {
|
||||
PS_AR, /* Parse array step. */
|
||||
PS_SAR, /* space after the '['. */
|
||||
PS_AWD, /* Array wildcard. */
|
||||
PS_NEG, /* Parse '-' (hyphen) */
|
||||
PS_Z, /* '0' (as an array item number). */
|
||||
PS_INT, /* Parse integer (as an array item number). */
|
||||
PS_AS, /* Space. */
|
||||
@ -1039,6 +1041,7 @@ enum json_path_states {
|
||||
PS_DWD, /* Double wildcard. */
|
||||
PS_KEYX, /* Key started with quote ("). */
|
||||
PS_KNMX, /* Parse quoted key name. */
|
||||
PS_LAST, /* Parse 'last' keyword */
|
||||
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. */
|
||||
@ -1054,67 +1057,72 @@ enum json_path_states {
|
||||
static int json_path_transitions[N_PATH_STATES][N_PATH_CLASSES]=
|
||||
{
|
||||
/*
|
||||
EOS $, * [ ] . 0
|
||||
EOS $, * [ ] . - 0
|
||||
1..9 L S SPACE \ " ETC
|
||||
ERR BAD
|
||||
*/
|
||||
/* GO */ { JE_EOS, PS_PT, 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_NOT_JSON_CHR, JE_BAD_CHR},
|
||||
/* 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,
|
||||
JE_SYN, PS_LAX, JE_SYN, PS_GO, JE_SYN, JE_SYN, JE_SYN,
|
||||
JE_NOT_JSON_CHR, JE_BAD_CHR},
|
||||
/* PT */ { PS_OK, JE_SYN, PS_AST, 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_SYN, JE_SYN,
|
||||
JE_NOT_JSON_CHR, JE_BAD_CHR},
|
||||
/* AR */ { JE_EOS, JE_SYN, PS_AWD, JE_SYN, JE_SYN, JE_SYN, PS_Z,
|
||||
PS_INT, JE_SYN, JE_SYN, PS_SAR, JE_SYN, JE_SYN, JE_SYN,
|
||||
/* AR */ { JE_EOS, JE_SYN, PS_AWD, JE_SYN, JE_SYN, JE_SYN, PS_NEG,PS_Z,
|
||||
PS_INT, PS_LAST, JE_SYN, PS_SAR, JE_SYN, JE_SYN, JE_SYN,
|
||||
JE_NOT_JSON_CHR, JE_BAD_CHR},
|
||||
/* SAR */ { JE_EOS, JE_SYN, PS_AWD, JE_SYN, PS_PT, JE_SYN, PS_Z,
|
||||
PS_INT, JE_SYN, JE_SYN, PS_SAR, JE_SYN, JE_SYN, JE_SYN,
|
||||
/* SAR */ { JE_EOS, JE_SYN, PS_AWD, JE_SYN, PS_PT, 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},
|
||||
/* AWD */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, PS_PT, JE_SYN, JE_SYN,
|
||||
/* AWD */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, PS_PT, 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},
|
||||
/* Z */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, PS_PT, JE_SYN, JE_SYN,
|
||||
/* 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,
|
||||
JE_NOT_JSON_CHR, JE_BAD_CHR},
|
||||
/* Z */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, PS_PT, 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},
|
||||
/* INT */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, PS_PT, JE_SYN, PS_INT,
|
||||
/* INT */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, PS_PT, 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},
|
||||
/* AS */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, PS_PT, JE_SYN, JE_SYN, JE_SYN,
|
||||
JE_SYN, JE_SYN, PS_AS, JE_SYN, JE_SYN, JE_SYN,
|
||||
JE_NOT_JSON_CHR, JE_BAD_CHR},
|
||||
/* 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,JE_SYN, PS_KNM,
|
||||
PS_KNM, PS_KNM, PS_KNM, PS_KNM, JE_SYN, PS_KEYX, PS_KNM,
|
||||
JE_NOT_JSON_CHR, JE_BAD_CHR},
|
||||
/* KNM */ { PS_KOK, PS_KNM, PS_AST, PS_EAR, PS_KNM, PS_EKY, PS_KNM,
|
||||
/* KNM */ { PS_KOK, PS_KNM, PS_AST, PS_EAR, PS_KNM, PS_EKY, JE_SYN,PS_KNM,
|
||||
PS_KNM, PS_KNM, PS_KNM, PS_KNM, PS_ESC, PS_KNM, PS_KNM,
|
||||
JE_NOT_JSON_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_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,
|
||||
/* 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_NOT_JSON_CHR, JE_BAD_CHR},
|
||||
/* DWD */ { JE_SYN, JE_SYN, PS_AST, PS_AR, JE_SYN, PS_KEY, JE_SYN, JE_SYN,
|
||||
/* 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_SYN, JE_SYN,
|
||||
JE_NOT_JSON_CHR, JE_BAD_CHR},
|
||||
/* KEYX*/ { JE_EOS, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX,
|
||||
/* KEYX*/ { JE_EOS, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, JE_SYN,PS_KNMX,
|
||||
PS_KNMX,PS_KNMX, PS_KNMX, PS_KNMX, PS_ESCX, PS_EKYX, PS_KNMX,
|
||||
JE_NOT_JSON_CHR, JE_BAD_CHR},
|
||||
/* KNMX */{ JE_EOS, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX,
|
||||
/* KNMX */{ JE_EOS, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX, JE_SYN,PS_KNMX,
|
||||
PS_KNMX, PS_KNMX, PS_KNMX, PS_KNMX,PS_ESCX, PS_EKYX, PS_KNMX,
|
||||
JE_NOT_JSON_CHR, JE_BAD_CHR},
|
||||
/* LAST */{ 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,
|
||||
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, is_negative_index= 0, is_last= 0, prev_value=0;
|
||||
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_WILD;
|
||||
@ -1153,8 +1161,20 @@ int json_path_setup(json_path_t *p,
|
||||
p->types_used|= JSON_PATH_WILD;
|
||||
continue;
|
||||
case PS_INT:
|
||||
p->last_step->n_item*= 10;
|
||||
p->last_step->n_item+= p->s.c_next - '0';
|
||||
if (is_last)
|
||||
{
|
||||
prev_value*= 10;
|
||||
prev_value-= p->s.c_next - '0';
|
||||
p->last_step->n_item= -1 + prev_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->last_step->n_item*= 10;
|
||||
if (is_negative_index)
|
||||
p->last_step->n_item-= p->s.c_next - '0';
|
||||
else
|
||||
p->last_step->n_item+= p->s.c_next - '0';
|
||||
}
|
||||
continue;
|
||||
case PS_EKYX:
|
||||
p->last_step->key_end= p->s.c_str - c_len;
|
||||
@ -1166,6 +1186,7 @@ int json_path_setup(json_path_t *p,
|
||||
/* fall through */
|
||||
case PS_KEY:
|
||||
p->last_step++;
|
||||
is_negative_index= 0;
|
||||
if (p->last_step - p->steps >= JSON_DEPTH_LIMIT)
|
||||
return p->s.error= JE_DEPTH;
|
||||
p->types_used|= p->last_step->type= JSON_PATH_KEY | double_wildcard;
|
||||
@ -1180,11 +1201,14 @@ int json_path_setup(json_path_t *p,
|
||||
/* fall through */
|
||||
case PS_AR:
|
||||
p->last_step++;
|
||||
is_last= 0;
|
||||
if (p->last_step - p->steps >= JSON_DEPTH_LIMIT)
|
||||
return p->s.error= JE_DEPTH;
|
||||
p->types_used|= p->last_step->type= JSON_PATH_ARRAY | double_wildcard;
|
||||
double_wildcard= JSON_PATH_KEY_NULL;
|
||||
p->last_step->n_item= 0;
|
||||
prev_value= 0;
|
||||
is_negative_index= 0;
|
||||
continue;
|
||||
case PS_ESC:
|
||||
if (json_handle_esc(&p->s))
|
||||
@ -1203,6 +1227,19 @@ int json_path_setup(json_path_t *p,
|
||||
case PS_DWD:
|
||||
double_wildcard= JSON_PATH_DOUBLE_WILD;
|
||||
continue;
|
||||
case PS_NEG:
|
||||
p->types_used|= JSON_PATH_NEGATIVE_INDEX;
|
||||
is_negative_index= 1;
|
||||
if (is_last)
|
||||
p->last_step->n_item= 0;
|
||||
continue;
|
||||
case PS_LAST:
|
||||
if ((p->s.error= skip_string_verbatim(&p->s, "ast")))
|
||||
return 1;
|
||||
p->types_used|= JSON_PATH_NEGATIVE_INDEX;
|
||||
is_last= 1;
|
||||
p->last_step->n_item= -1;
|
||||
continue;
|
||||
};
|
||||
} while (state != PS_OK);
|
||||
|
||||
@ -1242,6 +1279,15 @@ int json_skip_level_and_count(json_engine_t *j, int *n_items_skipped)
|
||||
}
|
||||
|
||||
|
||||
int json_skip_array_and_count(json_engine_t *je, int *n_items)
|
||||
{
|
||||
json_engine_t j= *je;
|
||||
*n_items= 0;
|
||||
|
||||
return json_skip_level_and_count(&j, n_items);
|
||||
}
|
||||
|
||||
|
||||
int json_skip_key(json_engine_t *j)
|
||||
{
|
||||
if (json_read_value(j))
|
||||
@ -1254,7 +1300,7 @@ int json_skip_key(json_engine_t *j)
|
||||
}
|
||||
|
||||
|
||||
#define SKIPPED_STEP_MARK ((uint) ~0)
|
||||
#define SKIPPED_STEP_MARK ((int) ~0)
|
||||
|
||||
/*
|
||||
Current step of the patch matches the JSON construction.
|
||||
@ -1262,7 +1308,7 @@ int json_skip_key(json_engine_t *j)
|
||||
step of the path.
|
||||
*/
|
||||
static int handle_match(json_engine_t *je, json_path_t *p,
|
||||
json_path_step_t **p_cur_step, uint *array_counters)
|
||||
json_path_step_t **p_cur_step, int *array_counters)
|
||||
{
|
||||
json_path_step_t *next_step= *p_cur_step + 1;
|
||||
|
||||
@ -1299,13 +1345,28 @@ static int handle_match(json_engine_t *je, json_path_t *p,
|
||||
} while (next_step->type == JSON_PATH_ARRAY && next_step->n_item == 0);
|
||||
}
|
||||
|
||||
|
||||
array_counters[next_step - p->steps]= 0;
|
||||
|
||||
if ((int) je->value_type !=
|
||||
(int) (next_step->type & JSON_PATH_KEY_OR_ARRAY))
|
||||
return json_skip_level(je);
|
||||
|
||||
if (next_step->type == JSON_PATH_ARRAY)
|
||||
{
|
||||
int array_size;
|
||||
if (next_step->n_item >= 0)
|
||||
array_size= 0;
|
||||
else
|
||||
{
|
||||
json_engine_t j2= *je;
|
||||
if (json_skip_array_and_count(&j2, &array_size))
|
||||
{
|
||||
*je= j2;
|
||||
return 1;
|
||||
}
|
||||
array_size= -array_size;
|
||||
}
|
||||
array_counters[next_step - p->steps]= array_size;
|
||||
}
|
||||
|
||||
*p_cur_step= next_step;
|
||||
return 0;
|
||||
}
|
||||
@ -1330,7 +1391,7 @@ int json_key_matches(json_engine_t *je, json_string_t *k)
|
||||
|
||||
int json_find_path(json_engine_t *je,
|
||||
json_path_t *p, json_path_step_t **p_cur_step,
|
||||
uint *array_counters)
|
||||
int *array_counters)
|
||||
{
|
||||
json_string_t key_name;
|
||||
|
||||
@ -1773,9 +1834,10 @@ int json_get_path_next(json_engine_t *je, json_path_t *p)
|
||||
int json_path_parts_compare(
|
||||
const json_path_step_t *a, const json_path_step_t *a_end,
|
||||
const json_path_step_t *b, const json_path_step_t *b_end,
|
||||
enum json_value_types vt)
|
||||
enum json_value_types vt, const int *array_sizes)
|
||||
{
|
||||
int res, res2;
|
||||
const json_path_step_t *temp_b= b;
|
||||
|
||||
while (a <= a_end)
|
||||
{
|
||||
@ -1798,7 +1860,9 @@ int json_path_parts_compare(
|
||||
{
|
||||
if (b->type & JSON_PATH_ARRAY)
|
||||
{
|
||||
if ((a->type & JSON_PATH_WILD) || a->n_item == b->n_item)
|
||||
if ((a->type & JSON_PATH_WILD) ||
|
||||
(a->n_item >= 0 ? a->n_item == b->n_item :
|
||||
a->n_item == b->n_item - array_sizes[b-temp_b]))
|
||||
goto step_fits;
|
||||
goto step_failed;
|
||||
}
|
||||
@ -1833,11 +1897,13 @@ step_fits:
|
||||
}
|
||||
|
||||
/* Double wild handling needs recursions. */
|
||||
res= json_path_parts_compare(a+1, a_end, b, b_end, vt);
|
||||
res= json_path_parts_compare(a+1, a_end, b, b_end, vt,
|
||||
array_sizes + (b - temp_b));
|
||||
if (res == 0)
|
||||
return 0;
|
||||
|
||||
res2= json_path_parts_compare(a, a_end, b, b_end, vt);
|
||||
res2= json_path_parts_compare(a, a_end, b, b_end, vt,
|
||||
array_sizes + (b - temp_b));
|
||||
|
||||
return (res2 >= 0) ? res2 : res;
|
||||
|
||||
@ -1849,11 +1915,13 @@ step_fits_autowrap:
|
||||
}
|
||||
|
||||
/* Double wild handling needs recursions. */
|
||||
res= json_path_parts_compare(a+1, a_end, b+1, b_end, vt);
|
||||
res= json_path_parts_compare(a+1, a_end, b+1, b_end, vt,
|
||||
array_sizes + (b - temp_b));
|
||||
if (res == 0)
|
||||
return 0;
|
||||
|
||||
res2= json_path_parts_compare(a, a_end, b+1, b_end, vt);
|
||||
res2= json_path_parts_compare(a, a_end, b+1, b_end, vt,
|
||||
array_sizes + (b - temp_b));
|
||||
|
||||
return (res2 >= 0) ? res2 : res;
|
||||
|
||||
@ -1864,10 +1932,10 @@ step_fits_autowrap:
|
||||
|
||||
|
||||
int json_path_compare(const json_path_t *a, const json_path_t *b,
|
||||
enum json_value_types vt)
|
||||
enum json_value_types vt, const int *array_size)
|
||||
{
|
||||
return json_path_parts_compare(a->steps+1, a->last_step,
|
||||
b->steps+1, b->last_step, vt);
|
||||
b->steps+1, b->last_step, vt, array_size);
|
||||
}
|
||||
|
||||
|
||||
|
@ -140,7 +140,7 @@ test_search()
|
||||
json_path_t p;
|
||||
json_path_step_t *cur_step;
|
||||
int n_matches, scal_values;
|
||||
uint array_counters[JSON_DEPTH_LIMIT];
|
||||
int array_counters[JSON_DEPTH_LIMIT];
|
||||
|
||||
if (json_scan_start(&je, ci, s_e(fj0)) ||
|
||||
json_path_setup(&p, ci, s_e(fp0)))
|
||||
|
Loading…
x
Reference in New Issue
Block a user