Commit 9b9e36ed authored by Sergei Petrunia's avatar Sergei Petrunia

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.
parent 139ce6cb
...@@ -276,6 +276,23 @@ id select_type table type possible_keys key key_len ref rows filtered Extra ...@@ -276,6 +276,23 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
Warnings: Warnings:
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)) 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))
drop table t0,t1,t2; drop table t0,t1,t2;
#
# MDEV-8779: mysqld got signal 11 in sql/opt_range_mrr.cc:100(step_down_to)
#
set @tmp_mdev8779=@@optimizer_use_condition_selectivity;
set optimizer_use_condition_selectivity=5;
CREATE TABLE t1 (
i int(10) unsigned NOT NULL AUTO_INCREMENT,
n varchar(2048) NOT NULL,
d tinyint(1) unsigned NOT NULL,
p int(10) unsigned NOT NULL,
PRIMARY KEY (i)
) DEFAULT CHARSET=utf8;
insert into t1 values (1,'aaa',1,1), (2,'bbb',2,2);
SELECT * FROM t1 WHERE t1.d = 0 AND t1.p = '1' AND t1.i != '-1' AND t1.n = 'some text';
i n d p
set optimizer_use_condition_selectivity= @tmp_mdev8779;
DROP TABLE t1;
# #
# End of the test file # End of the test file
# #
......
...@@ -210,6 +210,23 @@ explain extended select * from t1 ta, t2 tb where ta.a < 40 and tb.a < 100 and t ...@@ -210,6 +210,23 @@ explain extended select * from t1 ta, t2 tb where ta.a < 40 and tb.a < 100 and t
drop table t0,t1,t2; drop table t0,t1,t2;
--echo #
--echo # MDEV-8779: mysqld got signal 11 in sql/opt_range_mrr.cc:100(step_down_to)
--echo #
set @tmp_mdev8779=@@optimizer_use_condition_selectivity;
set optimizer_use_condition_selectivity=5;
CREATE TABLE t1 (
i int(10) unsigned NOT NULL AUTO_INCREMENT,
n varchar(2048) NOT NULL,
d tinyint(1) unsigned NOT NULL,
p int(10) unsigned NOT NULL,
PRIMARY KEY (i)
) DEFAULT CHARSET=utf8;
insert into t1 values (1,'aaa',1,1), (2,'bbb',2,2);
SELECT * FROM t1 WHERE t1.d = 0 AND t1.p = '1' AND t1.i != '-1' AND t1.n = 'some text';
set optimizer_use_condition_selectivity= @tmp_mdev8779;
DROP TABLE t1;
--echo # --echo #
--echo # End of the test file --echo # End of the test file
--echo # --echo #
......
...@@ -2469,13 +2469,13 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, ...@@ -2469,13 +2469,13 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
DBUG_RETURN(0); // Can't use range DBUG_RETURN(0); // Can't use range
} }
key_parts= param.key_parts; key_parts= param.key_parts;
thd->mem_root= &alloc;
/* /*
Make an array with description of all key parts of all table keys. Make an array with description of all key parts of all table keys.
This is used in get_mm_parts function. This is used in get_mm_parts function.
*/ */
key_info= head->key_info; key_info= head->key_info;
uint max_key_len= 0;
for (idx=0 ; idx < head->s->keys ; idx++, key_info++) for (idx=0 ; idx < head->s->keys ; idx++, key_info++)
{ {
KEY_PART_INFO *key_part_info; KEY_PART_INFO *key_part_info;
...@@ -2488,6 +2488,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, ...@@ -2488,6 +2488,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
param.key[param.keys]=key_parts; param.key[param.keys]=key_parts;
key_part_info= key_info->key_part; key_part_info= key_info->key_part;
uint cur_key_len= 0;
for (uint part= 0 ; part < n_key_parts ; for (uint part= 0 ; part < n_key_parts ;
part++, key_parts++, key_part_info++) part++, key_parts++, key_part_info++)
{ {
...@@ -2495,6 +2496,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, ...@@ -2495,6 +2496,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
key_parts->part= part; key_parts->part= part;
key_parts->length= key_part_info->length; key_parts->length= key_part_info->length;
key_parts->store_length= key_part_info->store_length; key_parts->store_length= key_part_info->store_length;
cur_key_len += key_part_info->store_length;
key_parts->field= key_part_info->field; key_parts->field= key_part_info->field;
key_parts->null_bit= key_part_info->null_bit; key_parts->null_bit= key_part_info->null_bit;
key_parts->image_type = key_parts->image_type =
...@@ -2503,10 +2505,21 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, ...@@ -2503,10 +2505,21 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
key_parts->flag= (uint8) key_part_info->key_part_flag; key_parts->flag= (uint8) key_part_info->key_part_flag;
} }
param.real_keynr[param.keys++]=idx; param.real_keynr[param.keys++]=idx;
if (cur_key_len > max_key_len)
max_key_len= cur_key_len;
} }
param.key_parts_end=key_parts; param.key_parts_end=key_parts;
param.alloced_sel_args= 0; param.alloced_sel_args= 0;
if (!(param.min_key= (uchar*)alloc_root(&alloc,max_key_len)) ||
!(param.max_key= (uchar*)alloc_root(&alloc,max_key_len)))
{
thd->no_errors=0;
free_root(&alloc,MYF(0)); // Return memory & allocator
DBUG_RETURN(0); // Can't use range
}
thd->mem_root= &alloc;
/* Calculate cost of full index read for the shortest covering index */ /* Calculate cost of full index read for the shortest covering index */
if (!force_quick_range && !head->covering_keys.is_clear_all()) if (!force_quick_range && !head->covering_keys.is_clear_all())
{ {
...@@ -2730,7 +2743,7 @@ bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param, ...@@ -2730,7 +2743,7 @@ bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param,
return TRUE; return TRUE;
param->key_parts= key_part; param->key_parts= key_part;
uint max_key_len= 0;
for (field_ptr= table->field; *field_ptr; field_ptr++) for (field_ptr= table->field; *field_ptr; field_ptr++)
{ {
if (bitmap_is_set(used_fields, (*field_ptr)->field_index)) 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, ...@@ -2745,6 +2758,8 @@ bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param,
store_length+= HA_KEY_NULL_LENGTH; store_length+= HA_KEY_NULL_LENGTH;
if (field->real_type() == MYSQL_TYPE_VARCHAR) if (field->real_type() == MYSQL_TYPE_VARCHAR)
store_length+= HA_KEY_BLOB_LENGTH; store_length+= HA_KEY_BLOB_LENGTH;
if (max_key_len < store_length)
max_key_len= store_length;
key_part->store_length= store_length; key_part->store_length= store_length;
key_part->field= field; key_part->field= field;
key_part->image_type= Field::itRAW; key_part->image_type= Field::itRAW;
...@@ -2754,6 +2769,12 @@ bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param, ...@@ -2754,6 +2769,12 @@ bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param,
key_part++; key_part++;
} }
} }
if (!(param->min_key= (uchar*)alloc_root(param->mem_root, max_key_len)) ||
!(param->max_key= (uchar*)alloc_root(param->mem_root, max_key_len)))
{
return true;
}
param->keys= keys; param->keys= keys;
param->key_parts_end= key_part; param->key_parts_end= key_part;
...@@ -4306,12 +4327,15 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar) ...@@ -4306,12 +4327,15 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
Field **field= (ppar->part_fields)? part_info->part_field_array : Field **field= (ppar->part_fields)? part_info->part_field_array :
part_info->subpart_field_array; part_info->subpart_field_array;
bool in_subpart_fields= FALSE; bool in_subpart_fields= FALSE;
uint max_key_len= 0;
uint cur_key_len;
for (uint part= 0; part < total_parts; part++, key_part++) for (uint part= 0; part < total_parts; part++, key_part++)
{ {
key_part->key= 0; key_part->key= 0;
key_part->part= part; key_part->part= part;
key_part->length= (uint16)(*field)->key_length(); key_part->length= (uint16)(*field)->key_length();
key_part->store_length= (uint16)get_partition_field_store_length(*field); key_part->store_length= (uint16)get_partition_field_store_length(*field);
cur_key_len += key_part->store_length;
DBUG_PRINT("info", ("part %u length %u store_length %u", part, DBUG_PRINT("info", ("part %u length %u store_length %u", part,
key_part->length, key_part->store_length)); key_part->length, key_part->store_length));
...@@ -4337,10 +4361,21 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar) ...@@ -4337,10 +4361,21 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
{ {
field= part_info->subpart_field_array; field= part_info->subpart_field_array;
in_subpart_fields= TRUE; in_subpart_fields= TRUE;
max_key_len= cur_key_len;
cur_key_len= 0;
} }
} }
range_par->key_parts_end= key_part; range_par->key_parts_end= key_part;
if (cur_key_len > max_key_len)
max_key_len= cur_key_len;
if (!(range_par->min_key= (uchar*)alloc_root(alloc,max_key_len)) ||
!(range_par->max_key= (uchar*)alloc_root(alloc,max_key_len)))
{
return true;
}
DBUG_EXECUTE("info", print_partitioning_index(range_par->key_parts, DBUG_EXECUTE("info", print_partitioning_index(range_par->key_parts,
range_par->key_parts_end);); range_par->key_parts_end););
return FALSE; return FALSE;
......
...@@ -643,8 +643,8 @@ public: ...@@ -643,8 +643,8 @@ public:
Used to store 'current key tuples', in both range analysis and Used to store 'current key tuples', in both range analysis and
partitioning (list) analysis partitioning (list) analysis
*/ */
uchar min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH], uchar *min_key;
max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; uchar *max_key;
/* Number of SEL_ARG objects allocated by SEL_ARG::clone_tree operations */ /* Number of SEL_ARG objects allocated by SEL_ARG::clone_tree operations */
uint alloced_sel_args; uint alloced_sel_args;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment