From d34c7d67e101d10a35157a99f12242fefc53a0b7 Mon Sep 17 00:00:00 2001 From: Rex Date: Thu, 5 Dec 2024 14:14:35 +1200 Subject: [PATCH] MDEV-35565 Server crashes simplifying group by During optimization, we may call update_depend_map_for_order() on a group by list containing an expression with an outer reference. The table map for this outer reference will be collected by Item_subselect::recalc_used_tables and used to return a depend_map. This map will indicate the presence of tables not in this select and can cause erroneous results, poor execution plans or crashes. We update the class used to collect these bitmaps to check whether the containing select_lex is applicable, and if not, set the OUTER_REF_TABLE_BIT bit in the table map. --- mysql-test/main/subselect_extra.result | 38 +++++++++++++++++ mysql-test/main/subselect_extra.test | 42 +++++++++++++++++++ .../main/subselect_extra_no_semijoin.result | 38 +++++++++++++++++ sql/item_subselect.cc | 17 ++++---- 4 files changed, 126 insertions(+), 9 deletions(-) diff --git a/mysql-test/main/subselect_extra.result b/mysql-test/main/subselect_extra.result index c654fdfca1303..18c704f825410 100644 --- a/mysql-test/main/subselect_extra.result +++ b/mysql-test/main/subselect_extra.result @@ -482,3 +482,41 @@ a b DROP VIEW v2; DROP TABLE t1,t2; set optimizer_switch= @tmp_subselect_extra_derived; +# +# MDEV-35565 Server crashes simplifying group by +# +create table t1 (a int) engine=myisam; +insert into t1 values (1),(2); +create table t2 (b int) engine=myisam; +insert into t2 values (1),(2); +# output from these sorts of queries are unstable, test only that it +# outputs a sensible error message and doesn't crash +select * from t1, t2 where b in +(select (select a from t1 order by b) as d from t1 group by (select d)); +ERROR 21000: Subquery returns more than 1 row +drop table t1, t2; +create table fact (id int, primary key (id)); +insert into fact values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table dim (id int, attr int, fromdate date, +primary key (id, fromdate), key (attr, fromdate)); +insert into dim +select id, id, date_add('2009-06-22', interval id day) from fact; +insert into dim +select id, id+1, date_add('2008-06-22', interval id day) from fact; +create view v as +select f.id, d.attr +from fact f +left join dim d +on d.id = f.id and +d.fromdate = (select max(fromdate) from dim where id = f.id); +explain extended select id from v where attr between 4 and 6; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY d range PRIMARY,attr attr 5 NULL 6 100.00 Using index condition +1 PRIMARY f eq_ref PRIMARY PRIMARY 4 test.d.id 1 100.00 Using where; Using index +3 DEPENDENT SUBQUERY dim ref PRIMARY PRIMARY 4 test.f.id 1 100.00 Using index +Warnings: +Note 1276 Field or reference 'test.f.id' of SELECT #3 was resolved in SELECT #2 +Note 1003 /* select#1 */ select `f`.`id` AS `id` from `test`.`fact` `f` join `test`.`dim` `d` where `f`.`id` = `d`.`id` and `d`.`attr` between 4 and 6 and `d`.`fromdate` = <`f`.`id`>((/* select#3 */ select max(`test`.`dim`.`fromdate`) from `test`.`dim` where `test`.`dim`.`id` = `f`.`id`)) +drop view v; +drop table fact, dim; +# end of 10.11 tests diff --git a/mysql-test/main/subselect_extra.test b/mysql-test/main/subselect_extra.test index 3f2f7b611fff2..3fabd347022f3 100644 --- a/mysql-test/main/subselect_extra.test +++ b/mysql-test/main/subselect_extra.test @@ -398,3 +398,45 @@ DROP VIEW v2; DROP TABLE t1,t2; set optimizer_switch= @tmp_subselect_extra_derived; + +--echo # +--echo # MDEV-35565 Server crashes simplifying group by +--echo # + +create table t1 (a int) engine=myisam; +insert into t1 values (1),(2); + +create table t2 (b int) engine=myisam; +insert into t2 values (1),(2); + +--echo # output from these sorts of queries are unstable, test only that it +--echo # outputs a sensible error message and doesn't crash +--error 1242 +select * from t1, t2 where b in +(select (select a from t1 order by b) as d from t1 group by (select d)); + +drop table t1, t2; + +create table fact (id int, primary key (id)); +insert into fact values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +create table dim (id int, attr int, fromdate date, + primary key (id, fromdate), key (attr, fromdate)); +insert into dim + select id, id, date_add('2009-06-22', interval id day) from fact; +insert into dim + select id, id+1, date_add('2008-06-22', interval id day) from fact; + +create view v as + select f.id, d.attr + from fact f + left join dim d + on d.id = f.id and + d.fromdate = (select max(fromdate) from dim where id = f.id); + +explain extended select id from v where attr between 4 and 6; + +drop view v; +drop table fact, dim; + +--echo # end of 10.11 tests diff --git a/mysql-test/main/subselect_extra_no_semijoin.result b/mysql-test/main/subselect_extra_no_semijoin.result index faeaf75c5900d..dc8c8c8c3ee3a 100644 --- a/mysql-test/main/subselect_extra_no_semijoin.result +++ b/mysql-test/main/subselect_extra_no_semijoin.result @@ -484,6 +484,44 @@ a b DROP VIEW v2; DROP TABLE t1,t2; set optimizer_switch= @tmp_subselect_extra_derived; +# +# MDEV-35565 Server crashes simplifying group by +# +create table t1 (a int) engine=myisam; +insert into t1 values (1),(2); +create table t2 (b int) engine=myisam; +insert into t2 values (1),(2); +# output from these sorts of queries are unstable, test only that it +# outputs a sensible error message and doesn't crash +select * from t1, t2 where b in +(select (select a from t1 order by b) as d from t1 group by (select d)); +ERROR 21000: Subquery returns more than 1 row +drop table t1, t2; +create table fact (id int, primary key (id)); +insert into fact values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table dim (id int, attr int, fromdate date, +primary key (id, fromdate), key (attr, fromdate)); +insert into dim +select id, id, date_add('2009-06-22', interval id day) from fact; +insert into dim +select id, id+1, date_add('2008-06-22', interval id day) from fact; +create view v as +select f.id, d.attr +from fact f +left join dim d +on d.id = f.id and +d.fromdate = (select max(fromdate) from dim where id = f.id); +explain extended select id from v where attr between 4 and 6; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY d range PRIMARY,attr attr 5 NULL 6 100.00 Using index condition +1 PRIMARY f eq_ref PRIMARY PRIMARY 4 test.d.id 1 100.00 Using where; Using index +3 DEPENDENT SUBQUERY dim ref PRIMARY PRIMARY 4 test.f.id 1 100.00 Using index +Warnings: +Note 1276 Field or reference 'test.f.id' of SELECT #3 was resolved in SELECT #2 +Note 1003 /* select#1 */ select `f`.`id` AS `id` from `test`.`fact` `f` join `test`.`dim` `d` where `f`.`id` = `d`.`id` and `d`.`attr` between 4 and 6 and `d`.`fromdate` = <`f`.`id`>((/* select#3 */ select max(`test`.`dim`.`fromdate`) from `test`.`dim` where `test`.`dim`.`id` = `f`.`id`)) +drop view v; +drop table fact, dim; +# end of 10.11 tests set optimizer_switch= @subselect_extra_no_sj_tmp; set @optimizer_switch_for_subselect_extra_test=null; # diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 6da58c20d6f3b..d86d471910c09 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -476,15 +476,14 @@ class Field_fixer: public Field_enumerator st_select_lex *new_parent; /* Select we're in */ void visit_field(Item_field *item) override { - //for (TABLE_LIST *tbl= new_parent->leaf_tables; tbl; tbl= tbl->next_local) - //{ - // if (tbl->table == field->table) - // { - used_tables|= item->field->table->map; - // return; - // } - //} - //used_tables |= OUTER_REF_TABLE_BIT; + st_select_lex *cmp= new_parent; + while (cmp->merged_into) + cmp= cmp->merged_into; + if (item->field->table->pos_in_table_list && + (item->field->table->pos_in_table_list->select_lex == cmp)) + used_tables|= item->field->table->map; + else + used_tables|= OUTER_REF_TABLE_BIT; } };