[Commits] c0e1ceabbf9: MDEV-23573: SIGSEGV in Column_stat::store_stat_fields

varun varunraiko1803 at gmail.com
Sat Sep 26 14:08:45 EEST 2020


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;
 
   /* 


More information about the commits mailing list