Commit abba01f6 authored by Jon Olav Hauglid's avatar Jon Olav Hauglid

Bug #52593 SHOW CREATE TABLE is blocked if table is locked

           for write by another connection

The problem was that if a table was locked in one connection by
LOCK TABLES ... WRITE, REPAIR TABLE or OPTIMIZE TABLE, SHOW CREATE
TABLE from another connection would be blocked. As SHOW CREATE TABLE
only reads metadata about the table, such blocking is not needed.

The problem was that when SHOW CREATE TABLE tried to get a metadata
lock on the table in order to open it, it used the wrong type of
metadata lock request. It used MDL_SHARED_READ which is used when
the intent is to read both table metadata and table data. Instead
it should have used MDL_SHARED_HIGH_PRIO which signifies an intent
to only read metadata.

This patch fixes the problem by making sure SHOW CREATE TABLE uses
the MDL_SHARED_HIGH_PRIO metadata lock request type when trying to
open the table. The patch also fixes a similar problem with the
mysql_list_fields API call.

Test case added to show_check.test.
parent 22a1cc8a
...@@ -1448,3 +1448,20 @@ DROP USER test_u@localhost; ...@@ -1448,3 +1448,20 @@ DROP USER test_u@localhost;
SHOW CREATE TABLE non_existent; SHOW CREATE TABLE non_existent;
ERROR 70100: Query execution was interrupted ERROR 70100: Query execution was interrupted
End of 5.1 tests End of 5.1 tests
#
# Bug#52593 SHOW CREATE TABLE is blocked if table is locked
# for write by another connection
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (i INT PRIMARY KEY);
LOCK TABLE t1 WRITE;
# Switching to connection 'con1'.
# This statement used to be blocked.
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`i` int(11) NOT NULL,
PRIMARY KEY (`i`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
# Switching to connection 'default'.
UNLOCK TABLES;
DROP TABLE t1;
...@@ -1212,6 +1212,32 @@ DISCONNECT con1; ...@@ -1212,6 +1212,32 @@ DISCONNECT con1;
--echo End of 5.1 tests --echo End of 5.1 tests
--echo #
--echo # Bug#52593 SHOW CREATE TABLE is blocked if table is locked
--echo # for write by another connection
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
connect(con1, localhost,root);
connection default;
CREATE TABLE t1 (i INT PRIMARY KEY);
LOCK TABLE t1 WRITE;
--echo # Switching to connection 'con1'.
connection con1;
--echo # This statement used to be blocked.
SHOW CREATE TABLE t1;
--echo # Switching to connection 'default'.
connection default;
disconnect con1;
UNLOCK TABLES;
DROP TABLE t1;
# Wait till all disconnects are completed # Wait till all disconnects are completed
--source include/wait_until_count_sessions.inc --source include/wait_until_count_sessions.inc
/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. /* Copyright 2000, 2010 Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/* Function with list databases, tables or fields */ /* Function with list databases, tables or fields */
...@@ -641,7 +641,9 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) ...@@ -641,7 +641,9 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{ {
Show_create_error_handler view_error_suppressor(thd, table_list); Show_create_error_handler view_error_suppressor(thd, table_list);
thd->push_internal_handler(&view_error_suppressor); thd->push_internal_handler(&view_error_suppressor);
bool error= open_normal_and_derived_tables(thd, table_list, 0); bool error=
open_normal_and_derived_tables(thd, table_list,
MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL);
thd->pop_internal_handler(); thd->pop_internal_handler();
if (error && (thd->killed || thd->is_error())) if (error && (thd->killed || thd->is_error()))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
...@@ -815,7 +817,8 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) ...@@ -815,7 +817,8 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
DBUG_ENTER("mysqld_list_fields"); DBUG_ENTER("mysqld_list_fields");
DBUG_PRINT("enter",("table: %s",table_list->table_name)); DBUG_PRINT("enter",("table: %s",table_list->table_name));
if (open_normal_and_derived_tables(thd, table_list, 0)) if (open_normal_and_derived_tables(thd, table_list,
MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL))
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
table= table_list->table; table= table_list->table;
......
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