[Commits] Rev 3011: MWL#234: Implement protection against changing @@do_not_replicate in the middle of statement or transaction. in http://bazaar.launchpad.net/~maria-captains/maria/5.2

knielsen at knielsen-hq.org knielsen at knielsen-hq.org
Wed Aug 10 15:54:01 EEST 2011


At http://bazaar.launchpad.net/~maria-captains/maria/5.2

------------------------------------------------------------
revno: 3011
revision-id: knielsen at knielsen-hq.org-20110810125401-4jxcurdt8j2wqwl4
parent: knielsen at knielsen-hq.org-20110809094948-k05esrp6gaxqd0yt
committer: knielsen at knielsen-hq.org
branch nick: work-5.2-mwl234
timestamp: Wed 2011-08-10 14:54:01 +0200
message:
  MWL#234: Implement protection against changing @@do_not_replicate in the middle of statement or transaction.
=== modified file 'mysql-test/suite/rpl/r/rpl_do_not_replicate.result'
--- a/mysql-test/suite/rpl/r/rpl_do_not_replicate.result	2011-08-09 09:49:48 +0000
+++ b/mysql-test/suite/rpl/r/rpl_do_not_replicate.result	2011-08-10 12:54:01 +0000
@@ -101,6 +101,60 @@ SELECT * FROM t1 ORDER by a;
 a       b
 2       8
 SET do_not_replicate=0;
+BEGIN;
+SET do_not_replicate=0;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+SET do_not_replicate=1;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+ROLLBACK;
+SET do_not_replicate=1;
+BEGIN;
+SET do_not_replicate=0;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+SET do_not_replicate=1;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+COMMIT;
+SET autocommit=0;
+INSERT INTO t2(a) VALUES(100);
+SET do_not_replicate=1;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+ROLLBACK;
+SET autocommit=1;
+SET do_not_replicate=1;
+CREATE FUNCTION foo (x INT) RETURNS INT BEGIN SET SESSION do_not_replicate=x; RETURN x; END|
+CREATE PROCEDURE bar(x INT) BEGIN SET SESSION do_not_replicate=x; END|
+CREATE FUNCTION baz (x INT) RETURNS INT BEGIN CALL bar(x); RETURN x; END|
+SELECT foo(0);
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+SELECT baz(0);
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+SET @a= foo(1);
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+SET @a= baz(1);
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+UPDATE t2 SET b=foo(0);
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+UPDATE t2 SET b=baz(0);
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+INSERT INTO t1 VALUES (101, foo(1));
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+INSERT INTO t1 VALUES (101, baz(0));
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+SELECT @@do_not_replicate;
+@@do_not_replicate
+1
+CALL bar(0);
+SELECT @@do_not_replicate;
+@@do_not_replicate
+0
+CALL bar(1);
+SELECT @@do_not_replicate;
+@@do_not_replicate
+1
+DROP FUNCTION foo;
+DROP PROCEDURE bar;
+DROP FUNCTION baz;
+SET do_not_replicate=0;
 DROP TABLE t1,t2;
 STOP SLAVE;
 SET GLOBAL replicate_ignore_do_not_replicate=0;

=== modified file 'mysql-test/suite/rpl/t/rpl_do_not_replicate.test'
--- a/mysql-test/suite/rpl/t/rpl_do_not_replicate.test	2011-08-09 09:49:48 +0000
+++ b/mysql-test/suite/rpl/t/rpl_do_not_replicate.test	2011-08-10 12:54:01 +0000
@@ -176,8 +176,62 @@ connection slave;
 SELECT * FROM t1 ORDER by a;
 
 
-# ToDo: Test behaviour when changing @@do_not_replicate inside a transaction or statement.
+# Test that it is not possible to d change @@do_not_replicate inside a
+# transaction or statement, thereby replicating only parts of statements
+# or transactions.
+connection master;
+SET do_not_replicate=0;
+
+BEGIN;
+--error ER_LOCK_OR_ACTIVE_TRANSACTION
+SET do_not_replicate=0;
+--error ER_LOCK_OR_ACTIVE_TRANSACTION
+SET do_not_replicate=1;
+ROLLBACK;
+SET do_not_replicate=1;
+BEGIN;
+--error ER_LOCK_OR_ACTIVE_TRANSACTION
+SET do_not_replicate=0;
+--error ER_LOCK_OR_ACTIVE_TRANSACTION
+SET do_not_replicate=1;
+COMMIT;
+SET autocommit=0;
+INSERT INTO t2(a) VALUES(100);
+--error ER_LOCK_OR_ACTIVE_TRANSACTION
+SET do_not_replicate=1;
+ROLLBACK;
+SET autocommit=1;
 
+SET do_not_replicate=1;
+--delimiter |
+CREATE FUNCTION foo (x INT) RETURNS INT BEGIN SET SESSION do_not_replicate=x; RETURN x; END|
+CREATE PROCEDURE bar(x INT) BEGIN SET SESSION do_not_replicate=x; END|
+CREATE FUNCTION baz (x INT) RETURNS INT BEGIN CALL bar(x); RETURN x; END|
+--delimiter ;
+--error ER_LOCK_OR_ACTIVE_TRANSACTION
+SELECT foo(0);
+--error ER_LOCK_OR_ACTIVE_TRANSACTION
+SELECT baz(0);
+--error ER_LOCK_OR_ACTIVE_TRANSACTION
+SET @a= foo(1);
+--error ER_LOCK_OR_ACTIVE_TRANSACTION
+SET @a= baz(1);
+--error ER_LOCK_OR_ACTIVE_TRANSACTION
+UPDATE t2 SET b=foo(0);
+--error ER_LOCK_OR_ACTIVE_TRANSACTION
+UPDATE t2 SET b=baz(0);
+--error ER_LOCK_OR_ACTIVE_TRANSACTION
+INSERT INTO t1 VALUES (101, foo(1));
+--error ER_LOCK_OR_ACTIVE_TRANSACTION
+INSERT INTO t1 VALUES (101, baz(0));
+SELECT @@do_not_replicate;
+CALL bar(0);
+SELECT @@do_not_replicate;
+CALL bar(1);
+SELECT @@do_not_replicate;
+DROP FUNCTION foo;
+DROP PROCEDURE bar;
+DROP FUNCTION baz;
 
 # Clean up.
 connection master;

=== modified file 'sql/set_var.cc'
--- a/sql/set_var.cc	2011-08-04 14:10:00 +0000
+++ b/sql/set_var.cc	2011-08-10 12:54:01 +0000
@@ -117,6 +117,7 @@ static bool set_option_log_bin_bit(THD *
 static bool set_option_autocommit(THD *thd, set_var *var);
 static int  check_log_update(THD *thd, set_var *var);
 static bool set_log_update(THD *thd, set_var *var);
+static int check_do_not_replicate(THD *thd, set_var *var);
 static int  check_pseudo_thread_id(THD *thd, set_var *var);
 void fix_binlog_format_after_update(THD *thd, enum_var_type type);
 static void fix_low_priority_updates(THD *thd, enum_var_type type);
@@ -830,7 +831,8 @@ static sys_var_thd_bit  sys_profiling(&v
 static sys_var_thd_ulong        sys_profiling_history_size(&vars, "profiling_history_size",
                                               &SV::profiling_history_size);
 #endif
-static sys_var_thd_bit  sys_do_not_replicate(&vars, "do_not_replicate", 0,
+static sys_var_thd_bit  sys_do_not_replicate(&vars, "do_not_replicate",
+                                             check_do_not_replicate,
                                              set_option_bit,
                                              OPTION_DO_NOT_REPLICATE);
 
@@ -3276,6 +3278,25 @@ static bool set_log_update(THD *thd, set
   return 0;
 }
 
+
+static int check_do_not_replicate(THD *thd, set_var *var)
+{
+  /*
+    We must not change @@do_not_replicate in the middle of a transaction or
+    statement, as that could result in only part of the transaction / statement
+    being replicated.
+    (This would be particularly serious if we were to replicate eg.
+    Rows_log_event without Table_map_log_event or transactional updates without
+    the COMMIT).
+  */
+  if (thd->locked_tables || thd->active_transaction())
+  {
+    my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
+    return 1;
+  }
+  return 0;
+}
+
 
 static int check_pseudo_thread_id(THD *thd, set_var *var)
 {



More information about the commits mailing list