revision-id: a6bcd05da441169f87acc433dd2e08cc7505ea95 (mariadb-10.2.22-108-ga6bcd05da44) parent(s): c676f58c270d75b6c1889b24b9833afc65b0d98b author: Varun Gupta committer: Varun Gupta timestamp: 2019-03-28 12:18:30 +0530 message: MDEV-18899: Server crashes in Field::set_warning_truncated_wrong_value 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. --- mysql-test/r/stat_tables.result | 57 ++++++++++++++++++++++++++++++++++ mysql-test/r/stat_tables_innodb.result | 57 ++++++++++++++++++++++++++++++++++ mysql-test/t/stat_tables.test | 40 ++++++++++++++++++++++++ sql/field.cc | 7 +++-- sql/sql_statistics.cc | 10 ++++-- 5 files changed, 166 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/stat_tables.result b/mysql-test/r/stat_tables.result index 3ebc3b47833..be868e55e84 100644 --- a/mysql-test/r/stat_tables.result +++ b/mysql-test/r/stat_tables.result @@ -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; diff --git a/mysql-test/r/stat_tables_innodb.result b/mysql-test/r/stat_tables_innodb.result index a6c5525a0d3..86088490871 100644 --- a/mysql-test/r/stat_tables_innodb.result +++ b/mysql-test/r/stat_tables_innodb.result @@ -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; diff --git a/mysql-test/t/stat_tables.test b/mysql-test/t/stat_tables.test index b89ab2bbd2d..89c11ed4acf 100644 --- a/mysql-test/t/stat_tables.test +++ b/mysql-test/t/stat_tables.test @@ -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; diff --git a/sql/field.cc b/sql/field.cc index 080cf34c76d..0621015c0e4 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -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; } diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index b5811c683e8..0a51346adb2 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -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: @@ -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: @@ -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);