MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Jon Olav Hauglid Date:February 18 2010 1:54pm
Subject:bzr commit into mysql-5.5-next-mr branch (jon.hauglid:3103) Bug#48315
View as plain text  
#At file:///export/home/z/mysql-next-4284-bug48315/ based on revid:jon.hauglid@stripped

 3103 Jon Olav Hauglid	2010-02-18
      Bug #48315 Metadata lock is not taken for merged views that use
                 an INFORMATION_SCHEMA table
      
      When a prepared statement using a merged view containing an information
      schema table was executed, a metadata lock of the view was not taken.
      This meant that it was possible for concurrent view DDL to execute,
      thereby breaking the binary log. For example, it was possible
      for DROP VIEW to appear in the binary log before a query using the view.
      This also happened when a statement in a stored routine was executed a
      second time.
      
      For such views, the information schema table is merged into the view
      during the prepare phase (or first execution of a statement in a routine).
      The problem was that we took a short cut and were not executing full-blown
      view opening during subsequent executions of the statement. As a result,
      a metadata lock on the view was not taken to protect the view definition.
      
      This patch resolves the problem by making sure a metadata lock is taken
      for views even after information schema tables are merged into them.
      
      Test cased added to view.test.

    modified:
      mysql-test/r/view.result
      mysql-test/t/view.test
      sql/sql_base.cc
=== modified file 'mysql-test/r/view.result'
--- a/mysql-test/r/view.result	2010-02-02 13:58:15 +0000
+++ b/mysql-test/r/view.result	2010-02-18 13:54:38 +0000
@@ -4004,3 +4004,36 @@ CREATE VIEW t2 AS SELECT * FROM t1;
 ERROR HY000: Can't execute the query because you have a conflicting read lock
 UNLOCK TABLES;
 DROP TABLE t1, t2;
+#
+# Bug#48315 Metadata lock is not taken for merged views that
+#           use an INFORMATION_SCHEMA table
+#
+DROP TABLE IF EXISTS t1;
+DROP VIEW IF EXISTS v1;
+DROP PROCEDURE IF EXISTS p1;
+# Connection default
+CREATE VIEW v1 AS SELECT schema_name FROM information_schema.schemata;
+CREATE TABLE t1 (str VARCHAR(50));
+CREATE PROCEDURE p1() INSERT INTO t1 SELECT * FROM v1;
+# CALL p1() so the view is merged.
+CALL p1();
+# Connection 3
+LOCK TABLE t1 READ;
+# Connection default
+# Try to CALL p1() again, this time it should block for t1.
+# Sending:
+CALL p1();
+# Connection 2
+# ... then try to drop the view. This should block.
+# Sending:
+DROP VIEW v1;
+# Connection 3
+# Now allow CALL p1() to complete
+UNLOCK TABLES;
+# Connection default
+# Reaping: CALL p1()
+# Connection 2
+# Reaping: DROP VIEW v1
+# Connection default
+DROP PROCEDURE p1;
+DROP TABLE t1;

=== modified file 'mysql-test/t/view.test'
--- a/mysql-test/t/view.test	2009-12-16 08:33:54 +0000
+++ b/mysql-test/t/view.test	2010-02-18 13:54:38 +0000
@@ -6,6 +6,9 @@ drop database if exists mysqltest;
 --enable_warnings
 use test;
 
+# Save the initial number of concurrent sessions.
+--source include/count_sessions.inc
+
 #
 # some basic test of views and its functionality
 #
@@ -3975,3 +3978,79 @@ CREATE VIEW t2 AS SELECT * FROM t1;
 
 UNLOCK TABLES;
 DROP TABLE t1, t2;
+
+
+--echo #
+--echo # Bug#48315 Metadata lock is not taken for merged views that
+--echo #           use an INFORMATION_SCHEMA table
+--echo #
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP VIEW IF EXISTS v1;
+DROP PROCEDURE IF EXISTS p1;
+--enable_warnings
+
+connect (con2, localhost, root);
+connect (con3, localhost, root);
+
+--echo # Connection default
+connection default;
+
+CREATE VIEW v1 AS SELECT schema_name FROM information_schema.schemata;
+CREATE TABLE t1 (str VARCHAR(50));
+CREATE PROCEDURE p1() INSERT INTO t1 SELECT * FROM v1;
+
+--echo # CALL p1() so the view is merged.
+CALL p1();
+
+--echo # Connection 3
+connection con3;
+LOCK TABLE t1 READ;
+
+--echo # Connection default
+connection default;
+--echo # Try to CALL p1() again, this time it should block for t1.
+--echo # Sending:
+--send CALL p1()
+
+--echo # Connection 2
+connection con2;
+let $wait_condition=
+  SELECT COUNT(*) = 1 from information_schema.processlist
+  WHERE state = "Table lock" AND info = "INSERT INTO t1 SELECT * FROM v1";
+--source include/wait_condition.inc
+--echo # ... then try to drop the view. This should block.
+--echo # Sending:
+--send DROP VIEW v1
+
+--echo # Connection 3
+connection con3;
+let $wait_condition=
+  SELECT COUNT(*) = 1 from information_schema.processlist
+  WHERE state = "Waiting for table" AND info = "DROP VIEW v1";
+--source include/wait_condition.inc
+--echo # Now allow CALL p1() to complete
+UNLOCK TABLES;
+
+--echo # Connection default
+connection default;
+--echo # Reaping: CALL p1()
+--reap
+
+--echo # Connection 2
+connection con2;
+--echo # Reaping: DROP VIEW v1
+--reap
+
+--echo # Connection default
+connection default;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+disconnect con2;
+disconnect con3;
+
+
+# Check that all connections opened by test cases in this file are really
+# gone so execution of other tests won't be affected by their presence.
+--source include/wait_until_count_sessions.inc

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2010-02-15 11:16:49 +0000
+++ b/sql/sql_base.cc	2010-02-18 13:54:38 +0000
@@ -4168,9 +4168,18 @@ open_and_process_table(THD *thd, LEX *le
       TABLE_LIST is processed. This code works only during re-execution.
     */
     if (tables->view)
-      goto process_view_routines;
-    if (!mysql_schema_table(thd, lex, tables) &&
-        !check_and_update_table_version(thd, tables, tables->table->s))
+    {
+      /*
+        We still need to take a MDL lock on the merged view to protect
+        it from concurrent changes.
+      */
+      if (!open_table_get_mdl_lock(thd, tables, &tables->mdl_request,
+                                   ot_ctx, flags))
+        goto process_view_routines;
+      /* Fall-through to return error. */
+    }
+    else if (!mysql_schema_table(thd, lex, tables) &&
+             !check_and_update_table_version(thd, tables, tables->table->s))
     {
       goto end;
     }


Attachment: [text/bzr-bundle] bzr/jon.hauglid@sun.com-20100218135438-seghgwgub9t8k6u9.bundle
Thread
bzr commit into mysql-5.5-next-mr branch (jon.hauglid:3103) Bug#48315Jon Olav Hauglid18 Feb
  • Re: bzr commit into mysql-5.5-next-mr branch (jon.hauglid:3103)Bug#48315Dmitry Lenev18 Feb