List:Commits« Previous MessageNext Message »
From:Andrei Elkin Date:January 27 2012 1:46am
Subject:bzr push into mysql-trunk-wl3584 branch (andrei.elkin:3578 to 3579) WL#3584
View as plain text  
 3579 Andrei Elkin	2012-01-27
      wl#3584 GTID
      
      The patch address Empty Group merged patch review (Sven) suggestions.

    modified:
      mysql-test/suite/rpl/r/rpl_gtid_mode.result
      mysql-test/suite/rpl/t/rpl_alter.test
      mysql-test/suite/rpl/t/rpl_gtid_mode.test
      sql/binlog.cc
      sql/log_event.cc
      sql/rpl_rli.cc
      sql/share/errmsg-utf8.txt
      sql/sys_vars.cc
 3578 Andrei Elkin	2012-01-27 [merge]
      merge from wl3584 repo.

    modified:
      mysql-test/suite/rpl/r/rpl_check_gtid.result
      mysql-test/suite/rpl/r/rpl_gtid_mode.result
      mysql-test/suite/rpl/t/rpl_check_gtid.test
      mysql-test/suite/rpl/t/rpl_gtid_mode.test
      sql/rpl_master.cc
      sql/rpl_slave.cc
=== added file 'mysql-test/suite/rpl/r/rpl_gtid_empty_group.result'
--- a/mysql-test/suite/rpl/r/rpl_gtid_empty_group.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/r/rpl_gtid_empty_group.result	2012-01-24 19:45:24 +0000
@@ -0,0 +1,41 @@
+include/master-slave.inc
+Warnings:
+Note	1756	Sending passwords in plain text without SSL/TLS is extremely insecure.
+Note	1757	Storing MySQL user name or password information in the master.info repository is not secure and is therefore not recommended. Please see the MySQL Manual for more about this issue and possible alternatives.
+[connection master]
+SET @save.binlog_format= @@global.binlog_format;
+SET @@global.binlog_format= row;
+include/restart_slave.inc
+SET @save.binlog_format= @@session.binlog_format;
+SET @@session.binlog_format= statement;
+CREATE TABLE t1(id INTEGER) ENGINE= Innodb /* group one */;
+UPDATE t1 SET id= 1 WHERE id = 0          /* group two */;
+CREATE TABLE t_ignore(id INTEGER) ENGINE= Innodb /* group three */;
+must be *three* groups logged, where the two last empty:
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+slave-bin.000001	#	Previous_gtids	#	#	
+slave-bin.000001	#	Gtid	#	#	SET @@SESSION.GTID_NEXT= 'GTID';
+slave-bin.000001	#	Query	#	#	use `test`; CREATE TABLE t1(id INTEGER) ENGINE= Innodb /* group one */
+slave-bin.000001	#	Gtid	#	#	SET @@SESSION.GTID_NEXT= 'GTID';
+slave-bin.000001	#	Query	#	#	BEGIN
+slave-bin.000001	#	Query	#	#	COMMIT
+slave-bin.000001	#	Gtid	#	#	SET @@SESSION.GTID_NEXT= 'GTID';
+slave-bin.000001	#	Query	#	#	BEGIN
+slave-bin.000001	#	Query	#	#	COMMIT
+FLUSH LOGS;
+DROP TABLE t2;
+ERROR 42S02: Unknown table 'test.t2'
+INSERT INTO t1 VALUES (1, 1);
+ERROR 21S01: Column count doesn't match value count at row 1
+BEGIN;
+INSERT INTO t1 VALUES (2);
+ROLLBACK;
+*** must be empty log ***
+show binlog events in 'master-bin.000002' from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000002	#	Previous_gtids	#	#	GTID:#-#
+DROP TABLE t1;
+DROP TABLE t_ignore;
+SET @@global.binlog_format= @save.binlog_format;
+include/rpl_end.inc

=== modified file 'mysql-test/suite/rpl/r/rpl_gtid_mode.result'
--- a/mysql-test/suite/rpl/r/rpl_gtid_mode.result	2012-01-26 23:01:01 +0000
+++ b/mysql-test/suite/rpl/r/rpl_gtid_mode.result	2012-01-27 01:26:40 +0000
@@ -65,6 +65,7 @@ SET GTID_NEXT = 'AUTOMATIC';
 SET GTID_NEXT = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1';
 SET GTID_NEXT = 'ANONYMOUS';
 ERROR HY000: GTID_NEXT cannot be set to ANONYMOUS when GTID_MODE = ON.
+ROLLBACK;
 ---- GTIDs are in binlog ----
 SET GTID_NEXT = 'AUTOMATIC';
 INSERT INTO t1 VALUES (2);

=== added file 'mysql-test/suite/rpl/t/rpl_gtid_empty_group-master.opt'
--- a/mysql-test/suite/rpl/t/rpl_gtid_empty_group-master.opt	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_gtid_empty_group-master.opt	2012-01-26 10:53:34 +0000
@@ -0,0 +1 @@
+--gtid-mode=on --disable-gtid-unsafe-statements --log-slave-updates --binlog-ignore-db=db_ignore_master

=== added file 'mysql-test/suite/rpl/t/rpl_gtid_empty_group-slave.opt'
--- a/mysql-test/suite/rpl/t/rpl_gtid_empty_group-slave.opt	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_gtid_empty_group-slave.opt	2012-01-26 10:53:34 +0000
@@ -0,0 +1 @@
+--gtid-mode=on --disable-gtid-unsafe-statements --log-slave-updates  --replicate-ignore-table=test.t_ignore

=== added file 'mysql-test/suite/rpl/t/rpl_gtid_empty_group.test'
--- a/mysql-test/suite/rpl/t/rpl_gtid_empty_group.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_gtid_empty_group.test	2012-01-24 19:45:24 +0000
@@ -0,0 +1,72 @@
+################################################################################
+# This test case checks that empty groups appearing on slave preserve GTID
+# properties. 
+# Such group can appear on slave as a result of
+#
+# a. ineffective binary logging (no events in row format)
+# b. filtered out query
+# c. processing of a master's empty group 
+#
+################################################################################
+--source include/master-slave.inc
+--source include/not_embedded.inc
+--source include/have_binlog_format_mixed.inc
+--source include/have_gtid.inc
+
+# prepare for a.
+--connection slave
+SET @save.binlog_format= @@global.binlog_format;
+SET @@global.binlog_format= row;
+source include/restart_slave_sql.inc;
+
+--connection master
+SET @save.binlog_format= @@session.binlog_format;
+SET @@session.binlog_format= statement;
+CREATE TABLE t1(id INTEGER) ENGINE= Innodb /* group one */;
+UPDATE t1 SET id= 1 WHERE id = 0          /* group two */;
+
+# load for b.
+CREATE TABLE t_ignore(id INTEGER) ENGINE= Innodb /* group three */;
+
+--sync_slave_with_master
+
+--echo must be *three* groups logged, where the two last empty:
+source include/show_binlog_events.inc;
+
+# todo: add c.
+# --connection slave
+# set @@session.gtid_next='`last_master s_id: last_master seqno + 1`;
+# begin;
+# commit;
+
+
+#
+# Testing of ROLLBACK as explicit so due to an error does 
+# not log anything.
+#
+
+--connection master
+FLUSH LOGS;
+--error ER_BAD_TABLE_ERROR
+DROP TABLE t2;
+--error ER_WRONG_VALUE_COUNT_ON_ROW
+INSERT INTO t1 VALUES (1, 1); 
+BEGIN;
+INSERT INTO t1 VALUES (2);
+ROLLBACK;
+
+--echo *** must be empty log ***
+
+let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
+source include/show_binlog_events.inc;
+
+# cleanup
+
+--connection master
+DROP TABLE t1;
+DROP TABLE t_ignore;
+
+--sync_slave_with_master
+SET @@global.binlog_format= @save.binlog_format;
+
+--source include/rpl_end.inc

=== modified file 'mysql-test/suite/rpl/t/rpl_gtid_mode.test'
--- a/mysql-test/suite/rpl/t/rpl_gtid_mode.test	2012-01-26 23:01:01 +0000
+++ b/mysql-test/suite/rpl/t/rpl_gtid_mode.test	2012-01-27 01:26:40 +0000
@@ -212,7 +212,7 @@ eval SET GTID_NEXT = '$uuida:1';
 # should generate error
 --error 1779 # ER_CANT_SET_GTID_NEXT_TO_ANONYMOUS_WHEN_GTID_MODE_IS_ON
 SET GTID_NEXT = 'ANONYMOUS';
-
+ROLLBACK;
 --echo ---- GTIDs are in binlog ----
 
 SET GTID_NEXT = 'AUTOMATIC';

=== modified file 'sql/binlog.cc'
--- a/sql/binlog.cc	2012-01-24 16:31:48 +0000
+++ b/sql/binlog.cc	2012-01-27 01:26:40 +0000
@@ -681,6 +681,50 @@ int gtid_before_write_cache(THD* thd, bi
 }
 
 /**
+   The function logs an empty group with GTID and performs cleanup.
+   Its logic wrt GTID is equivalent to one of binlog_commit(). 
+   It's called at the end of statement execution in case binlog_commit()
+   was skipped.
+   Such cases are due ineffective binlogging incl an empty group
+   re-execution.
+
+   @param thd   The thread handle
+
+   @return
+    nonzero if an error pops up.
+*/
+int gtid_empty_group_log_and_cleanup(THD *thd)
+{
+  int ret= 0;
+  binlog_cache_mngr *const cache_mngr= thd_get_cache_mngr(thd);
+  binlog_cache_data* cache_data= &cache_mngr->trx_cache;
+
+  DBUG_ENTER("gtid_empty_group_log_and_cleanup");
+
+  Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"),
+                          cache_data->is_trx_cache(), FALSE, TRUE, 0, TRUE);
+
+  DBUG_ASSERT(!end_evt.is_using_immediate_logging());
+
+  if (binlog_start_trans_and_stmt(thd, &end_evt) ||
+      write_event_to_cache(thd, &end_evt, cache_data) ||
+      gtid_before_write_cache(thd, cache_data)   ||
+      mysql_bin_log.write_cache(thd, cache_data, 0))
+    ret= 1;
+  cache_data->reset();
+
+  THD_TRANS *trans= &thd->transaction.stmt;
+  Ha_trx_info *ha_info= trans->ha_list;
+    
+  DBUG_ASSERT(thd->transaction.all.ha_list == 0);
+  ha_info->reset(); /* keep it conveniently zero-filled */
+  trans->ha_list= 0;
+  trans->no_2pc=0;
+
+  DBUG_RETURN(ret);
+}
+
+/**
   This function flushes a cache upon commit/rollback.
 
   @param thd                The thread whose transaction should be flushed

=== modified file 'sql/binlog.h'
--- a/sql/binlog.h	2012-01-23 13:44:47 +0000
+++ b/sql/binlog.h	2012-01-26 10:53:34 +0000
@@ -386,6 +386,7 @@ bool mysql_show_binlog_events(THD* thd);
 void check_binlog_cache_size(THD *thd);
 void check_binlog_stmt_cache_size(THD *thd);
 void register_binlog_handler(THD *thd, bool trx);
+int gtid_empty_group_log_and_cleanup(THD *thd);
 
 extern const char *log_bin_index;
 extern const char *log_bin_basename;

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2012-01-25 10:14:39 +0000
+++ b/sql/log_event.cc	2012-01-27 01:26:40 +0000
@@ -6832,6 +6832,33 @@ void Xid_log_event::print(FILE* file, PR
 
 #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
 /**
+   The methods combines few commit actions to make it useable
+   as in the single- so multi- threaded case.
+
+   @param  thd    a pointer to THD handle
+   @return false  as success and
+           true   as an error 
+*/
+
+bool Xid_log_event::do_commit(THD *thd)
+{
+  bool error= trans_commit(thd); /* Automatically rolls back on error. */
+  DBUG_EXECUTE_IF("crash_after_apply", 
+                  sql_print_information("Crashing crash_after_apply.");
+                  DBUG_SUICIDE(););
+  thd->mdl_context.release_transactional_locks();
+
+  if (thd->variables.gtid_next.type == GTID_GROUP &&
+      thd->owned_gtid.sidno != 0)
+  {
+    // GTID logging and cleanup runs regardless of the current res
+    error |= gtid_empty_group_log_and_cleanup(thd);
+  }
+
+  return error;
+}
+
+/**
    Worker commits Xid transaction and in case of its transactional
    info table marks the current group as done in the Coordnator's 
    Group Assigned Queue.
@@ -6877,12 +6904,7 @@ int Xid_log_event::do_apply_event_worker
                   sql_print_information("Crashing crash_after_update_pos_before_apply.");
                   DBUG_SUICIDE(););
 
-  error= trans_commit(thd); /* Automatically rolls back on error. */
-  DBUG_EXECUTE_IF("crash_after_apply", 
-                  sql_print_information("Crashing crash_after_apply.");
-                  DBUG_SUICIDE(););
-  thd->mdl_context.release_transactional_locks();
-
+  error= do_commit(thd);
 err:
   return error;
 }
@@ -6937,11 +6959,7 @@ int Xid_log_event::do_apply_event(Relay_
                   sql_print_information("Crashing crash_after_update_pos_before_apply.");
                   DBUG_SUICIDE(););
 
-  error= trans_commit(thd); /* Automatically rolls back on error. */
-  DBUG_EXECUTE_IF("crash_after_apply", 
-                  sql_print_information("Crashing crash_after_apply.");
-                  DBUG_SUICIDE(););
-  thd->mdl_context.release_transactional_locks();
+  error= do_commit(thd);
 
 err:
   mysql_cond_broadcast(&rli_ptr->data_cond);
@@ -11907,6 +11925,11 @@ int Gtid_log_event::do_apply_event(Relay
   DBUG_PRINT("info", ("setting gtid_next=%d:%lld",
                       sidno, spec.gtid.gno));
 
+  if (gtid_acquire_ownwership(thd))
+  {
+    DBUG_RETURN(1);
+  }
+
   DBUG_RETURN(0);
 }
 

=== modified file 'sql/log_event.h'
--- a/sql/log_event.h	2012-01-24 16:33:21 +0000
+++ b/sql/log_event.h	2012-01-26 10:53:34 +0000
@@ -2840,6 +2840,7 @@ private:
   virtual int do_apply_event(Relay_log_info const *rli);
   virtual int do_apply_event_worker(Slave_worker *rli);
   enum_skip_reason do_shall_skip(Relay_log_info *rli);
+  bool do_commit(THD *thd);
 #endif
 };
 

=== modified file 'sql/rpl_gtid.h'
--- a/sql/rpl_gtid.h	2012-01-23 13:44:47 +0000
+++ b/sql/rpl_gtid.h	2012-01-26 10:53:34 +0000
@@ -2443,6 +2443,8 @@ int gtid_check_session_variables_before_
 */
 int gtid_rollback(THD *thd);
 
+int gtid_acquire_ownwership(THD *thd);
+
 #endif // ifndef MYSQL_CLIENT
 
 #endif /* RPL_GTID_H_INCLUDED */

=== modified file 'sql/rpl_gtid_execution.cc'
--- a/sql/rpl_gtid_execution.cc	2012-01-20 10:59:58 +0000
+++ b/sql/rpl_gtid_execution.cc	2012-01-26 10:53:34 +0000
@@ -64,6 +64,7 @@ gtid_acquire_ownership(THD *thd, const G
     if (owner == 0)
     {
       thd->owned_gtid_set.ensure_sidno(gtid.sidno);
+      // error is reported on cancel
       if (gtid_state.acquire_ownership(gtid, thd) != RETURN_STATUS_OK)
         ret= GTID_STATEMENT_CANCEL;
       thd->owned_gtid= gtid;
@@ -89,6 +90,7 @@ gtid_acquire_ownership(THD *thd, const G
       if ((thd->system_thread &
            (SYSTEM_THREAD_SLAVE_SQL | SYSTEM_THREAD_SLAVE_WORKER)) != 0)
       {
+        // TODO: error is *not* reported on cancel
         DBUG_ASSERT(active_mi != NULL && active_mi->rli != NULL);
         if (active_mi->rli->abort_slave)
           DBUG_RETURN(GTID_STATEMENT_CANCEL);
@@ -285,12 +287,6 @@ gtid_before_statement_begin_commit_seque
         if (gtid_acquire_ownerships(thd, gtid_next_list) !=
             GTID_STATEMENT_EXECUTE)
           DBUG_RETURN(GTID_STATEMENT_CANCEL);
-        /// @todo: is this ok? might be controversial to register a handler before the statement executes /sven
-        if (!thd->owned_gtid_set.is_empty())
-          register_binlog_handler(thd, thd->lex->sql_command == SQLCOM_BEGIN ||
-                                  thd->lex->sql_command == SQLCOM_COMMIT ||
-                                  (thd->variables.option_bits &
-                                   OPTION_NOT_AUTOCOMMIT) != 0);
       }
     }
     else if (gtid_next->type == GTID_GROUP)
@@ -298,12 +294,6 @@ gtid_before_statement_begin_commit_seque
       // acquire group ownership for single group.
       enum_gtid_statement_status ret=
         gtid_acquire_ownership(thd, gtid_next->gtid);
-      /// @todo: is this ok? might be controversial to register a handler before the statement executes /sven
-      if (thd->owned_gtid.sidno != 0)
-        register_binlog_handler(thd, thd->lex->sql_command == SQLCOM_BEGIN ||
-                                thd->lex->sql_command == SQLCOM_COMMIT ||
-                                (thd->variables.option_bits &
-                                 OPTION_NOT_AUTOCOMMIT));
       DBUG_RETURN(ret);
     }
   }
@@ -421,3 +411,34 @@ int gtid_rollback(THD *thd)
 
   DBUG_RETURN(0);
 }
+
+int gtid_acquire_ownwership(THD *thd)
+{
+  DBUG_ENTER("gtid_acquire_ownwership");
+  /*
+    Execute gtid_before_statement, so that we acquire ownership of
+    groups as specified by gtid_next and gtid_next_list.
+  */
+  if (opt_bin_log)
+  {
+    /*
+      Initialize the cache manager if this was not done yet.
+      binlog_setup_trx_data is idempotent and if it's not called here
+      it's called elsewhere.  It is needed here just so that
+      thd->get_group_cache won't crash.
+    */
+    thd->binlog_setup_trx_data();
+    switch (gtid_before_statement(thd,
+                                  thd->get_group_cache(false),
+                                  thd->get_group_cache(true)))
+    {
+    case GTID_STATEMENT_CANCEL:
+      // error has (TODO: not always!) already been printed; don't print anything more here
+      DBUG_RETURN(-1);
+    case GTID_STATEMENT_SKIP:
+    case GTID_STATEMENT_EXECUTE:
+      break;
+    }
+  }
+  DBUG_RETURN(0);
+}

=== modified file 'sql/share/errmsg-utf8.txt'
--- a/sql/share/errmsg-utf8.txt	2012-01-23 13:44:47 +0000
+++ b/sql/share/errmsg-utf8.txt	2012-01-27 01:26:40 +0000
@@ -6699,3 +6699,6 @@ ER_GTID_MODE_CAN_ONLY_CHANGE_ONE_STEP_AT
 
 ER_MASTER_HAS_PURGED_REQUIRED_GTIDS
   eng "The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires."
+
+ER_CANT_SET_GTID_NEXT_WHEN_ITS_NOT_AUTOMATIC
+  eng "GTID_NEXT cannot be changed when it has been set to UUID:NUMBER. To reset GTID_NEXT, execute a ROLLBACK statement."

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2012-01-19 14:04:31 +0000
+++ b/sql/sql_base.cc	2012-01-26 10:53:34 +0000
@@ -1512,17 +1512,8 @@ void close_thread_tables(THD *thd)
     DEBUG_SYNC(thd, "before_close_thread_tables");
 #endif
 
-  /*
-    If gtid_next_list!=NULL or gtid_next=='sid:gno', then a
-    binlog_handler will be registered very early in the execution of
-    the statement.  Hence, allow stmt.is_empty() in these cases.
-    @todo Check if this causes any trouble. /Sven
-    @note Covered by Case 1 in test binlog.binlog_trx_empty_assertions
-  */
   DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt ||
-              (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) ||
-              thd->get_gtid_next_list() != NULL ||
-              thd->variables.gtid_next.type == GTID_GROUP);
+              (thd->state_flags & Open_tables_state::BACKUPS_AVAIL));
 
   /* Detach MERGE children after every statement. Even under LOCK TABLES. */
   for (table= thd->open_tables; table; table= table->next)
@@ -3406,16 +3397,7 @@ Locked_tables_list::unlock_locked_tables
     }
     thd->leave_locked_tables_mode();
 
-    /*
-      If gtid_next_list!=NULL or gtid_next=='sid:gno', then a
-      binlog_handler will be registered very early in the execution of
-      the statement.  Hence, allow stmt.is_empty() in these cases.
-      @todo Check if this causes any trouble. /Sven
-      @note Covered by Case 7 in test binlog.binlog_trx_empty_assertions
-    */
-    DBUG_ASSERT(thd->transaction.stmt.is_empty() ||
-                thd->get_gtid_next_list() != NULL ||
-                thd->variables.gtid_next.type == GTID_GROUP);
+    DBUG_ASSERT(thd->transaction.stmt.is_empty());
     close_thread_tables(thd);
     /*
       We rely on the caller to implicitly commit the
@@ -5766,18 +5748,9 @@ end:
     either not started or we're filling in an INFORMATION_SCHEMA
     table on the fly, and thus mustn't manipulate with the
     transaction of the enclosing statement.
-
-    If gtid_next_list!=NULL or gtid_next=='sid:gno', then a
-    binlog_handler will be registered very early in the execution of
-    the statement.  Hence, allow stmt.is_empty() in these cases.
-    @todo Check if this causes any trouble. /Sven
-    @todo Add test case in binlog.binlog_trx_empty_assertions /Sven
-    [running on fimafeng10-1]
   */
   DBUG_ASSERT(thd->transaction.stmt.is_empty() ||
-              (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) ||
-              thd->get_gtid_next_list() != NULL ||
-              thd->variables.gtid_next.type == GTID_GROUP);
+              (thd->state_flags & Open_tables_state::BACKUPS_AVAIL));
   close_thread_tables(thd);
   /* Don't keep locks for a failed statement. */
   thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
@@ -6048,18 +6021,9 @@ void close_tables_for_reopen(THD *thd, T
     either not started or we're filling in an INFORMATION_SCHEMA
     table on the fly, and thus mustn't manipulate with the
     transaction of the enclosing statement.
-
-    If gtid_next_list!=NULL or gtid_next=='sid:gno', then a
-    binlog_handler will be registered very early in the execution of
-    the statement.  Hence, allow stmt.is_empty() in these cases.
-    @todo Check if this causes any trouble /Sven.
-    @todo Add test case in binlog.binlog_trx_empty_assertions
-    [running on fimafeng11-1]
   */
   DBUG_ASSERT(thd->transaction.stmt.is_empty() ||
-              (thd->state_flags & Open_tables_state::BACKUPS_AVAIL) ||
-              thd->get_gtid_next_list() != NULL ||
-              thd->variables.gtid_next.type == GTID_GROUP);
+              (thd->state_flags & Open_tables_state::BACKUPS_AVAIL));
   close_thread_tables(thd);
   thd->mdl_context.rollback_to_savepoint(start_of_statement_svp);
 }
@@ -9492,18 +9456,8 @@ close_system_tables(THD *thd, Open_table
 void
 close_mysql_tables(THD *thd)
 {
-  /*
-    No need to commit/rollback statement transaction, it's not started.
-
-    If gtid_next_list!=NULL or gtid_next=='sid:gno', then a
-    binlog_handler will be registered very early in the execution of
-    the statement.  Hence, allow stmt.is_empty() in these cases.
-    @todo Check if this causes any trouble /Sven.
-    @note Covered by Case 8 in test binlog.binlog_trx_empty_assertions
- */
-  DBUG_ASSERT(thd->transaction.stmt.is_empty() ||
-              thd->get_gtid_next_list() != NULL ||
-              thd->variables.gtid_next.type == GTID_GROUP);
+  /* No need to commit/rollback statement transaction, it's not started. */
+  DBUG_ASSERT(thd->transaction.stmt.is_empty());
   close_thread_tables(thd);
   thd->mdl_context.release_transactional_locks();
 }

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2012-01-19 14:04:31 +0000
+++ b/sql/sql_class.cc	2012-01-26 10:53:34 +0000
@@ -776,7 +776,7 @@ THD::THD(bool enable_plugins)
    :Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION,
               /* statement id */ 0),
    rli_fake(0),
-   in_sub_stmt(0), n_execute_command_calls(0),
+    in_sub_stmt(0),
    binlog_unsafe_warning_flags(0),
    binlog_table_maps(0),
    binlog_accessed_db_names(NULL),

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2012-01-19 15:51:54 +0000
+++ b/sql/sql_class.h	2012-01-26 10:53:34 +0000
@@ -2052,13 +2052,6 @@ public:
   /* <> 0 if we are inside of trigger or stored function. */
   uint in_sub_stmt;
 
-  /*
-    The number of calls to mysql_execute_command on the stack. This
-    is incremented every time we enter mysql_execute_command and
-    decremented when we leave.
-  */
-  uint n_execute_command_calls;
-
   /* container for handler's private per-connection data */
   Ha_data ha_data[MAX_HA];
 
@@ -4470,13 +4463,6 @@ public:
 /** Identifies statements which may generate an optimizer trace */
 #define CF_OPTIMIZER_TRACE        (1U << 14)
 
-/**
-  Identifies statements that normally do not write anything to the
-  binary log, but could write something in case they invoke a stored
-  function (e.g. SELECT, DO, SET).
-*/
-#define CF_ONLY_BINLOGGABLE_WITH_SF    (1U << 15)
-
 /* Bits in server_command_flags */
 
 /**

=== modified file 'sql/sql_handler.cc'
--- a/sql/sql_handler.cc	2012-01-19 14:04:31 +0000
+++ b/sql/sql_handler.cc	2012-01-26 10:53:34 +0000
@@ -339,17 +339,8 @@ static bool mysql_ha_open_table(THD *thd
       No need to rollback statement transaction, it's not started.
       If called for re-open, no need to rollback either,
       it will be done at statement end.
-
-      If gtid_next_list!=NULL or gtid_next=='sid:gno', then a
-      binlog_handler will be registered very early in the execution of
-      the statement.  Hence, allow stmt.is_empty() in these cases.
-      @todo Check if this causes any trouble /Sven.
-      @todo Add test case in binlog.binlog_trx_empty_assertions /Sven
-      [running on tyr74-1]
     */
-    DBUG_ASSERT(thd->transaction.stmt.is_empty() ||
-                thd->get_gtid_next_list() != NULL ||
-                thd->variables.gtid_next.type == GTID_GROUP);
+    DBUG_ASSERT(thd->transaction.stmt.is_empty());
     close_thread_tables(thd);
     thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
     thd->set_open_tables(backup_open_tables);

=== modified file 'sql/sql_lex.cc'
--- a/sql/sql_lex.cc	2012-01-06 20:00:48 +0000
+++ b/sql/sql_lex.cc	2012-01-24 19:45:24 +0000
@@ -3714,17 +3714,6 @@ bool LEX::is_partition_management() cons
 }
 
 
-bool LEX::is_binloggable() const
-{
-  // todo: add flag 'cf_not_binloggable' and set for
-  // sqlcom_empty_query (and possibly for more statements?)
-  return (!(sql_command_flags[sql_command] & CF_ONLY_BINLOGGABLE_WITH_SF) ||
-          uses_stored_routines()) &&
-    sql_command != SQLCOM_EMPTY_QUERY &&
-    sql_command != SQLCOM_CHANGE_DB;
-}
-
-
 /**
   Set all fields to their "unspecified" value.
 */

=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h	2012-01-06 20:00:48 +0000
+++ b/sql/sql_lex.h	2012-01-24 19:45:24 +0000
@@ -2492,15 +2492,6 @@ struct LEX: public Query_tables_list
     }
     return FALSE;
   }
-
-  /**
-    Return true if it is possible that this statement is written to
-    the binary log.  This function is a rough approximation: SET,
-    SELECT, and DO are considered binloggable if they invoke a stored
-    function.  Other statements are binloggable or not based on their
-    SQLCOM_ type.
-  */
-  bool is_binloggable() const;
 };
 
 

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2012-01-19 14:04:31 +0000
+++ b/sql/sql_parse.cc	2012-01-26 10:53:34 +0000
@@ -372,8 +372,7 @@ void init_update_queries(void)
   sql_command_flags[SQLCOM_SELECT]=         CF_REEXECUTION_FRAGILE |
                                             CF_CAN_GENERATE_ROW_EVENTS |
                                             CF_OPTIMIZER_TRACE |
-                                            CF_CAN_BE_EXPLAINED |
-                                            CF_ONLY_BINLOGGABLE_WITH_SF;
+                                            CF_CAN_BE_EXPLAINED;
   // (1) so that subquery is traced when doing "SET @var = (subquery)"
   /*
     @todo SQLCOM_SET_OPTION should have CF_CAN_GENERATE_ROW_EVENTS
@@ -382,13 +381,11 @@ void init_update_queries(void)
   */
   sql_command_flags[SQLCOM_SET_OPTION]=     CF_REEXECUTION_FRAGILE |
                                             CF_AUTO_COMMIT_TRANS |
-                                            CF_OPTIMIZER_TRACE | // (1)
-                                            CF_ONLY_BINLOGGABLE_WITH_SF;
+                                            CF_OPTIMIZER_TRACE; // (1)
   // (1) so that subquery is traced when doing "DO @var := (subquery)"
   sql_command_flags[SQLCOM_DO]=             CF_REEXECUTION_FRAGILE |
                                             CF_CAN_GENERATE_ROW_EVENTS |
-                                            CF_OPTIMIZER_TRACE | // (1)
-                                            CF_ONLY_BINLOGGABLE_WITH_SF;
+                                            CF_OPTIMIZER_TRACE; // (1)
 
   sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
   sql_command_flags[SQLCOM_SHOW_STATUS]=      CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
@@ -1049,8 +1046,6 @@ bool dispatch_command(enum enum_server_c
   DBUG_ENTER("dispatch_command");
   DBUG_PRINT("info",("packet: '%*.s'; command: %d", packet_length, packet, command));
 
-  DBUG_ASSERT(thd->n_execute_command_calls == 0);
-
   /* SHOW PROFILE instrumentation, begin */
 #if defined(ENABLED_PROFILING)
   thd->profiling.start_new_query();
@@ -2092,28 +2087,11 @@ mysql_execute_command(THD *thd)
   DBUG_ENTER("mysql_execute_command");
   DBUG_ASSERT(!lex->describe || is_explainable_query(lex->sql_command));
 
-  thd->n_execute_command_calls++;
-  DBUG_PRINT("info", ("n_execute_command_calls=%d",
-                      thd->n_execute_command_calls));
-
 #ifdef WITH_PARTITION_STORAGE_ENGINE
   thd->work_part_info= 0;
 #endif
 
-  /*
-    If gtid_next_list!=NULL or gtid_next=='sid:gno', then a
-    binlog_handler will be registered later in this function so that
-    thd->transaction.stmt.is_empty() returns false.  When executing an
-    EXECUTE statement, this function will then be called again,
-    recursively, with thd->in_sub_stmt==false.  Hence, don't raise the
-    assertion in these cases.
-    @todo Check if this causes any trouble /Sven.
-    @note Covered by Case 2 in test binlog.binlog_trx_empty_assertions
-  */
-  DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt ||
-              (thd->n_execute_command_calls > 1 &&
-               (thd->get_gtid_next_list() != NULL ||
-                thd->variables.gtid_next.type == GTID_GROUP)));
+  DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt);
   /*
     In many cases first table of main SELECT_LEX have special meaning =>
     check that it is first table in global list and relink it first in 
@@ -2172,7 +2150,6 @@ mysql_execute_command(THD *thd)
           according to slave filtering rules.
           Returning success without producing any errors in this case.
         */
-        thd->n_execute_command_calls--;
         DBUG_RETURN(0);
       }
       
@@ -2215,7 +2192,6 @@ mysql_execute_command(THD *thd)
         my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
         if (thd->one_shot_set)
           reset_one_shot_variables(thd);
-        thd->n_execute_command_calls--;
         DBUG_RETURN(0);
       }
       
@@ -2261,7 +2237,6 @@ mysql_execute_command(THD *thd)
         */
         reset_one_shot_variables(thd);
       }
-      thd->n_execute_command_calls--;
       DBUG_RETURN(0);
     }
   }
@@ -2275,7 +2250,6 @@ mysql_execute_command(THD *thd)
     if (deny_updates_if_read_only_option(thd, all_tables))
     {
       my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
-      thd->n_execute_command_calls--;
       DBUG_RETURN(-1);
     }
 #ifdef HAVE_REPLICATION
@@ -2295,7 +2269,6 @@ mysql_execute_command(THD *thd)
 
   if (disable_gtid_unsafe_statements && !thd->is_ddl_gtid_compatible())
   {
-    thd->n_execute_command_calls--;
     DBUG_RETURN(-1);
   }
 
@@ -2305,7 +2278,6 @@ mysql_execute_command(THD *thd)
   */
   if (gtid_check_session_variables_before_statement(thd) != 0)
   {
-    thd->n_execute_command_calls--;
     DBUG_RETURN(-1);
   }
       
@@ -2332,54 +2304,6 @@ mysql_execute_command(THD *thd)
   }
 
 #ifndef DBUG_OFF
-  {
-    char buf[Gtid_specification::MAX_TEXT_LENGTH + 1];
-    global_sid_lock.rdlock();
-    thd->variables.gtid_next.to_string(&global_sid_map, buf);
-    global_sid_lock.unlock();
-    DBUG_PRINT("info", ("before gtid_before_statment: gtid_next=%s sqlcom=%d query='%s'", buf, lex->sql_command, thd->query()));
-  }
-#endif
-  /*
-    Execute gtid_before_statement, so that we acquire ownership of
-    groups as specified by gtid_next and gtid_next_list.
-  */
-  if (opt_bin_log && lex->is_binloggable() && thd->n_execute_command_calls == 1)
-  {
-    /*
-      Initialize the cache manager if this was not done yet.
-      binlog_setup_trx_data is idempotent and if it's not called here
-      it's called elsewhere.  It is needed here just so that
-      thd->get_group_cache won't crash.
-    */
-    thd->binlog_setup_trx_data();
-    switch (gtid_before_statement(thd,
-                                  thd->get_group_cache(false),
-                                  thd->get_group_cache(true)))
-    {
-    case GTID_STATEMENT_CANCEL:
-      // error has already been printed; don't print anything more here
-      thd->n_execute_command_calls--;
-      DBUG_RETURN(-1);
-    case GTID_STATEMENT_SKIP:
-      my_ok(thd);
-      thd->n_execute_command_calls--;
-      DBUG_RETURN(0);
-    case GTID_STATEMENT_EXECUTE:
-      break;
-    }
-  }
-#ifndef DBUG_OFF
-  {
-    char buf[Gtid_specification::MAX_TEXT_LENGTH + 1];
-    global_sid_lock.rdlock();
-    thd->variables.gtid_next.to_string(&global_sid_map, buf);
-    global_sid_lock.unlock();
-    DBUG_PRINT("info", ("after gtid_before_statment: gtid_next=%s sqlcom=%d query='%s'", buf, lex->sql_command, thd->query()));
-  }
-#endif
-
-#ifndef DBUG_OFF
   if (lex->sql_command != SQLCOM_SET_OPTION)
     DEBUG_SYNC(thd,"before_execute_sql_command");
 #endif
@@ -4217,16 +4141,8 @@ end_with_restore_list:
               is written into binary log as a separate statement or make both
               creation of routine and implicit GRANT parts of one fully atomic
               statement.
-
-        If gtid_next_list!=NULL or gtid_next=='sid:gno', then a
-        binlog_handler will be registered very early in the execution
-        of the statement.  Hence, allow stmt.is_empty() in these cases.
-        @todo Check if this causes any trouble /Sven.
-        @note Covered by Case 3 in test binlog.binlog_trx_empty_assertions
       */
-      DBUG_ASSERT(thd->transaction.stmt.is_empty() ||
-                  thd->get_gtid_next_list() != NULL ||
-                  thd->variables.gtid_next.type == GTID_GROUP);
+      DBUG_ASSERT(thd->transaction.stmt.is_empty());
       close_thread_tables(thd);
       /*
         Check if the definer exists on slave, 
@@ -4500,16 +4416,8 @@ create_sp_error:
               is written into binary log as a separate statement or make both
               dropping of routine and implicit REVOKE parts of one fully atomic
               statement.
-
-        If gtid_next_list!=NULL or gtid_next=='sid:gno', then a
-        binlog_handler will be registered very early in the execution of
-        the statement.  Hence, allow stmt.is_empty() in these cases.
-        @todo Check if this causes any trouble /Sven.
-        @note Covered by Case 5 in test binlog.binlog_trx_empty_assertions
       */
-      DBUG_ASSERT(thd->transaction.stmt.is_empty() ||
-                  thd->get_gtid_next_list() != NULL ||
-                  thd->variables.gtid_next.type == GTID_GROUP);
+      DBUG_ASSERT(thd->transaction.stmt.is_empty());
       close_thread_tables(thd);
 
       if (sp_result != SP_KEY_NOT_FOUND &&
@@ -4868,7 +4776,6 @@ finish:
     thd->mdl_context.release_statement_locks();
   }
 
-  thd->n_execute_command_calls--;
   DBUG_RETURN(res || thd->is_error());
 }
 
@@ -5992,6 +5899,14 @@ void mysql_parse(THD *thd, char *rawbuf,
                                  0);
 
           error= mysql_execute_command(thd);
+          if (thd->variables.gtid_next.type == GTID_GROUP &&
+              thd->owned_gtid.sidno != 0 &&
+              (thd->lex->sql_command == SQLCOM_COMMIT ||
+               stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END)))
+          {
+            // GTID logging and cleanup incl DDL
+            error |= gtid_empty_group_log_and_cleanup(thd);
+          }
           MYSQL_QUERY_EXEC_DONE(error);
 	}
       }

=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc	2012-01-19 14:04:31 +0000
+++ b/sql/sql_prepare.cc	2012-01-26 10:53:34 +0000
@@ -3328,18 +3328,8 @@ bool Prepared_statement::prepare(const c
   /* The order is important */
   lex->unit.cleanup();
 
-  /*
-    No need to commit statement transaction, it's not started.
-
-    If gtid_next_list!=NULL or gtid_next=='sid:gno', then a
-    binlog_handler will be registered very early in the execution of
-    the statement.  Hence, allow stmt.is_empty() in these cases.
-    @todo Check if this causes any trouble. /Sven
-    @note Covered by Case 1 in test binlog.binlog_trx_empty_assertions
-  */
-  DBUG_ASSERT(thd->transaction.stmt.is_empty() ||
-              thd->get_gtid_next_list() != NULL ||
-              thd->variables.gtid_next.type == GTID_GROUP);
+  /* No need to commit statement transaction, it's not started. */
+  DBUG_ASSERT(thd->transaction.stmt.is_empty());
 
   close_thread_tables(thd);
   thd->mdl_context.rollback_to_savepoint(mdl_savepoint);

=== modified file 'sql/sys_vars.cc'
--- a/sql/sys_vars.cc	2012-01-19 15:51:54 +0000
+++ b/sql/sys_vars.cc	2012-01-27 01:26:40 +0000
@@ -3832,6 +3832,66 @@ static Sys_var_mybool Sys_disable_gtid_u
 
 #ifdef HAVE_REPLICATION
 
+bool Sys_var_gtid_specification::session_update(THD *thd, set_var *var)
+{
+  DBUG_ENTER("Sys_var_gtid::session_update");
+  global_sid_lock.rdlock();
+  bool ret= (((Gtid_specification *)session_var_ptr(thd))->
+             parse(&global_sid_map,
+                   var->save_result.string_value.str) != 0);
+  global_sid_lock.unlock();
+  
+  if (gtid_acquire_ownwership(thd))
+  {
+    DBUG_RETURN(true);
+  }
+
+  DBUG_RETURN(ret);
+}
+
+bool Sys_var_gtid_set::session_update(THD *thd, set_var *var)
+{
+  DBUG_ENTER("Sys_var_gtid_set::session_update");
+  Gtid_set_or_null *gsn=
+    (Gtid_set_or_null *)session_var_ptr(thd);
+  char *value= var->save_result.string_value.str;
+  if (value == NULL)
+      gsn->set_null();
+  else
+  {
+    Gtid_set *gs= gsn->set_non_null(&global_sid_map);
+    if (gs == NULL)
+    {
+      my_error(ER_OUT_OF_RESOURCES, MYF(0)); // allocation failed
+      DBUG_RETURN(true);
+    }
+    /*
+      If string begins with '+', add to the existing set, otherwise
+      replace existing set.
+    */
+    while (isspace(*value))
+      value++;
+    if (*value == '+')
+      value++;
+    else
+      gs->clear();
+    // Add specified set of groups to Gtid_set.
+    global_sid_lock.rdlock();
+    enum_return_status ret= gs->add_gtid_text(value);
+    global_sid_lock.unlock();
+    if (ret != RETURN_STATUS_OK)
+    {
+      gsn->set_null();
+      DBUG_RETURN(true);
+    }
+  }
+  if (gtid_acquire_ownwership(thd))
+  {
+    DBUG_RETURN(true);
+  }
+  DBUG_RETURN(false);
+}
+
 static bool check_gtid_next_list(sys_var *self, THD *thd, set_var *var)
 {
   DBUG_ENTER("check_gtid_next_list");
@@ -3871,6 +3931,18 @@ static bool check_gtid_next(sys_var *sel
     my_error(ER_CANT_SET_GTID_NEXT_TO_GTID_WHEN_GTID_MODE_IS_OFF, MYF(0));
   if (gtid_mode == 3 && type == ANONYMOUS_GROUP)
     my_error(ER_CANT_SET_GTID_NEXT_TO_ANONYMOUS_WHEN_GTID_MODE_IS_ON, MYF(0));
+  if(thd->owned_gtid.sidno != 0)
+  {
+#ifndef DBUG_OFF
+    global_sid_lock.wrlock();
+    DBUG_ASSERT(gtid_state.get_owned_gtids()->
+                thread_owns_anything(thd->thread_id));
+    global_sid_lock.unlock();
+#endif
+    my_error(ER_CANT_SET_GTID_NEXT_WHEN_ITS_NOT_AUTOMATIC, MYF(0));
+    DBUG_RETURN(GTID_STATEMENT_CANCEL);
+  }
+
   DBUG_RETURN(false);
 }
 

=== modified file 'sql/sys_vars.h'
--- a/sql/sys_vars.h	2012-01-19 15:51:54 +0000
+++ b/sql/sys_vars.h	2012-01-26 10:53:34 +0000
@@ -1799,16 +1799,7 @@ public:
   {
     DBUG_ASSERT(size == sizeof(Gtid_specification));
   }
-  bool session_update(THD *thd, set_var *var)
-  {
-    DBUG_ENTER("Sys_var_gtid::session_update");
-    global_sid_lock.rdlock();
-    bool ret= (((Gtid_specification *)session_var_ptr(thd))->
-               parse(&global_sid_map,
-                     var->save_result.string_value.str) != 0);
-    global_sid_lock.unlock();
-    DBUG_RETURN(ret);
-  }
+  bool session_update(THD *thd, set_var *var);
   bool global_update(THD *thd, set_var *var)
   { DBUG_ASSERT(FALSE); return true; }
   void session_save_default(THD *thd, set_var *var)
@@ -1885,44 +1876,7 @@ public:
   {
     DBUG_ASSERT(size == sizeof(Gtid_set_or_null));
   }
-  bool session_update(THD *thd, set_var *var)
-  {
-    DBUG_ENTER("Sys_var_gtid_set::session_update");
-    Gtid_set_or_null *gsn=
-      (Gtid_set_or_null *)session_var_ptr(thd);
-    char *value= var->save_result.string_value.str;
-    if (value == NULL)
-      gsn->set_null();
-    else
-    {
-      Gtid_set *gs= gsn->set_non_null(&global_sid_map);
-      if (gs == NULL)
-      {
-        my_error(ER_OUT_OF_RESOURCES, MYF(0)); // allocation failed
-        DBUG_RETURN(true);
-      }
-      /*
-        If string begins with '+', add to the existing set, otherwise
-        replace existing set.
-      */
-      while (isspace(*value))
-        value++;
-      if (*value == '+')
-        value++;
-      else
-        gs->clear();
-      // Add specified set of groups to Gtid_set.
-      global_sid_lock.rdlock();
-      enum_return_status ret= gs->add_gtid_text(value);
-      global_sid_lock.unlock();
-      if (ret != RETURN_STATUS_OK)
-      {
-        gsn->set_null();
-        DBUG_RETURN(true);
-      }
-    }
-    DBUG_RETURN(false);
-  }
+  bool session_update(THD *thd, set_var *var);
   bool global_update(THD *thd, set_var *var)
   { DBUG_ASSERT(FALSE); return true; }
   void session_save_default(THD *thd, set_var *var)

=== modified file 'sql/transaction.cc'
--- a/sql/transaction.cc	2012-01-19 14:04:31 +0000
+++ b/sql/transaction.cc	2012-01-26 10:53:34 +0000
@@ -29,16 +29,8 @@ static bool trans_check(THD *thd)
   /*
     Always commit statement transaction before manipulating with
     the normal one.
-
-    If gtid_next_list!=NULL or gtid_next=='sid:gno', then a
-    binlog_handler will be registered very early in the execution of
-    the statement.  Hence, allow stmt.is_empty() in these cases.
-    @todo Check if this causes any trouble /Sven.
-    @note Covered by Case 6 in test binlog.binlog_trx_empty_assertions
-  */
-  DBUG_ASSERT(thd->transaction.stmt.is_empty() ||
-              thd->get_gtid_next_list() != NULL ||
-              thd->variables.gtid_next.type == GTID_GROUP);
+  */
+  DBUG_ASSERT(thd->transaction.stmt.is_empty());
 
   if (unlikely(thd->in_sub_stmt))
     my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk-wl3584 branch (andrei.elkin:3578 to 3579) WL#3584Andrei Elkin30 Jan