mirror of
https://github.com/MariaDB/server.git
synced 2025-07-08 17:02:21 +03:00
BUG#37051 Replication rules not evaluated correctly
Backporting patch to 5.0.
This commit is contained in:
6
mysql-test/include/master-slave-end.inc
Normal file
6
mysql-test/include/master-slave-end.inc
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
--connection master
|
||||||
|
--sync_slave_with_master
|
||||||
|
--connection slave
|
||||||
|
--disable_query_log
|
||||||
|
STOP SLAVE;
|
||||||
|
--enable_query_log
|
21
mysql-test/include/start_slave.inc
Normal file
21
mysql-test/include/start_slave.inc
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# ==== Purpose ====
|
||||||
|
#
|
||||||
|
# Issues START SLAVE on the current connection. Then waits until both
|
||||||
|
# the IO and SQL threads have started, or until a timeout is reached.
|
||||||
|
#
|
||||||
|
# Please use this instead of 'START SLAVE', to reduce the risk of test
|
||||||
|
# case bugs.
|
||||||
|
#
|
||||||
|
# ==== Usage ====
|
||||||
|
#
|
||||||
|
# source include/wait_for_slave_to_start.inc;
|
||||||
|
#
|
||||||
|
# Parameters to this macro are $slave_timeout and
|
||||||
|
# $master_connection. See wait_for_slave_param.inc for
|
||||||
|
# descriptions.
|
||||||
|
|
||||||
|
--disable_query_log
|
||||||
|
START SLAVE;
|
||||||
|
--enable_query_log
|
||||||
|
--echo include/start_slave.inc
|
||||||
|
source include/wait_for_slave_to_start.inc;
|
21
mysql-test/include/stop_slave.inc
Normal file
21
mysql-test/include/stop_slave.inc
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# ==== Purpose ====
|
||||||
|
#
|
||||||
|
# Issues STOP SLAVE on the current connection. Then waits until both
|
||||||
|
# the IO and SQL threads have stopped, or until a timeout is reached.
|
||||||
|
#
|
||||||
|
# Please use this instead of 'STOP SLAVE', to reduce the risk of test
|
||||||
|
# case bugs.
|
||||||
|
#
|
||||||
|
# ==== Usage ====
|
||||||
|
#
|
||||||
|
# source include/wait_for_slave_to_start.inc;
|
||||||
|
#
|
||||||
|
# Parameters to this macro are $slave_timeout and
|
||||||
|
# $master_connection. See wait_for_slave_param.inc for
|
||||||
|
# descriptions.
|
||||||
|
|
||||||
|
--disable_query_log
|
||||||
|
STOP SLAVE;
|
||||||
|
--enable_query_log
|
||||||
|
--echo include/stop_slave.inc
|
||||||
|
source include/wait_for_slave_to_stop.inc;
|
40
mysql-test/include/wait_for_slave_sql_error.inc
Normal file
40
mysql-test/include/wait_for_slave_sql_error.inc
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# ==== Purpose ====
|
||||||
|
#
|
||||||
|
# Waits until the SQL thread of the current connection has got an
|
||||||
|
# error, or until a timeout is reached. Also waits until the SQL
|
||||||
|
# thread has completely stopped.
|
||||||
|
#
|
||||||
|
# ==== Usage ====
|
||||||
|
#
|
||||||
|
# source include/wait_for_slave_sql_error.inc;
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
#
|
||||||
|
# $slave_sql_errno
|
||||||
|
# The expected SQL error number. This is required.
|
||||||
|
# (After BUG#41956 has been fixed, this will be required to be a
|
||||||
|
# symbolic name instead of a number.)
|
||||||
|
#
|
||||||
|
# $slave_timeout
|
||||||
|
# See wait_for_slave_param.inc for description.
|
||||||
|
#
|
||||||
|
# $master_connection
|
||||||
|
# See wait_for_slave_param.inc for description.
|
||||||
|
|
||||||
|
if (`SELECT '$slave_sql_errno' = ''`) {
|
||||||
|
--echo !!!ERROR IN TEST: you must set \$slave_sql_errno before sourcing wait_fro_slave_sql_error.inc
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
let $slave_param= Slave_SQL_Running;
|
||||||
|
let $slave_param_value= No;
|
||||||
|
let $slave_error_message= Failed while waiting for slave to stop the SQL thread (expecting error in the SQL thread);
|
||||||
|
source include/wait_for_slave_param.inc;
|
||||||
|
|
||||||
|
# NOTE: on mysql-5.0, there is no way to distinguish slave SQL error from IO error
|
||||||
|
let $_error= query_get_value(SHOW SLAVE STATUS, Last_Errno, 1);
|
||||||
|
if (`SELECT '$_error' != '$slave_sql_errno'`) {
|
||||||
|
--echo Slave stopped with wrong error code: $_error (expected $slave_sql_errno)
|
||||||
|
source include/show_rpl_debug_info.inc;
|
||||||
|
exit;
|
||||||
|
}
|
39
mysql-test/include/wait_for_slave_sql_error_and_skip.inc
Normal file
39
mysql-test/include/wait_for_slave_sql_error_and_skip.inc
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# ==== Purpose ====
|
||||||
|
#
|
||||||
|
# Wait for slave SQL error, skip the erroneous statement and restart
|
||||||
|
# slave
|
||||||
|
#
|
||||||
|
# ==== Usage ====
|
||||||
|
#
|
||||||
|
# let $slave_sql_error= <ERRNO>;
|
||||||
|
# source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
#
|
||||||
|
# $slave_sql_errno
|
||||||
|
# The error number to wait for. This is required. (See
|
||||||
|
# wait_for_slave_sql_error.inc)
|
||||||
|
#
|
||||||
|
# $show_sql_error
|
||||||
|
# If set, will print the error to the query log.
|
||||||
|
#
|
||||||
|
# $slave_timeout
|
||||||
|
# See wait_for_slave_param.inc for description.
|
||||||
|
#
|
||||||
|
# $master_connection
|
||||||
|
# See wait_for_slave_param.inc for description.
|
||||||
|
|
||||||
|
echo --source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
connection slave;
|
||||||
|
source include/wait_for_slave_sql_error.inc;
|
||||||
|
if ($show_sql_error)
|
||||||
|
{
|
||||||
|
# NOTE: on mysql-5.0, there is no way to distinguish slave SQL error from IO error
|
||||||
|
let $error= query_get_value("SHOW SLAVE STATUS", Last_Error, 1);
|
||||||
|
echo Last_SQL_Error = $error;
|
||||||
|
}
|
||||||
|
|
||||||
|
# skip the erroneous statement
|
||||||
|
set global sql_slave_skip_counter=1;
|
||||||
|
source include/start_slave.inc;
|
||||||
|
connection master;
|
@ -522,7 +522,7 @@ a b
|
|||||||
4 4
|
4 4
|
||||||
show master status /* there must be the UPDATE query event */;
|
show master status /* there must be the UPDATE query event */;
|
||||||
File Position Binlog_Do_DB Binlog_Ignore_DB
|
File Position Binlog_Do_DB Binlog_Ignore_DB
|
||||||
master-bin.000001 189
|
master-bin.000001 198
|
||||||
delete from t1;
|
delete from t1;
|
||||||
delete from t2;
|
delete from t2;
|
||||||
insert into t1 values (1,2),(3,4),(4,4);
|
insert into t1 values (1,2),(3,4),(4,4);
|
||||||
@ -532,7 +532,7 @@ UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a;
|
|||||||
ERROR 23000: Duplicate entry '4' for key 1
|
ERROR 23000: Duplicate entry '4' for key 1
|
||||||
show master status /* there must be the UPDATE query event */;
|
show master status /* there must be the UPDATE query event */;
|
||||||
File Position Binlog_Do_DB Binlog_Ignore_DB
|
File Position Binlog_Do_DB Binlog_Ignore_DB
|
||||||
master-bin.000001 204
|
master-bin.000001 213
|
||||||
drop table t1, t2;
|
drop table t1, t2;
|
||||||
drop table if exists t1, t2, t3;
|
drop table if exists t1, t2, t3;
|
||||||
CREATE TABLE t1 (a int, PRIMARY KEY (a));
|
CREATE TABLE t1 (a int, PRIMARY KEY (a));
|
||||||
|
151
mysql-test/r/rpl_filter_tables_not_exist.result
Normal file
151
mysql-test/r/rpl_filter_tables_not_exist.result
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
stop slave;
|
||||||
|
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;
|
||||||
|
start slave;
|
||||||
|
CREATE TABLE t1 (id int, a int);
|
||||||
|
CREATE TABLE t2 (id int, b int);
|
||||||
|
CREATE TABLE t3 (id int, c int);
|
||||||
|
CREATE TABLE t4 (id int, d int);
|
||||||
|
CREATE TABLE t5 (id int, e int);
|
||||||
|
CREATE TABLE t6 (id int, f int);
|
||||||
|
CREATE TABLE t7 (id int, g int);
|
||||||
|
CREATE TABLE t8 (id int, h int);
|
||||||
|
CREATE TABLE t9 (id int, i int);
|
||||||
|
INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
INSERT INTO t2 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
INSERT INTO t3 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
INSERT INTO t4 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
INSERT INTO t5 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
INSERT INTO t6 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
INSERT INTO t7 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
INSERT INTO t8 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
INSERT INTO t9 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
[on slave]
|
||||||
|
SHOW TABLES LIKE 't%';
|
||||||
|
Tables_in_test (t%)
|
||||||
|
t1
|
||||||
|
t2
|
||||||
|
t3
|
||||||
|
[on master]
|
||||||
|
UPDATE t7 LEFT JOIN t4 ON (t4.id=t7.id) SET d=0, g=0 where t7.id=1;
|
||||||
|
UPDATE t7 LEFT JOIN (t4, t5, t6) ON (t7.id=t4.id and t7.id=t5.id and t7.id=t6.id) SET d=0, e=0, f=0, g=0 where t7.id=1;
|
||||||
|
UPDATE t4 LEFT JOIN (t7, t8, t9) ON (t4.id=t7.id and t4.id=t8.id and t4.id=t9.id) SET d=0, g=0, h=0, i=0 where t4.id=1;
|
||||||
|
UPDATE t7 LEFT JOIN (t8, t9) ON (t7.id=t8.id and t7.id=t9.id) SET g=0, h=0, i=0 where t7.id=1;
|
||||||
|
UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET d=0 where t1.id=1;
|
||||||
|
UPDATE t1 LEFT JOIN t7 ON (t1.id=t7.id) SET g=0 where t1.id=1;
|
||||||
|
UPDATE t1 LEFT JOIN (t4, t5, t6) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t6.id) SET d=0, e=0, f=0 where t1.id=1;
|
||||||
|
UPDATE t1 LEFT JOIN (t4, t5, t8) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t8.id) SET d=0, e=0, h=0 where t1.id=1;
|
||||||
|
UPDATE t1 LEFT JOIN (t7, t8, t5) ON (t1.id=t7.id and t1.id=t8.id and t1.id=t5.id) SET g=0, h=0, e=0 where t1.id=1;
|
||||||
|
UPDATE t1 LEFT JOIN (t2, t3, t5) ON (t1.id=t2.id and t1.id=t3.id and t1.id=t5.id) SET e=0 where t1.id=1;
|
||||||
|
UPDATE t4 LEFT JOIN t1 ON (t1.id=t4.id) SET a=0, d=0 where t4.id=1;
|
||||||
|
UPDATE t4 LEFT JOIN (t1, t7) ON (t4.id=t1.id and t7.id=t4.id) SET a = 0, d=0, g=0 where t4.id=1;
|
||||||
|
UPDATE t4 LEFT JOIN (t1, t2, t3) ON (t1.id=t4.id and t2.id=t4.id and t3.id=t4.id) SET a=0, b=0, c=0, d=0 where t4.id=1;
|
||||||
|
UPDATE t4 LEFT JOIN (t1, t2, t5) ON (t1.id=t4.id and t2.id=t4.id and t5.id=t4.id) SET a=0, b=0, e=0, d=0 where t4.id=1;
|
||||||
|
UPDATE t4 LEFT JOIN (t1, t6, t7) ON (t4.id=t1.id and t4.id=t6.id and t4.id=t7.id) SET a=0, d=0, f=0, g=0 where t4.id=1;
|
||||||
|
UPDATE t7 LEFT JOIN (t4, t1, t2) ON (t7.id=t4.id and t7.id=t1.id and t7.id=t2.id) SET a=0, b=0, d=0, g=0 where t7.id=1;
|
||||||
|
UPDATE t7 LEFT JOIN (t8, t4, t1) ON (t7.id=t8.id and t7.id=t4.id and t7.id=t1.id) SET a=0, d=0, g=0, h=0 where t7.id=1;
|
||||||
|
UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0 where t1.id=1;
|
||||||
|
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||||
|
Last_SQL_Error = Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0 where t1.id=1'
|
||||||
|
set global sql_slave_skip_counter=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
UPDATE t1 LEFT JOIN (t4, t7) ON (t1.id=t4.id and t1.id=t7.id) SET a=0 where t1.id=1;
|
||||||
|
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||||
|
Last_SQL_Error = Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN (t4, t7) ON (t1.id=t4.id and t1.id=t7.id) SET a=0 where t1.id=1'
|
||||||
|
set global sql_slave_skip_counter=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
UPDATE t1 LEFT JOIN (t2, t4, t7) ON (t1.id=t2.id and t1.id=t4.id and t1.id=t7.id) SET a=0, b=0 where t1.id=1;
|
||||||
|
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||||
|
Last_SQL_Error = Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN (t2, t4, t7) ON (t1.id=t2.id and t1.id=t4.id and t1.id=t7.id) SET a=0, b=0 where t1.id=1'
|
||||||
|
set global sql_slave_skip_counter=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
UPDATE t1 LEFT JOIN (t2, t3, t7) ON (t1.id=t2.id and t1.id=t3.id and t1.id=t7.id) SET a=0, b=0, c=0 where t1.id=1;
|
||||||
|
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||||
|
Last_SQL_Error = Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN (t2, t3, t7) ON (t1.id=t2.id and t1.id=t3.id and t1.id=t7.id) SET a=0, b=0, c=0 where t1.id=1'
|
||||||
|
set global sql_slave_skip_counter=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
UPDATE t1 LEFT JOIN t7 ON (t1.id=t7.id) SET a=0, g=0 where t1.id=1;
|
||||||
|
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||||
|
Last_SQL_Error = Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN t7 ON (t1.id=t7.id) SET a=0, g=0 where t1.id=1'
|
||||||
|
set global sql_slave_skip_counter=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
UPDATE t7 LEFT JOIN t1 ON (t1.id=t7.id) SET a=0, g=0 where t7.id=1;
|
||||||
|
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||||
|
Last_SQL_Error = Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t7 LEFT JOIN t1 ON (t1.id=t7.id) SET a=0, g=0 where t7.id=1'
|
||||||
|
set global sql_slave_skip_counter=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
UPDATE t1 LEFT JOIN (t4, t5, t7) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t7.id) SET a=0, g=0 where t1.id=1;
|
||||||
|
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||||
|
Last_SQL_Error = Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN (t4, t5, t7) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t7.id) SET a=0, g=0 where t1.id=1'
|
||||||
|
set global sql_slave_skip_counter=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
UPDATE t1 LEFT JOIN (t4, t7, t8) ON (t1.id=t4.id and t1.id=t7.id and t1.id=t8.id) SET a=0, g=0 where t1.id=1;
|
||||||
|
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||||
|
Last_SQL_Error = Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN (t4, t7, t8) ON (t1.id=t4.id and t1.id=t7.id and t1.id=t8.id) SET a=0, g=0 where t1.id=1'
|
||||||
|
set global sql_slave_skip_counter=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
UPDATE t1 LEFT JOIN (t7, t8, t9) ON (t1.id=t7.id and t1.id=t8.id and t1.id=t9.id) SET a=0, g=0, h=0, i=0 where t1.id=1;
|
||||||
|
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||||
|
Last_SQL_Error = Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN (t7, t8, t9) ON (t1.id=t7.id and t1.id=t8.id and t1.id=t9.id) SET a=0, g=0, h=0, i=0 where t1.id=1'
|
||||||
|
set global sql_slave_skip_counter=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
UPDATE t7 LEFT JOIN (t1, t2, t3) ON (t7.id=t1.id and t7.id=t2.id and t7.id=t3.id) SET g=0, a=0, b=0, c=0 where t7.id=1;
|
||||||
|
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||||
|
Last_SQL_Error = Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t7 LEFT JOIN (t1, t2, t3) ON (t7.id=t1.id and t7.id=t2.id and t7.id=t3.id) SET g=0, a=0, b=0, c=0 where t7.id=1'
|
||||||
|
set global sql_slave_skip_counter=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
UPDATE t7 LEFT JOIN (t4, t5, t3) ON (t7.id=t4.id and t7.id=t5.id and t7.id=t3.id) SET g=0, c=0 where t7.id=1;
|
||||||
|
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||||
|
Last_SQL_Error = Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t7 LEFT JOIN (t4, t5, t3) ON (t7.id=t4.id and t7.id=t5.id and t7.id=t3.id) SET g=0, c=0 where t7.id=1'
|
||||||
|
set global sql_slave_skip_counter=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
UPDATE t7 LEFT JOIN (t8, t9, t3) ON (t7.id=t8.id and t7.id=t9.id and t7.id=t3.id) SET g=0, h=0, i=0, c=0 where t7.id=1;
|
||||||
|
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||||
|
Last_SQL_Error = Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t7 LEFT JOIN (t8, t9, t3) ON (t7.id=t8.id and t7.id=t9.id and t7.id=t3.id) SET g=0, h=0, i=0, c=0 where t7.id=1'
|
||||||
|
set global sql_slave_skip_counter=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0, d=0 where t1.id=1;
|
||||||
|
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||||
|
Last_SQL_Error = Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0, d=0 where t1.id=1'
|
||||||
|
set global sql_slave_skip_counter=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
UPDATE t1 LEFT JOIN (t4, t5, t6) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t6.id) SET a=0, d=0, e=0, f=0 where t1.id=1;
|
||||||
|
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||||
|
Last_SQL_Error = Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN (t4, t5, t6) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t6.id) SET a=0, d=0, e=0, f=0 where t1.id=1'
|
||||||
|
set global sql_slave_skip_counter=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
UPDATE t4 LEFT JOIN (t1, t5, t6) ON (t4.id=t1.id and t4.id=t5.id and t4.id=t6.id) SET a=0, e=0, f=0 where t4.id=1;
|
||||||
|
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||||
|
Last_SQL_Error = Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t4 LEFT JOIN (t1, t5, t6) ON (t4.id=t1.id and t4.id=t5.id and t4.id=t6.id) SET a=0, e=0, f=0 where t4.id=1'
|
||||||
|
set global sql_slave_skip_counter=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
UPDATE t7 LEFT JOIN (t1, t4, t2) ON (t7.id=t1.id and t7.id=t4.id and t7.id=t2.id) SET a=0, b=0, d=0, g=0 where t7.id=1;
|
||||||
|
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||||
|
Last_SQL_Error = Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t7 LEFT JOIN (t1, t4, t2) ON (t7.id=t1.id and t7.id=t4.id and t7.id=t2.id) SET a=0, b=0, d=0, g=0 where t7.id=1'
|
||||||
|
set global sql_slave_skip_counter=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
[on slave]
|
||||||
|
show tables like 't%';
|
||||||
|
Tables_in_test (t%)
|
||||||
|
t1
|
||||||
|
t2
|
||||||
|
t3
|
||||||
|
SELECT * FROM t1;
|
||||||
|
id a
|
||||||
|
1 1
|
||||||
|
2 2
|
||||||
|
3 3
|
||||||
|
SELECT * FROM t2;
|
||||||
|
id b
|
||||||
|
1 1
|
||||||
|
2 2
|
||||||
|
3 3
|
||||||
|
SELECT * FROM t3;
|
||||||
|
id c
|
||||||
|
1 1
|
||||||
|
2 2
|
||||||
|
3 3
|
||||||
|
[on master]
|
||||||
|
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
1
mysql-test/t/rpl_filter_tables_not_exist-slave.opt
Normal file
1
mysql-test/t/rpl_filter_tables_not_exist-slave.opt
Normal file
@ -0,0 +1 @@
|
|||||||
|
--replicate-do-table=test.t1 --replicate-do-table=test.t2 --replicate-do-table=test.t3 --replicate-ignore-table=test.t4 --replicate-ignore-table=test.t5 --replicate-ignore-table=test.t6
|
206
mysql-test/t/rpl_filter_tables_not_exist.test
Normal file
206
mysql-test/t/rpl_filter_tables_not_exist.test
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
# Test evaluation of replication table filter rules
|
||||||
|
#
|
||||||
|
# ==== Purpose ====
|
||||||
|
#
|
||||||
|
# Test if replication table filter rules are properly evaluated when
|
||||||
|
# some of the tables referenced by the multiple-table update do not
|
||||||
|
# exist on slave.
|
||||||
|
#
|
||||||
|
# ==== Method ====
|
||||||
|
#
|
||||||
|
# Master creates tables t1, t2, t3, t4, t5, t6, t7, t8, t9 and the
|
||||||
|
# slave is started with the following replication table filter rules:
|
||||||
|
#
|
||||||
|
# --replicate-do-table=t1
|
||||||
|
# --replicate-do-table=t2
|
||||||
|
# --replicate-do-table=t3
|
||||||
|
#
|
||||||
|
# and
|
||||||
|
#
|
||||||
|
# --replicate-ignore-table=t4
|
||||||
|
# --replicate-ignore-table=t5
|
||||||
|
# --replicate-ignore-table=t6
|
||||||
|
#
|
||||||
|
# So the slave only replicate changes to tables t1, t2 and t3 and only
|
||||||
|
# these tables exist on slave.
|
||||||
|
#
|
||||||
|
# From now on, tables t1, t2, and t3 are referenced as do tables,
|
||||||
|
# tables t4, t5, t6 are referenced as ignore tables, and tables t7,
|
||||||
|
# t8, t9 are referenced as other tables.
|
||||||
|
#
|
||||||
|
# All multi-table update tests reference tables that are not do
|
||||||
|
# tables, which do not exist on slave. And the following situations
|
||||||
|
# of multi-table update will be tested:
|
||||||
|
#
|
||||||
|
# 1. Do tables are not referenced at all
|
||||||
|
# 2. Do tables are not referenced for update
|
||||||
|
# 3. Ignore tables are referenced for update before do tables
|
||||||
|
# 4. Only do tables are referenced for update
|
||||||
|
# 5. Do tables and other tables are referenced for update
|
||||||
|
# 6. Do tables are referenced for update before ignore tables
|
||||||
|
#
|
||||||
|
# For 1, 2 and 3, the statement should be ignored by slave, for 4, 5
|
||||||
|
# and 6 the statement should be accepted by slave and cause an error
|
||||||
|
# because of non-exist tables.
|
||||||
|
#
|
||||||
|
# ==== Related bugs ====
|
||||||
|
#
|
||||||
|
# BUG#37051 Replication rules not evaluated correctly
|
||||||
|
|
||||||
|
|
||||||
|
source include/master-slave.inc;
|
||||||
|
|
||||||
|
# These tables are mentioned in do-table rules
|
||||||
|
CREATE TABLE t1 (id int, a int);
|
||||||
|
CREATE TABLE t2 (id int, b int);
|
||||||
|
CREATE TABLE t3 (id int, c int);
|
||||||
|
|
||||||
|
# These tables are mentioned in ignore-table rules
|
||||||
|
CREATE TABLE t4 (id int, d int);
|
||||||
|
CREATE TABLE t5 (id int, e int);
|
||||||
|
CREATE TABLE t6 (id int, f int);
|
||||||
|
|
||||||
|
# These tables are not mentioned in do-table or ignore-table rules
|
||||||
|
CREATE TABLE t7 (id int, g int);
|
||||||
|
CREATE TABLE t8 (id int, h int);
|
||||||
|
CREATE TABLE t9 (id int, i int);
|
||||||
|
|
||||||
|
INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
INSERT INTO t2 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
INSERT INTO t3 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
|
||||||
|
INSERT INTO t4 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
INSERT INTO t5 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
INSERT INTO t6 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
|
||||||
|
INSERT INTO t7 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
INSERT INTO t8 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
INSERT INTO t9 VALUES (1, 1), (2, 2), (3, 3);
|
||||||
|
|
||||||
|
# Only t1, t2, t3 should be replicated to slave
|
||||||
|
sync_slave_with_master;
|
||||||
|
echo [on slave];
|
||||||
|
SHOW TABLES LIKE 't%';
|
||||||
|
|
||||||
|
connection master;
|
||||||
|
echo [on master];
|
||||||
|
|
||||||
|
#
|
||||||
|
# Do tables are not referenced, these statements should be ignored by
|
||||||
|
# slave.
|
||||||
|
#
|
||||||
|
UPDATE t7 LEFT JOIN t4 ON (t4.id=t7.id) SET d=0, g=0 where t7.id=1;
|
||||||
|
UPDATE t7 LEFT JOIN (t4, t5, t6) ON (t7.id=t4.id and t7.id=t5.id and t7.id=t6.id) SET d=0, e=0, f=0, g=0 where t7.id=1;
|
||||||
|
UPDATE t4 LEFT JOIN (t7, t8, t9) ON (t4.id=t7.id and t4.id=t8.id and t4.id=t9.id) SET d=0, g=0, h=0, i=0 where t4.id=1;
|
||||||
|
UPDATE t7 LEFT JOIN (t8, t9) ON (t7.id=t8.id and t7.id=t9.id) SET g=0, h=0, i=0 where t7.id=1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Do tables are not referenced for update, these statements should be
|
||||||
|
# ignored by slave.
|
||||||
|
#
|
||||||
|
UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET d=0 where t1.id=1;
|
||||||
|
UPDATE t1 LEFT JOIN t7 ON (t1.id=t7.id) SET g=0 where t1.id=1;
|
||||||
|
UPDATE t1 LEFT JOIN (t4, t5, t6) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t6.id) SET d=0, e=0, f=0 where t1.id=1;
|
||||||
|
UPDATE t1 LEFT JOIN (t4, t5, t8) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t8.id) SET d=0, e=0, h=0 where t1.id=1;
|
||||||
|
UPDATE t1 LEFT JOIN (t7, t8, t5) ON (t1.id=t7.id and t1.id=t8.id and t1.id=t5.id) SET g=0, h=0, e=0 where t1.id=1;
|
||||||
|
UPDATE t1 LEFT JOIN (t2, t3, t5) ON (t1.id=t2.id and t1.id=t3.id and t1.id=t5.id) SET e=0 where t1.id=1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Ignore tables are referenced for update before do tables, these
|
||||||
|
# statements should be ignore by slave.
|
||||||
|
#
|
||||||
|
UPDATE t4 LEFT JOIN t1 ON (t1.id=t4.id) SET a=0, d=0 where t4.id=1;
|
||||||
|
UPDATE t4 LEFT JOIN (t1, t7) ON (t4.id=t1.id and t7.id=t4.id) SET a = 0, d=0, g=0 where t4.id=1;
|
||||||
|
UPDATE t4 LEFT JOIN (t1, t2, t3) ON (t1.id=t4.id and t2.id=t4.id and t3.id=t4.id) SET a=0, b=0, c=0, d=0 where t4.id=1;
|
||||||
|
UPDATE t4 LEFT JOIN (t1, t2, t5) ON (t1.id=t4.id and t2.id=t4.id and t5.id=t4.id) SET a=0, b=0, e=0, d=0 where t4.id=1;
|
||||||
|
UPDATE t4 LEFT JOIN (t1, t6, t7) ON (t4.id=t1.id and t4.id=t6.id and t4.id=t7.id) SET a=0, d=0, f=0, g=0 where t4.id=1;
|
||||||
|
UPDATE t7 LEFT JOIN (t4, t1, t2) ON (t7.id=t4.id and t7.id=t1.id and t7.id=t2.id) SET a=0, b=0, d=0, g=0 where t7.id=1;
|
||||||
|
UPDATE t7 LEFT JOIN (t8, t4, t1) ON (t7.id=t8.id and t7.id=t4.id and t7.id=t1.id) SET a=0, d=0, g=0, h=0 where t7.id=1;
|
||||||
|
|
||||||
|
# Sync slave to make sure all above statements are correctly ignored,
|
||||||
|
# if any of the above statement are not ignored, it would cause error
|
||||||
|
# and stop slave sql thread.
|
||||||
|
sync_slave_with_master;
|
||||||
|
connection master;
|
||||||
|
|
||||||
|
# Parameters for include/wait_for_slave_sql_error_and_skip.inc:
|
||||||
|
# Ask it to show SQL error message.
|
||||||
|
let $show_sql_error= 1;
|
||||||
|
# The expected error will always be 1146 (ER_NO_SUCH_TABLE).
|
||||||
|
let $slave_sql_errno= 1146;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Only do tables are referenced for update, these statements should
|
||||||
|
# cause error on slave
|
||||||
|
#
|
||||||
|
UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0 where t1.id=1;
|
||||||
|
source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
|
||||||
|
UPDATE t1 LEFT JOIN (t4, t7) ON (t1.id=t4.id and t1.id=t7.id) SET a=0 where t1.id=1;
|
||||||
|
source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
|
||||||
|
UPDATE t1 LEFT JOIN (t2, t4, t7) ON (t1.id=t2.id and t1.id=t4.id and t1.id=t7.id) SET a=0, b=0 where t1.id=1;
|
||||||
|
source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
|
||||||
|
UPDATE t1 LEFT JOIN (t2, t3, t7) ON (t1.id=t2.id and t1.id=t3.id and t1.id=t7.id) SET a=0, b=0, c=0 where t1.id=1;
|
||||||
|
source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Do tables and other tables are referenced for update, these
|
||||||
|
# statements should cause error on slave
|
||||||
|
#
|
||||||
|
UPDATE t1 LEFT JOIN t7 ON (t1.id=t7.id) SET a=0, g=0 where t1.id=1;
|
||||||
|
source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
|
||||||
|
UPDATE t7 LEFT JOIN t1 ON (t1.id=t7.id) SET a=0, g=0 where t7.id=1;
|
||||||
|
source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
|
||||||
|
UPDATE t1 LEFT JOIN (t4, t5, t7) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t7.id) SET a=0, g=0 where t1.id=1;
|
||||||
|
source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
|
||||||
|
UPDATE t1 LEFT JOIN (t4, t7, t8) ON (t1.id=t4.id and t1.id=t7.id and t1.id=t8.id) SET a=0, g=0 where t1.id=1;
|
||||||
|
source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
|
||||||
|
UPDATE t1 LEFT JOIN (t7, t8, t9) ON (t1.id=t7.id and t1.id=t8.id and t1.id=t9.id) SET a=0, g=0, h=0, i=0 where t1.id=1;
|
||||||
|
source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
|
||||||
|
UPDATE t7 LEFT JOIN (t1, t2, t3) ON (t7.id=t1.id and t7.id=t2.id and t7.id=t3.id) SET g=0, a=0, b=0, c=0 where t7.id=1;
|
||||||
|
source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
|
||||||
|
UPDATE t7 LEFT JOIN (t4, t5, t3) ON (t7.id=t4.id and t7.id=t5.id and t7.id=t3.id) SET g=0, c=0 where t7.id=1;
|
||||||
|
source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
|
||||||
|
UPDATE t7 LEFT JOIN (t8, t9, t3) ON (t7.id=t8.id and t7.id=t9.id and t7.id=t3.id) SET g=0, h=0, i=0, c=0 where t7.id=1;
|
||||||
|
source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Do tables are referenced for update before ignore tables
|
||||||
|
#
|
||||||
|
UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0, d=0 where t1.id=1;
|
||||||
|
source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
|
||||||
|
UPDATE t1 LEFT JOIN (t4, t5, t6) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t6.id) SET a=0, d=0, e=0, f=0 where t1.id=1;
|
||||||
|
source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
|
||||||
|
UPDATE t4 LEFT JOIN (t1, t5, t6) ON (t4.id=t1.id and t4.id=t5.id and t4.id=t6.id) SET a=0, e=0, f=0 where t4.id=1;
|
||||||
|
source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
|
||||||
|
UPDATE t7 LEFT JOIN (t1, t4, t2) ON (t7.id=t1.id and t7.id=t4.id and t7.id=t2.id) SET a=0, b=0, d=0, g=0 where t7.id=1;
|
||||||
|
source include/wait_for_slave_sql_error_and_skip.inc;
|
||||||
|
|
||||||
|
sync_slave_with_master;
|
||||||
|
echo [on slave];
|
||||||
|
|
||||||
|
# We should only have tables t1, t2, t3 on slave
|
||||||
|
show tables like 't%';
|
||||||
|
|
||||||
|
# The rows in these tables should remain untouched
|
||||||
|
SELECT * FROM t1;
|
||||||
|
SELECT * FROM t2;
|
||||||
|
SELECT * FROM t3;
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
connection master;
|
||||||
|
echo [on master];
|
||||||
|
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||||
|
source include/master-slave-end.inc;
|
@ -1117,6 +1117,11 @@ void Query_log_event::pack_info(Protocol *protocol)
|
|||||||
static void write_str_with_code_and_len(char **dst, const char *src,
|
static void write_str_with_code_and_len(char **dst, const char *src,
|
||||||
int len, uint code)
|
int len, uint code)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
only 1 byte to store the length of catalog, so it should not
|
||||||
|
surpass 255
|
||||||
|
*/
|
||||||
|
DBUG_ASSERT(len <= 255);
|
||||||
DBUG_ASSERT(src);
|
DBUG_ASSERT(src);
|
||||||
*((*dst)++)= code;
|
*((*dst)++)= code;
|
||||||
*((*dst)++)= (uchar) len;
|
*((*dst)++)= (uchar) len;
|
||||||
@ -1136,16 +1141,8 @@ static void write_str_with_code_and_len(char **dst, const char *src,
|
|||||||
|
|
||||||
bool Query_log_event::write(IO_CACHE* file)
|
bool Query_log_event::write(IO_CACHE* file)
|
||||||
{
|
{
|
||||||
uchar buf[QUERY_HEADER_LEN+
|
uchar buf[QUERY_HEADER_LEN + MAX_SIZE_LOG_EVENT_STATUS];
|
||||||
1+4+ // code of flags2 and flags2
|
uchar *start, *start_of_status;
|
||||||
1+8+ // code of sql_mode and sql_mode
|
|
||||||
1+1+FN_REFLEN+ // code of catalog and catalog length and catalog
|
|
||||||
1+4+ // code of autoinc and the 2 autoinc variables
|
|
||||||
1+6+ // code of charset and charset
|
|
||||||
1+1+MAX_TIME_ZONE_NAME_LENGTH+ // code of tz and tz length and tz name
|
|
||||||
1+2+ // code of lc_time_names and lc_time_names_number
|
|
||||||
1+2 // code of charset_database and charset_database_number
|
|
||||||
], *start, *start_of_status;
|
|
||||||
ulong event_length;
|
ulong event_length;
|
||||||
|
|
||||||
if (!query)
|
if (!query)
|
||||||
@ -1251,10 +1248,8 @@ bool Query_log_event::write(IO_CACHE* file)
|
|||||||
{
|
{
|
||||||
/* In the TZ sys table, column Name is of length 64 so this should be ok */
|
/* In the TZ sys table, column Name is of length 64 so this should be ok */
|
||||||
DBUG_ASSERT(time_zone_len <= MAX_TIME_ZONE_NAME_LENGTH);
|
DBUG_ASSERT(time_zone_len <= MAX_TIME_ZONE_NAME_LENGTH);
|
||||||
*start++= Q_TIME_ZONE_CODE;
|
write_str_with_code_and_len((char **)(&start),
|
||||||
*start++= time_zone_len;
|
time_zone_str, time_zone_len, Q_TIME_ZONE_CODE);
|
||||||
memcpy(start, time_zone_str, time_zone_len);
|
|
||||||
start+= time_zone_len;
|
|
||||||
}
|
}
|
||||||
if (lc_time_names_number)
|
if (lc_time_names_number)
|
||||||
{
|
{
|
||||||
@ -1270,7 +1265,17 @@ bool Query_log_event::write(IO_CACHE* file)
|
|||||||
int2store(start, charset_database_number);
|
int2store(start, charset_database_number);
|
||||||
start+= 2;
|
start+= 2;
|
||||||
}
|
}
|
||||||
|
if (table_map_for_update)
|
||||||
|
{
|
||||||
|
*start++= Q_TABLE_MAP_FOR_UPDATE_CODE;
|
||||||
|
int8store(start, table_map_for_update);
|
||||||
|
start+= 8;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
|
NOTE: When adding new status vars, please don't forget to update
|
||||||
|
the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update function
|
||||||
|
code_name in this file.
|
||||||
|
|
||||||
Here there could be code like
|
Here there could be code like
|
||||||
if (command-line-option-which-says-"log_this_variable" && inited)
|
if (command-line-option-which-says-"log_this_variable" && inited)
|
||||||
{
|
{
|
||||||
@ -1348,7 +1353,8 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
|
|||||||
auto_increment_increment(thd_arg->variables.auto_increment_increment),
|
auto_increment_increment(thd_arg->variables.auto_increment_increment),
|
||||||
auto_increment_offset(thd_arg->variables.auto_increment_offset),
|
auto_increment_offset(thd_arg->variables.auto_increment_offset),
|
||||||
lc_time_names_number(thd_arg->variables.lc_time_names->number),
|
lc_time_names_number(thd_arg->variables.lc_time_names->number),
|
||||||
charset_database_number(0)
|
charset_database_number(0),
|
||||||
|
table_map_for_update((ulonglong)thd_arg->table_map_for_update)
|
||||||
{
|
{
|
||||||
time_t end_time;
|
time_t end_time;
|
||||||
|
|
||||||
@ -1471,6 +1477,7 @@ code_name(int code)
|
|||||||
case Q_CATALOG_NZ_CODE: return "Q_CATALOG_NZ_CODE";
|
case Q_CATALOG_NZ_CODE: return "Q_CATALOG_NZ_CODE";
|
||||||
case Q_LC_TIME_NAMES_CODE: return "Q_LC_TIME_NAMES_CODE";
|
case Q_LC_TIME_NAMES_CODE: return "Q_LC_TIME_NAMES_CODE";
|
||||||
case Q_CHARSET_DATABASE_CODE: return "Q_CHARSET_DATABASE_CODE";
|
case Q_CHARSET_DATABASE_CODE: return "Q_CHARSET_DATABASE_CODE";
|
||||||
|
case Q_TABLE_MAP_FOR_UPDATE_CODE: return "Q_TABLE_MAP_FOR_UPDATE_CODE";
|
||||||
}
|
}
|
||||||
sprintf(buf, "CODE#%d", code);
|
sprintf(buf, "CODE#%d", code);
|
||||||
return buf;
|
return buf;
|
||||||
@ -1507,7 +1514,8 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
|
|||||||
db(NullS), catalog_len(0), status_vars_len(0),
|
db(NullS), catalog_len(0), status_vars_len(0),
|
||||||
flags2_inited(0), sql_mode_inited(0), charset_inited(0),
|
flags2_inited(0), sql_mode_inited(0), charset_inited(0),
|
||||||
auto_increment_increment(1), auto_increment_offset(1),
|
auto_increment_increment(1), auto_increment_offset(1),
|
||||||
time_zone_len(0), lc_time_names_number(0), charset_database_number(0)
|
time_zone_len(0), lc_time_names_number(0), charset_database_number(0),
|
||||||
|
table_map_for_update(0)
|
||||||
{
|
{
|
||||||
ulong data_len;
|
ulong data_len;
|
||||||
uint32 tmp;
|
uint32 tmp;
|
||||||
@ -1649,6 +1657,11 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
|
|||||||
charset_database_number= uint2korr(pos);
|
charset_database_number= uint2korr(pos);
|
||||||
pos+= 2;
|
pos+= 2;
|
||||||
break;
|
break;
|
||||||
|
case Q_TABLE_MAP_FOR_UPDATE_CODE:
|
||||||
|
CHECK_SPACE(pos, end, 8);
|
||||||
|
table_map_for_update= uint8korr(pos);
|
||||||
|
pos+= 8;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* That's why you must write status vars in growing order of code */
|
/* That's why you must write status vars in growing order of code */
|
||||||
DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\
|
DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\
|
||||||
@ -2036,6 +2049,8 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli,
|
|||||||
else
|
else
|
||||||
thd->variables.collation_database= thd->db_charset;
|
thd->variables.collation_database= thd->db_charset;
|
||||||
|
|
||||||
|
thd->table_map_for_update= (table_map)table_map_for_update;
|
||||||
|
|
||||||
/* Execute the query (note that we bypass dispatch_command()) */
|
/* Execute the query (note that we bypass dispatch_command()) */
|
||||||
const char* found_semicolon= NULL;
|
const char* found_semicolon= NULL;
|
||||||
mysql_parse(thd, thd->query, thd->query_length, &found_semicolon);
|
mysql_parse(thd, thd->query, thd->query_length, &found_semicolon);
|
||||||
|
@ -204,12 +204,15 @@ struct sql_ex_info
|
|||||||
packet (i.e. a query) sent from client to master;
|
packet (i.e. a query) sent from client to master;
|
||||||
First, an auxiliary log_event status vars estimation:
|
First, an auxiliary log_event status vars estimation:
|
||||||
*/
|
*/
|
||||||
#define MAX_SIZE_LOG_EVENT_STATUS (4 /* flags2 */ + \
|
#define MAX_SIZE_LOG_EVENT_STATUS (1 + 4 /* type, flags2 */ + \
|
||||||
8 /* sql mode */ + \
|
1 + 8 /* type, sql_mode */ + \
|
||||||
1 + 1 + 255 /* catalog */ + \
|
1 + 1 + 255 /* type, length, catalog */ + \
|
||||||
4 /* autoinc */ + \
|
1 + 4 /* type, auto_increment */ + \
|
||||||
6 /* charset */ + \
|
1 + 6 /* type, charset */ + \
|
||||||
MAX_TIME_ZONE_NAME_LENGTH)
|
1 + 1 + 255 /* type, length, time_zone */ + \
|
||||||
|
1 + 2 /* type, lc_time_names_number */ + \
|
||||||
|
1 + 2 /* type, charset_database_number */ + \
|
||||||
|
1 + 8 /* type, table_map_for_update */)
|
||||||
#define MAX_LOG_EVENT_HEADER ( /* in order of Query_log_event::write */ \
|
#define MAX_LOG_EVENT_HEADER ( /* in order of Query_log_event::write */ \
|
||||||
LOG_EVENT_HEADER_LEN + /* write_header */ \
|
LOG_EVENT_HEADER_LEN + /* write_header */ \
|
||||||
QUERY_HEADER_LEN + /* write_data */ \
|
QUERY_HEADER_LEN + /* write_data */ \
|
||||||
@ -273,6 +276,8 @@ struct sql_ex_info
|
|||||||
#define Q_LC_TIME_NAMES_CODE 7
|
#define Q_LC_TIME_NAMES_CODE 7
|
||||||
|
|
||||||
#define Q_CHARSET_DATABASE_CODE 8
|
#define Q_CHARSET_DATABASE_CODE 8
|
||||||
|
|
||||||
|
#define Q_TABLE_MAP_FOR_UPDATE_CODE 9
|
||||||
/* Intvar event post-header */
|
/* Intvar event post-header */
|
||||||
|
|
||||||
#define I_TYPE_OFFSET 0
|
#define I_TYPE_OFFSET 0
|
||||||
@ -800,6 +805,11 @@ public:
|
|||||||
const char *time_zone_str;
|
const char *time_zone_str;
|
||||||
uint lc_time_names_number; /* 0 means en_US */
|
uint lc_time_names_number; /* 0 means en_US */
|
||||||
uint charset_database_number;
|
uint charset_database_number;
|
||||||
|
/*
|
||||||
|
map for tables that will be updated for a multi-table update query
|
||||||
|
statement, for other query statements, this will be zero.
|
||||||
|
*/
|
||||||
|
ulonglong table_map_for_update;
|
||||||
|
|
||||||
#ifndef MYSQL_CLIENT
|
#ifndef MYSQL_CLIENT
|
||||||
|
|
||||||
|
@ -172,7 +172,9 @@ THD::THD()
|
|||||||
/* statement id */ 0),
|
/* statement id */ 0),
|
||||||
Open_tables_state(refresh_version),
|
Open_tables_state(refresh_version),
|
||||||
lock_id(&main_lock_id),
|
lock_id(&main_lock_id),
|
||||||
user_time(0), in_sub_stmt(0), global_read_lock(0), is_fatal_error(0),
|
user_time(0), in_sub_stmt(0),
|
||||||
|
table_map_for_update(0),
|
||||||
|
global_read_lock(0), is_fatal_error(0),
|
||||||
transaction_rollback_request(0), is_fatal_sub_stmt_error(0),
|
transaction_rollback_request(0), is_fatal_sub_stmt_error(0),
|
||||||
rand_used(0), time_zone_used(0),
|
rand_used(0), time_zone_used(0),
|
||||||
last_insert_id_used(0), last_insert_id_used_bin_log(0), insert_id_used(0),
|
last_insert_id_used(0), last_insert_id_used_bin_log(0), insert_id_used(0),
|
||||||
@ -651,6 +653,8 @@ void THD::cleanup_after_query()
|
|||||||
free_items();
|
free_items();
|
||||||
/* Reset where. */
|
/* Reset where. */
|
||||||
where= THD::DEFAULT_WHERE;
|
where= THD::DEFAULT_WHERE;
|
||||||
|
/* reset table map for multi-table update */
|
||||||
|
table_map_for_update= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1358,6 +1358,13 @@ public:
|
|||||||
Note: in the parser, stmt_arena == thd, even for PS/SP.
|
Note: in the parser, stmt_arena == thd, even for PS/SP.
|
||||||
*/
|
*/
|
||||||
Query_arena *stmt_arena;
|
Query_arena *stmt_arena;
|
||||||
|
|
||||||
|
/*
|
||||||
|
map for tables that will be updated for a multi-table update query
|
||||||
|
statement, for other query statements, this will be zero.
|
||||||
|
*/
|
||||||
|
table_map table_map_for_update;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
next_insert_id is set on SET INSERT_ID= #. This is used as the next
|
next_insert_id is set on SET INSERT_ID= #. This is used as the next
|
||||||
generated auto_increment value in handler.cc
|
generated auto_increment value in handler.cc
|
||||||
|
@ -2584,6 +2584,10 @@ mysql_execute_command(THD *thd)
|
|||||||
TABLE_LIST *all_tables;
|
TABLE_LIST *all_tables;
|
||||||
/* most outer SELECT_LEX_UNIT of query */
|
/* most outer SELECT_LEX_UNIT of query */
|
||||||
SELECT_LEX_UNIT *unit= &lex->unit;
|
SELECT_LEX_UNIT *unit= &lex->unit;
|
||||||
|
#ifdef HAVE_REPLICATION
|
||||||
|
/* have table map for update for multi-update statement (BUG#37051) */
|
||||||
|
bool have_table_map_for_update= FALSE;
|
||||||
|
#endif
|
||||||
/* Saved variable value */
|
/* Saved variable value */
|
||||||
DBUG_ENTER("mysql_execute_command");
|
DBUG_ENTER("mysql_execute_command");
|
||||||
thd->net.no_send_error= 0;
|
thd->net.no_send_error= 0;
|
||||||
@ -2664,6 +2668,48 @@ mysql_execute_command(THD *thd)
|
|||||||
all_tables->updating= 1;
|
all_tables->updating= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
For fix of BUG#37051, the master stores the table map for update
|
||||||
|
in the Query_log_event, and the value is assigned to
|
||||||
|
thd->variables.table_map_for_update before executing the update
|
||||||
|
query.
|
||||||
|
|
||||||
|
If thd->variables.table_map_for_update is set, then we are
|
||||||
|
replicating from a new master, we can use this value to apply
|
||||||
|
filter rules without opening all the tables. However If
|
||||||
|
thd->variables.table_map_for_update is not set, then we are
|
||||||
|
replicating from an old master, so we just skip this and
|
||||||
|
continue with the old method. And of course, the bug would still
|
||||||
|
exist for old masters.
|
||||||
|
*/
|
||||||
|
if (lex->sql_command == SQLCOM_UPDATE_MULTI &&
|
||||||
|
thd->table_map_for_update)
|
||||||
|
{
|
||||||
|
have_table_map_for_update= TRUE;
|
||||||
|
table_map table_map_for_update= thd->table_map_for_update;
|
||||||
|
uint nr= 0;
|
||||||
|
TABLE_LIST *table;
|
||||||
|
for (table=all_tables; table; table=table->next_global, nr++)
|
||||||
|
{
|
||||||
|
if (table_map_for_update & ((table_map)1 << nr))
|
||||||
|
table->updating= TRUE;
|
||||||
|
else
|
||||||
|
table->updating= FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (all_tables_not_ok(thd, all_tables))
|
||||||
|
{
|
||||||
|
/* we warn the slave SQL thread */
|
||||||
|
my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
|
||||||
|
if (thd->one_shot_set)
|
||||||
|
reset_one_shot_variables(thd);
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (table=all_tables; table; table=table->next_global)
|
||||||
|
table->updating= TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check if statment should be skipped because of slave filtering
|
Check if statment should be skipped because of slave filtering
|
||||||
rules
|
rules
|
||||||
@ -3608,7 +3654,7 @@ end_with_restore_list:
|
|||||||
|
|
||||||
#ifdef HAVE_REPLICATION
|
#ifdef HAVE_REPLICATION
|
||||||
/* Check slave filtering rules */
|
/* Check slave filtering rules */
|
||||||
if (unlikely(thd->slave_thread))
|
if (unlikely(thd->slave_thread && !have_table_map_for_update))
|
||||||
{
|
{
|
||||||
if (all_tables_not_ok(thd, all_tables))
|
if (all_tables_not_ok(thd, all_tables))
|
||||||
{
|
{
|
||||||
|
@ -775,7 +775,7 @@ reopen_tables:
|
|||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
tables_for_update= get_table_map(fields);
|
thd->table_map_for_update= tables_for_update= get_table_map(fields);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Setup timestamp handling and locking mode
|
Setup timestamp handling and locking mode
|
||||||
|
Reference in New Issue
Block a user