Commit 7fe455a6 authored by Konstantin Osipov's avatar Konstantin Osipov

A fix and a test case for Bug#51710 FLUSH TABLES <view> WITH READ

LOCK kills the server.

Prohibit FLUSH TABLES WITH READ LOCK application to views or
temporary tables.
Fix a subtle bug in the implementation when we actually
did not remove table share objects from the table cache after 
acquiring exclusive locks.

mysql-test/r/flush.result:
  Update results (Bug#51710)
mysql-test/t/flush.test:
  Add a test case for Bug#51710.
sql/sql_parse.cc:
  Fix Bug#51710 "FLUSH TABLES <view> WITH READ LOCK
  killes the server.
  Ensure we don't open views and temporary tables.
  Fix a yet another bug in the implementation which 
  did not actually remove the tables from cache after acquiring
  exclusive locks.
parent 366a68bb
...@@ -207,3 +207,30 @@ insert into t2 (a) values (3); ...@@ -207,3 +207,30 @@ insert into t2 (a) values (3);
unlock tables; unlock tables;
# --> connection con1 # --> connection con1
drop table t1, t2, t3; drop table t1, t2, t3;
#
# Bug#51710 FLUSH TABLES <view> WITH READ LOCK kills the server
#
drop view if exists v1, v2, v3;
drop table if exists t1, v1;
create table t1 (a int);
create view v1 as select 1;
create view v2 as select * from t1;
create view v3 as select * from v2;
flush table v1, v2, v3 with read lock;
ERROR HY000: 'test.v1' is not BASE TABLE
flush table v1 with read lock;
ERROR HY000: 'test.v1' is not BASE TABLE
flush table v2 with read lock;
ERROR HY000: 'test.v2' is not BASE TABLE
flush table v3 with read lock;
ERROR HY000: 'test.v3' is not BASE TABLE
create temporary table v1 (a int);
flush table v1 with read lock;
ERROR HY000: 'test.v1' is not BASE TABLE
drop view v1;
create table v1 (a int);
flush table v1 with read lock;
drop temporary table v1;
unlock tables;
drop view v2, v3;
drop table t1, v1;
...@@ -324,3 +324,34 @@ disconnect con1; ...@@ -324,3 +324,34 @@ disconnect con1;
--source include/wait_until_disconnected.inc --source include/wait_until_disconnected.inc
connection default; connection default;
drop table t1, t2, t3; drop table t1, t2, t3;
--echo #
--echo # Bug#51710 FLUSH TABLES <view> WITH READ LOCK kills the server
--echo #
--disable_warnings
drop view if exists v1, v2, v3;
drop table if exists t1, v1;
--enable_warnings
create table t1 (a int);
create view v1 as select 1;
create view v2 as select * from t1;
create view v3 as select * from v2;
--error ER_WRONG_OBJECT
flush table v1, v2, v3 with read lock;
--error ER_WRONG_OBJECT
flush table v1 with read lock;
--error ER_WRONG_OBJECT
flush table v2 with read lock;
--error ER_WRONG_OBJECT
flush table v3 with read lock;
create temporary table v1 (a int);
--error ER_WRONG_OBJECT
flush table v1 with read lock;
drop view v1;
create table v1 (a int);
flush table v1 with read lock;
drop temporary table v1;
unlock tables;
drop view v2, v3;
drop table t1, v1;
...@@ -1631,6 +1631,14 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, ...@@ -1631,6 +1631,14 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
- you can't flush WITH READ LOCK a non-existent table - you can't flush WITH READ LOCK a non-existent table
- you can't flush WITH READ LOCK under LOCK TABLES - you can't flush WITH READ LOCK under LOCK TABLES
- currently incompatible with the GRL (@todo: fix) - currently incompatible with the GRL (@todo: fix)
Effect on views and temporary tables.
------------------------------------
You can only apply this command to existing base tables.
If a view with such name exists, ER_WRONG_OBJECT is returned.
If a temporary table with such name exists, it's ignored:
if there is a base table, it's used, otherwise ER_NO_SUCH_TABLE
is returned.
*/ */
static bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables) static bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
...@@ -1665,6 +1673,21 @@ static bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables) ...@@ -1665,6 +1673,21 @@ static bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
if (lock_table_names(thd, all_tables)) if (lock_table_names(thd, all_tables))
goto error; goto error;
for (table_list= all_tables; table_list;
table_list= table_list->next_global)
{
/* Remove the table from cache. */
mysql_mutex_lock(&LOCK_open);
tdc_remove_table(thd, TDC_RT_REMOVE_ALL,
table_list->db,
table_list->table_name);
mysql_mutex_unlock(&LOCK_open);
/* Skip views and temporary tables. */
table_list->required_type= FRMTYPE_TABLE; /* Don't try to flush views. */
table_list->open_type= OT_BASE_ONLY; /* Ignore temporary tables. */
}
if (open_and_lock_tables(thd, all_tables, FALSE, if (open_and_lock_tables(thd, all_tables, FALSE,
MYSQL_OPEN_HAS_MDL_LOCK, MYSQL_OPEN_HAS_MDL_LOCK,
&lock_tables_prelocking_strategy) || &lock_tables_prelocking_strategy) ||
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment