From 5d2bc92523991e4304d4cbad8b4759023f6213d8 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 10 Oct 2005 15:10:14 +0200 Subject: [PATCH] BUG#12618: Removing fake locking mysql-test/r/rpl_multi_update3.result: New test case mysql-test/t/rpl_multi_update3.test: New test case sql/sql_parse.cc: Removed fake locking Changed so that filtering is done later for multi-update Removed redundant code sql/sql_update.cc: Moved call to sql_parse.cc --- mysql-test/r/rpl_multi_update3.result | 72 ++++++++++++++++++ mysql-test/t/rpl_multi_update3.test | 59 +++++++++++++++ sql/sql_parse.cc | 102 +++++--------------------- sql/sql_update.cc | 3 - 4 files changed, 151 insertions(+), 85 deletions(-) diff --git a/mysql-test/r/rpl_multi_update3.result b/mysql-test/r/rpl_multi_update3.result index 1b757b1400c..b81af7c6e39 100644 --- a/mysql-test/r/rpl_multi_update3.result +++ b/mysql-test/r/rpl_multi_update3.result @@ -122,3 +122,75 @@ SELECT * FROM t1; i j x y z 1 2 23 24 71 DROP TABLE t1, t2, t3; +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +DROP TABLE IF EXISTS t2; +Warnings: +Note 1051 Unknown table 't2' +CREATE TABLE t1 ( +idp int(11) NOT NULL default '0', +idpro int(11) default NULL, +price decimal(19,4) default NULL, +PRIMARY KEY (idp) +); +CREATE TABLE t2 ( +idpro int(11) NOT NULL default '0', +price decimal(19,4) default NULL, +nbprice int(11) default NULL, +PRIMARY KEY (idpro) +); +INSERT INTO t1 VALUES +(1,1,'3.0000'), +(2,2,'1.0000'), +(3,1,'1.0000'), +(4,1,'4.0000'), +(5,3,'2.0000'), +(6,2,'4.0000'); +INSERT INTO t2 VALUES +(1,'0.0000',0), +(2,'0.0000',0), +(3,'0.0000',0); +update +t2 +join +( select idpro, min(price) as min_price, count(*) as nbr_price +from t1 +where idpro>0 and price>0 +group by idpro +) as table_price +on t2.idpro = table_price.idpro +set t2.price = table_price.min_price, +t2.nbprice = table_price.nbr_price; +select "-- MASTER AFTER JOIN --" as ""; + +-- MASTER AFTER JOIN -- +select * from t1; +idp idpro price +1 1 3.0000 +2 2 1.0000 +3 1 1.0000 +4 1 4.0000 +5 3 2.0000 +6 2 4.0000 +select * from t2; +idpro price nbprice +1 1.0000 3 +2 1.0000 2 +3 2.0000 1 +select "-- SLAVE AFTER JOIN --" as ""; + +-- SLAVE AFTER JOIN -- +select * from t1; +idp idpro price +1 1 3.0000 +2 2 1.0000 +3 1 1.0000 +4 1 4.0000 +5 3 2.0000 +6 2 4.0000 +select * from t2; +idpro price nbprice +1 1.0000 3 +2 1.0000 2 +3 2.0000 1 diff --git a/mysql-test/t/rpl_multi_update3.test b/mysql-test/t/rpl_multi_update3.test index 64e46882c16..36ac7a59cb3 100644 --- a/mysql-test/t/rpl_multi_update3.test +++ b/mysql-test/t/rpl_multi_update3.test @@ -158,4 +158,63 @@ SELECT * FROM t1; connection master; DROP TABLE t1, t2, t3; +############################################################################## +# +# BUG#12618 +# +# TEST: Replication of a statement containing a join in a multi-update. + +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; + +CREATE TABLE t1 ( + idp int(11) NOT NULL default '0', + idpro int(11) default NULL, + price decimal(19,4) default NULL, + PRIMARY KEY (idp) +); + +CREATE TABLE t2 ( + idpro int(11) NOT NULL default '0', + price decimal(19,4) default NULL, + nbprice int(11) default NULL, + PRIMARY KEY (idpro) +); + +INSERT INTO t1 VALUES + (1,1,'3.0000'), + (2,2,'1.0000'), + (3,1,'1.0000'), + (4,1,'4.0000'), + (5,3,'2.0000'), + (6,2,'4.0000'); + +INSERT INTO t2 VALUES + (1,'0.0000',0), + (2,'0.0000',0), + (3,'0.0000',0); + +# This update sets t2 to the minimal prices for each product +update + t2 + join + ( select idpro, min(price) as min_price, count(*) as nbr_price + from t1 + where idpro>0 and price>0 + group by idpro + ) as table_price +on t2.idpro = table_price.idpro +set t2.price = table_price.min_price, + t2.nbprice = table_price.nbr_price; + +select "-- MASTER AFTER JOIN --" as ""; +select * from t1; +select * from t2; + +sync_slave_with_master; + +select "-- SLAVE AFTER JOIN --" as ""; +select * from t1; +select * from t2; + # End of 4.1 tests diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 3a538a7629b..54d51e42895 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1941,8 +1941,6 @@ mysql_execute_command(THD *thd) { int res= 0; LEX *lex= thd->lex; - bool slave_fake_lock= 0; - MYSQL_LOCK *fake_prev_lock= 0; SELECT_LEX *select_lex= &lex->select_lex; TABLE_LIST *tables= (TABLE_LIST*) select_lex->table_list.first; SELECT_LEX_UNIT *unit= &lex->unit; @@ -1971,35 +1969,21 @@ mysql_execute_command(THD *thd) #ifdef HAVE_REPLICATION if (thd->slave_thread) { - if (lex->sql_command == SQLCOM_UPDATE_MULTI) - { - DBUG_PRINT("info",("need faked locked tables")); - - if (check_multi_update_lock(thd, tables, &select_lex->item_list, - select_lex)) - goto error; - - /* Fix for replication, the tables are opened and locked, - now we pretend that we have performed a LOCK TABLES action */ - - 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. + Check if statment should be skipped because of slave filtering + rules Exceptions are: + - UPDATE MULTI: For this statement, we want to check the filtering + rules later in the code - SET: we always execute it (Not that many SET commands exists in the binary log anyway -- only 4.1 masters write SET statements, in 5.0 there are no SET statements in the binary log) - DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we have stale files on slave caused by exclusion of one tmp table). */ - if (!(lex->sql_command == SQLCOM_SET_OPTION) && + if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) && + !(lex->sql_command == SQLCOM_SET_OPTION) && !(lex->sql_command == SQLCOM_DROP_TABLE && lex->drop_temporary && lex->drop_if_exists) && all_tables_not_ok(thd,tables)) @@ -2852,6 +2836,20 @@ unsent_create_error: { if ((res= multi_update_precheck(thd, tables))) break; + + if ((res= mysql_multi_update_lock(thd, tables, &select_lex->item_list, + select_lex))) + break; + + /* Check slave filtering rules */ + if (thd->slave_thread) + if (all_tables_not_ok(thd,tables)) + { + /* we warn the slave SQL thread */ + my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); + break; + } + res= mysql_multi_update(thd,tables, &select_lex->item_list, &lex->value_list, @@ -3764,14 +3762,6 @@ purposes internal to the MySQL server", MYF(0)); send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); error: - if (unlikely(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; } @@ -5303,58 +5293,6 @@ bool check_simple_select() return 0; } -/* - Setup locking for multi-table updates. Used by the replication slave. - Replication slave SQL thread examines (all_tables_not_ok()) the - locking state of referenced tables to determine if the query has to - be executed or ignored. Since in multi-table update, the - 'default' lock is read-only, this lock is corrected early enough by - calling this function, before the slave decides to execute/ignore. - - 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 -*/ -static bool check_multi_update_lock(THD *thd, TABLE_LIST *tables, - List *fields, SELECT_LEX *select_lex) -{ - bool res= 1; - TABLE_LIST *table; - DBUG_ENTER("check_multi_update_lock"); - - 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_access(thd, UPDATE_ACL, table->db, &table->grant.privilege,0,1) || - (grant_option && check_grant(thd, UPDATE_ACL, table,0,1,1))) && - check_one_table_access(thd, SELECT_ACL, table)) - goto error; - table->next= save; - } - - if (mysql_multi_update_lock(thd, tables, fields, select_lex)) - goto error; - - res= 0; - -error: - DBUG_RETURN(res); -} - Comp_creator *comp_eq_creator(bool invert) { diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 2857bce09ed..a978a5edc64 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -672,9 +672,6 @@ int mysql_multi_update(THD *thd, multi_update *result; DBUG_ENTER("mysql_multi_update"); - if ((res= mysql_multi_update_lock(thd, table_list, fields, select_lex))) - DBUG_RETURN(res); - /* Setup timestamp handling */ for (tl= update_list; tl; tl= tl->next) {