Skip to content

Commit 9b9e36e

Browse files
committed
MDEV-8779: mysqld got signal 11 in sql/opt_range_mrr.cc:100(step_down_to)
The crash was caused by range optimizer using RANGE_OPT_PARAM::min_key (and max_key) to store keys. Buffer size was a good upper bound for range analysis and partition pruning, but not for EITS selectivity calculations. Fixed by making these buffers variable-size. The sizes are calculated from [pseudo]indexes used for range analysis.
1 parent 139ce6c commit 9b9e36e

File tree

4 files changed

+73
-4
lines changed

4 files changed

+73
-4
lines changed

mysql-test/r/selectivity_no_engine.result

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,23 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
276276
Warnings:
277277
Note 1003 select `test`.`ta`.`a` AS `a`,`test`.`tb`.`a` AS `a` from `test`.`t1` `ta` join `test`.`t2` `tb` where ((`test`.`tb`.`a` = `test`.`ta`.`a`) and (`test`.`ta`.`a` < 40) and (`test`.`ta`.`a` < 100))
278278
drop table t0,t1,t2;
279+
#
280+
# MDEV-8779: mysqld got signal 11 in sql/opt_range_mrr.cc:100(step_down_to)
281+
#
282+
set @tmp_mdev8779=@@optimizer_use_condition_selectivity;
283+
set optimizer_use_condition_selectivity=5;
284+
CREATE TABLE t1 (
285+
i int(10) unsigned NOT NULL AUTO_INCREMENT,
286+
n varchar(2048) NOT NULL,
287+
d tinyint(1) unsigned NOT NULL,
288+
p int(10) unsigned NOT NULL,
289+
PRIMARY KEY (i)
290+
) DEFAULT CHARSET=utf8;
291+
insert into t1 values (1,'aaa',1,1), (2,'bbb',2,2);
292+
SELECT * FROM t1 WHERE t1.d = 0 AND t1.p = '1' AND t1.i != '-1' AND t1.n = 'some text';
293+
i n d p
294+
set optimizer_use_condition_selectivity= @tmp_mdev8779;
295+
DROP TABLE t1;
279296
#
280297
# End of the test file
281298
#

mysql-test/t/selectivity_no_engine.test

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,23 @@ explain extended select * from t1 ta, t2 tb where ta.a < 40 and tb.a < 100 and t
210210

211211
drop table t0,t1,t2;
212212

213+
--echo #
214+
--echo # MDEV-8779: mysqld got signal 11 in sql/opt_range_mrr.cc:100(step_down_to)
215+
--echo #
216+
set @tmp_mdev8779=@@optimizer_use_condition_selectivity;
217+
set optimizer_use_condition_selectivity=5;
218+
CREATE TABLE t1 (
219+
i int(10) unsigned NOT NULL AUTO_INCREMENT,
220+
n varchar(2048) NOT NULL,
221+
d tinyint(1) unsigned NOT NULL,
222+
p int(10) unsigned NOT NULL,
223+
PRIMARY KEY (i)
224+
) DEFAULT CHARSET=utf8;
225+
insert into t1 values (1,'aaa',1,1), (2,'bbb',2,2);
226+
SELECT * FROM t1 WHERE t1.d = 0 AND t1.p = '1' AND t1.i != '-1' AND t1.n = 'some text';
227+
set optimizer_use_condition_selectivity= @tmp_mdev8779;
228+
DROP TABLE t1;
229+
213230
--echo #
214231
--echo # End of the test file
215232
--echo #

sql/opt_range.cc

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2469,13 +2469,13 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
24692469
DBUG_RETURN(0); // Can't use range
24702470
}
24712471
key_parts= param.key_parts;
2472-
thd->mem_root= &alloc;
24732472

24742473
/*
24752474
Make an array with description of all key parts of all table keys.
24762475
This is used in get_mm_parts function.
24772476
*/
24782477
key_info= head->key_info;
2478+
uint max_key_len= 0;
24792479
for (idx=0 ; idx < head->s->keys ; idx++, key_info++)
24802480
{
24812481
KEY_PART_INFO *key_part_info;
@@ -2488,13 +2488,15 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
24882488

24892489
param.key[param.keys]=key_parts;
24902490
key_part_info= key_info->key_part;
2491+
uint cur_key_len= 0;
24912492
for (uint part= 0 ; part < n_key_parts ;
24922493
part++, key_parts++, key_part_info++)
24932494
{
24942495
key_parts->key= param.keys;
24952496
key_parts->part= part;
24962497
key_parts->length= key_part_info->length;
24972498
key_parts->store_length= key_part_info->store_length;
2499+
cur_key_len += key_part_info->store_length;
24982500
key_parts->field= key_part_info->field;
24992501
key_parts->null_bit= key_part_info->null_bit;
25002502
key_parts->image_type =
@@ -2503,10 +2505,21 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
25032505
key_parts->flag= (uint8) key_part_info->key_part_flag;
25042506
}
25052507
param.real_keynr[param.keys++]=idx;
2508+
if (cur_key_len > max_key_len)
2509+
max_key_len= cur_key_len;
25062510
}
25072511
param.key_parts_end=key_parts;
25082512
param.alloced_sel_args= 0;
25092513

2514+
if (!(param.min_key= (uchar*)alloc_root(&alloc,max_key_len)) ||
2515+
!(param.max_key= (uchar*)alloc_root(&alloc,max_key_len)))
2516+
{
2517+
thd->no_errors=0;
2518+
free_root(&alloc,MYF(0)); // Return memory & allocator
2519+
DBUG_RETURN(0); // Can't use range
2520+
}
2521+
2522+
thd->mem_root= &alloc;
25102523
/* Calculate cost of full index read for the shortest covering index */
25112524
if (!force_quick_range && !head->covering_keys.is_clear_all())
25122525
{
@@ -2730,7 +2743,7 @@ bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param,
27302743
return TRUE;
27312744

27322745
param->key_parts= key_part;
2733-
2746+
uint max_key_len= 0;
27342747
for (field_ptr= table->field; *field_ptr; field_ptr++)
27352748
{
27362749
if (bitmap_is_set(used_fields, (*field_ptr)->field_index))
@@ -2745,6 +2758,8 @@ bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param,
27452758
store_length+= HA_KEY_NULL_LENGTH;
27462759
if (field->real_type() == MYSQL_TYPE_VARCHAR)
27472760
store_length+= HA_KEY_BLOB_LENGTH;
2761+
if (max_key_len < store_length)
2762+
max_key_len= store_length;
27482763
key_part->store_length= store_length;
27492764
key_part->field= field;
27502765
key_part->image_type= Field::itRAW;
@@ -2754,6 +2769,12 @@ bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param,
27542769
key_part++;
27552770
}
27562771
}
2772+
2773+
if (!(param->min_key= (uchar*)alloc_root(param->mem_root, max_key_len)) ||
2774+
!(param->max_key= (uchar*)alloc_root(param->mem_root, max_key_len)))
2775+
{
2776+
return true;
2777+
}
27572778
param->keys= keys;
27582779
param->key_parts_end= key_part;
27592780

@@ -4306,12 +4327,15 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
43064327
Field **field= (ppar->part_fields)? part_info->part_field_array :
43074328
part_info->subpart_field_array;
43084329
bool in_subpart_fields= FALSE;
4330+
uint max_key_len= 0;
4331+
uint cur_key_len;
43094332
for (uint part= 0; part < total_parts; part++, key_part++)
43104333
{
43114334
key_part->key= 0;
43124335
key_part->part= part;
43134336
key_part->length= (uint16)(*field)->key_length();
43144337
key_part->store_length= (uint16)get_partition_field_store_length(*field);
4338+
cur_key_len += key_part->store_length;
43154339

43164340
DBUG_PRINT("info", ("part %u length %u store_length %u", part,
43174341
key_part->length, key_part->store_length));
@@ -4337,10 +4361,21 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
43374361
{
43384362
field= part_info->subpart_field_array;
43394363
in_subpart_fields= TRUE;
4364+
max_key_len= cur_key_len;
4365+
cur_key_len= 0;
43404366
}
43414367
}
43424368
range_par->key_parts_end= key_part;
43434369

4370+
if (cur_key_len > max_key_len)
4371+
max_key_len= cur_key_len;
4372+
4373+
if (!(range_par->min_key= (uchar*)alloc_root(alloc,max_key_len)) ||
4374+
!(range_par->max_key= (uchar*)alloc_root(alloc,max_key_len)))
4375+
{
4376+
return true;
4377+
}
4378+
43444379
DBUG_EXECUTE("info", print_partitioning_index(range_par->key_parts,
43454380
range_par->key_parts_end););
43464381
return FALSE;

sql/opt_range.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -643,8 +643,8 @@ class RANGE_OPT_PARAM
643643
Used to store 'current key tuples', in both range analysis and
644644
partitioning (list) analysis
645645
*/
646-
uchar min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH],
647-
max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH];
646+
uchar *min_key;
647+
uchar *max_key;
648648

649649
/* Number of SEL_ARG objects allocated by SEL_ARG::clone_tree operations */
650650
uint alloced_sel_args;

0 commit comments

Comments
 (0)