diff options
author | Rucha Deodhar <rucha.deodhar@mariadb.com> | 2021-11-22 22:59:30 +0530 |
---|---|---|
committer | Rucha Deodhar <rucha.deodhar@mariadb.com> | 2022-04-13 21:16:32 +0530 |
commit | dfcbb30a92c2f1d33ceefb56a1d3fa13f8d0ce67 (patch) | |
tree | 6014f93bf6585a548054bf3a06e3d26b86b17e47 | |
parent | e98013cb5c3695729114a56e1181b23c69801ae0 (diff) | |
download | mariadb-git-dfcbb30a92c2f1d33ceefb56a1d3fa13f8d0ce67.tar.gz |
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.
-rw-r--r-- | include/json_lib.h | 18 | ||||
-rw-r--r-- | mysql-test/main/func_json.result | 262 | ||||
-rw-r--r-- | mysql-test/main/func_json.test | 222 | ||||
-rw-r--r-- | sql/item_jsonfunc.cc | 107 | ||||
-rw-r--r-- | sql/json_table.cc | 5 | ||||
-rw-r--r-- | strings/json_lib.c | 142 | ||||
-rw-r--r-- | unittest/json_lib/json_lib-t.c | 2 |
7 files changed, 682 insertions, 76 deletions
diff --git a/include/json_lib.h b/include/json_lib.h index 2d85a7653f2..41ab88b06ce 100644 --- a/include/json_lib.h +++ b/include/json_lib.h @@ -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 diff --git a/mysql-test/main/func_json.result b/mysql-test/main/func_json.result index 206547c7d7a..5bcd90f3410 100644 --- a/mysql-test/main/func_json.result +++ b/mysql-test/main/func_json.result @@ -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 +# diff --git a/mysql-test/main/func_json.test b/mysql-test/main/func_json.test index 1e7d29dd350..ea7358f4563 100644 --- a/mysql-test/main/func_json.test +++ b/mysql-test/main/func_json.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 # diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 561bc529ce4..e7d4e247999 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -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; diff --git a/sql/json_table.cc b/sql/json_table.cc index cb3787e4f25..e48646ace3c 100644 --- a/sql/json_table.cc +++ b/sql/json_table.cc @@ -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; diff --git a/strings/json_lib.c b/strings/json_lib.c index b5b6dd6516d..526a55b7179 100644 --- a/strings/json_lib.c +++ b/strings/json_lib.c @@ -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); } diff --git a/unittest/json_lib/json_lib-t.c b/unittest/json_lib/json_lib-t.c index 378ebe201f5..c5a6df54e1d 100644 --- a/unittest/json_lib/json_lib-t.c +++ b/unittest/json_lib/json_lib-t.c @@ -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))) |