#At file:///home/lsoares/Workspace/bzr/work/bugfixing/48297/mysql-5.1-bugteam/ based on revid:joro@stripped
3199 Luis Soares 2009-10-27
BUG#48297: Schema name is ignored when LOAD DATA is written into
binlog, replication aborts
In SBR or MBR, the schema name is not being written to the binlog
when executing a LOAD DATA statement. This becomes a problem when
the current database (lets call it db1) is different from the
table's schema (lets call it db2). For instance, take the
following statements:
use db1;
load data local infile 'infile.txt' into table db2.t
Should this statement be logged without t's schema (db2), when
replaying it, one can get db1.t populated instead of db2.t (if
db1.t exists). On the other hand, if there is no db1.t at all,
replication will stop.
We fix this by always logging the table (in load file) with fully
qualified name when its schema is different from the current
database or when no default database was selected.
modified:
mysql-test/extra/rpl_tests/rpl_loaddata.test
mysql-test/suite/rpl/r/rpl_loaddata.result
sql/sql_load.cc
=== modified file 'mysql-test/extra/rpl_tests/rpl_loaddata.test'
--- a/mysql-test/extra/rpl_tests/rpl_loaddata.test 2008-11-13 19:19:00 +0000
+++ b/mysql-test/extra/rpl_tests/rpl_loaddata.test 2009-10-27 15:15:53 +0000
@@ -158,4 +158,65 @@ LOAD DATA INFILE "../../std_data/words.d
DROP TABLE IF EXISTS t1;
+# BUG#48297: Schema name is ignored when LOAD DATA is written into binlog,
+# replication aborts
+-- source include/master-slave-reset.inc
+
+-- let $db1= b48297_db1
+-- let $db2= b42897_db2
+
+-- connection master
+
+-- disable_warnings
+-- eval drop database if exists $db1
+-- eval drop database if exists $db2
+-- enable_warnings
+
+-- eval create database $db1
+-- eval create database $db2
+
+-- eval use $db1
+-- eval CREATE TABLE t1 (c1 VARCHAR(256)) engine=$engine_type;
+
+-- eval use $db2
+
+-- echo ### assertion: works with cross-referenced database
+-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+-- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1
+
+-- eval use $db1
+-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+-- echo ### assertion: works with fully qualified name on current database
+-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+-- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1
+
+-- echo ### assertion: works without fully qualified name on current database
+-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+-- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE t1
+
+-- echo ### create connection without default database
+-- echo ### connect (conn2,localhost,root,,*NO-ONE*);
+connect (conn2,localhost,root,,*NO-ONE*);
+-- connection conn2
+-- echo ### assertion: works without stating the default database
+-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+-- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1
+-- echo ### disconnect and switch back to master connection
+-- disconnect conn2
+-- connection master
+
+-- sync_slave_with_master
+-- eval use $db1
+
+let $diff_table_1=master:$db1.t1;
+let $diff_table_2=slave:$db1.t1;
+source include/diff_tables.inc;
+
+-- connection master
+
+-- eval DROP DATABASE $db1
+-- eval DROP DATABASE $db2
+
+-- sync_slave_with_master
+
# End of 4.1 tests
=== modified file 'mysql-test/suite/rpl/r/rpl_loaddata.result'
--- a/mysql-test/suite/rpl/r/rpl_loaddata.result 2009-09-28 12:41:10 +0000
+++ b/mysql-test/suite/rpl/r/rpl_loaddata.result 2009-10-27 15:15:53 +0000
@@ -86,3 +86,32 @@ CREATE TABLE t1 (word CHAR(20) NOT NULL
LOAD DATA INFILE "../../std_data/words.dat" INTO TABLE t1;
ERROR 23000: Duplicate entry 'Aarhus' for key 'PRIMARY'
DROP TABLE IF EXISTS t1;
+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;
+drop database if exists b48297_db1;
+drop database if exists b42897_db2;
+create database b48297_db1;
+create database b42897_db2;
+use b48297_db1;
+CREATE TABLE t1 (c1 VARCHAR(256)) engine=MyISAM;;
+use b42897_db2;
+### assertion: works with cross-referenced database
+LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE b48297_db1.t1;
+use b48297_db1;
+### assertion: works with fully qualified name on current database
+LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE b48297_db1.t1;
+### assertion: works without fully qualified name on current database
+LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE t1;
+### create connection without default database
+### connect (conn2,localhost,root,,*NO-ONE*);
+### assertion: works without stating the default database
+LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE b48297_db1.t1;
+### disconnect and switch back to master connection
+use b48297_db1;
+Comparing tables master:b48297_db1.t1 and slave:b48297_db1.t1
+DROP DATABASE b48297_db1;
+DROP DATABASE b42897_db2;
=== modified file 'sql/sql_load.cc'
--- a/sql/sql_load.cc 2009-10-16 10:29:42 +0000
+++ b/sql/sql_load.cc 2009-10-27 15:15:53 +0000
@@ -84,7 +84,7 @@ static int read_sep_field(THD *thd, COPY
bool ignore_check_option_errors);
#ifndef EMBEDDED_LIBRARY
static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex,
- const char* db_arg,
+ const char* db_arg, /* table's database */
const char* table_name_arg,
enum enum_duplicates duplicates,
bool ignore,
@@ -501,7 +501,8 @@ int mysql_load(THD *thd,sql_exchange *ex
if (thd->transaction.stmt.modified_non_trans_table)
write_execute_load_query_log_event(thd, ex,
- tdb, table_list->table_name,
+ table_list->db,
+ table_list->table_name,
handle_duplicates, ignore,
transactional_table,
errcode);
@@ -548,7 +549,7 @@ int mysql_load(THD *thd,sql_exchange *ex
{
int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
write_execute_load_query_log_event(thd, ex,
- tdb, table_list->table_name,
+ table_list->db, table_list->table_name,
handle_duplicates, ignore,
transactional_table,
errcode);
@@ -573,7 +574,7 @@ err:
/* Not a very useful function; just to avoid duplication of code */
static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex,
- const char* db_arg,
+ const char* db_arg, /* table's database */
const char* table_name_arg,
enum enum_duplicates duplicates,
bool ignore,
@@ -590,8 +591,27 @@ static bool write_execute_load_query_log
Item *item, *val;
String pfield, pfields;
int n;
+ const char *tbl= table_name_arg;
+ const char *tdb= (thd->db != NULL ? thd->db : db_arg);
+ String string_buf;
- Load_log_event lle(thd, ex, db_arg, table_name_arg, fv, duplicates,
+ if (!thd->db || strcmp(db_arg, thd->db))
+ {
+ /*
+ If used database differs from table's database,
+ prefix table name with database name so that it
+ becomes a FQ name.
+ */
+ string_buf.set_charset(system_charset_info);
+ string_buf.append(db_arg);
+ string_buf.append("`");
+ string_buf.append(".");
+ string_buf.append("`");
+ string_buf.append(table_name_arg);
+ tbl= string_buf.c_ptr_safe();
+ }
+
+ Load_log_event lle(thd, ex, tdb, tbl, fv, duplicates,
ignore, transactional_table);
/*
Attachment: [text/bzr-bundle] bzr/luis.soares@sun.com-20091027151553-ri74b2zdchw8wyg7.bundle
| Thread |
|---|
| • bzr commit into mysql-5.1-bugteam branch (luis.soares:3199) Bug#48297 | Luis Soares | 27 Oct |