MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Li-Bing.Song Date:August 13 2010 9:06am
Subject:bzr commit into mysql-5.1-bugteam branch (Li-Bing.Song:3479) Bug#39804
Bug#51501
View as plain text  
#At file:///home/anders/work/bzrwork1/mysql-5.1-wl5370/ based on revid:li-bing.song@stripped

 3479 Li-Bing.Song@stripped	2010-08-13
      Bug #39804 Failing CREATE ... SELECT doesn't appear in binary log
      Bug #51501  	RBR, slave stops with HA_ERR_KEY_NOT_FOUND
      
      Failing CREATE ... SELECT that updates non-transactional tables
      via stored function(bug#39804) or the creating non-transactional
      table already exists(Rows are inserted into it, but it can not be
      dropt) is not binlogged on SBR. The cause is that the statement
      will never be binlogged on SBR if it fails. As the table will be 
      dropt automatically after an error happens.
      
      In this patch, the statement will be binlogged on SBR if a other
      non-trasactional table is modified or the creating non-transactional
      table already exists(It means it can not be dropt).
      
      It also fix Bug#55625  RBR breaks on failing 'CREATE TABLE'
      
      It will be binlogged if a nontrasactional table is modified.
      But the 'CREATE TABLE' statement will always be binlogged even
      when the creating table is dropt automatically on master. But
      it can not be dropt automatically on slave. This will cause the 
      second 'CREATE TABLE' on the same name fails on slave(It can be
      executed on master well). 
      
      Because rows for different tables are in different events. So
      after this patch, only the row events on other tables are binlogged
      with 'ROLLBACK'. The 'CREATE TABLE' event and all row events on the
      creating table are truncated. They will never be binlogged.
     @ sql/log.cc
        add binlog_truncate_stmt() to truncate a statement.
     @ sql/sql_class.h
        add variable modified_other_non_trans_table in select_create class.
        It is set on the rare occasion that SELECT clause calls a function
        in which a non-transaction table is modified.

    renamed:
      mysql-test/suite/rpl/r/rpl_create_if_not_exists.result => mysql-test/suite/rpl/r/rpl_create_table.result
      mysql-test/suite/rpl/t/rpl_create_if_not_exists.test => mysql-test/suite/rpl/t/rpl_create_table.test
    modified:
      mysql-test/suite/rpl/t/rpl_row_create_table.test
      sql/log.cc
      sql/sql_class.h
      sql/sql_insert.cc
      mysql-test/suite/rpl/r/rpl_create_table.result
      mysql-test/suite/rpl/t/rpl_create_table.test
=== renamed file 'mysql-test/suite/rpl/r/rpl_create_if_not_exists.result' => 'mysql-test/suite/rpl/r/rpl_create_table.result'
--- a/mysql-test/suite/rpl/r/rpl_create_if_not_exists.result	2010-01-16 07:44:24 +0000
+++ b/mysql-test/suite/rpl/r/rpl_create_table.result	2010-08-13 09:06:24 +0000
@@ -65,3 +65,179 @@ c1
 DROP TABLE t1;
 DROP TABLE t2;
 DROP TABLE t3;
+
+# BUG#39804 Failing CREATE ... SELECT doesn't appear in binary log.
+
+DROP FUNCTION IF EXISTS f1;
+CREATE TABLE t2(a INT) ENGINE=MyISAM;
+CREATE TABLE t3(a INT) ENGINE=Innodb;
+CREATE FUNCTION f_insert_t2() RETURNS INT
+BEGIN
+INSERT INTO t2 VALUES(1);
+RETURN 1;
+END|
+CREATE FUNCTION f_insert_t3() RETURNS INT
+BEGIN
+INSERT INTO t3 VALUES(1);
+RETURN 1;
+END|
+
+# Case 1: Verify the statement can be binlogged well if no error happens
+# ---------------------------------------------------------------------
+# There is no any other table modified
+CREATE TABLE t1(a INT) ENGINE=MyISAM SELECT 1 AS a;
+Comparing tables master:test.t2 and slave:test.t2
+Comparing tables master:test.t3 and slave:test.t3
+CREATE TABLE IF NOT EXISTS t1 SELECT 1 AS a;
+Warnings:
+Note	1050	Table 't1' already exists
+Comparing tables master:test.t2 and slave:test.t2
+Comparing tables master:test.t3 and slave:test.t3
+DROP TABLE t1;
+
+# Tables t2 and t3 are modified in the statement.
+CREATE TABLE t1(a INT) ENGINE=Innodb SELECT 1 AS a 
+UNION ALL SELECT f_insert_t2() UNION ALL SELECT f_insert_t3();
+Comparing tables master:test.t2 and slave:test.t2
+Comparing tables master:test.t3 and slave:test.t3
+CREATE TABLE IF NOT EXISTS t1 SELECT 1 AS a 
+UNION ALL SELECT f_insert_t2() UNION ALL SELECT f_insert_t3();
+Warnings:
+Note	1050	Table 't1' already exists
+Comparing tables master:test.t2 and slave:test.t2
+Comparing tables master:test.t3 and slave:test.t3
+DROP TABLE t1;
+
+# Case 2: Verify it can be binlogged well if error(table already exists)
+# happens
+# --------------------------------------------------------------------- 
+
+CREATE TABLE t1(a INT KEY) ENGINE=MyISAM;
+CREATE TABLE t4(a INT KEY) ENGINE=Innodb;
+
+# Create a MyISAM table and there is no any other table modified
+CREATE TABLE IF NOT EXISTS t1(UNIQUE(a)) ENGINE=MyISAM
+SELECT 1 AS a UNION ALL SELECT 1;
+Comparing tables master:test.t1 and slave:test.t1
+
+# Create a Innodb table and there is no any other table modified
+CREATE TABLE IF NOT EXISTS t4(UNIQUE(a)) ENGINE=Innodb
+SELECT 1 AS a UNION ALL SELECT 1;
+# The statement should not be binlogged.
+show binlog events in 'master-bin.000001' from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+
+# Create a MyISAM table and the transaction table(t3) is updated.
+CREATE TABLE IF NOT EXISTS t1(UNIQUE(a)) ENGINE=MyISAM
+SELECT 1 AS a UNION ALL SELECT f_insert_t3 ();
+Comparing tables master:test.t1 and slave:test.t1
+
+# Create a Innodb table and the transaction table(t3) is updated.
+CREATE TABLE IF NOT EXISTS t4(UNIQUE(a)) ENGINE=Innodb
+SELECT 1 AS a UNION ALL SELECT f_insert_t3();
+# The statement should not be binlogged.
+show binlog events in 'master-bin.000001' from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+
+# Create a MyISAM table and both of the transaction table(t3) and
+# non-transaction table(t2) are updated.
+CREATE TABLE IF NOT EXISTS t1(UNIQUE(a)) ENGINE=MyISAM
+SELECT f_insert_t2() AS a UNION ALL SELECT f_insert_t3 ();
+Comparing tables master:test.t2 and slave:test.t2
+Comparing tables master:test.t3 and slave:test.t3
+
+# Create a Innodb table and both of the transaction table(t3) and
+# non-transaction table(t2) are updated.
+CREATE TABLE IF NOT EXISTS t4(UNIQUE(a)) ENGINE=Innodb
+SELECT f_insert_t2() AS a UNION ALL SELECT f_insert_t3();
+Comparing tables master:test.t2 and slave:test.t2
+Comparing tables master:test.t3 and slave:test.t3
+
+# Create a MyISAM table and there is no any other table modified
+CREATE TABLE  t1(UNIQUE(a)) ENGINE=MyISAM
+SELECT 1 AS a UNION ALL SELECT 1;
+# The statement should not be binlogged.
+show binlog events in 'master-bin.000001' from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+
+# Create a Innodb table and there is no any other table modified
+CREATE TABLE  t4(UNIQUE(a)) ENGINE=Innodb
+SELECT 1 AS a UNION ALL SELECT 1;
+# The statement should not be binlogged.
+show binlog events in 'master-bin.000001' from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+
+# Create a MyISAM table and the transaction table(t3) is updated.
+CREATE TABLE  t1(UNIQUE(a)) ENGINE=MyISAM
+SELECT 1 AS a UNION ALL SELECT f_insert_t3 ();
+# The statement should not be binlogged.
+show binlog events in 'master-bin.000001' from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+
+# Create a Innodb table and the transaction table(t3) is updated.
+CREATE TABLE  t4(UNIQUE(a)) ENGINE=Innodb
+SELECT 1 AS a UNION ALL SELECT f_insert_t3();
+# The statement should not be binlogged.
+show binlog events in 'master-bin.000001' from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+
+# Create a MyISAM table and both of the transaction table(t3) and
+# non-transaction table(t2) are updated.
+CREATE TABLE  t1(UNIQUE(a)) ENGINE=MyISAM
+SELECT f_insert_t2() AS a UNION ALL SELECT f_insert_t3 ();
+Comparing tables master:test.t2 and slave:test.t2
+Comparing tables master:test.t3 and slave:test.t3
+
+# Create a Innodb table and both of the transaction table(t3) and
+# non-transaction table(t2) are updated.
+CREATE TABLE  t4(UNIQUE(a)) ENGINE=Innodb
+SELECT f_insert_t2() AS a UNION ALL SELECT f_insert_t3();
+Comparing tables master:test.t2 and slave:test.t2
+Comparing tables master:test.t3 and slave:test.t3
+DROP TABLE t1;
+DROP TABLE t4;
+
+# Create a MyISAM table and there is no any other table modified
+CREATE TABLE  t1(UNIQUE(a)) ENGINE=MyISAM
+SELECT 1 AS a UNION ALL SELECT 1;
+# The statement should not be binlogged.
+show binlog events in 'master-bin.000001' from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+
+# Create a Innodb table and there is no any other table modified
+CREATE TABLE  t4(UNIQUE(a)) ENGINE=Innodb
+SELECT 1 AS a UNION ALL SELECT 1;
+# The statement should not be binlogged.
+show binlog events in 'master-bin.000001' from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+
+# Create a MyISAM table and the transaction table(t3) is updated.
+CREATE TABLE  t1(UNIQUE(a)) ENGINE=MyISAM
+SELECT 1 AS a UNION ALL SELECT f_insert_t3 ();
+# The statement should not be binlogged.
+show binlog events in 'master-bin.000001' from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+
+# Create a Innodb table and the transaction table(t3) is updated.
+CREATE TABLE  t4(UNIQUE(a)) ENGINE=Innodb
+SELECT 1 AS a UNION ALL SELECT f_insert_t3();
+# The statement should not be binlogged.
+show binlog events in 'master-bin.000001' from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+
+# Create a MyISAM table and both of the transaction table(t3) and
+# non-transaction table(t2) are updated.
+CREATE TABLE  t1(UNIQUE(a)) ENGINE=MyISAM
+SELECT f_insert_t2() AS a UNION ALL SELECT f_insert_t3 ();
+Comparing tables master:test.t2 and slave:test.t2
+Comparing tables master:test.t3 and slave:test.t3
+
+# Create a Innodb table and both of the transaction table(t3) and
+# non-transaction table(t2) are updated.
+CREATE TABLE  t4(UNIQUE(a)) ENGINE=Innodb
+SELECT f_insert_t2() AS a UNION ALL SELECT f_insert_t3();
+Comparing tables master:test.t2 and slave:test.t2
+Comparing tables master:test.t3 and slave:test.t3
+DROP TABLE t2, t3;
+DROP FUNCTION f_insert_t2;
+DROP FUNCTION f_insert_t3;

=== renamed file 'mysql-test/suite/rpl/t/rpl_create_if_not_exists.test' => 'mysql-test/suite/rpl/t/rpl_create_table.test'
--- a/mysql-test/suite/rpl/t/rpl_create_if_not_exists.test	2010-07-23 05:36:37 +0000
+++ b/mysql-test/suite/rpl/t/rpl_create_table.test	2010-08-13 09:06:24 +0000
@@ -28,6 +28,7 @@
 #
 
 source include/master-slave.inc;
+source include/have_innodb.inc;
 disable_warnings;
 DROP DATABASE IF EXISTS mysqltest;
 
@@ -122,4 +123,182 @@ DROP TABLE t1;
 DROP TABLE t2;
 DROP TABLE t3;
 
+--echo
+--echo # BUG#39804 Failing CREATE ... SELECT doesn't appear in binary log.
+--echo
+--disable_warnings
+DROP FUNCTION IF EXISTS f1;
+--enable_warnings
+
+CREATE TABLE t2(a INT) ENGINE=MyISAM;
+CREATE TABLE t3(a INT) ENGINE=Innodb;
+
+--delimiter |
+CREATE FUNCTION f_insert_t2() RETURNS INT
+BEGIN
+  INSERT INTO t2 VALUES(1);
+  RETURN 1;
+END|
+
+CREATE FUNCTION f_insert_t3() RETURNS INT
+BEGIN
+  INSERT INTO t3 VALUES(1);
+  RETURN 1;
+END|
+--delimiter ;
+
+--echo
+--echo # Case 1: Verify the statement can be binlogged well if no error happens
+--echo # ---------------------------------------------------------------------
+--echo # There is no any other table modified
+CREATE TABLE t1(a INT) ENGINE=MyISAM SELECT 1 AS a;
+let $diff_table=test.t2;
+source include/rpl_diff_tables.inc;
+let $diff_table=test.t3;
+source include/rpl_diff_tables.inc;
+
+CREATE TABLE IF NOT EXISTS t1 SELECT 1 AS a;
+let $diff_table=test.t2;
+source include/rpl_diff_tables.inc;
+let $diff_table=test.t3;
+source include/rpl_diff_tables.inc;
+DROP TABLE t1;
+
+--echo
+--echo # Tables t2 and t3 are modified in the statement.
+CREATE TABLE t1(a INT) ENGINE=Innodb SELECT 1 AS a 
+  UNION ALL SELECT f_insert_t2() UNION ALL SELECT f_insert_t3();
+let $diff_table=test.t2;
+source include/rpl_diff_tables.inc;
+let $diff_table=test.t3;
+source include/rpl_diff_tables.inc;
+
+CREATE TABLE IF NOT EXISTS t1 SELECT 1 AS a 
+  UNION ALL SELECT f_insert_t2() UNION ALL SELECT f_insert_t3();
+let $diff_table=test.t2;
+source include/rpl_diff_tables.inc;
+let $diff_table=test.t3;
+source include/rpl_diff_tables.inc;
+DROP TABLE t1;
+
+--echo
+--echo # Case 2: Verify it can be binlogged well if error(table already exists)
+--echo # happens
+--echo # --------------------------------------------------------------------- 
+--echo
+
+CREATE TABLE t1(a INT KEY) ENGINE=MyISAM;
+CREATE TABLE t4(a INT KEY) ENGINE=Innodb;
+
+let _n=3;
+let _set_exist=1;
+while ($_n)
+{
+  let $_if_exist_opt=;
+  dec $_n;
+
+  # first: the table already exists, 'IF NOT EXISTS' is set.
+  if ($_set_exist)
+  {
+    let $_if_exist_opt= IF NOT EXISTS;
+  }
+
+  # second: the table already exists, 'IF NOT EXISTS' is not set.
+
+  # third: Drop the table.
+  if (!$_n)
+  {
+    DROP TABLE t1;
+    DROP TABLE t4;
+    dec $_drop;
+  }
+
+  let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
+  let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1);
+
+  --echo
+  --echo # Create a MyISAM table and there is no any other table modified
+  --error 0, 1050, 1062
+  eval CREATE TABLE $_if_exist_opt t1(UNIQUE(a)) ENGINE=MyISAM
+    SELECT 1 AS a UNION ALL SELECT 1;
+  if (!$_set_exist)
+  {
+    --echo # The statement should not be binlogged.
+    source include/show_binlog_events.inc;
+  }
+  if ($_set_exist)
+  {
+    let $diff_table=test.t1;
+    source include/rpl_diff_tables.inc;
+  }
+
+  let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
+  let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1);
+  --echo
+  --echo # Create a Innodb table and there is no any other table modified
+  --error 0, 1050, 1062
+  eval CREATE TABLE $_if_exist_opt t4(UNIQUE(a)) ENGINE=Innodb
+    SELECT 1 AS a UNION ALL SELECT 1;
+  --echo # The statement should not be binlogged.
+  source include/show_binlog_events.inc;
+
+  let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
+  let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1);
+  --echo
+  --echo # Create a MyISAM table and the transaction table(t3) is updated.
+  --error 0, 1050, 1062
+  eval CREATE TABLE $_if_exist_opt t1(UNIQUE(a)) ENGINE=MyISAM
+    SELECT 1 AS a UNION ALL SELECT f_insert_t3 ();
+  if (!$_set_exist)
+  {
+    --echo # The statement should not be binlogged.
+    source include/show_binlog_events.inc;
+  }
+  if ($_set_exist)
+  {
+    let $diff_table=test.t1;
+    source include/rpl_diff_tables.inc;
+  }
+
+  let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
+  let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1);
+  --echo
+  --echo # Create a Innodb table and the transaction table(t3) is updated.
+  --error 0, 1050, 1062
+  eval CREATE TABLE $_if_exist_opt t4(UNIQUE(a)) ENGINE=Innodb
+    SELECT 1 AS a UNION ALL SELECT f_insert_t3();
+  --echo # The statement should not be binlogged.
+  source include/show_binlog_events.inc;
+
+  --echo
+  --echo # Create a MyISAM table and both of the transaction table(t3) and
+  --echo # non-transaction table(t2) are updated.
+  --error 0, 1050, 1062
+  eval CREATE TABLE $_if_exist_opt t1(UNIQUE(a)) ENGINE=MyISAM
+    SELECT f_insert_t2() AS a UNION ALL SELECT f_insert_t3 ();
+  let $diff_table=test.t2;
+  source include/rpl_diff_tables.inc;
+  let $diff_table=test.t3;
+  source include/rpl_diff_tables.inc;
+
+  --echo
+  --echo # Create a Innodb table and both of the transaction table(t3) and
+  --echo # non-transaction table(t2) are updated.
+  --error 0, 1050, 1062
+  eval CREATE TABLE $_if_exist_opt t4(UNIQUE(a)) ENGINE=Innodb
+    SELECT f_insert_t2() AS a UNION ALL SELECT f_insert_t3();
+  let $diff_table=test.t2;
+  source include/rpl_diff_tables.inc;
+  let $diff_table=test.t3;
+  source include/rpl_diff_tables.inc;
+
+  if ($_set_exist)
+  {
+    dec $_set_exist;
+  }
+}
+
+DROP TABLE t2, t3;
+DROP FUNCTION f_insert_t2;
+DROP FUNCTION f_insert_t3;
 source include/master-slave-end.inc;

=== modified file 'mysql-test/suite/rpl/t/rpl_row_create_table.test'
--- a/mysql-test/suite/rpl/t/rpl_row_create_table.test	2010-08-11 14:00:41 +0000
+++ b/mysql-test/suite/rpl/t/rpl_row_create_table.test	2010-08-13 09:06:24 +0000
@@ -320,7 +320,6 @@ sync_slave_with_master;
 --echo # binlogged in a transaction, except 'CREATE TABLE ... SELECT' on RBR. 
 --echo # It also fix bug#55877
 --echo
-SET GLOBAL autocommit=0;
 source include/master-slave-reset.inc;
 connection master;
 --disable_warnings

=== modified file 'sql/log.cc'
--- a/sql/log.cc	2010-07-02 18:30:47 +0000
+++ b/sql/log.cc	2010-08-13 09:06:24 +0000
@@ -4095,6 +4095,17 @@ void THD::binlog_set_stmt_begin() {
   trx_data->before_stmt_pos= pos;
 }
 
+void THD::binlog_truncate_stmt()
+{
+  binlog_trx_data *trx_data=
+    (binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
+
+  if (trx_data)
+  {
+    DBUG_ASSERT(trx_data->before_stmt_pos != MY_OFF_T_UNDEF);
+    trx_data->truncate(trx_data->before_stmt_pos);
+  }
+}
 
 /*
   Write a table map to the binary log.

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2010-07-30 06:23:25 +0000
+++ b/sql/sql_class.h	2010-08-13 09:06:24 +0000
@@ -1438,6 +1438,7 @@ public:
   */
   void binlog_start_trans_and_stmt();
   void binlog_set_stmt_begin();
+  void binlog_truncate_stmt();
   int binlog_write_table_map(TABLE *table, bool is_transactional);
   int binlog_write_row(TABLE* table, bool is_transactional,
                        MY_BITMAP const* cols, size_t colcnt,
@@ -2658,6 +2659,11 @@ class select_create: public select_inser
   /* m_lock or thd->extra_lock */
   MYSQL_LOCK **m_plock;
 
+  /*
+    It is set on the rare occasion that SELECT clause calls a function
+    in which a non-transaction table is modified.
+  */
+  bool modified_other_non_trans_table;
   virtual int write_to_binlog(bool is_trans, int errcode);
 public:
   select_create (TABLE_LIST *table_arg,
@@ -2670,7 +2676,8 @@ public:
     create_info(create_info_par),
     select_tables(select_tables_arg),
     alter_info(alter_info_arg),
-    m_plock(NULL)
+    m_plock(NULL),
+    modified_other_non_trans_table(FALSE)
     {}
   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
 

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2010-07-30 06:23:25 +0000
+++ b/sql/sql_insert.cc	2010-08-13 09:06:24 +0000
@@ -3360,9 +3360,21 @@ void select_insert::abort() {
 	  query_cache_invalidate3(thd, table, 1);
     }
     DBUG_ASSERT(transactional_table || !changed ||
-		thd->transaction.stmt.modified_non_trans_table);
+		thd->transaction.stmt.modified_non_trans_table ||
+                can_rollback_data());
     table->file->ha_release_auto_increment();
   }
+  /*
+    It is a rare case. It happens only when SELECT clause calls a function
+    in which a non-transaction table is modified.
+  */
+  else if (thd->transaction.stmt.modified_non_trans_table &&
+           mysql_bin_log.is_open())
+  {
+    int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
+    /* error of writing binary log is ignored */
+    write_to_binlog(FALSE, errcode);
+  }
 
   DBUG_VOID_RETURN;
 }
@@ -3396,8 +3408,9 @@ int select_create::write_to_binlog(bool 
     String query;
     int result;
 
+    thd->binlog_start_trans_and_stmt();
     /* Binlog the CREATE TABLE IF NOT EXISTS statement */
-    result= binlog_show_create_table(&table, 1, errcode);
+    result= binlog_show_create_table(&table, 1, 0);
     if (result)
       return result;
 
@@ -3707,16 +3720,31 @@ select_create::prepare(List<Item> &value
 
   unit= u;
 
-  /*
-    Start a statement transaction before the create if we are using
-    row-based replication for the statement.  If we are creating a
-    temporary table, we need to start a statement transaction.
-  */
-  if ((thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) == 0 &&
-      thd->current_stmt_binlog_row_based &&
-      mysql_bin_log.is_open())
+  /* All operations in a store function has finished before call prepar. */
+  modified_other_non_trans_table=
+    thd->transaction.stmt.modified_non_trans_table;
+
+  if (mysql_bin_log.is_open())
   {
-    thd->binlog_start_trans_and_stmt();
+    /*
+      Start a statement transaction before the create if we are using
+      row-based replication for the statement.  If we are creating a
+      temporary table, we need to start a statement transaction.
+     */
+    if ((thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) == 0 &&
+        thd->current_stmt_binlog_row_based)
+    {
+      thd->binlog_start_trans_and_stmt();
+      /*
+        The row events generated by SELECT clause are before 'CREATE TABLE'
+        statement. The end pos of these row events is record by
+        thd->binlog_set_stmt_begin() late. It is used to truncate
+        'CREATE TABLE' and following row events when an error happens.
+      */
+      if (thd->binlog_flush_pending_rows_event(TRUE))
+        DBUG_RETURN(-1);
+      thd->binlog_set_stmt_begin();
+    }
   }
 
   DBUG_EXECUTE_IF("sleep_create_select_before_check_if_exists", my_sleep(6000000););
@@ -3925,28 +3953,25 @@ void select_create::abort()
 {
   DBUG_ENTER("select_create::abort");
 
-  /*
-    In select_insert::abort() we roll back the statement, including
-    truncating the transaction cache of the binary log. To do this, we
-    pretend that the statement is transactional, even though it might
-    be the case that it was not.
-
-    We roll back the statement prior to deleting the table and prior
-    to releasing the lock on the table, since there might be potential
-    for failure if the rollback is executed after the drop or after
-    unlocking the table.
-
-    We also roll back the statement regardless of whether the creation
-    of the table succeeded or not, since we need to reset the binary
-    log state.
-  */
-  tmp_disable_binlog(thd);
-  select_insert::abort();
-  thd->transaction.stmt.modified_non_trans_table= FALSE;
-  reenable_binlog(thd);
   /* possible error of writing binary log is ignored deliberately */
   (void)thd->binlog_flush_pending_rows_event(TRUE);
 
+  if (modified_other_non_trans_table)
+  {
+    /*
+      The creating table will be dropt, so 'CREATE TABLE...' and row events on
+      the table should be truncated.
+    */
+    if (!create_info->table_existed && thd->current_stmt_binlog_row_based &&
+        !(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
+        mysql_bin_log.is_open())
+      thd->binlog_truncate_stmt();
+  }
+  else if (!create_info->table_existed)
+    thd->transaction.stmt.modified_non_trans_table= FALSE;
+
+  select_insert::abort();
+
   if (m_plock)
   {
     mysql_unlock_tables(thd, *m_plock);


Attachment: [text/bzr-bundle] bzr/li-bing.song@sun.com-20100813090624-5x3y0a0ykxx5ix0a.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (Li-Bing.Song:3479) Bug#39804Bug#51501Li-Bing.Song13 Aug
  • Re: bzr commit into mysql-5.1-bugteam branch (Li-Bing.Song:3479)Bug#39804 Bug#51501Konstantin Osipov16 Aug
    • Re: bzr commit into mysql-5.1-bugteam branch (Li-Bing.Song:3479)Bug#39804 Bug#51501Libing Song17 Aug