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
This commit is contained in:
parent
2b603902cc
commit
5d2bc92523
@ -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
|
||||
|
@ -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
|
||||
|
102
sql/sql_parse.cc
102
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<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)
|
||||
{
|
||||
|
@ -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…
x
Reference in New Issue
Block a user