Skip to content

Commit d61bc94

Browse files
committed
MDEV-30659 Server crash on EXPLAIN SELECT/SELECT on table with engine Aria for LooseScan Strategy
Amended patch from Monty: The issue was that Loose_scan_opt::save_to_position() did not take into account records_out from best_access_path() Make sure that POSITION object filled by Loose_scan_opt::save_to_position() has records_out not higher than any other possible access method.
1 parent d5d7c8b commit d61bc94

File tree

6 files changed

+175
-6
lines changed

6 files changed

+175
-6
lines changed

mysql-test/main/selectivity.result

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2011,3 +2011,57 @@ INSERT INTO t2 VALUES (1),(2);
20112011
SELECT STRAIGHT_JOIN pk FROM t1 JOIN t2 ON a = pk WHERE b >= 'A' ORDER BY t2.pk LIMIT 8 OFFSET 1;
20122012
pk
20132013
DROP TABLE t1, t2;
2014+
#
2015+
# MDEV-30659 Server crash on EXPLAIN SELECT/SELECT on table with
2016+
# engine Aria for LooseScan Strategy
2017+
#
2018+
create table t1 (old_c1 integer, old_c2 integer, c1 integer,
2019+
c2 integer, c3 integer) engine=aria;
2020+
insert into t1(c1,c2,c3)
2021+
values (1,1,1), (1,2,2), (1,3,3),
2022+
(2,1,4), (2,2,5), (2,3,6),
2023+
(2,4,7), (2,5,8);
2024+
create index t1_c2 on t1 (c2,c1);
2025+
explain select * from t1 where t1.c2 in (select a.c2 from t1 a) and
2026+
c2 >= 3 order by c2;
2027+
id select_type table type possible_keys key key_len ref rows Extra
2028+
1 PRIMARY a range t1_c2 t1_c2 5 NULL 5 Using where; Using index; LooseScan
2029+
1 PRIMARY t1 ref t1_c2 t1_c2 5 test.a.c2 1
2030+
drop table t1;
2031+
create table t1 (old_c1 integer, old_c2 integer, c1 integer,
2032+
c2 integer, c3 integer) engine=aria;
2033+
create trigger trg_t1 before update on t1 for each row
2034+
begin
2035+
set new.old_c1=old.c1;
2036+
set new.old_c2=old.c2;
2037+
end;
2038+
/
2039+
insert into t1 (c1,c2,c3) values
2040+
(1,1,1), (1,2,2), (1,3,3), (2,1,4), (2,2,5), (2,3,6), (2,4,7), (2,5,8);
2041+
create index t1_c2 on t1 (c2,c1);
2042+
analyze table t1 persistent for all;
2043+
Table Op Msg_type Msg_text
2044+
test.t1 analyze status Engine-independent statistics collected
2045+
test.t1 analyze status OK
2046+
create table t2 as select * from t1;
2047+
truncate table t1;
2048+
insert into t1 select * from t2;
2049+
explain select * from t1 where t1.c2 in (select a.c2 from t1 a) and c2 >= 3 order by c2;
2050+
id select_type table type possible_keys key key_len ref rows Extra
2051+
1 PRIMARY a range t1_c2 t1_c2 5 NULL 5 Using where; Using index; LooseScan
2052+
1 PRIMARY t1 ref t1_c2 t1_c2 5 test.a.c2 1
2053+
drop trigger trg_t1;
2054+
drop table t1,t2;
2055+
create table t1 (old_c1 integer, old_c2 integer, c1 integer,
2056+
c2 integer, c3 integer) engine=aria;
2057+
insert into t1 (c1,c2,c3) values
2058+
(1,1,1), (1,2,2), (1,3,3), (2,1,4), (2,2,5), (2,3,6), (2,4,7), (2,5,8);
2059+
create index t1_c2 on t1 (c2,c1);
2060+
create table t2 as select * from t1;
2061+
truncate table t1;
2062+
insert into t1 select * from t2;
2063+
explain select * from t1 where t1.c2 in (select a.c2 from t1 a) and c2 >= 3 order by c2;
2064+
id select_type table type possible_keys key key_len ref rows Extra
2065+
1 PRIMARY a range t1_c2 t1_c2 5 NULL 5 Using where; Using index; LooseScan
2066+
1 PRIMARY t1 ref t1_c2 t1_c2 5 test.a.c2 2
2067+
drop table t1,t2;

mysql-test/main/selectivity.test

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,3 +1376,54 @@ INSERT INTO t2 VALUES (1),(2);
13761376
SELECT STRAIGHT_JOIN pk FROM t1 JOIN t2 ON a = pk WHERE b >= 'A' ORDER BY t2.pk LIMIT 8 OFFSET 1;
13771377

13781378
DROP TABLE t1, t2;
1379+
1380+
--echo #
1381+
--echo # MDEV-30659 Server crash on EXPLAIN SELECT/SELECT on table with
1382+
--echo # engine Aria for LooseScan Strategy
1383+
--echo #
1384+
1385+
create table t1 (old_c1 integer, old_c2 integer, c1 integer,
1386+
c2 integer, c3 integer) engine=aria;
1387+
insert into t1(c1,c2,c3)
1388+
values (1,1,1), (1,2,2), (1,3,3),
1389+
(2,1,4), (2,2,5), (2,3,6),
1390+
(2,4,7), (2,5,8);
1391+
create index t1_c2 on t1 (c2,c1);
1392+
1393+
explain select * from t1 where t1.c2 in (select a.c2 from t1 a) and
1394+
c2 >= 3 order by c2;
1395+
drop table t1;
1396+
1397+
create table t1 (old_c1 integer, old_c2 integer, c1 integer,
1398+
c2 integer, c3 integer) engine=aria;
1399+
1400+
delimiter /;
1401+
create trigger trg_t1 before update on t1 for each row
1402+
begin
1403+
set new.old_c1=old.c1;
1404+
set new.old_c2=old.c2;
1405+
end;
1406+
/
1407+
delimiter ;/
1408+
1409+
insert into t1 (c1,c2,c3) values
1410+
(1,1,1), (1,2,2), (1,3,3), (2,1,4), (2,2,5), (2,3,6), (2,4,7), (2,5,8);
1411+
create index t1_c2 on t1 (c2,c1);
1412+
analyze table t1 persistent for all;
1413+
create table t2 as select * from t1;
1414+
truncate table t1;
1415+
insert into t1 select * from t2;
1416+
explain select * from t1 where t1.c2 in (select a.c2 from t1 a) and c2 >= 3 order by c2;
1417+
drop trigger trg_t1;
1418+
drop table t1,t2;
1419+
1420+
create table t1 (old_c1 integer, old_c2 integer, c1 integer,
1421+
c2 integer, c3 integer) engine=aria;
1422+
insert into t1 (c1,c2,c3) values
1423+
(1,1,1), (1,2,2), (1,3,3), (2,1,4), (2,2,5), (2,3,6), (2,4,7), (2,5,8);
1424+
create index t1_c2 on t1 (c2,c1);
1425+
create table t2 as select * from t1;
1426+
truncate table t1;
1427+
insert into t1 select * from t2;
1428+
explain select * from t1 where t1.c2 in (select a.c2 from t1 a) and c2 >= 3 order by c2;
1429+
drop table t1,t2;

mysql-test/main/selectivity_innodb.result

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2018,6 +2018,60 @@ INSERT INTO t2 VALUES (1),(2);
20182018
SELECT STRAIGHT_JOIN pk FROM t1 JOIN t2 ON a = pk WHERE b >= 'A' ORDER BY t2.pk LIMIT 8 OFFSET 1;
20192019
pk
20202020
DROP TABLE t1, t2;
2021+
#
2022+
# MDEV-30659 Server crash on EXPLAIN SELECT/SELECT on table with
2023+
# engine Aria for LooseScan Strategy
2024+
#
2025+
create table t1 (old_c1 integer, old_c2 integer, c1 integer,
2026+
c2 integer, c3 integer) engine=aria;
2027+
insert into t1(c1,c2,c3)
2028+
values (1,1,1), (1,2,2), (1,3,3),
2029+
(2,1,4), (2,2,5), (2,3,6),
2030+
(2,4,7), (2,5,8);
2031+
create index t1_c2 on t1 (c2,c1);
2032+
explain select * from t1 where t1.c2 in (select a.c2 from t1 a) and
2033+
c2 >= 3 order by c2;
2034+
id select_type table type possible_keys key key_len ref rows Extra
2035+
1 PRIMARY a range t1_c2 t1_c2 5 NULL 5 Using where; Using index; LooseScan
2036+
1 PRIMARY t1 ref t1_c2 t1_c2 5 test.a.c2 1
2037+
drop table t1;
2038+
create table t1 (old_c1 integer, old_c2 integer, c1 integer,
2039+
c2 integer, c3 integer) engine=aria;
2040+
create trigger trg_t1 before update on t1 for each row
2041+
begin
2042+
set new.old_c1=old.c1;
2043+
set new.old_c2=old.c2;
2044+
end;
2045+
/
2046+
insert into t1 (c1,c2,c3) values
2047+
(1,1,1), (1,2,2), (1,3,3), (2,1,4), (2,2,5), (2,3,6), (2,4,7), (2,5,8);
2048+
create index t1_c2 on t1 (c2,c1);
2049+
analyze table t1 persistent for all;
2050+
Table Op Msg_type Msg_text
2051+
test.t1 analyze status Engine-independent statistics collected
2052+
test.t1 analyze status OK
2053+
create table t2 as select * from t1;
2054+
truncate table t1;
2055+
insert into t1 select * from t2;
2056+
explain select * from t1 where t1.c2 in (select a.c2 from t1 a) and c2 >= 3 order by c2;
2057+
id select_type table type possible_keys key key_len ref rows Extra
2058+
1 PRIMARY a range t1_c2 t1_c2 5 NULL 5 Using where; Using index; LooseScan
2059+
1 PRIMARY t1 ref t1_c2 t1_c2 5 test.a.c2 1
2060+
drop trigger trg_t1;
2061+
drop table t1,t2;
2062+
create table t1 (old_c1 integer, old_c2 integer, c1 integer,
2063+
c2 integer, c3 integer) engine=aria;
2064+
insert into t1 (c1,c2,c3) values
2065+
(1,1,1), (1,2,2), (1,3,3), (2,1,4), (2,2,5), (2,3,6), (2,4,7), (2,5,8);
2066+
create index t1_c2 on t1 (c2,c1);
2067+
create table t2 as select * from t1;
2068+
truncate table t1;
2069+
insert into t1 select * from t2;
2070+
explain select * from t1 where t1.c2 in (select a.c2 from t1 a) and c2 >= 3 order by c2;
2071+
id select_type table type possible_keys key key_len ref rows Extra
2072+
1 PRIMARY a range t1_c2 t1_c2 5 NULL 5 Using where; Using index; LooseScan
2073+
1 PRIMARY t1 ref t1_c2 t1_c2 5 test.a.c2 2
2074+
drop table t1,t2;
20212075
set optimizer_switch=@save_optimizer_switch_for_selectivity_test;
20222076
set @tmp_ust= @@use_stat_tables;
20232077
set @tmp_oucs= @@optimizer_use_condition_selectivity;

sql/opt_subselect.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,14 +294,23 @@ class Loose_scan_opt
294294
}
295295
}
296296

297-
void save_to_position(JOIN_TAB *tab, double record_count, POSITION *pos)
297+
void save_to_position(JOIN_TAB *tab, double record_count,
298+
double records_out,
299+
POSITION *pos)
298300
{
299301
pos->read_time= best_loose_scan_cost;
300302
if (best_loose_scan_cost != DBL_MAX)
301303
{
304+
/*
305+
Make sure LooseScan plan doesn't produce more rows than
306+
the records_out of other table access method.
307+
*/
308+
set_if_smaller(best_loose_scan_records, records_out);
309+
302310
pos->loops= record_count;
303311
pos->records_read= best_loose_scan_records;
304-
pos->records_init= pos->records_out= pos->records_read;
312+
pos->records_init= pos->records_read;
313+
pos->records_out= best_loose_scan_records;
305314
pos->key= best_loose_scan_start_key;
306315
pos->cond_selectivity= 1.0;
307316
pos->loosescan_picker.loosescan_key= best_loose_scan_key;

sql/sql_select.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8155,7 +8155,6 @@ best_access_path(JOIN *join,
81558155
best.uses_jbuf= FALSE;
81568156
best.spl_plan= 0;
81578157

8158-
pos->loops= record_count;
81598158
disable_jbuf= disable_jbuf || idx == join->const_tables;
81608159

81618160
trace_wrapper.add_table_name(s);
@@ -9282,6 +9281,7 @@ best_access_path(JOIN *join,
92829281
crash_if_first_double_is_bigger(best.records_out, best.records_read);
92839282

92849283
/* Update the cost information for the current partial plan */
9284+
pos->loops= record_count;
92859285
pos->records_init= best.records_read;
92869286
pos->records_after_filter= best.records_after_filter;
92879287
pos->records_read= best.records;
@@ -9299,7 +9299,8 @@ best_access_path(JOIN *join,
92999299
pos->key_dependent= (best.type == JT_EQ_REF ? (table_map) 0 :
93009300
key_dependent & remaining_tables);
93019301

9302-
loose_scan_opt.save_to_position(s, record_count, loose_scan_pos);
9302+
loose_scan_opt.save_to_position(s, record_count, pos->records_out,
9303+
loose_scan_pos);
93039304

93049305
if (!best.key &&
93059306
idx == join->const_tables && // First table
@@ -30525,9 +30526,8 @@ static bool get_range_limit_read_cost(const POSITION *pos,
3052530526
cond_selectivity= best_rows / range_rows;
3052630527
else
3052730528
cond_selectivity= 1.0;
30528-
#if 0 // FIXME: cond_selectivity=8/4 = 2 in main.update_use_source
30529+
3052930530
DBUG_ASSERT(cond_selectivity <= 1.000000001);
30530-
#endif
3053130531
set_if_smaller(cond_selectivity, 1.0);
3053230532

3053330533
/*

sql/sql_select.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,6 +1022,7 @@ class POSITION
10221022
*/
10231023
double read_time;
10241024

1025+
/* record combinations before this table */
10251026
double loops;
10261027

10271028
double prefix_record_count;

0 commit comments

Comments
 (0)