Hi Mats
Nice work, approved
Mats Kindahl wrote:
> #At file:///home/bzr/bugs/b34707-5.1-rpl/
>
> 2658 Mats Kindahl 2008-08-13
> Bug #34707: Row based replication: slave creates table within wrong database
>
> The failure was caused by executing a CREATE-SELECT statement that creates a
> table in another database than the current one. In row-based logging, the
> CREATE statement was written to the binary log without the database, hence
> creating the table in the wrong database, causing the following inserts to
> fail since the table didn't exist in the given database.
>
> Fixed the bug by adding a parameter to store_create_info() that will make
> the function print the database name before the table name and used that
> in the calls that write the CREATE statement to the binary log. The database
> name is only printed if it is different than the currently selected database.
>
> The output of SHOW CREATE TABLE has not changed and is still printed without
> the database name.
> modified:
> mysql-test/suite/rpl/r/rpl_row_create_table.result
> mysql-test/suite/rpl/t/rpl_row_create_table.test
> sql/sql_insert.cc
> sql/sql_show.cc
> sql/sql_show.h
> sql/sql_table.cc
>
> per-file messages:
> mysql-test/suite/rpl/r/rpl_row_create_table.result
> Result file change.
> mysql-test/suite/rpl/t/rpl_row_create_table.test
> Added test to check that CREATE-SELECT into another database than the
> current one replicates.
> sql/sql_insert.cc
> Adding parameter to calls to store_create_info().
> sql/sql_show.cc
> Adding parameter to calls to store_create_info().
>
> Extending store_create_info() with parameter 'show_database' that will cause
> the database to be written before the table name.
> sql/sql_show.h
> Adding parameter to call to store_create_info() to tell if the database should be
> shown or not.
> sql/sql_table.cc
> Adding parameter to calls to store_create_info().
> === modified file 'mysql-test/suite/rpl/r/rpl_row_create_table.result'
> --- a/mysql-test/suite/rpl/r/rpl_row_create_table.result 2008-04-08 07:43:00 +0000
> +++ b/mysql-test/suite/rpl/r/rpl_row_create_table.result 2008-08-13 13:06:25 +0000
> @@ -430,4 +430,25 @@ a
> 1
> 2
> DROP TABLE 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;
> +CREATE DATABASE mysqltest1;
> +CREATE TABLE mysqltest1.without_select (f1 BIGINT);
> +CREATE TABLE mysqltest1.with_select AS SELECT 1 AS f1;
> +show binlog events from <binlog_start>;
> +Log_name Pos Event_type Server_id End_log_pos Info
> +master-bin.000001 # Query # # CREATE DATABASE mysqltest1
> +master-bin.000001 # Query # # use `test`; CREATE TABLE mysqltest1.without_select (f1
> BIGINT)
> +master-bin.000001 # Query # # use `test`; BEGIN
> +master-bin.000001 # Query # # use `test`; CREATE TABLE `mysqltest1`.`with_select` (
> + `f1` int(1) NOT NULL DEFAULT '0'
> +)
> +master-bin.000001 # Table_map # # table_id: # (mysqltest1.with_select)
> +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
> +master-bin.000001 # Query # # use `test`; COMMIT
> +DROP DATABASE mysqltest1;
> end of the tests
>
> === modified file 'mysql-test/suite/rpl/t/rpl_row_create_table.test'
> --- a/mysql-test/suite/rpl/t/rpl_row_create_table.test 2008-04-08 07:43:00 +0000
> +++ b/mysql-test/suite/rpl/t/rpl_row_create_table.test 2008-08-13 13:06:25 +0000
> @@ -259,5 +259,22 @@ connection master;
> DROP TABLE t1;
> sync_slave_with_master;
>
> +#
> +# BUG#34707: Row based replication: slave creates table within wrong database
> +#
> +
> +source include/master-slave-reset.inc;
> +
> +connection master;
> +CREATE DATABASE mysqltest1;
> +
> +CREATE TABLE mysqltest1.without_select (f1 BIGINT);
> +CREATE TABLE mysqltest1.with_select AS SELECT 1 AS f1;
> +source include/show_binlog_events.inc;
> +sync_slave_with_master;
> +
> +connection master;
> +DROP DATABASE mysqltest1;
> +sync_slave_with_master;
>
> --echo end of the tests
>
> === modified file 'sql/sql_insert.cc'
> --- a/sql/sql_insert.cc 2008-07-11 18:51:10 +0000
> +++ b/sql/sql_insert.cc 2008-08-13 13:06:25 +0000
> @@ -3616,7 +3616,8 @@ select_create::binlog_show_create_table(
> tmp_table_list.table = *tables;
> query.length(0); // Have to zero it since constructor doesn't
>
> - result= store_create_info(thd, &tmp_table_list, &query, create_info);
> + result= store_create_info(thd, &tmp_table_list, &query, create_info,
> + /* show_database */ TRUE);
> DBUG_ASSERT(result == 0); /* store_create_info() always return 0 */
>
> thd->binlog_query(THD::STMT_QUERY_TYPE,
>
> === modified file 'sql/sql_show.cc'
> --- a/sql/sql_show.cc 2008-05-12 10:09:10 +0000
> +++ b/sql/sql_show.cc 2008-08-13 13:06:25 +0000
> @@ -619,7 +619,8 @@ mysqld_show_create(THD *thd, TABLE_LIST
>
> if ((table_list->view ?
> view_store_create_info(thd, table_list, &buffer) :
> - store_create_info(thd, table_list, &buffer, NULL)))
> + store_create_info(thd, table_list, &buffer, NULL,
> + FALSE /* show_database */)))
> DBUG_RETURN(TRUE);
>
> List<Item> field_list;
> @@ -810,7 +811,8 @@ mysqld_dump_create_info(THD *thd, TABLE_
> DBUG_PRINT("enter",("table: %s",table_list->table->s->table_name.str));
>
> protocol->prepare_for_resend();
> - if (store_create_info(thd, table_list, packet, NULL))
> + if (store_create_info(thd, table_list, packet, NULL,
> + FALSE /* show_database */))
> DBUG_RETURN(-1);
>
> if (fd < 0)
> @@ -1062,7 +1064,7 @@ static bool get_field_default_value(THD
> */
>
> int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
> - HA_CREATE_INFO *create_info_arg)
> + HA_CREATE_INFO *create_info_arg, bool show_database)
> {
> List<Item> field_list;
> char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], def_value_buf[MAX_FIELD_WIDTH];
> @@ -1110,6 +1112,25 @@ int store_create_info(THD *thd, TABLE_LI
> alias= share->table_name.str;
> }
> }
> +
> + /*
> + Print the database before the table name if told to do that. The
> + database name is only printed in the event that it is different
> + from the current database. The main reason for doing this is to
> + avoid having to update gazillions of tests and result files, but
> + it also saves a few bytes of the binary log.
> + */
> + if (show_database)
> + {
> + const LEX_STRING *const db=
> + table_list->schema_table ? &INFORMATION_SCHEMA_NAME :
> &table->s->db;
> + if (strcmp(db->str, thd->db) != 0)
> + {
> + append_identifier(thd, packet, db->str, db->length);
> + packet->append(STRING_WITH_LEN("."));
> + }
> + }
> +
> append_identifier(thd, packet, alias, strlen(alias));
> packet->append(STRING_WITH_LEN(" (\n"));
> /*
>
> === modified file 'sql/sql_show.h'
> --- a/sql/sql_show.h 2007-08-02 22:14:05 +0000
> +++ b/sql/sql_show.h 2008-08-13 13:06:25 +0000
> @@ -33,7 +33,7 @@ find_files_result find_files(THD *thd, L
> const char *path, const char *wild, bool dir);
>
> int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
> - HA_CREATE_INFO *create_info_arg);
> + HA_CREATE_INFO *create_info_arg, bool show_database);
> int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff);
>
> int copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table);
>
> === modified file 'sql/sql_table.cc'
> --- a/sql/sql_table.cc 2008-07-17 18:26:55 +0000
> +++ b/sql/sql_table.cc 2008-08-13 13:06:25 +0000
> @@ -4956,8 +4956,9 @@ bool mysql_create_like_table(THD* thd, T
> }
> VOID(pthread_mutex_unlock(&LOCK_open));
>
> - IF_DBUG(int result=) store_create_info(thd, table, &query,
> - create_info);
> + IF_DBUG(int result=)
> + store_create_info(thd, table, &query,
> + create_info, TRUE /* show_database */);
>
> DBUG_ASSERT(result == 0); // store_create_info() always return 0
> write_bin_log(thd, TRUE, query.ptr(), query.length());
>
>
--
Turbolinux China
A: A12 Jianguomenwai Avenue Chaoyang District Beijing PRC
Z: 100022
E: hezx@stripped
T: 86-010-65054020-318
F: 86-010-65054017