[Commits] c0e1ceabbf9: MDEV-23573: SIGSEGV in Column_stat::store_stat_fields
revision-id: c0e1ceabbf9b8a824daf36a2bbc29301f545daff (mariadb-10.1.43-293-gc0e1ceabbf9) parent(s): 1be8ac390d3665d061141fe50a1c9e63b7b4b294 author: Varun Gupta committer: Varun Gupta timestamp: 2020-09-26 16:36:52 +0530 message: MDEV-23573: SIGSEGV in Column_stat::store_stat_fields For EITS collection min and max fields are allocated for each column that is set in the read_set bitmap of a table. This allocation of min and max fields happens inside alloc_statistics_for_table. For a partitioned table ha_rnd_init is called inside the function collect_statistics_for_table which sets the read_set bitmap for the columns inside the partition expression. This happens only when there is a write lock on the partitioned table. But the allocation happens before this, so min and max fields are not allocated for the columns involved in the partition expression. This resulted in a crash, as the EITS statistics were collected but there was no min and max field to store the value to. The fix would be to call ha_rnd_init inside the function alloc_statistics_for_table that would make sure that min and max fields are allocated for the columns involved in the partition expression. --- mysql-test/r/stat_tables.result | 10 +++++++ mysql-test/r/stat_tables_innodb.result | 10 +++++++ mysql-test/t/stat_tables.test | 10 +++++++ sql/sql_statistics.cc | 49 +++++++++++++++++----------------- 4 files changed, 55 insertions(+), 24 deletions(-) diff --git a/mysql-test/r/stat_tables.result b/mysql-test/r/stat_tables.result index d26221b5f8d..469bd322ee0 100644 --- a/mysql-test/r/stat_tables.result +++ b/mysql-test/r/stat_tables.result @@ -742,3 +742,13 @@ drop table t1; set @@optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity; set @save_optimizer_switch=@@optimizer_switch; set use_stat_tables=@save_use_stat_tables; +# +# MDEV-23753: SIGSEGV in Column_stat::store_stat_fields +# +CREATE TABLE t1 (a INT, b INT) PARTITION BY HASH (b) PARTITIONS 2; +LOCK TABLES t1 WRITE; +ANALYZE TABLE t1 PERSISTENT FOR COLUMNS (a) INDEXES (); +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +DROP TABLE t1; diff --git a/mysql-test/r/stat_tables_innodb.result b/mysql-test/r/stat_tables_innodb.result index fd9f337c30d..d3dcffb14c7 100644 --- a/mysql-test/r/stat_tables_innodb.result +++ b/mysql-test/r/stat_tables_innodb.result @@ -769,6 +769,16 @@ drop table t1; set @@optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity; set @save_optimizer_switch=@@optimizer_switch; set use_stat_tables=@save_use_stat_tables; +# +# MDEV-23753: SIGSEGV in Column_stat::store_stat_fields +# +CREATE TABLE t1 (a INT, b INT) PARTITION BY HASH (b) PARTITIONS 2; +LOCK TABLES t1 WRITE; +ANALYZE TABLE t1 PERSISTENT FOR COLUMNS (a) INDEXES (); +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +DROP TABLE t1; set optimizer_switch=@save_optimizer_switch_for_stat_tables_test; # # MDEV-22851: Engine independent index statistics are incorrect for large tables on Windows. diff --git a/mysql-test/t/stat_tables.test b/mysql-test/t/stat_tables.test index e9f37698a73..df16b3c9403 100644 --- a/mysql-test/t/stat_tables.test +++ b/mysql-test/t/stat_tables.test @@ -1,4 +1,5 @@ --source include/have_stat_tables.inc +--source include/have_partition.inc select @@global.use_stat_tables; select @@session.use_stat_tables; @@ -503,3 +504,12 @@ set @@optimizer_use_condition_selectivity= @save_optimizer_use_condition_selecti set @save_optimizer_switch=@@optimizer_switch; set use_stat_tables=@save_use_stat_tables; + +--echo # +--echo # MDEV-23753: SIGSEGV in Column_stat::store_stat_fields +--echo # + +CREATE TABLE t1 (a INT, b INT) PARTITION BY HASH (b) PARTITIONS 2; +LOCK TABLES t1 WRITE; +ANALYZE TABLE t1 PERSISTENT FOR COLUMNS (a) INDEXES (); +DROP TABLE t1; diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index c2581fd6105..1f1ef41a9dd 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -2099,6 +2099,9 @@ int alloc_statistics_for_table(THD* thd, TABLE *table) ulonglong *idx_avg_frequency= (ulonglong*) alloc_root(&table->mem_root, sizeof(ulonglong) * key_parts); + if (table->file->ha_rnd_init(TRUE)) + DBUG_RETURN(1); + uint columns= 0; for (field_ptr= table->field; *field_ptr; field_ptr++) { @@ -2591,36 +2594,34 @@ int collect_statistics_for_table(THD *thd, TABLE *table) restore_record(table, s->default_values); /* Perform a full table scan to collect statistics on 'table's columns */ - if (!(rc= file->ha_rnd_init(TRUE))) - { - DEBUG_SYNC(table->in_use, "statistics_collection_start"); - while ((rc= file->ha_rnd_next(table->record[0])) != HA_ERR_END_OF_FILE) - { - if (thd->killed) - break; + DEBUG_SYNC(table->in_use, "statistics_collection_start"); - if (rc) - { - if (rc == HA_ERR_RECORD_DELETED) - continue; - break; - } + while ((rc= file->ha_rnd_next(table->record[0])) != HA_ERR_END_OF_FILE) + { + if (thd->killed) + break; - for (field_ptr= table->field; *field_ptr; field_ptr++) - { - table_field= *field_ptr; - if (!bitmap_is_set(table->read_set, table_field->field_index)) - continue; - if ((rc= table_field->collected_stats->add(rows))) - break; - } - if (rc) + if (rc) + { + if (rc == HA_ERR_RECORD_DELETED) + continue; + break; + } + + for (field_ptr= table->field; *field_ptr; field_ptr++) + { + table_field= *field_ptr; + if (!bitmap_is_set(table->read_set, table_field->field_index)) + continue; + if ((rc= table_field->collected_stats->add(rows))) break; - rows++; } - file->ha_rnd_end(); + if (rc) + break; + rows++; } + file->ha_rnd_end(); rc= (rc == HA_ERR_END_OF_FILE && !thd->killed) ? 0 : 1; /*
participants (1)
-
varun