Skip to content

Commit

Permalink
MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
Browse files Browse the repository at this point in the history
To fix the crash there we need to make sure that the
server while storing the statistical values in statistical tables should do it
in a multi-byte safe way.
Also there is no need to throw warnings if there is truncation while storing
values from statistical fields.
  • Loading branch information
Varun Gupta committed Mar 28, 2019
1 parent 1e9c2b2 commit 38cad68
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 5 deletions.
57 changes: 57 additions & 0 deletions mysql-test/r/stat_tables.result
Original file line number Diff line number Diff line change
Expand Up @@ -624,4 +624,61 @@ SELECT MAX(pk) FROM t1;
MAX(pk)
NULL
DROP TABLE t1;
#
# MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
#
set names utf8;
set @save_optimizer_use_condition_selectivity=@@optimizer_use_condition_selectivity;
set optimizer_use_condition_selectivity=4;
set use_stat_tables=preferably;
set @save_histogram_size= @@histogram_size;
set histogram_size=255;
create table t1 ( a varchar(255) character set utf8);
insert into t1 values (REPEAT('ӥ',255)), (REPEAT('ç',255));
analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats where db_name='test' and table_name='t1';
HEX(RIGHT(min_value, 1)) length(min_value)
A7 254
select HEX(RIGHT(max_value, 1)), length(max_value) from mysql.column_stats where db_name='test' and table_name='t1';
HEX(RIGHT(max_value, 1)) length(max_value)
A5 254
analyze select * from t1 where a >= 'ӥ';
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2.00 50.00 50.00 Using where
set @save_sql_mode= @@sql_mode;
set sql_mode='ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
update mysql.column_stats set min_value= REPEAT('ӥ',255) where db_name='test' and table_name='t1';
Warnings:
Warning 1265 Data truncated for column 'min_value' at row 1
select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats where db_name='test' and table_name='t1';
HEX(RIGHT(min_value, 1)) length(min_value)
D3 255
analyze select * from t1 where a >= 'ӥ';
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2.00 50.00 50.00 Using where
set names latin1;
drop table t1;
CREATE TABLE t1 (col1 date);
INSERT INTO t1 VALUES('2004-01-01'),('2004-02-29');
INSERT INTO t1 VALUES('0000-10-31');
analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
update mysql.column_stats set min_value='2004-0-31123' where db_name='test' and table_name='t1';
select min_value from mysql.column_stats where db_name='test' and table_name='t1';
min_value
2004-0-31123
select * from t1;
col1
2004-01-01
2004-02-29
0000-10-31
drop table t1;
set @@sql_mode= @save_sql_mode;
set use_stat_tables=@save_use_stat_tables;
set @@histogram_size= @save_histogram_size;
set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
57 changes: 57 additions & 0 deletions mysql-test/r/stat_tables_innodb.result
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,63 @@ SELECT MAX(pk) FROM t1;
MAX(pk)
NULL
DROP TABLE t1;
#
# MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
#
set names utf8;
set @save_optimizer_use_condition_selectivity=@@optimizer_use_condition_selectivity;
set optimizer_use_condition_selectivity=4;
set use_stat_tables=preferably;
set @save_histogram_size= @@histogram_size;
set histogram_size=255;
create table t1 ( a varchar(255) character set utf8);
insert into t1 values (REPEAT('ӥ',255)), (REPEAT('ç',255));
analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats where db_name='test' and table_name='t1';
HEX(RIGHT(min_value, 1)) length(min_value)
A7 254
select HEX(RIGHT(max_value, 1)), length(max_value) from mysql.column_stats where db_name='test' and table_name='t1';
HEX(RIGHT(max_value, 1)) length(max_value)
A5 254
analyze select * from t1 where a >= 'ӥ';
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2.00 50.00 50.00 Using where
set @save_sql_mode= @@sql_mode;
set sql_mode='ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
update mysql.column_stats set min_value= REPEAT('ӥ',255) where db_name='test' and table_name='t1';
Warnings:
Warning 1265 Data truncated for column 'min_value' at row 1
select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats where db_name='test' and table_name='t1';
HEX(RIGHT(min_value, 1)) length(min_value)
D3 255
analyze select * from t1 where a >= 'ӥ';
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2.00 50.00 50.00 Using where
set names latin1;
drop table t1;
CREATE TABLE t1 (col1 date);
INSERT INTO t1 VALUES('2004-01-01'),('2004-02-29');
INSERT INTO t1 VALUES('0000-10-31');
analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
update mysql.column_stats set min_value='2004-0-31123' where db_name='test' and table_name='t1';
select min_value from mysql.column_stats where db_name='test' and table_name='t1';
min_value
2004-0-31123
select * from t1;
col1
2004-01-01
2004-02-29
0000-10-31
drop table t1;
set @@sql_mode= @save_sql_mode;
set use_stat_tables=@save_use_stat_tables;
set @@histogram_size= @save_histogram_size;
set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
set optimizer_switch=@save_optimizer_switch_for_stat_tables_test;
SET SESSION STORAGE_ENGINE=DEFAULT;
40 changes: 40 additions & 0 deletions mysql-test/t/stat_tables.test
Original file line number Diff line number Diff line change
Expand Up @@ -401,4 +401,44 @@ SELECT MAX(pk) FROM t1;

DROP TABLE t1;

--echo #
--echo # MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value
--echo #

set names utf8;
set @save_optimizer_use_condition_selectivity=@@optimizer_use_condition_selectivity;
set optimizer_use_condition_selectivity=4;
set use_stat_tables=preferably;
set @save_histogram_size= @@histogram_size;
set histogram_size=255;

create table t1 ( a varchar(255) character set utf8);
insert into t1 values (REPEAT('ӥ',255)), (REPEAT('ç',255));

analyze table t1;
select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats where db_name='test' and table_name='t1';
select HEX(RIGHT(max_value, 1)), length(max_value) from mysql.column_stats where db_name='test' and table_name='t1';
analyze select * from t1 where a >= 'ӥ';

set @save_sql_mode= @@sql_mode;
set sql_mode='ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
update mysql.column_stats set min_value= REPEAT('ӥ',255) where db_name='test' and table_name='t1';
select HEX(RIGHT(min_value, 1)), length(min_value) from mysql.column_stats where db_name='test' and table_name='t1';
analyze select * from t1 where a >= 'ӥ';

set names latin1;
drop table t1;

CREATE TABLE t1 (col1 date);
INSERT INTO t1 VALUES('2004-01-01'),('2004-02-29');
INSERT INTO t1 VALUES('0000-10-31');
analyze table t1;
update mysql.column_stats set min_value='2004-0-31123' where db_name='test' and table_name='t1';
select min_value from mysql.column_stats where db_name='test' and table_name='t1';
select * from t1;
drop table t1;

set @@sql_mode= @save_sql_mode;
set use_stat_tables=@save_use_stat_tables;
set @@histogram_size= @save_histogram_size;
set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
7 changes: 5 additions & 2 deletions sql/field.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7027,8 +7027,11 @@ Field_longstr::check_string_copy_error(const String_copier *copier,
if (!(pos= copier->most_important_error_pos()))
return FALSE;

convert_to_printable(tmp, sizeof(tmp), pos, (end - pos), cs, 6);
set_warning_truncated_wrong_value("string", tmp);
if (!is_stat_field)
{
convert_to_printable(tmp, sizeof(tmp), pos, (end - pos), cs, 6);
set_warning_truncated_wrong_value("string", tmp);
}
return TRUE;
}

Expand Down
10 changes: 7 additions & 3 deletions sql/sql_statistics.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1060,7 +1060,9 @@ class Column_stat: public Stat_table
else
{
table_field->collected_stats->min_value->val_str(&val);
stat_field->store(val.ptr(), val.length(), &my_charset_bin);
uint32 length= Well_formed_prefix(val.charset(), val.ptr(),
MY_MIN(val.length(), stat_field->field_length)).length();
stat_field->store(val.ptr(), length, &my_charset_bin);
}
break;
case COLUMN_STAT_MAX_VALUE:
Expand All @@ -1069,7 +1071,9 @@ class Column_stat: public Stat_table
else
{
table_field->collected_stats->max_value->val_str(&val);
stat_field->store(val.ptr(), val.length(), &my_charset_bin);
uint32 length= Well_formed_prefix(val.charset(), val.ptr(),
MY_MIN(val.length(), stat_field->field_length)).length();
stat_field->store(val.ptr(), length, &my_charset_bin);
}
break;
case COLUMN_STAT_NULLS_RATIO:
Expand Down Expand Up @@ -3059,7 +3063,7 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
}
}
}

table->stats_is_read= TRUE;

DBUG_RETURN(0);
Expand Down

0 comments on commit 38cad68

Please sign in to comment.