Skip to content

Commit e5377be

Browse files
author
Alexey Botchkov
committed
MDEV-11562 Assertion `js->state == JST_VALUE' failed in check_contains(json_engine_t*, json_engine_t*).
check_contains() fixed. When an item of an array is a complex structure, it can be half-read after the end of the recursive check_contains() call. So we just manually get to it's ending.
1 parent 8938031 commit e5377be

File tree

5 files changed

+36
-24
lines changed

5 files changed

+36
-24
lines changed

include/json_lib.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -295,13 +295,27 @@ int json_read_value(json_engine_t *j);
295295
int json_skip_key(json_engine_t *j);
296296

297297

298+
typedef const int *json_level_t;
299+
300+
/*
301+
json_skip_to_level() makes parser quickly get out of nested
302+
loops and arrays. It is used when we're not interested in what is
303+
there in the rest of these structures.
304+
The 'level' should be remembered in advance.
305+
json_level_t level= json_get_level(j);
306+
.... // getting into the nested JSON structures
307+
json_skip_to_level(j, level);
308+
*/
309+
#define json_get_level(j) (j->stack_p)
310+
311+
int json_skip_to_level(json_engine_t *j, json_level_t level);
312+
298313
/*
299-
json_skip_level() makes parser quickly skip the JSON content
300-
to the end of the current object or array.
301-
It is used when we're not interested in the rest of an array
302-
or the rest of the keys of an object.
314+
json_skip_level() works as above with just current structre.
315+
So it gets to the end of the current JSON array or object.
303316
*/
304-
int json_skip_level(json_engine_t *j);
317+
#define json_skip_level(json_engine) \
318+
json_skip_to_level((json_engine), (json_engine)->stack_p)
305319

306320

307321
#define json_skip_array_item json_skip_key

mysql-test/r/func_json.result

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,12 @@ json_contains('[1, {"a":1}]', '{}')
143143
select json_contains('[1, {"a":1}]', '{"a":1}');
144144
json_contains('[1, {"a":1}]', '{"a":1}')
145145
1
146+
select json_contains('[{"abc":"def", "def":"abc"}]', '["foo","bar"]');
147+
json_contains('[{"abc":"def", "def":"abc"}]', '["foo","bar"]')
148+
0
149+
select json_contains('[{"abc":"def", "def":"abc"}, "bar"]', '["bar", {}]');
150+
json_contains('[{"abc":"def", "def":"abc"}, "bar"]', '["bar", {}]')
151+
1
146152
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[1]");
147153
json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[1]")
148154
1

mysql-test/t/func_json.test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ select json_contains('{"b":[1,2], "a":1}', '{"a":1, "b":2}');
5353
select json_contains('{"a":1}', '{}');
5454
select json_contains('[1, {"a":1}]', '{}');
5555
select json_contains('[1, {"a":1}]', '{"a":1}');
56+
select json_contains('[{"abc":"def", "def":"abc"}]', '["foo","bar"]');
57+
select json_contains('[{"abc":"def", "def":"abc"}, "bar"]', '["bar", {}]');
5658

5759
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[1]");
5860
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[10]");

sql/item_jsonfunc.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -796,17 +796,20 @@ static int check_contains(json_engine_t *js, json_engine_t *value)
796796
{
797797
while (json_scan_next(js) == 0 && js->state != JST_ARRAY_END)
798798
{
799+
json_level_t c_level;
799800
DBUG_ASSERT(js->state == JST_VALUE);
800801
if (json_read_value(js))
801802
return FALSE;
802803

804+
c_level= json_value_scalar(js) ? NULL : json_get_level(js);
803805
if (check_contains(js, value))
804806
{
805807
if (json_skip_level(js))
806808
return FALSE;
807809
return TRUE;
808810
}
809-
if (value->s.error || js->s.error)
811+
if (value->s.error || js->s.error ||
812+
(c_level && json_skip_to_level(js, c_level)))
810813
return FALSE;
811814
}
812815
return FALSE;

strings/json_lib.c

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,25 +1158,12 @@ int json_path_setup(json_path_t *p,
11581158
}
11591159

11601160

1161-
int json_skip_level(json_engine_t *j)
1161+
int json_skip_to_level(json_engine_t *j, json_level_t level)
11621162
{
1163-
int ct= 0;
1164-
1165-
while (json_scan_next(j) == 0)
1166-
{
1167-
switch (j->state) {
1168-
case JST_OBJ_START:
1169-
case JST_ARRAY_START:
1170-
ct++;
1171-
break;
1172-
case JST_OBJ_END:
1173-
case JST_ARRAY_END:
1174-
if (ct == 0)
1175-
return 0;
1176-
ct--;
1177-
break;
1178-
}
1179-
}
1163+
do {
1164+
if (j->stack_p < level)
1165+
return 0;
1166+
} while (json_scan_next(j) == 0);
11801167

11811168
return 1;
11821169
}

0 commit comments

Comments
 (0)