summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2013-01-13 00:40:38 -0800
committerIgor Babaev <igor@askmonty.org>2013-01-13 00:40:38 -0800
commit7d5c56cb410bd0363e1c66c31149a79086584bbb (patch)
treecf76debbd4fa1d761c00f5798aec2e1843185686
parent7d9df8075e4c9392f4352e6ccd86921994f264bc (diff)
downloadmariadb-git-7d5c56cb410bd0363e1c66c31149a79086584bbb.tar.gz
Fixed bug mdev-4019.
The bug could cause a crash when several connections needed persistent statistics for the same table. Also added a missing call of set_statistics_for_table() in the code of the function mysql_update.
-rw-r--r--mysql-test/r/stat_tables_par.result20
-rw-r--r--mysql-test/r/stat_tables_par_innodb.result20
-rw-r--r--mysql-test/t/stat_tables_par.test33
-rw-r--r--sql/sql_base.cc1
-rw-r--r--sql/sql_statistics.cc10
-rw-r--r--sql/sql_update.cc2
-rw-r--r--sql/table.h1
7 files changed, 85 insertions, 2 deletions
diff --git a/mysql-test/r/stat_tables_par.result b/mysql-test/r/stat_tables_par.result
index 76a42e993f6..a98f934fa96 100644
--- a/mysql-test/r/stat_tables_par.result
+++ b/mysql-test/r/stat_tables_par.result
@@ -219,4 +219,24 @@ set debug_sync='RESET';
set global use_stat_tables=@save_global_use_stat_tables;
DROP DATABASE dbt3_s001;
use test;
+set @save_global_use_stat_tables=@@global.use_stat_tables;
+set global use_stat_tables='preferably';
+set debug_sync='RESET';
+create table t1 (a int, b int, key(a));
+insert t1 values (1,1),(2,2);
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+SET debug_sync='after_open_table_ignore_flush WAIT_FOR go';
+select * from information_schema.statistics where table_schema='test';
+select * from t1;
+a b
+1 1
+2 2
+SET DEBUG_SYNC= "now SIGNAL go";
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME NON_UNIQUE INDEX_SCHEMA INDEX_NAME SEQ_IN_INDEX COLUMN_NAME COLLATION CARDINALITY SUB_PART PACKED NULLABLE INDEX_TYPE COMMENT INDEX_COMMENT
+def test t1 1 test a 1 a A 2 NULL NULL YES BTREE
+set debug_sync='RESET';
+drop table t1;
+set global use_stat_tables=@save_global_use_stat_tables;
set use_stat_tables=@save_use_stat_tables;
diff --git a/mysql-test/r/stat_tables_par_innodb.result b/mysql-test/r/stat_tables_par_innodb.result
index ff1a296e5af..e0c00c482a0 100644
--- a/mysql-test/r/stat_tables_par_innodb.result
+++ b/mysql-test/r/stat_tables_par_innodb.result
@@ -228,6 +228,26 @@ set debug_sync='RESET';
set global use_stat_tables=@save_global_use_stat_tables;
DROP DATABASE dbt3_s001;
use test;
+set @save_global_use_stat_tables=@@global.use_stat_tables;
+set global use_stat_tables='preferably';
+set debug_sync='RESET';
+create table t1 (a int, b int, key(a));
+insert t1 values (1,1),(2,2);
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+SET debug_sync='after_open_table_ignore_flush WAIT_FOR go';
+select * from information_schema.statistics where table_schema='test';
+select * from t1;
+a b
+1 1
+2 2
+SET DEBUG_SYNC= "now SIGNAL go";
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME NON_UNIQUE INDEX_SCHEMA INDEX_NAME SEQ_IN_INDEX COLUMN_NAME COLLATION CARDINALITY SUB_PART PACKED NULLABLE INDEX_TYPE COMMENT INDEX_COMMENT
+def test t1 1 test a 1 a A 2 NULL NULL YES BTREE
+set debug_sync='RESET';
+drop table t1;
+set global use_stat_tables=@save_global_use_stat_tables;
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_par.test b/mysql-test/t/stat_tables_par.test
index 57b57e3ebba..6c4e1be6e48 100644
--- a/mysql-test/t/stat_tables_par.test
+++ b/mysql-test/t/stat_tables_par.test
@@ -242,4 +242,37 @@ DROP DATABASE dbt3_s001;
use test;
+#
+# Bug mdev-4019: crash when executing in parallel ANALYZE and
+# SELECT * FROM information_schema.statistics
+#
+
+set @save_global_use_stat_tables=@@global.use_stat_tables;
+set global use_stat_tables='preferably';
+set debug_sync='RESET';
+
+create table t1 (a int, b int, key(a));
+insert t1 values (1,1),(2,2);
+
+analyze table t1;
+
+SET debug_sync='after_open_table_ignore_flush WAIT_FOR go';
+send select * from information_schema.statistics where table_schema='test';
+
+connect(con1, localhost, root);
+connection con1;
+select * from t1;
+SET DEBUG_SYNC= "now SIGNAL go";
+
+connection default;
+reap;
+
+connection default;
+disconnect con1;
+set debug_sync='RESET';
+
+drop table t1;
+set global use_stat_tables=@save_global_use_stat_tables;
+
+
set use_stat_tables=@save_use_stat_tables;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index b7f321e6290..cb1555ea142 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -4654,6 +4654,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
Field **table_field_ptr= tables->table->field;
for ( ; *field_ptr; field_ptr++, table_field_ptr++)
(*table_field_ptr)->read_stats= (*field_ptr)->read_stats;
+ tables->table->stats_is_read= table_share->stats_cb.stats_is_read;
}
}
}
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index 9de5aa080e1..68f26ebf90b 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -2501,6 +2501,8 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
}
}
+ table->stats_is_read= TRUE;
+
DBUG_RETURN(0);
}
@@ -2559,6 +2561,8 @@ bool statistics_for_tables_is_needed(THD *thd, TABLE_LIST *tables)
table_share->stats_cb.stats_can_be_read &&
!table_share->stats_cb.stats_is_read)
return TRUE;
+ if (table_share->stats_cb.stats_is_read)
+ tl->table->stats_is_read= TRUE;
}
}
@@ -2618,6 +2622,8 @@ int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables)
(void) read_statistics_for_table(thd, tl->table, stat_tables);
table_share->stats_cb.stats_is_read= TRUE;
}
+ if (table_share->stats_cb.stats_is_read)
+ tl->table->stats_is_read= TRUE;
}
}
@@ -3045,7 +3051,7 @@ void set_statistics_for_table(THD *thd, TABLE *table)
Use_stat_tables_mode use_stat_table_mode= get_use_stat_tables_mode(thd);
table->used_stat_records=
(use_stat_table_mode <= COMPLEMENTARY ||
- !stats_cb->stats_is_read || read_stats->cardinality_is_null) ?
+ !table->stats_is_read || read_stats->cardinality_is_null) ?
table->file->stats.records : read_stats->cardinality;
KEY *key_info, *key_info_end;
for (key_info= table->key_info, key_info_end= key_info+table->s->keys;
@@ -3053,7 +3059,7 @@ void set_statistics_for_table(THD *thd, TABLE *table)
{
key_info->is_statistics_from_stat_tables=
(use_stat_table_mode > COMPLEMENTARY &&
- stats_cb->stats_is_read &&
+ table->stats_is_read &&
key_info->read_stats->avg_frequency_is_inited() &&
key_info->read_stats->get_avg_frequency(0) > 0.5);
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 78b693c5237..31df7a2a4b1 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -32,6 +32,7 @@
#include "sql_view.h" // check_key_in_view
#include "sp_head.h"
#include "sql_trigger.h"
+#include "sql_statistics.h"
#include "probes_mysql.h"
#include "debug_sync.h"
#include "key.h" // is_key_used
@@ -404,6 +405,7 @@ int mysql_update(THD *thd,
#endif
/* Update the table->file->stats.records number */
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
+ set_statistics_for_table(thd, table);
select= make_select(table, 0, 0, conds, 0, &error);
if (error || !limit || thd->is_error() ||
diff --git a/sql/table.h b/sql/table.h
index a2b197ac1f3..ac0eb0dad89 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1189,6 +1189,7 @@ public:
bool no_partitions_used; /* If true, all partitions have been pruned away */
#endif
uint max_keys; /* Size of allocated key_info array. */
+ bool stats_is_read; /* Persistent statistics is read for the table */
MDL_ticket *mdl_ticket;
void init(THD *thd, TABLE_LIST *tl);