summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2012-08-27 14:19:25 -0700
committerIgor Babaev <igor@askmonty.org>2012-08-27 14:19:25 -0700
commitd0ad93fbc7eca575364e46f67c4613efb0807047 (patch)
tree6b9aae82750afbb2093c2d997076666b91838dcc
parentf4631d6f71c19a98eccf4998eccb49dd69897661 (diff)
downloadmariadb-git-d0ad93fbc7eca575364e46f67c4613efb0807047.tar.gz
Fixed bug mdev-487.
The function collect_statistics_for_table() when scanning a table did not take into account that the handler function ha_rnd_next could return the code HA_ERR_RECORD_DELETE that should not be considered as an indication of an error. Also fixed a potential memory leak in this function.
-rw-r--r--mysql-test/r/stat_tables.result11
-rw-r--r--mysql-test/r/stat_tables_innodb.result11
-rw-r--r--mysql-test/t/stat_tables.test13
-rw-r--r--sql/sql_statistics.cc36
4 files changed, 65 insertions, 6 deletions
diff --git a/mysql-test/r/stat_tables.result b/mysql-test/r/stat_tables.result
index 4cc486b10ef..3cc650e7050 100644
--- a/mysql-test/r/stat_tables.result
+++ b/mysql-test/r/stat_tables.result
@@ -353,4 +353,15 @@ Table Op Msg_type Msg_text
test.t1 analyze status Table is already up to date
alter table t1 add column a varchar(8);
drop table t1;
+#
+# Bug mdev-487: memory leak in ANALYZE with stat tables
+#
+SET use_stat_tables = 'preferably';
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2);
+DELETE FROM t1 WHERE a=1;
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+DROP TABLE t1;
set use_stat_tables=@save_use_stat_tables;
diff --git a/mysql-test/r/stat_tables_innodb.result b/mysql-test/r/stat_tables_innodb.result
index 250f24fee02..bb0497ee331 100644
--- a/mysql-test/r/stat_tables_innodb.result
+++ b/mysql-test/r/stat_tables_innodb.result
@@ -380,6 +380,17 @@ Table Op Msg_type Msg_text
test.t1 analyze status OK
alter table t1 add column a varchar(8);
drop table t1;
+#
+# Bug mdev-487: memory leak in ANALYZE with stat tables
+#
+SET use_stat_tables = 'preferably';
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2);
+DELETE FROM t1 WHERE a=1;
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+DROP TABLE t1;
set use_stat_tables=@save_use_stat_tables;
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 67e66a52a6a..3ef5b4e9b92 100644
--- a/mysql-test/t/stat_tables.test
+++ b/mysql-test/t/stat_tables.test
@@ -166,5 +166,18 @@ alter table t1 add column a varchar(8);
drop table t1;
+--echo #
+--echo # Bug mdev-487: memory leak in ANALYZE with stat tables
+--echo #
+
+SET use_stat_tables = 'preferably';
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2);
+DELETE FROM t1 WHERE a=1;
+
+ANALYZE TABLE t1;
+
+DROP TABLE t1;
set use_stat_tables=@save_use_stat_tables;
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index f58659862c4..c3d95da007e 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -179,6 +179,7 @@ public:
inline void init(THD *thd, Field * table_field);
inline void add(ha_rows rowno);
inline void finish(ha_rows rows);
+ inline void cleanup();
};
@@ -1895,6 +1896,22 @@ void Column_statistics_collected::finish(ha_rows rows)
/**
@brief
+ Clean up auxiliary structures used for aggregation
+*/
+
+inline
+void Column_statistics_collected::cleanup()
+{
+ if (count_distinct)
+ {
+ delete count_distinct;
+ count_distinct= NULL;
+ }
+}
+
+
+/**
+ @brief
Collect statistical data on an index
@param
@@ -2047,7 +2064,11 @@ int collect_statistics_for_table(THD *thd, TABLE *table)
break;
if (rc)
+ {
+ if (rc == HA_ERR_RECORD_DELETED)
+ continue;
break;
+ }
for (field_ptr= table->field; *field_ptr; field_ptr++)
{
@@ -2071,14 +2092,17 @@ int collect_statistics_for_table(THD *thd, TABLE *table)
{
table->collected_stats->cardinality_is_null= FALSE;
table->collected_stats->cardinality= rows;
+ }
- 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;
+ 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->finish(rows);
- }
+ else
+ table_field->collected_stats->cleanup();
}
if (!rc)