Skip to content

Commit 2e3e818

Browse files
committed
MDEV-7445: Server crash with Signal 6
Problem was in rewriting left expression which had 2 references on it. Solved with making subselect reference main. Item_in_optimized can have not Item_in_subselect reference in left part so type casting with no check is dangerous. Item::cols() should be checked after Item::fix_fields().
1 parent 7ccde2c commit 2e3e818

File tree

8 files changed

+164
-17
lines changed

8 files changed

+164
-17
lines changed

mysql-test/r/subselect.result

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7027,3 +7027,23 @@ From
70277027
Group By TestCase.Revenue, TestCase.TemplateID;
70287028
ControlRev
70297029
NULL
7030+
#
7031+
# MDEV-7445:Server crash with Signal 6
7032+
#
7033+
CREATE PROCEDURE procedure2()
7034+
BEGIN
7035+
Select
7036+
(Select Sum(`TestCase`.Revenue) From mysql.slow_log E
7037+
Where TestCase.TemplateID not in (Select 1 from mysql.slow_log where 2=2)
7038+
) As `ControlRev`
7039+
From
7040+
(Select 3 as Revenue, 4 as TemplateID) As `TestCase`
7041+
Group By TestCase.Revenue, TestCase.TemplateID;
7042+
END |
7043+
call procedure2();
7044+
ControlRev
7045+
NULL
7046+
call procedure2();
7047+
ControlRev
7048+
NULL
7049+
drop procedure procedure2;

mysql-test/r/subselect_no_mat.result

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7024,6 +7024,26 @@ From
70247024
Group By TestCase.Revenue, TestCase.TemplateID;
70257025
ControlRev
70267026
NULL
7027+
#
7028+
# MDEV-7445:Server crash with Signal 6
7029+
#
7030+
CREATE PROCEDURE procedure2()
7031+
BEGIN
7032+
Select
7033+
(Select Sum(`TestCase`.Revenue) From mysql.slow_log E
7034+
Where TestCase.TemplateID not in (Select 1 from mysql.slow_log where 2=2)
7035+
) As `ControlRev`
7036+
From
7037+
(Select 3 as Revenue, 4 as TemplateID) As `TestCase`
7038+
Group By TestCase.Revenue, TestCase.TemplateID;
7039+
END |
7040+
call procedure2();
7041+
ControlRev
7042+
NULL
7043+
call procedure2();
7044+
ControlRev
7045+
NULL
7046+
drop procedure procedure2;
70277047
set optimizer_switch=default;
70287048
select @@optimizer_switch like '%materialization=on%';
70297049
@@optimizer_switch like '%materialization=on%'

mysql-test/r/subselect_no_opts.result

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7022,4 +7022,24 @@ From
70227022
Group By TestCase.Revenue, TestCase.TemplateID;
70237023
ControlRev
70247024
NULL
7025+
#
7026+
# MDEV-7445:Server crash with Signal 6
7027+
#
7028+
CREATE PROCEDURE procedure2()
7029+
BEGIN
7030+
Select
7031+
(Select Sum(`TestCase`.Revenue) From mysql.slow_log E
7032+
Where TestCase.TemplateID not in (Select 1 from mysql.slow_log where 2=2)
7033+
) As `ControlRev`
7034+
From
7035+
(Select 3 as Revenue, 4 as TemplateID) As `TestCase`
7036+
Group By TestCase.Revenue, TestCase.TemplateID;
7037+
END |
7038+
call procedure2();
7039+
ControlRev
7040+
NULL
7041+
call procedure2();
7042+
ControlRev
7043+
NULL
7044+
drop procedure procedure2;
70257045
set @optimizer_switch_for_subselect_test=null;

mysql-test/r/subselect_no_scache.result

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7033,6 +7033,26 @@ From
70337033
Group By TestCase.Revenue, TestCase.TemplateID;
70347034
ControlRev
70357035
NULL
7036+
#
7037+
# MDEV-7445:Server crash with Signal 6
7038+
#
7039+
CREATE PROCEDURE procedure2()
7040+
BEGIN
7041+
Select
7042+
(Select Sum(`TestCase`.Revenue) From mysql.slow_log E
7043+
Where TestCase.TemplateID not in (Select 1 from mysql.slow_log where 2=2)
7044+
) As `ControlRev`
7045+
From
7046+
(Select 3 as Revenue, 4 as TemplateID) As `TestCase`
7047+
Group By TestCase.Revenue, TestCase.TemplateID;
7048+
END |
7049+
call procedure2();
7050+
ControlRev
7051+
NULL
7052+
call procedure2();
7053+
ControlRev
7054+
NULL
7055+
drop procedure procedure2;
70367056
set optimizer_switch=default;
70377057
select @@optimizer_switch like '%subquery_cache=on%';
70387058
@@optimizer_switch like '%subquery_cache=on%'

mysql-test/r/subselect_no_semijoin.result

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7022,5 +7022,25 @@ From
70227022
Group By TestCase.Revenue, TestCase.TemplateID;
70237023
ControlRev
70247024
NULL
7025+
#
7026+
# MDEV-7445:Server crash with Signal 6
7027+
#
7028+
CREATE PROCEDURE procedure2()
7029+
BEGIN
7030+
Select
7031+
(Select Sum(`TestCase`.Revenue) From mysql.slow_log E
7032+
Where TestCase.TemplateID not in (Select 1 from mysql.slow_log where 2=2)
7033+
) As `ControlRev`
7034+
From
7035+
(Select 3 as Revenue, 4 as TemplateID) As `TestCase`
7036+
Group By TestCase.Revenue, TestCase.TemplateID;
7037+
END |
7038+
call procedure2();
7039+
ControlRev
7040+
NULL
7041+
call procedure2();
7042+
ControlRev
7043+
NULL
7044+
drop procedure procedure2;
70257045
set @optimizer_switch_for_subselect_test=null;
70267046
set @join_cache_level_for_subselect_test=NULL;

mysql-test/t/subselect.test

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5902,3 +5902,24 @@ From
59025902
(Select 3 as Revenue, 4 as TemplateID) As `TestCase`
59035903
Group By TestCase.Revenue, TestCase.TemplateID;
59045904

5905+
--echo #
5906+
--echo # MDEV-7445:Server crash with Signal 6
5907+
--echo #
5908+
5909+
--delimiter |
5910+
CREATE PROCEDURE procedure2()
5911+
BEGIN
5912+
Select
5913+
(Select Sum(`TestCase`.Revenue) From mysql.slow_log E
5914+
Where TestCase.TemplateID not in (Select 1 from mysql.slow_log where 2=2)
5915+
) As `ControlRev`
5916+
From
5917+
(Select 3 as Revenue, 4 as TemplateID) As `TestCase`
5918+
Group By TestCase.Revenue, TestCase.TemplateID;
5919+
5920+
END |
5921+
--delimiter ;
5922+
call procedure2();
5923+
call procedure2();
5924+
5925+
drop procedure procedure2;

sql/item_cmpfunc.cc

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1442,9 +1442,25 @@ bool Item_in_optimizer::eval_not_null_tables(uchar *opt_arg)
14421442
bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
14431443
{
14441444
DBUG_ENTER("Item_in_optimizer::fix_left");
1445-
if ((!args[0]->fixed && args[0]->fix_fields(thd, args)) ||
1446-
(!cache && !(cache= Item_cache::get_cache(args[0]))))
1445+
Item **ref0= args;
1446+
if (args[1]->type() == Item::SUBSELECT_ITEM &&
1447+
((Item_subselect *)args[1])->is_in_predicate())
1448+
{
1449+
/*
1450+
left_expr->fix_fields() may cause left_expr to be substituted for
1451+
another item. (e.g. an Item_field may be changed into Item_ref). This
1452+
transformation is undone at the end of statement execution (e.g. the
1453+
Item_ref is deleted). However, Item_in_optimizer::args[0] may keep
1454+
the pointer to the post-transformation item. Because of that, on the
1455+
next execution we need to copy args[1]->left_expr again.
1456+
*/
1457+
ref0= &(((Item_in_subselect *)args[1])->left_expr);
1458+
args[0]= ref0[0];
1459+
}
1460+
if ((!args[0]->fixed && args[0]->fix_fields(thd, ref0)) ||
1461+
(!cache && !(cache= Item_cache::get_cache(ref0[0]))))
14471462
DBUG_RETURN(1);
1463+
args[0]= ref0[0];
14481464
DBUG_PRINT("info", ("actual fix fields"));
14491465

14501466
cache->setup(args[0]);
@@ -1500,17 +1516,27 @@ bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
15001516
bool Item_in_optimizer::fix_fields(THD *thd, Item **ref)
15011517
{
15021518
DBUG_ASSERT(fixed == 0);
1519+
Item_subselect *sub= 0;
1520+
uint col;
1521+
1522+
/*
1523+
MAX/MIN optimization can convert the subquery into
1524+
expr + Item_singlerow_subselect
1525+
*/
1526+
if (args[1]->type() == Item::SUBSELECT_ITEM)
1527+
sub= (Item_subselect *)args[1];
1528+
15031529
if (fix_left(thd, ref))
15041530
return TRUE;
15051531
if (args[0]->maybe_null)
15061532
maybe_null=1;
15071533

15081534
if (!args[1]->fixed && args[1]->fix_fields(thd, args+1))
15091535
return TRUE;
1510-
Item_in_subselect * sub= (Item_in_subselect *)args[1];
1511-
if (args[0]->cols() != sub->engine->cols())
1536+
if ((sub && ((col= args[0]->cols()) != sub->engine->cols())) ||
1537+
(!sub && (args[1]->cols() != (col= 1))))
15121538
{
1513-
my_error(ER_OPERAND_COLUMNS, MYF(0), args[0]->cols());
1539+
my_error(ER_OPERAND_COLUMNS, MYF(0), col);
15141540
return TRUE;
15151541
}
15161542
if (args[1]->maybe_null)

sql/opt_subselect.cc

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,18 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
620620
thd->stmt_arena->state != Query_arena::PREPARED)
621621
*/
622622
{
623+
SELECT_LEX *current= thd->lex->current_select;
624+
thd->lex->current_select= current->return_after_parsing();
625+
char const *save_where= thd->where;
626+
thd->where= "IN/ALL/ANY subquery";
627+
628+
bool failure= !in_subs->left_expr->fixed &&
629+
in_subs->left_expr->fix_fields(thd, &in_subs->left_expr);
630+
thd->lex->current_select= current;
631+
thd->where= save_where;
632+
if (failure)
633+
DBUG_RETURN(-1); /* purecov: deadcode */
634+
623635
/*
624636
Check if the left and right expressions have the same # of
625637
columns, i.e. we don't have a case like
@@ -633,18 +645,6 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
633645
my_error(ER_OPERAND_COLUMNS, MYF(0), in_subs->left_expr->cols());
634646
DBUG_RETURN(-1);
635647
}
636-
637-
SELECT_LEX *current= thd->lex->current_select;
638-
thd->lex->current_select= current->return_after_parsing();
639-
char const *save_where= thd->where;
640-
thd->where= "IN/ALL/ANY subquery";
641-
642-
bool failure= !in_subs->left_expr->fixed &&
643-
in_subs->left_expr->fix_fields(thd, &in_subs->left_expr);
644-
thd->lex->current_select= current;
645-
thd->where= save_where;
646-
if (failure)
647-
DBUG_RETURN(-1); /* purecov: deadcode */
648648
}
649649

650650
DBUG_PRINT("info", ("Checking if subq can be converted to semi-join"));

0 commit comments

Comments
 (0)