Commit 70b18065 authored by Mats Kindahl's avatar Mats Kindahl
Browse files

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.
parent e05be97a
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -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
+17 −0
Original line number Diff line number Diff line
@@ -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
+2 −0
Original line number Diff line number Diff line
@@ -4338,6 +4338,8 @@ static int write_locked_table_maps(THD *thd)
                       (long) thd, (long) thd->lock,
                       (long) thd->locked_tables, (long) thd->extra_lock));

  DBUG_PRINT("debug", ("get_binlog_table_maps(): %d", thd->get_binlog_table_maps()));

  if (thd->get_binlog_table_maps() == 0)
  {
    MYSQL_LOCK *locks[3];
+2 −2
Original line number Diff line number Diff line
@@ -1377,6 +1377,8 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data,
                      FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT),
                      FLAGSTR(thd->options, OPTION_BEGIN)));

  thd->binlog_flush_pending_rows_event(TRUE);

  /*
    NULL denotes ROLLBACK with nothing to replicate: i.e., rollback of
    only transactional tables.  If the transaction contain changes to
@@ -1395,8 +1397,6 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data,
      were, we would have to ensure that we're not ending a statement
      inside a stored function.
     */
    thd->binlog_flush_pending_rows_event(TRUE);

    error= mysql_bin_log.write(thd, &trx_data->trans_log, end_ev);
    trx_data->reset();

+23 −1
Original line number Diff line number Diff line
@@ -3558,6 +3558,24 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end)
}


static const char *
show_query_type(THD::enum_binlog_query_type qtype)
{
  switch (qtype) {
  case THD::ROW_QUERY_TYPE:
    return "ROW";
  case THD::STMT_QUERY_TYPE:
    return "STMT";
  case THD::MYSQL_QUERY_TYPE:
    return "MYSQL";
  }

  static char buf[64];
  sprintf(buf, "UNKNOWN#%d", qtype);
  return buf;
}


/*
  Member function that will log query, either row-based or
  statement-based depending on the value of the 'current_stmt_binlog_row_based'
@@ -3586,7 +3604,8 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
                      THD::killed_state killed_status_arg)
{
  DBUG_ENTER("THD::binlog_query");
  DBUG_PRINT("enter", ("qtype: %d  query: '%s'", qtype, query_arg));
  DBUG_PRINT("enter", ("qtype: %s  query: '%s'",
                       show_query_type(qtype), query_arg));
  DBUG_ASSERT(query_arg && mysql_bin_log.is_open());

  /*
@@ -3625,6 +3644,9 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,

  switch (qtype) {
  case THD::ROW_QUERY_TYPE:
    DBUG_PRINT("debug",
               ("current_stmt_binlog_row_based: %d",
                current_stmt_binlog_row_based));
    if (current_stmt_binlog_row_based)
      DBUG_RETURN(0);
    /* Otherwise, we fall through */
Loading