From 3b94309a6cec8d8149c9f312229d18227036e01d Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Tue, 12 Jan 2021 11:17:37 +0530 Subject: [PATCH] MDEV-23753: 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 | 14 ++++++++++++++ mysql-test/r/stat_tables_innodb.result | 14 ++++++++++++++ mysql-test/t/stat_tables.test | 12 ++++++++++++ sql/sql_statistics.cc | 4 ++++ 4 files changed, 44 insertions(+) diff --git a/mysql-test/r/stat_tables.result b/mysql-test/r/stat_tables.result index bb3a0a80f7e..a52db46d119 100644 --- a/mysql-test/r/stat_tables.result +++ b/mysql-test/r/stat_tables.result @@ -825,5 +825,19 @@ length(a) set names latin1; set @@use_stat_tables=@save_use_stat_tables; drop table t1; +# +# 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 +ANALYZE TABLE t1 PERSISTENT FOR COLUMNS (nonexisting) INDEXES (nonexisting); +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze error Invalid argument +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 23b952cc891..3be6b0bd4b3 100644 --- a/mysql-test/r/stat_tables_innodb.result +++ b/mysql-test/r/stat_tables_innodb.result @@ -852,6 +852,20 @@ length(a) set names latin1; set @@use_stat_tables=@save_use_stat_tables; drop table t1; +# +# 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 +ANALYZE TABLE t1 PERSISTENT FOR COLUMNS (nonexisting) INDEXES (nonexisting); +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze error Invalid argument +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 4c21e21ea70..f7c18637cdd 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; @@ -568,5 +569,16 @@ set names latin1; set @@use_stat_tables=@save_use_stat_tables; drop table t1; +--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 (); +ANALYZE TABLE t1 PERSISTENT FOR COLUMNS (nonexisting) INDEXES (nonexisting); +DROP TABLE t1; + + --echo # please keep this at the last set @@global.histogram_size=@save_histogram_size; diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index ab8edbf584b..b63172045e6 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -2110,6 +2110,10 @@ 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); + table->file->ha_rnd_end(); + uint columns= 0; for (field_ptr= table->field; *field_ptr; field_ptr++) {