Bug#7011
Merge from 4.0 sql/sql_select.cc: Auto merged
This commit is contained in:
commit
ed9f484556
42
mysql-test/r/rpl_multi_update2.result
Normal file
42
mysql-test/r/rpl_multi_update2.result
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
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;
|
||||||
|
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
|
1
mysql-test/t/rpl_multi_update2-slave.opt
Normal file
1
mysql-test/t/rpl_multi_update2-slave.opt
Normal file
@ -0,0 +1 @@
|
|||||||
|
--replicate-ignore-table=nothing.sensible
|
33
mysql-test/t/rpl_multi_update2.test
Normal file
33
mysql-test/t/rpl_multi_update2.test
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Let's verify that multi-update is not always skipped by slave if
|
||||||
|
# some replicate-* rules exist.
|
||||||
|
# (BUG#7011)
|
||||||
|
|
||||||
|
source include/master-slave.inc;
|
||||||
|
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
SELECT * FROM t2 ORDER BY a;
|
@ -564,6 +564,10 @@ int mysql_multi_update(THD *thd, TABLE_LIST *table_list,
|
|||||||
COND *conds, ulong options,
|
COND *conds, ulong options,
|
||||||
enum enum_duplicates handle_duplicates, bool ignore,
|
enum enum_duplicates handle_duplicates, bool ignore,
|
||||||
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex);
|
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex);
|
||||||
|
int mysql_multi_update_lock(THD *thd,
|
||||||
|
TABLE_LIST *table_list,
|
||||||
|
List<Item> *fields,
|
||||||
|
SELECT_LEX *select_lex);
|
||||||
int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
|
int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
|
||||||
TABLE_LIST *insert_table_list, TABLE *table,
|
TABLE_LIST *insert_table_list, TABLE *table,
|
||||||
List<Item> &fields, List_item *values,
|
List<Item> &fields, List_item *values,
|
||||||
|
@ -52,6 +52,8 @@ static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
|
|||||||
#endif
|
#endif
|
||||||
static void decrease_user_connections(USER_CONN *uc);
|
static void decrease_user_connections(USER_CONN *uc);
|
||||||
static bool check_db_used(THD *thd,TABLE_LIST *tables);
|
static bool check_db_used(THD *thd,TABLE_LIST *tables);
|
||||||
|
static bool check_multi_update_lock(THD *thd, TABLE_LIST *tables,
|
||||||
|
List<Item> *fields, SELECT_LEX *select_lex);
|
||||||
static void remove_escape(char *name);
|
static void remove_escape(char *name);
|
||||||
static void refresh_status(void);
|
static void refresh_status(void);
|
||||||
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
|
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
|
||||||
@ -1883,6 +1885,8 @@ 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;
|
||||||
@ -1900,6 +1904,23 @@ 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
|
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
|
given and the table list says the query should not be replicated
|
||||||
@ -3582,6 +3603,14 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5012,6 +5041,58 @@ 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)
|
||||||
{
|
{
|
||||||
|
@ -464,30 +464,23 @@ static table_map get_table_map(List<Item> *items)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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,
|
int mysql_multi_update_lock(THD *thd,
|
||||||
TABLE_LIST *table_list,
|
TABLE_LIST *table_list,
|
||||||
List<Item> *fields,
|
List<Item> *fields,
|
||||||
List<Item> *values,
|
SELECT_LEX *select_lex)
|
||||||
COND *conds,
|
|
||||||
ulong options,
|
|
||||||
enum enum_duplicates handle_duplicates, bool ignore,
|
|
||||||
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
|
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
multi_update *result;
|
|
||||||
TABLE_LIST *tl;
|
TABLE_LIST *tl;
|
||||||
TABLE_LIST *update_list= (TABLE_LIST*) thd->lex->select_lex.table_list.first;
|
TABLE_LIST *update_list= (TABLE_LIST*) thd->lex->select_lex.table_list.first;
|
||||||
List<Item> total_list;
|
|
||||||
const bool using_lock_tables= thd->locked_tables != 0;
|
const bool using_lock_tables= thd->locked_tables != 0;
|
||||||
bool initialized_dervied= 0;
|
bool initialized_dervied= 0;
|
||||||
DBUG_ENTER("mysql_multi_update");
|
DBUG_ENTER("mysql_multi_update_lock");
|
||||||
|
|
||||||
select_lex->select_limit= HA_POS_ERROR;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The following loop is here to to ensure that we only lock tables
|
The following loop is here to to ensure that we only lock tables
|
||||||
@ -593,7 +586,7 @@ int mysql_multi_update(THD *thd,
|
|||||||
(grant_option && check_grant(thd, wants, tl, 0, 0, 0)))
|
(grant_option && check_grant(thd, wants, tl, 0, 0, 0)))
|
||||||
{
|
{
|
||||||
tl->next= save;
|
tl->next= save;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
tl->next= save;
|
tl->next= save;
|
||||||
}
|
}
|
||||||
@ -616,11 +609,7 @@ int mysql_multi_update(THD *thd,
|
|||||||
/* Relock the tables with the correct modes */
|
/* Relock the tables with the correct modes */
|
||||||
res= lock_tables(thd, table_list, table_count);
|
res= lock_tables(thd, table_list, table_count);
|
||||||
if (using_lock_tables)
|
if (using_lock_tables)
|
||||||
{
|
|
||||||
if (res)
|
|
||||||
DBUG_RETURN(res);
|
|
||||||
break; // Don't have to do setup_field()
|
break; // Don't have to do setup_field()
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We must setup fields again as the file may have been reopened
|
We must setup fields again as the file may have been reopened
|
||||||
@ -651,6 +640,32 @@ int mysql_multi_update(THD *thd,
|
|||||||
*/
|
*/
|
||||||
close_thread_tables(thd);
|
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, bool ignore,
|
||||||
|
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
TABLE_LIST *tl;
|
||||||
|
TABLE_LIST *update_list= (TABLE_LIST*) thd->lex->select_lex.table_list.first;
|
||||||
|
List<Item> total_list;
|
||||||
|
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 */
|
/* Setup timestamp handling */
|
||||||
for (tl= update_list; tl; tl= tl->next)
|
for (tl= update_list; tl; tl= tl->next)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user