[Commits] c01ee954bf3: MDEV-26047: MariaDB server crash at Item_subselect::init_expr_cache_tracker
revision-id: c01ee954bf3b10fef85af7b8c77d319ff7bd6b61 (mariadb-10.2.43-72-gc01ee954bf3) parent(s): 3c209bfc040ddfc41ece8357d772547432353fd2 author: Sergei Petrunia committer: Sergei Petrunia timestamp: 2022-04-22 20:26:14 +0300 message: 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. --- mysql-test/r/subselect_innodb.result | 32 ++++++++++++++++++++++++++++++++ mysql-test/t/subselect_innodb.test | 28 ++++++++++++++++++++++++++++ sql/item_subselect.cc | 11 +++++++++++ 3 files changed, 71 insertions(+) diff --git a/mysql-test/r/subselect_innodb.result b/mysql-test/r/subselect_innodb.result index 4eaea099451..4796245f8e3 100644 --- a/mysql-test/r/subselect_innodb.result +++ b/mysql-test/r/subselect_innodb.result @@ -629,3 +629,35 @@ a b 2019-03-10 02:55:05 2019-03-10 02:55:05 DROP TABLE t1,t2; set character_set_connection=@save_character_set_connection; +# +# MDEV-26047: MariaDB server crash at Item_subselect::init_expr_cache_tracker +# +CREATE TABLE t1 (a int) engine=innodb; +SELECT 1 IN ( +SELECT NULL +FROM t1 +WHERE +a IS NOT NULL +GROUP BY +(SELECT NULL from dual WHERE a = 1) +); +1 IN ( +SELECT NULL +FROM t1 +WHERE +a IS NOT NULL +GROUP BY +(SELECT NULL from dual WHERE a = 1) +) +0 +drop table t1; +# Testcase from MDEV-26164 +create table t1(a int); +# Disable the warning as it includes current time and changes for every test run. +select 1 from t1 where not exists +( +select 1 from t1 where binary current_time() +group by (select a),(select 1) +); +1 +drop table t1; diff --git a/mysql-test/t/subselect_innodb.test b/mysql-test/t/subselect_innodb.test index 2c117fe00d6..f42ac514d53 100644 --- a/mysql-test/t/subselect_innodb.test +++ b/mysql-test/t/subselect_innodb.test @@ -627,3 +627,31 @@ SELECT * FROM t1 WHERE (SELECT 1,CONCAT(a) FROM t1) = (SELECT 1,CONCAT(a) FROM t DROP TABLE t1,t2; set character_set_connection=@save_character_set_connection; + +--echo # +--echo # MDEV-26047: MariaDB server crash at Item_subselect::init_expr_cache_tracker +--echo # +CREATE TABLE t1 (a int) engine=innodb; + +SELECT 1 IN ( + SELECT NULL + FROM t1 + WHERE + a IS NOT NULL + GROUP BY + (SELECT NULL from dual WHERE a = 1) +); +drop table t1; + +--echo # Testcase from MDEV-26164 +create table t1(a int); +--echo # Disable the warning as it includes current time and changes for every test run. +--disable_warnings +select 1 from t1 where not exists +( + select 1 from t1 where binary current_time() + group by (select a),(select 1) +); +--enable_warnings +drop table t1; + diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 7033d38c07b..de9b5dc8438 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -752,6 +752,7 @@ bool Item_subselect::exec() DBUG_ENTER("Item_subselect::exec"); DBUG_ASSERT(fixed); + DBUG_ASSERT(!eliminated); /* 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, DBUG_ASSERT(thd == tmp_thd); + /* + Do not create subquery cache if the subquery was eliminated. + The optimizer may eliminate subquery items (see + eliminate_subselect_processor). However it does not update + all query's data structures, so the eliminated item may be + still reachable. + */ + if (eliminated) + DBUG_RETURN(this); + if (expr_cache) DBUG_RETURN(expr_cache);
participants (1)
-
psergey