List:Commits« Previous MessageNext Message »
From:Jon Olav Hauglid Date:July 23 2010 11:07am
Subject:bzr push into mysql-trunk-runtime branch (jon.hauglid:3083 to 3084) Bug#55498
View as plain text  
 3084 Jon Olav Hauglid	2010-07-23
      Bug #55498 SHOW CREATE TRIGGER takes wrong type of metadata lock
      
      The first problem was that SHOW CREATE TRIGGER took a stronger metadata
      lock than required. This caused the statement to be blocked when it was
      not needed. For example, LOCK TABLE WRITE in one connection would block
      SHOW CREATE TRIGGER in another connection.
      
      Another problem was that a SHOW CREATE TRIGGER statement issued inside
      a transaction did not release its metadata locks at the end of the
      statement execution. This happened even if SHOW CREATE TRIGGER is an
      information statement. The consequence was that SHOW CREATE TRIGGER
      was able to block other connections from accessing the table
      (e.g. using ALTER TABLE).
      
      This patch fixes the problem by changing SHOW CREATE TRIGGER to take
      a MDL_SHARED_HIGH_PRIO metadata lock similar to what is already done
      for SHOW CREATE TABLE. The patch also changes SHOW CREATE TRIGGER to
      explicitly release any metadata locks taken by the statement after
      it completes.
      
      Test case added to show_check.test.

    modified:
      mysql-test/r/show_check.result
      mysql-test/t/show_check.test
      sql/sql_show.cc
 3083 Davi Arnaut	2010-07-22
      Do not generate autotools configuration scripts when cmake is to be used.

    renamed:
      BUILD/choose_configure.sh => BUILD/cmake_configure.sh
    modified:
      BUILD/FINISH.sh
      BUILD/Makefile.am
      BUILD/autorun.sh
=== modified file 'mysql-test/r/show_check.result'
--- a/mysql-test/r/show_check.result	2010-07-22 09:10:35 +0000
+++ b/mysql-test/r/show_check.result	2010-07-23 08:44:55 +0000
@@ -1487,3 +1487,30 @@ UNLOCK TABLES;
 # Connection default
 COMMIT;
 DROP TABLE t1;
+#
+# Bug#55498 SHOW CREATE TRIGGER takes wrong type of metadata lock.
+#
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.a = 1;
+# Test 1: SHOW CREATE TRIGGER with WRITE locked table.
+# Connection con1
+LOCK TABLE t1 WRITE;
+# Connection default
+SHOW CREATE TRIGGER t1_bi;
+Trigger	sql_mode	SQL Original Statement	character_set_client	collation_connection	Database Collation
+t1_bi		CREATE DEFINER=`root`@`localhost` TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.a = 1	utf8	utf8_general_ci	latin1_swedish_ci
+# Connection con1
+UNLOCK TABLES;
+# Test 2: ALTER TABLE with SHOW CREATE TRIGGER in transaction
+# Connection default
+START TRANSACTION;
+SHOW CREATE TRIGGER t1_bi;
+Trigger	sql_mode	SQL Original Statement	character_set_client	collation_connection	Database Collation
+t1_bi		CREATE DEFINER=`root`@`localhost` TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.a = 1	utf8	utf8_general_ci	latin1_swedish_ci
+# Connection con1
+ALTER TABLE t1 CHARACTER SET = utf8;
+# Connection default
+COMMIT;
+DROP TRIGGER t1_bi;
+DROP TABLE t1;

=== modified file 'mysql-test/t/show_check.test'
--- a/mysql-test/t/show_check.test	2010-07-22 09:10:35 +0000
+++ b/mysql-test/t/show_check.test	2010-07-23 08:44:55 +0000
@@ -1279,6 +1279,52 @@ disconnect con1;
 DROP TABLE t1;
 
 
+--echo #
+--echo # Bug#55498 SHOW CREATE TRIGGER takes wrong type of metadata lock.
+--echo #
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.a = 1;
+
+--echo # Test 1: SHOW CREATE TRIGGER with WRITE locked table.
+
+--echo # Connection con1
+connect (con1, localhost, root);
+LOCK TABLE t1 WRITE;
+
+--echo # Connection default
+connection default;
+# Should not block.
+SHOW CREATE TRIGGER t1_bi;
+
+--echo # Connection con1
+connection con1;
+UNLOCK TABLES;
+
+--echo # Test 2: ALTER TABLE with SHOW CREATE TRIGGER in transaction
+
+--echo # Connection default
+connection default;
+START TRANSACTION;
+SHOW CREATE TRIGGER t1_bi;
+
+--echo # Connection con1
+connection con1;
+# Should not block.
+ALTER TABLE t1 CHARACTER SET = utf8;
+
+--echo # Connection default
+connection default;
+COMMIT;
+DROP TRIGGER t1_bi;
+DROP TABLE t1;
+disconnect con1;
+
+
 # Wait till all disconnects are completed
 --source include/wait_until_count_sessions.inc
 

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2010-07-22 09:10:35 +0000
+++ b/sql/sql_show.cc	2010-07-23 08:44:55 +0000
@@ -7779,6 +7779,10 @@ TABLE_LIST *get_trigger_table(THD *thd, 
 bool show_create_trigger(THD *thd, const sp_name *trg_name)
 {
   TABLE_LIST *lst= get_trigger_table(thd, trg_name);
+  uint num_tables; /* NOTE: unused, only to pass to open_tables(). */
+  Table_triggers_list *triggers;
+  int trigger_idx;
+  bool error= TRUE;
 
   if (!lst)
     return TRUE;
@@ -7790,35 +7794,35 @@ bool show_create_trigger(THD *thd, const
   }
 
   /*
-    Open the table by name in order to load Table_triggers_list object.
-
-    NOTE: there is race condition here -- the table can be dropped after
-    LOCK_open is released. It will be fixed later by acquiring shared
-    metadata lock on trigger or table name.
+    Metadata locks taken during SHOW CREATE TRIGGER should be released when
+    the statement completes as it is an information statement.
   */
+  MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint();
 
-  uint num_tables; /* NOTE: unused, only to pass to open_tables(). */
-
-  if (open_tables(thd, &lst, &num_tables, 0))
+  /*
+    Open the table by name in order to load Table_triggers_list object.
+  */
+  if (open_tables(thd, &lst, &num_tables,
+                  MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL))
   {
     my_error(ER_TRG_CANT_OPEN_TABLE, MYF(0),
              (const char *) trg_name->m_db.str,
              (const char *) lst->table_name);
 
-    return TRUE;
+    goto exit;
 
     /* Perform closing actions and return error status. */
   }
 
-  Table_triggers_list *triggers= lst->table->triggers;
+  triggers= lst->table->triggers;
 
   if (!triggers)
   {
     my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
-    return TRUE;
+    goto exit;
   }
 
-  int trigger_idx= triggers->find_trigger_by_name(&trg_name->m_name);
+  trigger_idx= triggers->find_trigger_by_name(&trg_name->m_name);
 
   if (trigger_idx < 0)
   {
@@ -7826,16 +7830,22 @@ bool show_create_trigger(THD *thd, const
              (const char *) trg_name->m_db.str,
              (const char *) lst->table_name);
 
-    return TRUE;
+    goto exit;
   }
 
-  return show_create_trigger_impl(thd, triggers, trigger_idx);
+  error= show_create_trigger_impl(thd, triggers, trigger_idx);
 
   /*
     NOTE: if show_create_trigger_impl() failed, that means we could not
     send data to the client. In this case we simply raise the error
     status and client connection will be closed.
   */
+
+exit:
+  close_thread_tables(thd);
+  /* Release any metadata locks taken during SHOW CREATE TRIGGER. */
+  thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
+  return error;
 }
 
 class IS_internal_schema_access : public ACL_internal_schema_access


Attachment: [text/bzr-bundle] bzr/jon.hauglid@oracle.com-20100723084455-ugvzj728mi8l3vp1.bundle
Thread
bzr push into mysql-trunk-runtime branch (jon.hauglid:3083 to 3084) Bug#55498Jon Olav Hauglid23 Jul