mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
fix for BUG#11139 (multi-delete with alias breaking replication if table rules are
present): the problem originally was that the tables in auxilliary_tables did not have the correct real_name, which caused problems in the second call to tables_ok(). The fix corrects the real_name problem, and also sets the updating flag properly, which makes the second call to tables_ok() unnecessary.
This commit is contained in:
@ -4,6 +4,26 @@ reset master;
|
|||||||
reset slave;
|
reset slave;
|
||||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||||
start slave;
|
start slave;
|
||||||
|
set sql_log_bin=0;
|
||||||
|
create database mysqltest_from;
|
||||||
|
set sql_log_bin=1;
|
||||||
|
create database mysqltest_to;
|
||||||
|
use mysqltest_from;
|
||||||
|
drop table if exists a;
|
||||||
|
CREATE TABLE a (i INT);
|
||||||
|
INSERT INTO a VALUES(1);
|
||||||
|
DELETE alias FROM a alias WHERE alias.i=1;
|
||||||
|
SELECT * FROM a;
|
||||||
|
i
|
||||||
|
insert into a values(2),(3);
|
||||||
|
delete a alias FROM a alias where alias.i=2;
|
||||||
|
select * from a;
|
||||||
|
i
|
||||||
|
3
|
||||||
|
use mysqltest_to;
|
||||||
|
select * from a;
|
||||||
|
i
|
||||||
|
3
|
||||||
create table t1 (a int);
|
create table t1 (a int);
|
||||||
create table t2 (a int);
|
create table t2 (a int);
|
||||||
insert into t1 values (1);
|
insert into t1 values (1);
|
||||||
@ -15,7 +35,10 @@ select * from t2;
|
|||||||
a
|
a
|
||||||
1
|
1
|
||||||
select * from t1;
|
select * from t1;
|
||||||
ERROR 42S02: Table 'test.t1' doesn't exist
|
ERROR 42S02: Table 'mysqltest_to.t1' doesn't exist
|
||||||
select * from t2;
|
select * from t2;
|
||||||
ERROR 42S02: Table 'test.t2' doesn't exist
|
ERROR 42S02: Table 'mysqltest_to.t2' doesn't exist
|
||||||
drop table t1,t2;
|
set sql_log_bin=0;
|
||||||
|
drop database mysqltest_from;
|
||||||
|
set sql_log_bin=1;
|
||||||
|
drop database mysqltest_to;
|
||||||
|
@ -1 +1 @@
|
|||||||
--replicate-wild-ignore-table=test.%
|
"--replicate-rewrite-db=mysqltest_from->mysqltest_to" --replicate-do-table=mysqltest_to.a
|
||||||
|
@ -1,4 +1,41 @@
|
|||||||
|
#multi delete replication bugs
|
||||||
|
|
||||||
|
|
||||||
source include/master-slave.inc;
|
source include/master-slave.inc;
|
||||||
|
|
||||||
|
#BUG#11139 - improper wild-table and table rules
|
||||||
|
#checking for multi deletes with an alias
|
||||||
|
|
||||||
|
connection master;
|
||||||
|
set sql_log_bin=0;
|
||||||
|
create database mysqltest_from;
|
||||||
|
set sql_log_bin=1;
|
||||||
|
|
||||||
|
connection slave;
|
||||||
|
create database mysqltest_to;
|
||||||
|
|
||||||
|
|
||||||
|
connection master;
|
||||||
|
use mysqltest_from;
|
||||||
|
--disable_warnings
|
||||||
|
drop table if exists a;
|
||||||
|
--enable_warnings
|
||||||
|
CREATE TABLE a (i INT);
|
||||||
|
INSERT INTO a VALUES(1);
|
||||||
|
DELETE alias FROM a alias WHERE alias.i=1;
|
||||||
|
SELECT * FROM a;
|
||||||
|
insert into a values(2),(3);
|
||||||
|
delete a alias FROM a alias where alias.i=2;
|
||||||
|
select * from a;
|
||||||
|
save_master_pos;
|
||||||
|
connection slave;
|
||||||
|
|
||||||
|
use mysqltest_to;
|
||||||
|
sync_with_master;
|
||||||
|
select * from a;
|
||||||
|
|
||||||
|
# BUG#3461
|
||||||
|
connection master;
|
||||||
create table t1 (a int);
|
create table t1 (a int);
|
||||||
create table t2 (a int);
|
create table t2 (a int);
|
||||||
|
|
||||||
@ -19,7 +56,13 @@ select * from t1;
|
|||||||
error 1146;
|
error 1146;
|
||||||
select * from t2;
|
select * from t2;
|
||||||
|
|
||||||
|
# cleanup
|
||||||
connection master;
|
connection master;
|
||||||
drop table t1,t2;
|
set sql_log_bin=0;
|
||||||
|
drop database mysqltest_from;
|
||||||
|
set sql_log_bin=1;
|
||||||
|
connection slave;
|
||||||
|
drop database mysqltest_to;
|
||||||
|
|
||||||
# End of 4.1 tests
|
# End of 4.1 tests
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ void kill_one_thread(THD *thd, ulong id);
|
|||||||
bool net_request_file(NET* net, const char* fname);
|
bool net_request_file(NET* net, const char* fname);
|
||||||
char* query_table_status(THD *thd,const char *db,const char *table_name);
|
char* query_table_status(THD *thd,const char *db,const char *table_name);
|
||||||
|
|
||||||
|
|
||||||
#define x_free(A) { my_free((gptr) (A),MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); }
|
#define x_free(A) { my_free((gptr) (A),MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); }
|
||||||
#define safeFree(x) { if(x) { my_free((gptr) x,MYF(0)); x = NULL; } }
|
#define safeFree(x) { if(x) { my_free((gptr) x,MYF(0)); x = NULL; } }
|
||||||
#define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1))
|
#define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1))
|
||||||
@ -464,6 +465,7 @@ void mysql_reset_thd_for_next_command(THD *thd);
|
|||||||
bool mysql_new_select(LEX *lex, bool move_down);
|
bool mysql_new_select(LEX *lex, bool move_down);
|
||||||
void create_select_for_variable(const char *var_name);
|
void create_select_for_variable(const char *var_name);
|
||||||
void mysql_init_multi_delete(LEX *lex);
|
void mysql_init_multi_delete(LEX *lex);
|
||||||
|
void fix_multi_delete_lex(LEX* lex);
|
||||||
void init_max_user_conn(void);
|
void init_max_user_conn(void);
|
||||||
void init_update_queries(void);
|
void init_update_queries(void);
|
||||||
void free_max_user_conn(void);
|
void free_max_user_conn(void);
|
||||||
|
@ -746,14 +746,7 @@ static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
|
|||||||
rules (see code below). For that reason, users should not set conflicting
|
rules (see code below). For that reason, users should not set conflicting
|
||||||
rules because they may get unpredicted results (precedence order is
|
rules because they may get unpredicted results (precedence order is
|
||||||
explained in the manual).
|
explained in the manual).
|
||||||
If no table of the list is marked "updating" (so far this can only happen
|
|
||||||
if the statement is a multi-delete (SQLCOM_DELETE_MULTI) and the "tables"
|
|
||||||
is the tables in the FROM): then we always return 0, because there is no
|
|
||||||
reason we play this statement on this slave if it updates nothing. In the
|
|
||||||
case of SQLCOM_DELETE_MULTI, there will be a second call to tables_ok(),
|
|
||||||
with tables having "updating==TRUE" (those after the DELETE), so this
|
|
||||||
second call will make the decision (because
|
|
||||||
all_tables_not_ok() = !tables_ok(1st_list) && !tables_ok(2nd_list)).
|
|
||||||
|
|
||||||
RETURN VALUES
|
RETURN VALUES
|
||||||
0 should not be logged/replicated
|
0 should not be logged/replicated
|
||||||
|
@ -60,6 +60,9 @@ 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,
|
||||||
const char *table_name);
|
const char *table_name);
|
||||||
|
|
||||||
|
static TABLE_LIST* get_table_by_alias(TABLE_LIST* tl, const char* db,
|
||||||
|
const char* alias);
|
||||||
|
|
||||||
const char *any_db="*any*"; // Special symbol for check_access
|
const char *any_db="*any*"; // Special symbol for check_access
|
||||||
|
|
||||||
const char *command_name[]={
|
const char *command_name[]={
|
||||||
@ -125,10 +128,7 @@ static bool end_active_trans(THD *thd)
|
|||||||
*/
|
*/
|
||||||
inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
|
inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
|
||||||
{
|
{
|
||||||
return (table_rules_on && tables && !tables_ok(thd,tables) &&
|
return (table_rules_on && tables && !tables_ok(thd,tables));
|
||||||
((thd->lex->sql_command != SQLCOM_DELETE_MULTI) ||
|
|
||||||
!tables_ok(thd,
|
|
||||||
(TABLE_LIST *)thd->lex->auxilliary_table_list.first)));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -4248,6 +4248,40 @@ void create_select_for_variable(const char *var_name)
|
|||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TABLE_LIST* get_table_by_alias(TABLE_LIST* tl, const char* db,
|
||||||
|
const char* alias)
|
||||||
|
{
|
||||||
|
for (;tl;tl= tl->next)
|
||||||
|
{
|
||||||
|
if (!strcmp(db,tl->db) &&
|
||||||
|
tl->alias && !my_strcasecmp(table_alias_charset,tl->alias,alias))
|
||||||
|
return tl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sets up lex->auxilliary_table_list */
|
||||||
|
void fix_multi_delete_lex(LEX* lex)
|
||||||
|
{
|
||||||
|
TABLE_LIST *tl;
|
||||||
|
TABLE_LIST *good_list= (TABLE_LIST*)lex->select_lex.table_list.first;
|
||||||
|
|
||||||
|
for (tl= (TABLE_LIST*)lex->auxilliary_table_list.first; tl; tl= tl->next)
|
||||||
|
{
|
||||||
|
TABLE_LIST* good_table= get_table_by_alias(good_list,tl->db,tl->alias);
|
||||||
|
if (good_table && !good_table->derived)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
real_name points to a member of Table_ident which is
|
||||||
|
allocated via thd->strmake() from THD memroot
|
||||||
|
*/
|
||||||
|
tl->real_name= good_table->real_name;
|
||||||
|
tl->real_name_length= good_table->real_name_length;
|
||||||
|
good_table->updating= tl->updating;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void mysql_init_multi_delete(LEX *lex)
|
void mysql_init_multi_delete(LEX *lex)
|
||||||
{
|
{
|
||||||
@ -5570,13 +5604,7 @@ int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
|
|||||||
(*table_count)++;
|
(*table_count)++;
|
||||||
/* All tables in aux_tables must be found in FROM PART */
|
/* All tables in aux_tables must be found in FROM PART */
|
||||||
TABLE_LIST *walk;
|
TABLE_LIST *walk;
|
||||||
for (walk= delete_tables; walk; walk= walk->next)
|
walk= get_table_by_alias(delete_tables,target_tbl->db,target_tbl->alias);
|
||||||
{
|
|
||||||
if (!my_strcasecmp(table_alias_charset,
|
|
||||||
target_tbl->alias, walk->alias) &&
|
|
||||||
!strcmp(walk->db, target_tbl->db))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!walk)
|
if (!walk)
|
||||||
{
|
{
|
||||||
my_error(ER_UNKNOWN_TABLE, MYF(0), target_tbl->real_name,
|
my_error(ER_UNKNOWN_TABLE, MYF(0), target_tbl->real_name,
|
||||||
|
@ -4295,12 +4295,10 @@ single_multi:
|
|||||||
}
|
}
|
||||||
where_clause opt_order_clause
|
where_clause opt_order_clause
|
||||||
delete_limit_clause {}
|
delete_limit_clause {}
|
||||||
| table_wild_list
|
| table_wild_list {mysql_init_multi_delete(Lex);}
|
||||||
{ mysql_init_multi_delete(Lex); }
|
FROM join_table_list {fix_multi_delete_lex(Lex);} where_clause
|
||||||
FROM join_table_list where_clause
|
| FROM table_wild_list { mysql_init_multi_delete(Lex);}
|
||||||
| FROM table_wild_list
|
USING join_table_list {fix_multi_delete_lex(Lex);} where_clause
|
||||||
{ mysql_init_multi_delete(Lex); }
|
|
||||||
USING join_table_list where_clause
|
|
||||||
{}
|
{}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user