summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/json_lib.h24
-rw-r--r--mysql-test/r/func_json.result6
-rw-r--r--mysql-test/t/func_json.test2
-rw-r--r--sql/item_jsonfunc.cc5
-rw-r--r--strings/json_lib.c23
5 files changed, 36 insertions, 24 deletions
diff --git a/include/json_lib.h b/include/json_lib.h
index b26d865fd36..ce7f27317bc 100644
--- a/include/json_lib.h
+++ b/include/json_lib.h
@@ -295,13 +295,27 @@ int json_read_value(json_engine_t *j);
int json_skip_key(json_engine_t *j);
+typedef const int *json_level_t;
+
+/*
+ json_skip_to_level() makes parser quickly get out of nested
+ loops and arrays. It is used when we're not interested in what is
+ there in the rest of these structures.
+ The 'level' should be remembered in advance.
+ json_level_t level= json_get_level(j);
+ .... // getting into the nested JSON structures
+ json_skip_to_level(j, level);
+*/
+#define json_get_level(j) (j->stack_p)
+
+int json_skip_to_level(json_engine_t *j, json_level_t level);
+
/*
- json_skip_level() makes parser quickly skip the JSON content
- to the end of the current object or array.
- It is used when we're not interested in the rest of an array
- or the rest of the keys of an object.
+ json_skip_level() works as above with just current structre.
+ So it gets to the end of the current JSON array or object.
*/
-int json_skip_level(json_engine_t *j);
+#define json_skip_level(json_engine) \
+ json_skip_to_level((json_engine), (json_engine)->stack_p)
#define json_skip_array_item json_skip_key
diff --git a/mysql-test/r/func_json.result b/mysql-test/r/func_json.result
index 99e1e95372f..6466b1a2dc2 100644
--- a/mysql-test/r/func_json.result
+++ b/mysql-test/r/func_json.result
@@ -143,6 +143,12 @@ json_contains('[1, {"a":1}]', '{}')
select json_contains('[1, {"a":1}]', '{"a":1}');
json_contains('[1, {"a":1}]', '{"a":1}')
1
+select json_contains('[{"abc":"def", "def":"abc"}]', '["foo","bar"]');
+json_contains('[{"abc":"def", "def":"abc"}]', '["foo","bar"]')
+0
+select json_contains('[{"abc":"def", "def":"abc"}, "bar"]', '["bar", {}]');
+json_contains('[{"abc":"def", "def":"abc"}, "bar"]', '["bar", {}]')
+1
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[1]");
json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[1]")
1
diff --git a/mysql-test/t/func_json.test b/mysql-test/t/func_json.test
index 8685d82b635..8e36a3ed18b 100644
--- a/mysql-test/t/func_json.test
+++ b/mysql-test/t/func_json.test
@@ -53,6 +53,8 @@ select json_contains('{"b":[1,2], "a":1}', '{"a":1, "b":2}');
select json_contains('{"a":1}', '{}');
select json_contains('[1, {"a":1}]', '{}');
select json_contains('[1, {"a":1}]', '{"a":1}');
+select json_contains('[{"abc":"def", "def":"abc"}]', '["foo","bar"]');
+select json_contains('[{"abc":"def", "def":"abc"}, "bar"]', '["bar", {}]');
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[1]");
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[10]");
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc
index 7bf2283dd53..9535feb0d8e 100644
--- a/sql/item_jsonfunc.cc
+++ b/sql/item_jsonfunc.cc
@@ -796,17 +796,20 @@ static int check_contains(json_engine_t *js, json_engine_t *value)
{
while (json_scan_next(js) == 0 && js->state != JST_ARRAY_END)
{
+ json_level_t c_level;
DBUG_ASSERT(js->state == JST_VALUE);
if (json_read_value(js))
return FALSE;
+ c_level= json_value_scalar(js) ? NULL : json_get_level(js);
if (check_contains(js, value))
{
if (json_skip_level(js))
return FALSE;
return TRUE;
}
- if (value->s.error || js->s.error)
+ if (value->s.error || js->s.error ||
+ (c_level && json_skip_to_level(js, c_level)))
return FALSE;
}
return FALSE;
diff --git a/strings/json_lib.c b/strings/json_lib.c
index acca7eb0739..a93200cd4dd 100644
--- a/strings/json_lib.c
+++ b/strings/json_lib.c
@@ -1158,25 +1158,12 @@ int json_path_setup(json_path_t *p,
}
-int json_skip_level(json_engine_t *j)
+int json_skip_to_level(json_engine_t *j, json_level_t level)
{
- int ct= 0;
-
- while (json_scan_next(j) == 0)
- {
- switch (j->state) {
- case JST_OBJ_START:
- case JST_ARRAY_START:
- ct++;
- break;
- case JST_OBJ_END:
- case JST_ARRAY_END:
- if (ct == 0)
- return 0;
- ct--;
- break;
- }
- }
+ do {
+ if (j->stack_p < level)
+ return 0;
+ } while (json_scan_next(j) == 0);
return 1;
}