diff options
author | Varun Gupta <varun.gupta@mariadb.com> | 2019-09-18 01:59:29 +0530 |
---|---|---|
committer | Varun Gupta <varun.gupta@mariadb.com> | 2019-09-18 15:06:02 +0530 |
commit | 273d8eb12c40a6dcd05a8148bdfba3f1fd96e764 (patch) | |
tree | 4d67cbf15ce5cc7fac333cac019f70eb4afb3916 | |
parent | c471bfb34e970075d8649247ab088b19a097eaf4 (diff) | |
download | mariadb-git-273d8eb12c40a6dcd05a8148bdfba3f1fd96e764.tar.gz |
MDEV-20589: Server still crashes in Field::set_warning_truncated_wrong_value
The flag is_stat_field is not set for the min_value and max_value of field items
inside table share. This is a must requirement as we don't want to throw
warnings of truncation when we read values from the statistics table to the column
statistics of table share fields.
-rw-r--r-- | mysql-test/r/stat_tables.result | 23 | ||||
-rw-r--r-- | mysql-test/r/stat_tables_innodb.result | 23 | ||||
-rw-r--r-- | mysql-test/t/stat_tables.test | 22 | ||||
-rw-r--r-- | sql/field.cc | 14 | ||||
-rw-r--r-- | sql/field.h | 1 | ||||
-rw-r--r-- | sql/sql_statistics.cc | 4 |
6 files changed, 73 insertions, 14 deletions
diff --git a/mysql-test/r/stat_tables.result b/mysql-test/r/stat_tables.result index c47a47cea31..bb3a0a80f7e 100644 --- a/mysql-test/r/stat_tables.result +++ b/mysql-test/r/stat_tables.result @@ -802,5 +802,28 @@ set use_stat_tables=@save_use_stat_tables; set @@histogram_size= @save_histogram_size; set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity; drop table t1; +# +# MDEV-20589: Server still crashes in Field::set_warning_truncated_wrong_value +# +set names utf8; +create table t1 ( a varchar(255) character set utf8); +insert into t1 values (REPEAT('ӥ',255)), (REPEAT('ç',255)); +set use_stat_tables='preferably'; +analyze table t1 persistent for all; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +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('ӥ',256) where db_name='test' and table_name='t1'; +Warnings: +Warning 1265 Data truncated for column 'min_value' at row 1 +set @@sql_mode= @save_sql_mode; +select length(a) from t1 where a=REPEAT('ӥ',255); +length(a) +510 +set names latin1; +set @@use_stat_tables=@save_use_stat_tables; +drop table t1; # please keep this at the last set @@global.histogram_size=@save_histogram_size; diff --git a/mysql-test/r/stat_tables_innodb.result b/mysql-test/r/stat_tables_innodb.result index dcfdb55f9c9..a436efb5fea 100644 --- a/mysql-test/r/stat_tables_innodb.result +++ b/mysql-test/r/stat_tables_innodb.result @@ -829,6 +829,29 @@ set use_stat_tables=@save_use_stat_tables; set @@histogram_size= @save_histogram_size; set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity; drop table t1; +# +# MDEV-20589: Server still crashes in Field::set_warning_truncated_wrong_value +# +set names utf8; +create table t1 ( a varchar(255) character set utf8); +insert into t1 values (REPEAT('ӥ',255)), (REPEAT('ç',255)); +set use_stat_tables='preferably'; +analyze table t1 persistent for all; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +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('ӥ',256) where db_name='test' and table_name='t1'; +Warnings: +Warning 1265 Data truncated for column 'min_value' at row 1 +set @@sql_mode= @save_sql_mode; +select length(a) from t1 where a=REPEAT('ӥ',255); +length(a) +510 +set names latin1; +set @@use_stat_tables=@save_use_stat_tables; +drop table t1; # please keep this at the last set @@global.histogram_size=@save_histogram_size; set optimizer_switch=@save_optimizer_switch_for_stat_tables_test; diff --git a/mysql-test/t/stat_tables.test b/mysql-test/t/stat_tables.test index 880e6378ca5..4c21e21ea70 100644 --- a/mysql-test/t/stat_tables.test +++ b/mysql-test/t/stat_tables.test @@ -546,5 +546,27 @@ set @@histogram_size= @save_histogram_size; set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity; drop table t1; +--echo # +--echo # MDEV-20589: Server still crashes in Field::set_warning_truncated_wrong_value +--echo # + +set names utf8; +create table t1 ( a varchar(255) character set utf8); +insert into t1 values (REPEAT('ӥ',255)), (REPEAT('ç',255)); + +set use_stat_tables='preferably'; +analyze table t1 persistent for all; + +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('ӥ',256) where db_name='test' and table_name='t1'; +set @@sql_mode= @save_sql_mode; + +select length(a) from t1 where a=REPEAT('ӥ',255); + +set names latin1; +set @@use_stat_tables=@save_use_stat_tables; +drop table t1; + --echo # please keep this at the last set @@global.histogram_size=@save_histogram_size; diff --git a/sql/field.cc b/sql/field.cc index 2b1ba0e1372..fd4cd8d5c54 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2436,14 +2436,14 @@ Field *Field::clone(MEM_ROOT *root, TABLE *new_table) } - Field *Field::clone(MEM_ROOT *root, TABLE *new_table, my_ptrdiff_t diff, bool stat_flag) { Field *tmp; if ((tmp= (Field*) memdup_root(root,(char*) this,size_of()))) { - tmp->init(new_table); + if (new_table) + tmp->init(new_table); tmp->move_field_offset(diff); } tmp->is_stat_field= stat_flag; @@ -2451,16 +2451,6 @@ Field *Field::clone(MEM_ROOT *root, TABLE *new_table, my_ptrdiff_t diff, } -Field *Field::clone(MEM_ROOT *root, my_ptrdiff_t diff) -{ - Field *tmp; - if ((tmp= (Field*) memdup_root(root,(char*) this,size_of()))) - { - tmp->move_field_offset(diff); - } - return tmp; -} - int Field::set_default() { if (default_value) diff --git a/sql/field.h b/sql/field.h index 19a716cfd5d..3f027868c3c 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1220,7 +1220,6 @@ public: Field *clone(MEM_ROOT *mem_root, TABLE *new_table); Field *clone(MEM_ROOT *mem_root, TABLE *new_table, my_ptrdiff_t diff, bool stat_flag= FALSE); - Field *clone(MEM_ROOT *mem_root, my_ptrdiff_t diff); inline void move_field(uchar *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg) { ptr=ptr_arg; null_ptr=null_ptr_arg; null_bit=null_bit_arg; diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index 26032d8d535..578d3fac641 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -1153,12 +1153,14 @@ public: case COLUMN_STAT_MIN_VALUE: table_field->read_stats->min_value->set_notnull(); stat_field->val_str(&val); + DBUG_ASSERT(table_field->read_stats->min_value->is_stat_field); table_field->read_stats->min_value->store(val.ptr(), val.length(), &my_charset_bin); break; case COLUMN_STAT_MAX_VALUE: table_field->read_stats->max_value->set_notnull(); stat_field->val_str(&val); + DBUG_ASSERT(table_field->read_stats->min_value->is_stat_field); table_field->read_stats->max_value->store(val.ptr(), val.length(), &my_charset_bin); break; @@ -2045,7 +2047,7 @@ void create_min_max_statistical_fields_for_table_share(THD *thd, Field *fld; Field *table_field= *field_ptr; my_ptrdiff_t diff= record - table_share->default_values; - if (!(fld= table_field->clone(&stats_cb->mem_root, diff))) + if (!(fld= table_field->clone(&stats_cb->mem_root, NULL, diff, TRUE))) continue; if (i == 0) table_field->read_stats->min_value= fld; |