1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

MDEV-41067: Fix JSON_OVERLAPS for nested arrays

Problem: JSON_OVERLAPS treats unequal nested arrays as equal when only
one parser reaches the array end. Requiring both ends also exposes a
cleanup issue: scanning ']' moves stack_p to the parent, so skipping
the current level consumes parent elements. This misses the common [2]
in [[1],[2]] and [[],[2]], and can skip unequal recursive elements.

Fix: Require both parsers to reach JST_ARRAY_END. Remember their array
levels before comparing and skip to those saved levels after completed
comparisons and mismatches, preserving parent siblings. Explain why the
saved levels are needed. Add regression coverage for both argument
orders, unequal lengths, empty arrays, recursive comparisons, type
mismatches, array order and a later common object member.
This commit is contained in:
DerZc
2026-09-21 12:35:21 +08:00
committed by Georgi Kodinov
parent d0164223c5
commit 6e62fd0112
3 changed files with 77 additions and 5 deletions

View File

@@ -2712,6 +2712,47 @@ SELECT JSON_OVERLAPS(@json1, @json2);
JSON_OVERLAPS(@json1, @json2)
0
#
# MDEV-41067: Empty and nonempty nested JSON arrays
#
SELECT JSON_OVERLAPS('[[1]]', '[[]]') AS forward,
JSON_OVERLAPS('[[]]', '[[1]]') AS reverse;
forward reverse
0 0
SELECT JSON_OVERLAPS('[[1],[2]]', '[[],[2]]') AS forward,
JSON_OVERLAPS('[[],[2]]', '[[1],[2]]') AS reverse;
forward reverse
1 1
SELECT JSON_OVERLAPS('[[1]]', '[[1,2]]') AS forward,
JSON_OVERLAPS('[[1,2]]', '[[1]]') AS reverse;
forward reverse
0 0
SELECT JSON_OVERLAPS('[[]]', '[[]]') AS r;
r
1
SELECT JSON_OVERLAPS('[[[1],2]]', '[[[1],2]]') AS r;
r
1
SELECT JSON_OVERLAPS('[[[1],2]]', '[[[1],3]]') AS forward,
JSON_OVERLAPS('[[[1],3]]', '[[[1],2]]') AS reverse;
forward reverse
0 0
SELECT JSON_OVERLAPS('[[[],1],[4]]', '[[{},1],[4]]') AS forward,
JSON_OVERLAPS('[[{},1],[4]]', '[[[],1],[4]]') AS reverse;
forward reverse
1 1
SELECT JSON_OVERLAPS('[[true]]', '[[1]]') AS forward,
JSON_OVERLAPS('[[1]]', '[[true]]') AS reverse;
forward reverse
0 0
SELECT JSON_OVERLAPS('[[1,2]]', '[[2,1]]') AS forward,
JSON_OVERLAPS('[[2,1]]', '[[1,2]]') AS reverse;
forward reverse
0 0
SELECT JSON_OVERLAPS('{"a":[1],"b":2}', '{"a":[],"b":2}') AS forward,
JSON_OVERLAPS('{"a":[],"b":2}', '{"a":[1],"b":2}') AS reverse;
forward reverse
1 1
#
# MDEV-30304: Json Range only affects first row of the result set
#
CREATE TABLE t1 ( j JSON );

View File

@@ -1907,6 +1907,28 @@ SET @json2 = '{"kk":{"k1":"v1","k2":"v2","k3":"v3"}}';
SELECT JSON_OVERLAPS(@json2, @json1);
SELECT JSON_OVERLAPS(@json1, @json2);
--echo #
--echo # MDEV-41067: Empty and nonempty nested JSON arrays
--echo #
SELECT JSON_OVERLAPS('[[1]]', '[[]]') AS forward,
JSON_OVERLAPS('[[]]', '[[1]]') AS reverse;
SELECT JSON_OVERLAPS('[[1],[2]]', '[[],[2]]') AS forward,
JSON_OVERLAPS('[[],[2]]', '[[1],[2]]') AS reverse;
SELECT JSON_OVERLAPS('[[1]]', '[[1,2]]') AS forward,
JSON_OVERLAPS('[[1,2]]', '[[1]]') AS reverse;
SELECT JSON_OVERLAPS('[[]]', '[[]]') AS r;
SELECT JSON_OVERLAPS('[[[1],2]]', '[[[1],2]]') AS r;
SELECT JSON_OVERLAPS('[[[1],2]]', '[[[1],3]]') AS forward,
JSON_OVERLAPS('[[[1],3]]', '[[[1],2]]') AS reverse;
SELECT JSON_OVERLAPS('[[[],1],[4]]', '[[{},1],[4]]') AS forward,
JSON_OVERLAPS('[[{},1],[4]]', '[[[],1],[4]]') AS reverse;
SELECT JSON_OVERLAPS('[[true]]', '[[1]]') AS forward,
JSON_OVERLAPS('[[1]]', '[[true]]') AS reverse;
SELECT JSON_OVERLAPS('[[1,2]]', '[[2,1]]') AS forward,
JSON_OVERLAPS('[[2,1]]', '[[1,2]]') AS reverse;
SELECT JSON_OVERLAPS('{"a":[1],"b":2}', '{"a":[],"b":2}') AS forward,
JSON_OVERLAPS('{"a":[],"b":2}', '{"a":[1],"b":2}') AS reverse;
--echo #
--echo # MDEV-30304: Json Range only affects first row of the result set
--echo #

View File

@@ -4791,6 +4791,13 @@ static bool json_compare_arr_and_obj(json_engine_t *js, json_engine_t *value)
bool json_compare_arrays_in_order(json_engine_t *js, json_engine_t *value)
{
/*
Remember the array levels for json_skip_to_level(): after ']' is
scanned, stack_p already points to the parent, where
json_skip_level() could incorrectly consume parent elements.
*/
const int js_level= json_get_level(js);
const int value_level= json_get_level(value);
bool res= false;
while (json_scan_next(js) == 0 && json_scan_next(value) == 0 &&
js->state == JST_VALUE && value->state == JST_VALUE)
@@ -4799,19 +4806,21 @@ bool json_compare_arrays_in_order(json_engine_t *js, json_engine_t *value)
return FALSE;
if (js->value_type != value->value_type)
{
json_skip_current_level(js, value);
json_skip_to_level(js, js_level);
json_skip_to_level(value, value_level);
return FALSE;
}
res= check_overlaps(js, value, true);
if (!res)
{
json_skip_current_level(js, value);
json_skip_to_level(js, js_level);
json_skip_to_level(value, value_level);
return FALSE;
}
}
res= (value->state == JST_ARRAY_END || value->state == JST_OBJ_END ?
TRUE : FALSE);
json_skip_current_level(js, value);
res= (js->state == JST_ARRAY_END && value->state == JST_ARRAY_END);
json_skip_to_level(js, js_level);
json_skip_to_level(value, value_level);
return res;
}