MDEV-37913: disable_index_merge_plans causes SELECT data loss when more than 100 ORs

(Variant 2)
SEL_TREE* tree_or(SEL_TREE *X, SEL_TREE *Y) tries to conserve memory by
reusing object *X for the return value when possible.

MDEV-34620 has added logic to disable construction of index_merge plans
for N-way ORs with large N. That logic interfered with object reuse logic:

for the parameters of:
X = SEL_TREE{ trees=[key1_treeA, key2_treeB]}
Y = SEL_TREE{ trees=[key1_treeC]}

we would decide to reuse object X.
For key1, we would produce key_or(key1_treeA, key1_treeC)
but key2_treeB would be just left there.
Then, we would construct a range scan from key2_treeB.

Fixed by moving the "disable building index_merge plans" logic into a
location where it would not interfere with object reuse logic.
This commit is contained in:
Sergei Petrunia 2025-10-24 22:09:45 +03:00 committed by Sergei Golubchik
parent 292bab3565
commit 240b4e83e0
4 changed files with 75 additions and 2 deletions

View File

@ -3736,6 +3736,27 @@ DROP TABLE t1;
#
# End of 10.5 tests
#
#
# MDEV-37913: disable_index_merge_plans causes SELECT data loss when more than 100 ORs
#
CREATE TABLE t1 (
id int primary key,
key1 int,
index(key1)
);
INSERT INTO t1 VALUES
(1, 1),
(2, 1),
(3, 2);
$query;
id key1
1 1
2 1
3 2
drop table t1;
#
# End of 10.11 tests
#
set global innodb_stats_persistent= @innodb_stats_persistent_save;
set global innodb_stats_persistent_sample_pages=
@innodb_stats_persistent_sample_pages_save;

View File

@ -2533,6 +2533,32 @@ DROP TABLE t1;
--echo # End of 10.5 tests
--echo #
--echo #
--echo # MDEV-37913: disable_index_merge_plans causes SELECT data loss when more than 100 ORs
--echo #
CREATE TABLE t1 (
id int primary key,
key1 int,
index(key1)
);
INSERT INTO t1 VALUES
(1, 1),
(2, 1),
(3, 2);
let $query=`
select concat('select * from t1 where (key1 = 2 AND id = 3) ',
REPEAT(' OR (key1 = 1)', 100))
`;
evalp $query;
drop table t1;
--echo #
--echo # End of 10.11 tests
--echo #
set global innodb_stats_persistent= @innodb_stats_persistent_save;
set global innodb_stats_persistent_sample_pages=
@innodb_stats_persistent_sample_pages_save;

View File

@ -3725,6 +3725,27 @@ DROP TABLE t1;
#
# End of 10.5 tests
#
#
# MDEV-37913: disable_index_merge_plans causes SELECT data loss when more than 100 ORs
#
CREATE TABLE t1 (
id int primary key,
key1 int,
index(key1)
);
INSERT INTO t1 VALUES
(1, 1),
(2, 1),
(3, 2);
$query;
id key1
1 1
2 1
3 2
drop table t1;
#
# End of 10.11 tests
#
set global innodb_stats_persistent= @innodb_stats_persistent_save;
set global innodb_stats_persistent_sample_pages=
@innodb_stats_persistent_sample_pages_save;

View File

@ -9974,8 +9974,6 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
{
bool must_be_ored= sel_trees_must_be_ored(param, tree1, tree2, ored_keys);
no_imerge_from_ranges= must_be_ored;
if (param->disable_index_merge_plans)
no_imerge_from_ranges= true;
if (no_imerge_from_ranges && no_merges1 && no_merges2)
{
@ -10025,6 +10023,13 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
DBUG_RETURN(result);
}
/*
Ok, the result now has the ranges that one gets for (RT1 OR RT2).
If construction of SEL_IMERGE is disabled, stop right here.
*/
if (param->disable_index_merge_plans)
DBUG_RETURN(result);
SEL_IMERGE *imerge_from_ranges;
if (!(imerge_from_ranges= new SEL_IMERGE()))
result= NULL;