Commit 99838052 authored by lars@mysql.com's avatar lars@mysql.com

BUG#12618: Removing fake locking

parent e8f291f5
...@@ -122,3 +122,75 @@ SELECT * FROM t1; ...@@ -122,3 +122,75 @@ SELECT * FROM t1;
i j x y z i j x y z
1 2 23 24 71 1 2 23 24 71
DROP TABLE t1, t2, t3; 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
...@@ -158,4 +158,63 @@ SELECT * FROM t1; ...@@ -158,4 +158,63 @@ SELECT * FROM t1;
connection master; connection master;
DROP TABLE t1, t2, t3; 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 # End of 4.1 tests
...@@ -1941,8 +1941,6 @@ mysql_execute_command(THD *thd) ...@@ -1941,8 +1941,6 @@ mysql_execute_command(THD *thd)
{ {
int res= 0; int res= 0;
LEX *lex= thd->lex; LEX *lex= thd->lex;
bool slave_fake_lock= 0;
MYSQL_LOCK *fake_prev_lock= 0;
SELECT_LEX *select_lex= &lex->select_lex; SELECT_LEX *select_lex= &lex->select_lex;
TABLE_LIST *tables= (TABLE_LIST*) select_lex->table_list.first; TABLE_LIST *tables= (TABLE_LIST*) select_lex->table_list.first;
SELECT_LEX_UNIT *unit= &lex->unit; SELECT_LEX_UNIT *unit= &lex->unit;
...@@ -1971,35 +1969,21 @@ mysql_execute_command(THD *thd) ...@@ -1971,35 +1969,21 @@ mysql_execute_command(THD *thd)
#ifdef HAVE_REPLICATION #ifdef HAVE_REPLICATION
if (thd->slave_thread) 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 Check if statment should be skipped because of slave filtering
given and the table list says the query should not be replicated. rules
Exceptions are: 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 - SET: we always execute it (Not that many SET commands exists in
the binary log anyway -- only 4.1 masters write SET statements, the binary log anyway -- only 4.1 masters write SET statements,
in 5.0 there are no SET statements in the binary log) in 5.0 there are no SET statements in the binary log)
- DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we - DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we
have stale files on slave caused by exclusion of one tmp table). 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->sql_command == SQLCOM_DROP_TABLE &&
lex->drop_temporary && lex->drop_if_exists) && lex->drop_temporary && lex->drop_if_exists) &&
all_tables_not_ok(thd,tables)) all_tables_not_ok(thd,tables))
...@@ -2852,6 +2836,20 @@ unsent_create_error: ...@@ -2852,6 +2836,20 @@ unsent_create_error:
{ {
if ((res= multi_update_precheck(thd, tables))) if ((res= multi_update_precheck(thd, tables)))
break; 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, res= mysql_multi_update(thd,tables,
&select_lex->item_list, &select_lex->item_list,
&lex->value_list, &lex->value_list,
...@@ -3764,14 +3762,6 @@ purposes internal to the MySQL server", MYF(0)); ...@@ -3764,14 +3762,6 @@ purposes internal to the MySQL server", MYF(0));
send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
error: 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; DBUG_VOID_RETURN;
} }
...@@ -5303,58 +5293,6 @@ bool check_simple_select() ...@@ -5303,58 +5293,6 @@ bool check_simple_select()
return 0; 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) Comp_creator *comp_eq_creator(bool invert)
{ {
......
...@@ -672,9 +672,6 @@ int mysql_multi_update(THD *thd, ...@@ -672,9 +672,6 @@ int mysql_multi_update(THD *thd,
multi_update *result; multi_update *result;
DBUG_ENTER("mysql_multi_update"); DBUG_ENTER("mysql_multi_update");
if ((res= mysql_multi_update_lock(thd, table_list, fields, select_lex)))
DBUG_RETURN(res);
/* Setup timestamp handling */ /* Setup timestamp handling */
for (tl= update_list; tl; tl= tl->next) for (tl= update_list; tl; tl= tl->next)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment