Loading mysql-test/r/rpl_multi_update3.result +72 −0 Original line number Diff line number Diff line Loading @@ -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 mysql-test/t/rpl_multi_update3.test +59 −0 Original line number Diff line number Diff line Loading @@ -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 sql/sql_parse.cc +20 −82 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)) Loading Loading @@ -2852,6 +2836,20 @@ mysql_execute_command(THD *thd) { 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, Loading Loading @@ -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; } Loading Loading @@ -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<Item> *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) { Loading sql/sql_update.cc +0 −3 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading
mysql-test/r/rpl_multi_update3.result +72 −0 Original line number Diff line number Diff line Loading @@ -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
mysql-test/t/rpl_multi_update3.test +59 −0 Original line number Diff line number Diff line Loading @@ -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
sql/sql_parse.cc +20 −82 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)) Loading Loading @@ -2852,6 +2836,20 @@ mysql_execute_command(THD *thd) { 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, Loading Loading @@ -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; } Loading Loading @@ -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<Item> *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) { Loading
sql/sql_update.cc +0 −3 Original line number Diff line number Diff line Loading @@ -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) { Loading