MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Konstantin Osipov Date:February 15 2010 4:44pm
Subject:bzr push into mysql-6.0-codebase branch (kostja:3767 to 3768) Bug#47648
View as plain text  
 3768 Konstantin Osipov	2010-02-15 [merge]
      Merge next-4284 -> 6.0-codebase-4284 (Bug#47648)

    modified:
      mysql-test/r/merge.result
      mysql-test/t/merge.test
      storage/myisammrg/ha_myisammrg.cc
 3767 Alexander Nozdrin	2010-02-15
      Disable backup.backup_xpfm_compat_restore_lctn1 due to Bug 51191.

    modified:
      mysql-test/suite/backup/t/disabled.def
      mysql-test/suite/rpl/t/rpl_slave_load_remove_tmpfile.test
=== modified file 'mysql-test/r/merge.result'
--- a/mysql-test/r/merge.result	2009-12-11 15:44:05 +0000
+++ b/mysql-test/r/merge.result	2010-02-15 16:43:30 +0000
@@ -2365,7 +2365,9 @@ UNLOCK TABLES;
 DROP TRIGGER t2_ai;
 DROP TABLE tm1, t1, t2;
 #
-# Don't select MERGE child when trying to get prelocked table.
+# Don't allow an update of a MERGE child in a trigger
+# if the table's already being modified by the main
+# statement.
 #
 CREATE TABLE t1 (c1 INT) ENGINE=MyISAM;
 CREATE TABLE tm1 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1)
@@ -2374,19 +2376,45 @@ CREATE TRIGGER tm1_ai AFTER INSERT ON tm
 FOR EACH ROW INSERT INTO t1 VALUES(11);
 LOCK TABLE tm1 WRITE, t1 WRITE;
 INSERT INTO tm1 VALUES (1);
+ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
+SELECT * FROM tm1;
+c1
+1
+UNLOCK TABLES;
+LOCK TABLE t1 WRITE, tm1 WRITE;
+INSERT INTO tm1 VALUES (1);
+ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
+SELECT * FROM tm1;
+c1
+1
+1
+UNLOCK TABLES;
+DROP TRIGGER tm1_ai;
+DROP TABLE tm1, t1;
+#
+# Don't select MERGE child when trying to get a prelocked table.
+#
+# Due to a limitation demonstrated by the previous test
+# we can no longer use a write-locked prelocked table.
+# The test is kept for historical purposes.
+#
+CREATE TABLE t1 (c1 INT) ENGINE=MyISAM;
+CREATE TABLE tm1 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1)
+INSERT_METHOD=LAST;
+CREATE TRIGGER tm1_ai AFTER INSERT ON tm1
+FOR EACH ROW SELECT max(c1) FROM t1 INTO @var;
+LOCK TABLE tm1 WRITE, t1 WRITE;
+INSERT INTO tm1 VALUES (1);
 SELECT * FROM tm1;
 c1
 1
-11
 UNLOCK TABLES;
 LOCK TABLE t1 WRITE, tm1 WRITE;
 INSERT INTO tm1 VALUES (1);
 SELECT * FROM tm1;
 c1
 1
-11
 1
-11
 UNLOCK TABLES;
 DROP TRIGGER tm1_ai;
 DROP TABLE tm1, t1;
@@ -2398,7 +2426,7 @@ CREATE TABLE t5 (c1 INT) ENGINE=MyISAM;
 CREATE TABLE tm1 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1,t2,t3,t4,t5)
 INSERT_METHOD=LAST;
 CREATE TRIGGER t2_au AFTER UPDATE ON t2
-FOR EACH ROW INSERT INTO t3 VALUES(33);
+FOR EACH ROW SELECT MAX(c1) FROM t1 INTO @var;
 CREATE FUNCTION f1() RETURNS INT
 RETURN (SELECT MAX(c1) FROM t4);
 LOCK TABLE tm1 WRITE, t1 WRITE, t2 WRITE, t3 WRITE, t4 WRITE, t5 WRITE;
@@ -2416,7 +2444,6 @@ c1
 1
 4
 3
-33
 4
 5
 DROP TRIGGER t2_au;
@@ -2452,4 +2479,29 @@ ERROR HY000: Unable to open underlying t
 DROP TABLE t1, t3;
 # Connection default.
 # Disconnecting con1, all mdl_tickets must have been released.
+#
+# A test case for Bug#47648   main.merge fails sporadically
+#
+# Make sure we correctly maintain lex->query_tables_last_own.
+#
+create table t1 (c1 int not null);
+create table t2 (c1 int not null);
+create table t3 (c1 int not null);
+create function f1 () returns int return (select max(c1) from t3);
+create table t4 (c1 int not null) engine=merge union=(t1,t2) insert_method=last ;
+select * from t4 where c1 < f1();
+c1
+prepare stmt from "select * from t4 where c1 < f1()";
+execute stmt;
+c1
+execute stmt;
+c1
+execute stmt;
+c1
+drop function f1;
+execute stmt;
+ERROR 42000: FUNCTION test.f1 does not exist
+execute stmt;
+ERROR 42000: FUNCTION test.f1 does not exist
+drop table t4, t3, t2, t1;
 End of 6.0 tests

=== modified file 'mysql-test/t/merge.test'
--- a/mysql-test/t/merge.test	2009-12-11 15:44:05 +0000
+++ b/mysql-test/t/merge.test	2010-02-15 16:43:30 +0000
@@ -1806,7 +1806,9 @@ UNLOCK TABLES;
 DROP TRIGGER t2_ai;
 DROP TABLE tm1, t1, t2;
 --echo #
---echo # Don't select MERGE child when trying to get prelocked table.
+--echo # Don't allow an update of a MERGE child in a trigger
+--echo # if the table's already being modified by the main
+--echo # statement.
 --echo #
 CREATE TABLE t1 (c1 INT) ENGINE=MyISAM;
 CREATE TABLE tm1 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1)
@@ -1814,6 +1816,31 @@ CREATE TABLE tm1 (c1 INT) ENGINE=MRG_MYI
 CREATE TRIGGER tm1_ai AFTER INSERT ON tm1
   FOR EACH ROW INSERT INTO t1 VALUES(11);
 LOCK TABLE tm1 WRITE, t1 WRITE;
+--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
+INSERT INTO tm1 VALUES (1);
+SELECT * FROM tm1;
+UNLOCK TABLES;
+LOCK TABLE t1 WRITE, tm1 WRITE;
+--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
+INSERT INTO tm1 VALUES (1);
+SELECT * FROM tm1;
+UNLOCK TABLES;
+DROP TRIGGER tm1_ai;
+DROP TABLE tm1, t1;
+
+--echo #
+--echo # Don't select MERGE child when trying to get a prelocked table.
+--echo #
+--echo # Due to a limitation demonstrated by the previous test
+--echo # we can no longer use a write-locked prelocked table.
+--echo # The test is kept for historical purposes.
+--echo #
+CREATE TABLE t1 (c1 INT) ENGINE=MyISAM;
+CREATE TABLE tm1 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1)
+  INSERT_METHOD=LAST;
+CREATE TRIGGER tm1_ai AFTER INSERT ON tm1
+  FOR EACH ROW SELECT max(c1) FROM t1 INTO @var;
+LOCK TABLE tm1 WRITE, t1 WRITE;
 INSERT INTO tm1 VALUES (1);
 SELECT * FROM tm1;
 UNLOCK TABLES;
@@ -1835,7 +1862,7 @@ CREATE TABLE t5 (c1 INT) ENGINE=MyISAM;
 CREATE TABLE tm1 (c1 INT) ENGINE=MRG_MYISAM UNION=(t1,t2,t3,t4,t5)
   INSERT_METHOD=LAST;
 CREATE TRIGGER t2_au AFTER UPDATE ON t2
-  FOR EACH ROW INSERT INTO t3 VALUES(33);
+  FOR EACH ROW SELECT MAX(c1) FROM t1 INTO @var;
 CREATE FUNCTION f1() RETURNS INT
   RETURN (SELECT MAX(c1) FROM t4);
 LOCK TABLE tm1 WRITE, t1 WRITE, t2 WRITE, t3 WRITE, t4 WRITE, t5 WRITE;
@@ -1902,6 +1929,31 @@ connection default;
 --echo # Disconnecting con1, all mdl_tickets must have been released.
 disconnect con1;
 
+--echo #
+--echo # A test case for Bug#47648   main.merge fails sporadically
+--echo #
+--echo # Make sure we correctly maintain lex->query_tables_last_own.
+--echo #
+create table t1 (c1 int not null);
+create table t2 (c1 int not null);
+create table t3 (c1 int not null);
+
+create function f1 () returns int return (select max(c1) from t3);
+
+create table t4 (c1 int not null) engine=merge union=(t1,t2) insert_method=last ;
+
+select * from t4 where c1 < f1();
+prepare stmt from "select * from t4 where c1 < f1()";
+execute stmt;
+execute stmt;
+execute stmt;
+drop function f1;
+--error ER_SP_DOES_NOT_EXIST
+execute stmt;
+--error ER_SP_DOES_NOT_EXIST
+execute stmt;
+drop table t4, t3, t2, t1;
+
 --echo End of 6.0 tests
 
 --disable_result_log

=== modified file 'storage/myisammrg/ha_myisammrg.cc'
--- a/storage/myisammrg/ha_myisammrg.cc	2010-02-10 21:11:06 +0000
+++ b/storage/myisammrg/ha_myisammrg.cc	2010-02-15 16:43:30 +0000
@@ -460,6 +460,18 @@ int ha_myisammrg::add_children_list(void
   */
   if (thd->lex->query_tables_last == &parent_l->next_global)
     thd->lex->query_tables_last= this->children_last_l;
+  /*
+    The branch below works only when re-executing a prepared
+    statement or a stored routine statement:
+    We've just modified query_tables_last. Keep it in sync with
+    query_tables_last_own, if it was set by the prelocking code.
+    This ensures that the check that prohibits double updates (*)
+    can correctly identify what tables belong to the main statement.
+    (*) A double update is, e.g. when a user issues UPDATE t1 and
+    t1 has an AFTER UPDATE trigger that also modifies t1.
+  */
+  if (thd->lex->query_tables_own_last == &parent_l->next_global)
+    thd->lex->query_tables_own_last= this->children_last_l;
 
 end:
   DBUG_RETURN(0);
@@ -891,6 +903,15 @@ int ha_myisammrg::detach_children(void)
     if (thd->lex->query_tables_last == this->children_last_l)
       thd->lex->query_tables_last= this->children_l->prev_global;
 
+    /*
+      If the statement requires prelocking, and prelocked
+      tables were added right after merge children, modify the
+      last own table pointer to point at prev_global of the merge
+      parent.
+    */
+    if (thd->lex->query_tables_own_last == this->children_last_l)
+      thd->lex->query_tables_own_last= this->children_l->prev_global;
+
     /* Terminate child list. So it cannot be tried to remove again. */
     *this->children_last_l= NULL;
     this->children_l->prev_global= NULL;


Attachment: [text/bzr-bundle] bzr/kostja@sun.com-20100215164330-7efayi19n4qcemu0.bundle
Thread
bzr push into mysql-6.0-codebase branch (kostja:3767 to 3768) Bug#47648Konstantin Osipov15 Feb