Skip to content

Commit 5100b20

Browse files
committed
MDEV-26047: MariaDB server crash at Item_subselect::init_expr_cache_tracker
The cause of crash: remove_redundant_subquery_clauses() removes redundant item expressions. The primary goal of this is to remove the subquery items. The removal process unlinks the subquery from SELECT_LEX tree, but does not remove it from SELECT_LEX:::ref_pointer_array or from JOIN::all_fields. Then, setup_subquery_caches() tries to wrap the subquery item in an expression cache, which fails, the first reason for failure being that the item doesn't have a query plan. Solution: do not wrap eliminated items with expression cache. (also added an assert to check that we do not attempt to execute them). This may look like an incomplete fix: why don't we remove any mention of eliminated item everywhere? The difficulties here are: * items can be "un-removed" (see set_fake_select_as_master_processor) * it's difficult to remove an element from ref_pointer_array: Item_ref objects refer to elements of that array, so one can't shift elements in it. Replacing eliminated subselect with a dummy Item doesn't look like a good idea, either.
1 parent 9b2d366 commit 5100b20

File tree

3 files changed

+71
-0
lines changed

3 files changed

+71
-0
lines changed

mysql-test/r/subselect_innodb.result

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,3 +629,35 @@ a b
629629
2019-03-10 02:55:05 2019-03-10 02:55:05
630630
DROP TABLE t1,t2;
631631
set character_set_connection=@save_character_set_connection;
632+
#
633+
# MDEV-26047: MariaDB server crash at Item_subselect::init_expr_cache_tracker
634+
#
635+
CREATE TABLE t1 (a int) engine=innodb;
636+
SELECT 1 IN (
637+
SELECT NULL
638+
FROM t1
639+
WHERE
640+
a IS NOT NULL
641+
GROUP BY
642+
(SELECT NULL from dual WHERE a = 1)
643+
);
644+
1 IN (
645+
SELECT NULL
646+
FROM t1
647+
WHERE
648+
a IS NOT NULL
649+
GROUP BY
650+
(SELECT NULL from dual WHERE a = 1)
651+
)
652+
0
653+
drop table t1;
654+
# Testcase from MDEV-26164
655+
create table t1(a int);
656+
# Disable the warning as it includes current time and changes for every test run.
657+
select 1 from t1 where not exists
658+
(
659+
select 1 from t1 where binary current_time()
660+
group by (select a),(select 1)
661+
);
662+
1
663+
drop table t1;

mysql-test/t/subselect_innodb.test

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,3 +627,31 @@ SELECT * FROM t1 WHERE (SELECT 1,CONCAT(a) FROM t1) = (SELECT 1,CONCAT(a) FROM t
627627
DROP TABLE t1,t2;
628628

629629
set character_set_connection=@save_character_set_connection;
630+
631+
--echo #
632+
--echo # MDEV-26047: MariaDB server crash at Item_subselect::init_expr_cache_tracker
633+
--echo #
634+
CREATE TABLE t1 (a int) engine=innodb;
635+
636+
SELECT 1 IN (
637+
SELECT NULL
638+
FROM t1
639+
WHERE
640+
a IS NOT NULL
641+
GROUP BY
642+
(SELECT NULL from dual WHERE a = 1)
643+
);
644+
drop table t1;
645+
646+
--echo # Testcase from MDEV-26164
647+
create table t1(a int);
648+
--echo # Disable the warning as it includes current time and changes for every test run.
649+
--disable_warnings
650+
select 1 from t1 where not exists
651+
(
652+
select 1 from t1 where binary current_time()
653+
group by (select a),(select 1)
654+
);
655+
--enable_warnings
656+
drop table t1;
657+

sql/item_subselect.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,7 @@ bool Item_subselect::exec()
752752

753753
DBUG_ENTER("Item_subselect::exec");
754754
DBUG_ASSERT(fixed);
755+
DBUG_ASSERT(!eliminated);
755756

756757
/*
757758
Do not execute subselect in case of a fatal error
@@ -1313,6 +1314,16 @@ Item* Item_singlerow_subselect::expr_cache_insert_transformer(THD *tmp_thd,
13131314

13141315
DBUG_ASSERT(thd == tmp_thd);
13151316

1317+
/*
1318+
Do not create subquery cache if the subquery was eliminated.
1319+
The optimizer may eliminate subquery items (see
1320+
eliminate_subselect_processor). However it does not update
1321+
all query's data structures, so the eliminated item may be
1322+
still reachable.
1323+
*/
1324+
if (eliminated)
1325+
DBUG_RETURN(this);
1326+
13161327
if (expr_cache)
13171328
DBUG_RETURN(expr_cache);
13181329

0 commit comments

Comments
 (0)