List:Commits« Previous MessageNext Message »
From:Alfranio Correia Date:April 22 2010 9:36am
Subject:bzr commit into mysql-5.1-rep+2 branch (alfranio.correia:3182)
Bug#50479
View as plain text  
#At file:///home/acorreia/workspace.sun/repository.mysql/bzrwork/bug-50479/mysql-5.1-rep%2B2/ based on revid:sven.sandberg@stripped

 3182 Alfranio Correia	2010-04-22
      BUG#50479 DDL stmt on row-only/stmt-only tables generate spurious binlog_format errors
      
      In the fix of BUG#39934 in 5.1-rep+3, errors are generated when
      binlog_format=row and a statement modifies a table restricted to
      statement-logging (ER_BINLOG_ROW_MODE_AND_STMT_ENGINE); or if
      binlog_format=statement and a statement modifies a table restricted to
      row-logging (ER_BINLOG_STMT_MODE_AND_ROW_ENGINE).
      
      However, some DDL statements that lock tables (e.g. ALTER TABLE,
      CREATE INDEX and CREATE TRIGGER) were causing spurious errors,
      although no row might be inserted into the binary log.
      
      To fix the problem, we tagged statements that may generate
      rows into the binary log and thence the warning messages are
      only printed out when the appropriate conditions hold and rows
      might be changed.
     @ mysql-test/suite/binlog/r/binlog_spurious_ddl_errors.result
        Added test case.
     @ mysql-test/suite/binlog/t/binlog_spurious_ddl_errors-master.opt
        Added test case.
     @ mysql-test/suite/binlog/t/binlog_spurious_ddl_errors.test
        Added test case.
     @ sql/log_event.cc
        Reorganized the Query_log_event's constructor based on the
        CF_CAN_GENERATE_ROW_EVENTS flag and as such any statement
        that has the associated flag should go through a cache
        before being written to the binary log.
     @ sql/mysql_priv.h
        Added a function to check the CF_CAN_GENERATE_ROW_EVENTS.
     @ sql/sql_class.cc
        Created a hook to be used by innodb that checks if a statement
        may write rows to the binary log. In other words, if it has
        the CF_CAN_GENERATE_ROW_EVENTS flag associated.
     @ sql/sql_class.h
        Defined the CF_CAN_GENERATE_ROW_EVENTS flag.
     @ sql/sql_parse.cc
        Updated the sql_command_flags and added a function to check the CF_CAN_GENERATE_ROW_EVENTS.
     @ storage/innobase/handler/ha_innodb.cc
        Added a call to the hook thd_generates_rows().
     @ storage/innobase/handler/ha_innodb.h
        Defined an external reference to the hook thd_generates_rows().
     @ storage/innodb_plugin/handler/ha_innodb.cc
        Added a call to the hook thd_generates_rows().
     @ storage/innodb_plugin/handler/ha_innodb.h
        Defined an external reference to the hook thd_generates_rows().

    added:
      mysql-test/suite/binlog/r/binlog_spurious_ddl_errors.result
      mysql-test/suite/binlog/t/binlog_spurious_ddl_errors-master.opt
      mysql-test/suite/binlog/t/binlog_spurious_ddl_errors.test
    modified:
      sql/log_event.cc
      sql/mysql_priv.h
      sql/sql_class.cc
      sql/sql_class.h
      sql/sql_db.cc
      sql/sql_parse.cc
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/handler/ha_innodb.h
      storage/innodb_plugin/handler/ha_innodb.cc
      storage/innodb_plugin/handler/ha_innodb.h
=== added file 'mysql-test/suite/binlog/r/binlog_spurious_ddl_errors.result'
--- a/mysql-test/suite/binlog/r/binlog_spurious_ddl_errors.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/r/binlog_spurious_ddl_errors.result	2010-04-22 09:36:21 +0000
@@ -0,0 +1,50 @@
+SET @old_binlog_format= @@global.binlog_format;
+INSTALL PLUGIN example SONAME 'ha_example.so';
+################################################################################
+# Verifies if ER_BINLOG_STMT_MODE_AND_ROW_ENGINE happens by setting the binlog
+# format to STATEMENT and the transaction isolation level to READ COMMITTED as
+# such changes force Innodb to accept changes in the row format.
+#
+# When CREATE TABLE, ALTER TABLE, CREATE INDEX and CREATE TRIGGER are executed
+# any error should be triggered.
+# 
+# In contrats, CREATE TABLE ... SELECT should trigger the following error:
+# ER_BINLOG_STMT_MODE_AND_ROW_ENGINE.
+################################################################################
+SET binlog_format = STATEMENT;
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+CREATE TABLE t_row (a VARCHAR(100)) ENGINE = InnoDB;
+ALTER TABLE t_row ADD COLUMN b INT;
+CREATE TRIGGER trig_row BEFORE INSERT ON t_row FOR EACH ROW INSERT INTO t_stmt VALUES (1);
+CREATE INDEX i ON t_row(a);
+CREATE TABLE t_row_new ENGINE = InnoDB SELECT * FROM t_row;
+ERROR HY000: Cannot execute statement: binlogging impossible since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.
+DROP TABLE t_row;
+
+
+################################################################################
+# Verifies if ER_BINLOG_ROW_MODE_AND_STMT_ENGINE happens by setting the binlog
+# format to ROW and using a engine, i.e. EXAMPLE, that only supports STATEMENT.
+#
+# When CREATE TABLE, ALTER TABLE, CREATE INDEX and CREATE TRIGGER are executed
+# the error ER_BINLOG_ROW_MODE_AND_STMT_ENGINE is not triggered. Note that other
+# errors are triggered due to restrictions in the engine.
+# 
+# In contrats, CREATE TABLE ... SELECT should trigger the following error:
+# ER_BINLOG_ROW_MODE_AND_STMT_ENGINE.
+################################################################################
+SET binlog_format = ROW;
+CREATE TABLE t_stmt (a VARCHAR(100)) ENGINE = EXAMPLE;
+ALTER TABLE t_stmt ADD COLUMN b INT;
+ERROR 42000: This version of MySQL doesn't yet support 'ALTER TABLE'
+CREATE TRIGGER trig_stmt BEFORE INSERT ON t_stmt FOR EACH ROW INSERT INTO t_stmt VALUES (1);
+CREATE INDEX i ON t_stmt(a);
+ERROR 42000: Too many key parts specified; max 0 parts allowed
+CREATE TABLE t_stmt_new ENGINE = EXAMPLE SELECT * FROM t_stmt;
+ERROR HY000: Cannot execute statement: binlogging impossible since BINLOG_FORMAT = ROW and at least one table uses a storage engine limited to statement-logging.
+DROP TABLE t_stmt;
+
+
+UNINSTALL PLUGIN example;
+SET @@global.binlog_format = @old_binlog_format;
+SET @@session.binlog_format = @old_binlog_format;

=== added file 'mysql-test/suite/binlog/t/binlog_spurious_ddl_errors-master.opt'
--- a/mysql-test/suite/binlog/t/binlog_spurious_ddl_errors-master.opt	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/t/binlog_spurious_ddl_errors-master.opt	2010-04-22 09:36:21 +0000
@@ -0,0 +1 @@
+--innodb $EXAMPLE_PLUGIN_OPT

=== added file 'mysql-test/suite/binlog/t/binlog_spurious_ddl_errors.test'
--- a/mysql-test/suite/binlog/t/binlog_spurious_ddl_errors.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/t/binlog_spurious_ddl_errors.test	2010-04-22 09:36:21 +0000
@@ -0,0 +1,95 @@
+################################################################################
+# BUG#50479 DDL stmt on row-only/stmt-only tables generate spurious
+#           binlog_format errors
+#
+# In the fix of BUG#39934 in 5.1-rep+3, errors are generated when
+# binlog_format=row and a statement modifies a table restricted to
+# statement-logging (ER_BINLOG_ROW_MODE_AND_STMT_ENGINE); or if
+# binlog_format=statement and a statement modifies a table limited to
+# row-logging (ER_BINLOG_STMT_MODE_AND_ROW_ENGINE).
+#
+# In this test case, we check if some DDL statements that lock tables do not
+# trigger errors as they do not generate rows events and as such are harmless
+# from the point of view of conflicts between the engine's supported logging
+# format and the value of binlog_format.
+#
+# In particular, we check if:
+#   1 - ALTER TABLE, CREATE INDEX and CREATE TRIGGER do not generate either
+#   ER_BINLOG_STMT_MODE_AND_ROW_ENGINE or ER_BINLOG_STMT_MODE_AND_ROW_ENGINE
+#
+#   2 - CREATE TABLE ... SELECT generates an error because the command can
+#   generate row events but CREATE TABLE without SELECT does not generate
+#   an error.
+################################################################################
+--source include/have_innodb.inc
+--source include/have_example_plugin.inc
+--source include/have_log_bin.inc
+
+SET @old_binlog_format= @@global.binlog_format;
+INSTALL PLUGIN example SONAME 'ha_example.so';
+
+--echo ################################################################################
+--echo # Verifies if ER_BINLOG_STMT_MODE_AND_ROW_ENGINE happens by setting the binlog
+--echo # format to STATEMENT and the transaction isolation level to READ COMMITTED as
+--echo # such changes force Innodb to accept changes in the row format.
+--echo #
+--echo # When CREATE TABLE, ALTER TABLE, CREATE INDEX and CREATE TRIGGER are executed
+--echo # any error should be triggered.
+--echo # 
+--echo # In contrast, CREATE TABLE ... SELECT should trigger the following error:
+--echo # ER_BINLOG_STMT_MODE_AND_ROW_ENGINE.
+--echo ################################################################################
+SET binlog_format = STATEMENT;
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+CREATE TABLE t_row (a VARCHAR(100)) ENGINE = InnoDB;
+
+ALTER TABLE t_row ADD COLUMN b INT;
+
+CREATE TRIGGER trig_row BEFORE INSERT ON t_row FOR EACH ROW INSERT INTO t_stmt VALUES (1);
+
+CREATE INDEX i ON t_row(a);
+
+--error ER_BINLOG_STMT_MODE_AND_ROW_ENGINE
+CREATE TABLE t_row_new ENGINE = InnoDB SELECT * FROM t_row;
+
+DROP TABLE t_row;
+
+--echo
+--echo
+
+--echo ################################################################################
+--echo # Verifies if ER_BINLOG_ROW_MODE_AND_STMT_ENGINE happens by setting the binlog
+--echo # format to ROW and using a engine, i.e. EXAMPLE, that only supports STATEMENT.
+--echo #
+--echo # When CREATE TABLE, ALTER TABLE, CREATE INDEX and CREATE TRIGGER are executed
+--echo # the error ER_BINLOG_ROW_MODE_AND_STMT_ENGINE is not triggered. Note that other
+--echo # errors are triggered due to restrictions in the engine.
+--echo # 
+--echo # In contrast, CREATE TABLE ... SELECT should trigger the following error:
+--echo # ER_BINLOG_ROW_MODE_AND_STMT_ENGINE.
+--echo ################################################################################
+SET binlog_format = ROW;
+CREATE TABLE t_stmt (a VARCHAR(100)) ENGINE = EXAMPLE;
+
+--error ER_NOT_SUPPORTED_YET
+ALTER TABLE t_stmt ADD COLUMN b INT;
+
+CREATE TRIGGER trig_stmt BEFORE INSERT ON t_stmt FOR EACH ROW INSERT INTO t_stmt VALUES (1);
+
+--error ER_TOO_MANY_KEY_PARTS
+CREATE INDEX i ON t_stmt(a);
+
+--error ER_BINLOG_ROW_MODE_AND_STMT_ENGINE
+CREATE TABLE t_stmt_new ENGINE = EXAMPLE SELECT * FROM t_stmt;
+
+DROP TABLE t_stmt;
+
+--echo
+--echo
+
+--echo ################################################################################
+--echo #                                 CLEAN UP                                     #
+--echo ################################################################################
+UNINSTALL PLUGIN example;
+SET @@global.binlog_format = @old_binlog_format;
+SET @@session.binlog_format = @old_binlog_format;

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2010-03-03 14:43:35 +0000
+++ b/sql/log_event.cc	2010-04-22 09:36:21 +0000
@@ -2459,79 +2459,33 @@ Query_log_event::Query_log_event(THD* th
     cache.
   */
   LEX *lex= thd->lex;
-  bool implicit_commit= FALSE;
+  bool use_cache= FALSE;
   cache_type= Log_event::EVENT_INVALID_CACHE;
   switch (lex->sql_command)
-  {
-    case SQLCOM_ALTER_DB:
-    case SQLCOM_CREATE_FUNCTION:
-    case SQLCOM_DROP_FUNCTION:
-    case SQLCOM_DROP_PROCEDURE:
-    case SQLCOM_INSTALL_PLUGIN:
-    case SQLCOM_UNINSTALL_PLUGIN:
-    case SQLCOM_ALTER_TABLESPACE:
-      implicit_commit= TRUE;
-      break;
+  { 
     case SQLCOM_DROP_TABLE:
-      implicit_commit= !(lex->drop_temporary && thd->in_multi_stmt_transaction());
+      use_cache= (lex->drop_temporary && thd->in_multi_stmt_transaction());
       break;
-    case SQLCOM_ALTER_TABLE:
     case SQLCOM_CREATE_TABLE:
-      implicit_commit= !((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
-                   thd->in_multi_stmt_transaction()) &&
-                  !(lex->select_lex.item_list.elements &&
+      use_cache= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
+                   thd->in_multi_stmt_transaction()) ||
+                 (lex->select_lex.item_list.elements &&
                    thd->is_current_stmt_binlog_format_row());
       break;
     case SQLCOM_SET_OPTION:
-      implicit_commit= (lex->autocommit ? TRUE : FALSE);
-      break;
-    /*
-      Replace what follows after CF_AUTO_COMMIT_TRANS is backported by:
-
-      default:
-        implicit_commit= ((sql_command_flags[lex->sql_command] &
-                      CF_AUTO_COMMIT_TRANS));
+      use_cache= (lex->autocommit ? FALSE : TRUE);
       break;
-    */
-    case SQLCOM_CREATE_INDEX:
-    case SQLCOM_TRUNCATE:
-    case SQLCOM_CREATE_DB:
-    case SQLCOM_DROP_DB:
-    case SQLCOM_ALTER_DB_UPGRADE:
-    case SQLCOM_RENAME_TABLE:
-    case SQLCOM_DROP_INDEX:
-    case SQLCOM_CREATE_VIEW:
-    case SQLCOM_DROP_VIEW:
-    case SQLCOM_CREATE_TRIGGER:
-    case SQLCOM_DROP_TRIGGER:
-    case SQLCOM_CREATE_EVENT:
-    case SQLCOM_ALTER_EVENT:
-    case SQLCOM_DROP_EVENT:
-    case SQLCOM_REPAIR:
-    case SQLCOM_OPTIMIZE:
-    case SQLCOM_ANALYZE:
-    case SQLCOM_CREATE_USER:
-    case SQLCOM_DROP_USER:
-    case SQLCOM_RENAME_USER:
-    case SQLCOM_REVOKE_ALL:
-    case SQLCOM_REVOKE:
-    case SQLCOM_GRANT:
-    case SQLCOM_CREATE_PROCEDURE:
-    case SQLCOM_CREATE_SPFUNCTION:
-    case SQLCOM_ALTER_PROCEDURE:
-    case SQLCOM_ALTER_FUNCTION:
-    case SQLCOM_ASSIGN_TO_KEYCACHE:
-    case SQLCOM_PRELOAD_KEYS:
-    case SQLCOM_FLUSH:
-    case SQLCOM_CHECK:
-      implicit_commit= TRUE;
+    case SQLCOM_RELEASE_SAVEPOINT:
+    case SQLCOM_ROLLBACK_TO_SAVEPOINT:
+    case SQLCOM_SAVEPOINT:
+      use_cache= TRUE;
       break;
     default:
-      implicit_commit= FALSE;
+      use_cache= can_generate_rows(thd);
       break;
   }
 
-  if (implicit_commit || direct)
+  if (!use_cache || direct)
   {
     cache_type= Log_event::EVENT_NO_CACHE;
   }

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2010-03-03 14:43:35 +0000
+++ b/sql/mysql_priv.h	2010-04-22 09:36:21 +0000
@@ -992,6 +992,7 @@ void mysql_parse(THD *thd, const char *i
                  const char ** semicolon);
 
 bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
+bool can_generate_rows(const THD *thd);
 bool is_update_query(enum enum_sql_command command);
 bool is_log_table_write_query(enum enum_sql_command command);
 bool alloc_query(THD *thd, const char *packet, uint packet_length);

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2010-03-03 14:43:35 +0000
+++ b/sql/sql_class.cc	2010-04-22 09:36:21 +0000
@@ -3089,6 +3089,11 @@ extern "C" bool thd_binlog_filter_ok(con
 {
   return binlog_filter->db_ok(thd->db);
 }
+
+extern "C" bool thd_generates_rows(const MYSQL_THD thd)
+{
+  return can_generate_rows(thd);
+}
 #endif // INNODB_COMPATIBILITY_HOOKS */
 
 /****************************************************************************
@@ -3647,7 +3652,8 @@ int THD::decide_logging_format(TABLE_LIS
         */
         my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE), MYF(0));
       }
-      else if (variables.binlog_format == BINLOG_FORMAT_ROW)
+      else if (variables.binlog_format == BINLOG_FORMAT_ROW &&
+               can_generate_rows(this))
       {
         /*
           2. Error: Cannot modify table that uses a storage engine
@@ -3685,7 +3691,8 @@ int THD::decide_logging_format(TABLE_LIS
           */
           my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_MODE), MYF(0));
         }
-        else if ((flags_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
+        else if ((flags_all_set & HA_BINLOG_STMT_CAPABLE) == 0 &&
+                 can_generate_rows(this))
         {
           /*
             5. Error: Cannot modify table that uses a storage engine

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2010-03-03 14:43:35 +0000
+++ b/sql/sql_class.h	2010-04-22 09:36:21 +0000
@@ -3130,6 +3130,11 @@ public:
   joins are currently prohibited in these statements.
 */
 #define CF_REEXECUTION_FRAGILE 32
+/**
+  Identifies statements that may generate row events
+  and that may end up in the binary log.
+*/
+#define CF_CAN_GENERATE_ROW_EVENTS 64
 
 /* Functions in sql_class.cc */
 

=== modified file 'sql/sql_db.cc'
--- a/sql/sql_db.cc	2010-02-12 23:30:44 +0000
+++ b/sql/sql_db.cc	2010-04-22 09:36:21 +0000
@@ -181,7 +181,7 @@ uchar* dboptions_get_key(my_dbopt_t *opt
 static inline int write_to_binlog(THD *thd, char *query, uint q_len,
                                   char *db, uint db_len)
 {
-  Query_log_event qinfo(thd, query, q_len, FALSE, TRUE, FALSE, 0);
+  Query_log_event qinfo(thd, query, q_len, FALSE, TRUE, FALSE, 1);
   qinfo.db= db;
   qinfo.db_len= db_len;
   return mysql_bin_log.write(&qinfo);

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2010-03-03 14:43:35 +0000
+++ b/sql/sql_parse.cc	2010-04-22 09:36:21 +0000
@@ -253,12 +253,24 @@ void init_update_queries(void)
 {
   bzero((uchar*) &sql_command_flags, sizeof(sql_command_flags));
 
-  sql_command_flags[SQLCOM_CREATE_TABLE]=   CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
+  /*
+    In general, DDL statements do not generate row events and do not go
+    through a cache before being written to the binary log. However, the
+    CREATE TABLE...SELECT is an exception because it may generate row
+    events. For that reason,  the SQLCOM_CREATE_TABLE  which represents
+    a CREATE TABLE, including the CREATE TABLE...SELECT, has the
+    CF_CAN_GENERATE_ROW_EVENTS flag. The distinction between a regular
+    CREATE TABLE and the CREATE TABLE...SELECT is made in other parts of
+    the code, in particular in the Query_log_event's constructor.
+  */
+  sql_command_flags[SQLCOM_CREATE_TABLE]=   CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
+                                            CF_CAN_GENERATE_ROW_EVENTS;
   sql_command_flags[SQLCOM_CREATE_INDEX]=   CF_CHANGES_DATA;
   sql_command_flags[SQLCOM_ALTER_TABLE]=    CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND;
   sql_command_flags[SQLCOM_TRUNCATE]=       CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND;
   sql_command_flags[SQLCOM_DROP_TABLE]=     CF_CHANGES_DATA;
-  sql_command_flags[SQLCOM_LOAD]=           CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
+  sql_command_flags[SQLCOM_LOAD]=           CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
+                                            CF_CAN_GENERATE_ROW_EVENTS;
   sql_command_flags[SQLCOM_CREATE_DB]=      CF_CHANGES_DATA;
   sql_command_flags[SQLCOM_DROP_DB]=        CF_CHANGES_DATA;
   sql_command_flags[SQLCOM_RENAME_TABLE]=   CF_CHANGES_DATA;
@@ -270,24 +282,24 @@ void init_update_queries(void)
   sql_command_flags[SQLCOM_DROP_EVENT]=     CF_CHANGES_DATA;
 
   sql_command_flags[SQLCOM_UPDATE]=	    CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
-                                            CF_REEXECUTION_FRAGILE;
+                                            CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS;
   sql_command_flags[SQLCOM_UPDATE_MULTI]=   CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
-                                            CF_REEXECUTION_FRAGILE;
+                                            CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS;
   sql_command_flags[SQLCOM_INSERT]=	    CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
-                                            CF_REEXECUTION_FRAGILE;
+                                            CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS;
   sql_command_flags[SQLCOM_INSERT_SELECT]=  CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
-                                            CF_REEXECUTION_FRAGILE;
+                                            CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS;
   sql_command_flags[SQLCOM_DELETE]=         CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
-                                            CF_REEXECUTION_FRAGILE;
+                                            CF_CAN_GENERATE_ROW_EVENTS | CF_REEXECUTION_FRAGILE;
   sql_command_flags[SQLCOM_DELETE_MULTI]=   CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
-                                            CF_REEXECUTION_FRAGILE;
+                                            CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS;
   sql_command_flags[SQLCOM_REPLACE]=        CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
-                                            CF_REEXECUTION_FRAGILE;
+                                            CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS;
   sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
-                                            CF_REEXECUTION_FRAGILE;
-  sql_command_flags[SQLCOM_SELECT]=         CF_REEXECUTION_FRAGILE;
+                                            CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS;
+  sql_command_flags[SQLCOM_SELECT]=         CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS;
   sql_command_flags[SQLCOM_SET_OPTION]=     CF_REEXECUTION_FRAGILE;
-  sql_command_flags[SQLCOM_DO]=             CF_REEXECUTION_FRAGILE;
+  sql_command_flags[SQLCOM_DO]=             CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS;
 
   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;
@@ -344,8 +356,10 @@ void init_update_queries(void)
     last called (or executed) statement is preserved.
     See mysql_execute_command() for how CF_ROW_COUNT is used.
   */
-  sql_command_flags[SQLCOM_CALL]= 		CF_HAS_ROW_COUNT | CF_REEXECUTION_FRAGILE;
-  sql_command_flags[SQLCOM_EXECUTE]= 		CF_HAS_ROW_COUNT;
+  sql_command_flags[SQLCOM_CALL]= 		CF_HAS_ROW_COUNT | CF_REEXECUTION_FRAGILE |
+                                                CF_CAN_GENERATE_ROW_EVENTS;
+  sql_command_flags[SQLCOM_EXECUTE]= 		CF_HAS_ROW_COUNT | 
+                                                CF_CAN_GENERATE_ROW_EVENTS;
 
   /*
     The following admin table operations are allowed
@@ -356,6 +370,11 @@ void init_update_queries(void)
   sql_command_flags[SQLCOM_ANALYZE]=          CF_WRITE_LOGS_COMMAND;
 }
 
+bool can_generate_rows(const THD *thd)
+{
+  return (sql_command_flags[thd->lex->sql_command] &
+          CF_CAN_GENERATE_ROW_EVENTS);
+}
 
 bool is_update_query(enum enum_sql_command command)
 {

=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc	2010-03-03 14:43:35 +0000
+++ b/storage/innobase/handler/ha_innodb.cc	2010-04-22 09:36:21 +0000
@@ -7165,7 +7165,9 @@ ha_innobase::external_lock(
 	if (lock_type == F_WRLCK &&
 	    !(table_flags() & HA_BINLOG_STMT_CAPABLE) &&
 	    thd_binlog_format(thd) == BINLOG_FORMAT_STMT &&
-            thd_binlog_filter_ok(thd))
+            thd_binlog_filter_ok(thd) &&
+            thd_generates_rows(thd)
+           )
         {
 		/* The error may be suppressed by test cases, by setting
 		the no_innodb_binlog_errors debug symbol. */

=== modified file 'storage/innobase/handler/ha_innodb.h'
--- a/storage/innobase/handler/ha_innodb.h	2010-01-22 09:57:02 +0000
+++ b/storage/innobase/handler/ha_innodb.h	2010-04-22 09:36:21 +0000
@@ -258,4 +258,11 @@ void thd_mark_transaction_to_rollback(MY
   @retval 1 the query is not filtered, 0 otherwise.
 */
 bool thd_binlog_filter_ok(const MYSQL_THD thd);
+/**
+  Check if the query may generate row changes which
+  may end up in the binary.
+  @param  thd   Thread handle
+  @return 1 the query may generate row changes, 0 otherwise.
+*/
+bool thd_generates_rows(const MYSQL_THD thd);
 }

=== modified file 'storage/innodb_plugin/handler/ha_innodb.cc'
--- a/storage/innodb_plugin/handler/ha_innodb.cc	2010-02-12 23:30:44 +0000
+++ b/storage/innodb_plugin/handler/ha_innodb.cc	2010-04-22 09:36:21 +0000
@@ -7914,6 +7914,7 @@ ha_innobase::external_lock(
 	           && !(table_flags() & HA_BINLOG_STMT_CAPABLE)
 #if MYSQL_VERSION_ID > 50140
                    && thd_binlog_filter_ok(thd)
+                   && thd_generates_rows(thd)
 #endif /* MYSQL_VERSION_ID > 50140 */
 		   )
 		{

=== modified file 'storage/innodb_plugin/handler/ha_innodb.h'
--- a/storage/innodb_plugin/handler/ha_innodb.h	2009-11-30 12:11:36 +0000
+++ b/storage/innodb_plugin/handler/ha_innodb.h	2010-04-22 09:36:21 +0000
@@ -265,6 +265,13 @@ void thd_mark_transaction_to_rollback(MY
   @retval 1 the query is not filtered, 0 otherwise.
 */
 bool thd_binlog_filter_ok(const MYSQL_THD thd);
+/**
+  Check if the query may generate row changes which
+  may end up in the binary.
+  @param  thd   Thread handle
+  @return 1 the query may generate row changes, 0 otherwise.
+*/
+bool thd_generates_rows(const MYSQL_THD thd);
 #endif /* MYSQL_VERSION_ID > 50140 */
 }
 


Attachment: [text/bzr-bundle]
Thread
bzr commit into mysql-5.1-rep+2 branch (alfranio.correia:3182)Bug#50479Alfranio Correia22 Apr