List:Internals« Previous MessageNext Message »
From:antony Date:January 14 2005 1:04am
Subject:bk commit into 4.0 tree (antony:1.2025)
View as plain text  
Below is the list of changes that have just been committed into a local
4.0 repository of antony. When antony does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://www.mysql.com/doc/I/n/Installing_source_tree.html

ChangeSet
  1.2025 05/01/14 01:03:59 antony@stripped +6 -0
  Bug#7011 - Multi-table update replication failure
    Perform lock analysis early for slaves.
    New tests included.

  mysql-test/t/rpl_multi_update2.test
    1.1 05/01/14 01:03:54 antony@stripped +35 -0

  mysql-test/t/rpl_multi_update2-slave.opt
    1.1 05/01/14 01:03:54 antony@stripped +1 -0

  mysql-test/t/rpl_multi_update2.test
    1.0 05/01/14 01:03:54 antony@stripped +0 -0
    BitKeeper file /usr/home/antony/work/bug7011/mysql-test/t/rpl_multi_update2.test

  mysql-test/t/rpl_multi_update2-slave.opt
    1.0 05/01/14 01:03:54 antony@stripped +0 -0
    BitKeeper file /usr/home/antony/work/bug7011/mysql-test/t/rpl_multi_update2-slave.opt

  mysql-test/r/rpl_multi_update2.result
    1.1 05/01/14 01:03:53 antony@stripped +43 -0

  sql/sql_update.cc
    1.106 05/01/14 01:03:53 antony@stripped +33 -18
    Bug#7011 - Multi-table update replication failure
      Split off multi table lock analysis into new 
      function: mysql_multi_update_lock()

  sql/sql_parse.cc
    1.387 05/01/14 01:03:53 antony@stripped +76 -1
    Bug#7011 - Multi-table update replication failure
      New function: check_multi_update_lock()
      Slave needs to perform lock early - this is done by faking a LOCK TABLES
      

  sql/mysql_priv.h
    1.230 05/01/14 01:03:53 antony@stripped +3 -0
    Bug#7011 - Multi-table update replication failure
      New function: mysql_multi_update_lock()

  mysql-test/r/rpl_multi_update2.result
    1.0 05/01/14 01:03:53 antony@stripped +0 -0
    BitKeeper file /usr/home/antony/work/bug7011/mysql-test/r/rpl_multi_update2.result

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	antony
# Host:	ltantony.rdg.cyberkinetica.homeunix.net
# Root:	/usr/home/antony/work/bug7011

--- 1.229/sql/mysql_priv.h	2004-10-22 20:51:02 +01:00
+++ 1.230/sql/mysql_priv.h	2005-01-14 01:03:53 +00:00
@@ -469,6 +469,9 @@
 		 List<Item> &values,COND *conds, 
                  ORDER *order, ha_rows limit,
 		 enum enum_duplicates handle_duplicates);
+int mysql_multi_update_lock(THD *thd,
+			    TABLE_LIST *table_list,
+			    List<Item> *fields);
 int mysql_multi_update(THD *thd, TABLE_LIST *table_list,
 		       List<Item> *fields, List<Item> *values,
 		       COND *conds, ulong options,

--- 1.386/sql/sql_parse.cc	2004-10-24 09:32:06 +01:00
+++ 1.387/sql/sql_parse.cc	2005-01-14 01:03:53 +00:00
@@ -56,6 +56,8 @@
 static void decrease_user_connections(USER_CONN *uc);
 static bool check_db_used(THD *thd,TABLE_LIST *tables);
 static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
+static bool check_multi_update_lock(THD *thd, TABLE_LIST *tables, 
+				    List<Item> *fields);
 static void mysql_init_query(THD *thd);
 static void remove_escape(char *name);
 static void refresh_status(void);
@@ -1338,10 +1340,25 @@
   LEX	*lex= &thd->lex;
   TABLE_LIST *tables=(TABLE_LIST*) lex->select_lex.table_list.first;
   SELECT_LEX *select_lex = lex->select;
+  bool slave_fake_lock= 0;
+  MYSQL_LOCK *fake_prev_lock= 0;
   DBUG_ENTER("mysql_execute_command");
 
   if (thd->slave_thread)
   {
+    if (lex->sql_command == SQLCOM_MULTI_UPDATE)
+    {
+      DBUG_PRINT("info",("need faked locked tables"));
+      
+      if (!check_multi_update_lock(thd, tables, &select_lex->item_list))
+      {
+	fake_prev_lock= thd->locked_tables;
+	if (thd->lock)
+          thd->locked_tables= thd->lock;
+	thd->lock= 0;
+	slave_fake_lock= 1;
+      }
+    }
     /* 
       Skip if we are in the slave thread, some table rules have been
       given and the table list says the query should not be replicated
@@ -1949,7 +1966,7 @@
     if (select_lex->item_list.elements != lex->value_list.elements)
     {
       send_error(&thd->net,ER_WRONG_VALUE_COUNT);
-      DBUG_VOID_RETURN;
+      goto error;
     }
     {
       const char *msg= 0;
@@ -2641,6 +2658,14 @@
     send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0);
 
 error:
+  if (slave_fake_lock)
+  {
+    DBUG_PRINT("info",("undoing faked lock"));
+    thd->lock= thd->locked_tables;
+    thd->locked_tables= fake_prev_lock;
+    if (thd->lock == thd->locked_tables)
+      thd->lock= 0;
+  }
   DBUG_VOID_RETURN;
 }
 
@@ -3906,4 +3931,54 @@
     return 1;
   }
   return 0;
+}
+
+/*
+  Check the locking for multi-table updates. Used by the slave replication.
+
+  SYNOPSIS
+    check_multi_update_lock()
+    thd		Current thread
+    tables	List of user-supplied tables
+    fields	List of fields requiring update
+
+  RETURN VALUES
+    0	ok
+    1	error	; No errors should be sent to the client
+*/
+static bool check_multi_update_lock(THD *thd, TABLE_LIST *tables, 
+				    List<Item> *fields)
+{
+  bool old_errors= thd->no_errors, res= 1;
+  TABLE_LIST *table;
+  DBUG_ENTER("check_multi_update_lock");
+  
+  thd->no_errors= 1;
+  if (check_db_used(thd, tables))
+    goto error;
+
+  /*
+    Ensure that we have UPDATE or SELECT privilege for each table
+    The exact privilege is checked in mysql_multi_update()
+  */
+  for (table= tables ; table ; table= table->next)
+  {
+    TABLE_LIST *save= table->next;
+    table->next= 0;
+    if (check_one_table_access(thd, UPDATE_ACL, table, 1) &&
+	check_one_table_access(thd, SELECT_ACL, table, 1))
+	goto error;
+    table->next= save;
+  }
+    
+  if (mysql_multi_update_lock(thd, tables, fields))
+    goto error;
+  
+  res= 0;
+  
+error:
+  if (res)
+    close_thread_tables(thd);
+  thd->no_errors= old_errors;
+  DBUG_RETURN(res);
 }

--- 1.105/sql/sql_update.cc	2004-12-18 02:34:06 +00:00
+++ 1.106/sql/sql_update.cc	2005-01-14 01:03:53 +00:00
@@ -403,26 +403,20 @@
 }
 
 
-
 /*
-  Setup multi-update handling and call SELECT to do the join
+  Prepare tables for multi-update 
+  Analyse which tables need specific privileges and perform locking
+  as required
 */
 
-int mysql_multi_update(THD *thd,
-		       TABLE_LIST *table_list,
-		       List<Item> *fields,
-		       List<Item> *values,
-		       COND *conds,
-		       ulong options,
-		       enum enum_duplicates handle_duplicates)
+int mysql_multi_update_lock(THD *thd,
+			    TABLE_LIST *table_list,
+			    List<Item> *fields)
 {
   int res;
-  multi_update *result;
   TABLE_LIST *tl;
   const bool using_lock_tables= thd->locked_tables != 0;
-  DBUG_ENTER("mysql_multi_update");
-
-  thd->select_limit= HA_POS_ERROR;
+  DBUG_ENTER("mysql_multi_update_lock");
 
   for (;;)
   {
@@ -490,7 +484,7 @@
           (grant_option && check_grant(thd, wants, tl, 0, 0)))
       {
 	tl->next= save;
-	DBUG_RETURN(0);
+	DBUG_RETURN(1);
       }
       tl->next= save;
     }
@@ -498,11 +492,7 @@
     /* Relock the tables with the correct modes */
     res= lock_tables(thd,table_list);
     if (using_lock_tables)
-    {
-      if (res)
-        DBUG_RETURN(res);
       break;                                 // Don't have to do setup_field()
-    }
 
     /*
       We must setup fields again as the file may have been reopened
@@ -535,6 +525,31 @@
     */
     close_thread_tables(thd);
   }
+  
+  DBUG_RETURN(res);
+}
+
+/*
+  Setup multi-update handling and call SELECT to do the join
+*/
+
+int mysql_multi_update(THD *thd,
+		       TABLE_LIST *table_list,
+		       List<Item> *fields,
+		       List<Item> *values,
+		       COND *conds,
+		       ulong options,
+		       enum enum_duplicates handle_duplicates)
+{
+  int res;
+  TABLE_LIST *tl;
+  multi_update *result;
+  DBUG_ENTER("mysql_multi_update");
+
+  thd->select_limit= HA_POS_ERROR;
+
+  if ((res= mysql_multi_update_lock(thd, table_list, fields)))
+    DBUG_RETURN(res);
 
   /*
     Count tables and setup timestamp handling
--- New file ---
+++ mysql-test/r/rpl_multi_update2.result	05/01/14 01:03:53
slave stop;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
slave start;
drop table if exists t1,t2;
CREATE TABLE t1 (
a int unsigned not null auto_increment primary key,
b int unsigned
) TYPE=MyISAM;
CREATE TABLE t2 (
a int unsigned not null auto_increment primary key,
b int unsigned
) TYPE=MyISAM;
INSERT INTO t1 VALUES (NULL, 0);
INSERT INTO t1 SELECT NULL, 0 FROM t1;
INSERT INTO t2 VALUES (NULL, 0), (NULL,1);
SELECT * FROM t1 ORDER BY a;
a	b
1	0
2	0
SELECT * FROM t2 ORDER BY a;
a	b
1	0
2	1
UPDATE t1, t2 SET t1.b = (t2.b+4) WHERE t1.a = t2.a;
SELECT * FROM t1 ORDER BY a;
a	b
1	4
2	5
SELECT * FROM t2 ORDER BY a;
a	b
1	0
2	1
SELECT * FROM t1 ORDER BY a;
a	b
1	4
2	5
SELECT * FROM t2 ORDER BY a;
a	b
1	0
2	1

--- New file ---
+++ mysql-test/t/rpl_multi_update2-slave.opt	05/01/14 01:03:54
--replicate-ignore-table=nothing.sensible

--- New file ---
+++ mysql-test/t/rpl_multi_update2.test	05/01/14 01:03:54
# Let's verify that multi-update does not give error on slave
# (BUG#1701)

source include/master-slave.inc;
drop table if exists t1,t2;

CREATE TABLE t1 (
 a int unsigned not null auto_increment primary key,
 b int unsigned
) TYPE=MyISAM;

CREATE TABLE t2 (
 a int unsigned not null auto_increment primary key,
 b int unsigned
) TYPE=MyISAM;

INSERT INTO t1 VALUES (NULL, 0);
INSERT INTO t1 SELECT NULL, 0 FROM t1; # needed to trigger BUG#1701

INSERT INTO t2 VALUES (NULL, 0), (NULL,1);

SELECT * FROM t1 ORDER BY a;
SELECT * FROM t2 ORDER BY a;

UPDATE t1, t2 SET t1.b = (t2.b+4) WHERE t1.a = t2.a;
SELECT * FROM t1 ORDER BY a;
SELECT * FROM t2 ORDER BY a;

save_master_pos;
connection slave;
sync_with_master;

# Test for Bug#7011 - replication fail on multi-update
SELECT * FROM t1 ORDER BY a;
SELECT * FROM t2 ORDER BY a;

Thread
bk commit into 4.0 tree (antony:1.2025)antony14 Jan