From 3fad4e8df1281c43d4fd343d3107b0a8e52c2327 Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Mon, 22 Feb 2010 03:25:33 +0000 Subject: BUG#49019 Mixing self-logging eng. and regular eng. does not switch to row in mixed mode Reading from a self-logging engine and updating a transactional engine such as Innodb generates changes that are written to the binary log in the statement format and may make slaves diverge. In the mixed mode, such changes should be written to the binary log in the row format. Note that the issue does not happen if we mix a self-logging engine and MyIsam as this case is caught by checking the mixture of non-transactional and transactional engines. So, we classify a mixed statement where one reads from NDB and writes into another engine as unsafe: if (multi_engine && flags_some_set & HA_HAS_OWN_BINLOGGING) lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE); mysql-test/suite/rpl_ndb/r/rpl_ndb_mixed_engines_transactions.result: Augmented test case to check mixed statements mysql-test/suite/rpl_ndb/t/rpl_ndb_mixed_engines_transactions.test: Augmented test case to check mixed statements sql/share/errmsg-utf8.txt: Added ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE sql/sql_class.cc: Redefined flags' name in order to have two sets of flags: (i) flags that are checked when there is a write operation; (ii) flags that are checked regardless of the type of the operation. Classified a mixed statement where one reads from NDB and writes into another engine as unsafe: if (multi_engine && flags_some_set & HA_HAS_OWN_BINLOGGING) lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE); sql/sql_lex.cc: Added error ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE sql/sql_lex.h: Added BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE --- sql/share/errmsg-utf8.txt | 3 +++ sql/sql_class.cc | 63 ++++++++++++++++++++++++++++------------------- sql/sql_lex.cc | 3 ++- sql/sql_lex.h | 6 +++++ 4 files changed, 48 insertions(+), 27 deletions(-) (limited to 'sql') diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 7ea8c75e43e..30d12e89ca0 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6321,3 +6321,6 @@ ER_SPATIAL_MUST_HAVE_GEOM_COL 42000 ER_TOO_LONG_INDEX_COMMENT eng "Comment for index '%-.64s' is too long (max = %lu)" + +ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE + eng "Mixing self-logging and non-self-logging engines in a statement is unsafe." diff --git a/sql/sql_class.cc b/sql/sql_class.cc index b7ded3b632f..436b9a587b0 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3587,12 +3587,14 @@ int THD::decide_logging_format(TABLE_LIST *tables) capabilities, and one with the intersection of all the engine capabilities. */ + handler::Table_flags flags_write_some_set= 0; handler::Table_flags flags_some_set= 0; - handler::Table_flags flags_all_set= + handler::Table_flags flags_write_all_set= HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE; + my_bool multi_write_engine= FALSE; my_bool multi_engine= FALSE; - my_bool mixed_engine= FALSE; + my_bool trans_non_trans_multi_engine= FALSE; my_bool all_trans_engines= TRUE; TABLE* prev_write_table= NULL; TABLE* prev_access_table= NULL; @@ -3619,26 +3621,42 @@ int THD::decide_logging_format(TABLE_LIST *tables) continue; if (table->table->s->table_category == TABLE_CATEGORY_PERFORMANCE) lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_TABLE); + handler::Table_flags const flags= table->table->file->ha_table_flags(); + DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%llx", + table->table_name, flags)); if (table->lock_type >= TL_WRITE_ALLOW_WRITE) { - handler::Table_flags const flags= table->table->file->ha_table_flags(); - DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%llx", - table->table_name, flags)); if (prev_write_table && prev_write_table->file->ht != table->table->file->ht) - multi_engine= TRUE; + multi_write_engine= TRUE; all_trans_engines= all_trans_engines && table->table->file->has_transactions(); prev_write_table= table->table; - flags_all_set &= flags; - flags_some_set |= flags; + flags_write_all_set &= flags; + flags_write_some_set |= flags; } + flags_some_set |= flags; if (prev_access_table && prev_access_table->file->ht != table->table->file->ht) - mixed_engine= mixed_engine || (prev_access_table->file->has_transactions() != - table->table->file->has_transactions()); + { + multi_engine= TRUE; + trans_non_trans_multi_engine= trans_non_trans_multi_engine || + (prev_access_table->file->has_transactions() != + table->table->file->has_transactions()); + } prev_access_table= table->table; } + DBUG_PRINT("info", ("flags_write_all_set: 0x%llx", flags_write_all_set)); + DBUG_PRINT("info", ("flags_write_some_set: 0x%llx", flags_write_some_set)); + DBUG_PRINT("info", ("flags_some_set: 0x%llx", flags_some_set)); + DBUG_PRINT("info", ("multi_write_engine: %d", multi_write_engine)); + DBUG_PRINT("info", ("multi_engine: %d", multi_engine)); + DBUG_PRINT("info", ("trans_non_trans_multi_engine: %d", + trans_non_trans_multi_engine)); + + int error= 0; + int unsafe_flags; + /* Set the statement as unsafe if: @@ -3708,32 +3726,25 @@ int THD::decide_logging_format(TABLE_LIST *tables) isolation level but if we have pure repeatable read or serializable the lock history on the slave will be different from the master. */ - if (mixed_engine || + if (trans_non_trans_multi_engine || (trans_has_updated_trans_table(this) && !all_trans_engines)) lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS); - DBUG_PRINT("info", ("flags_all_set: 0x%llx", flags_all_set)); - DBUG_PRINT("info", ("flags_some_set: 0x%llx", flags_some_set)); - DBUG_PRINT("info", ("multi_engine: %d", multi_engine)); - - int error= 0; - int unsafe_flags; - /* If more than one engine is involved in the statement and at least one is doing it's own logging (is *self-logging*), the statement cannot be logged atomically, so we generate an error rather than allowing the binlog to become corrupt. */ - if (multi_engine && - (flags_some_set & HA_HAS_OWN_BINLOGGING)) - { + if (multi_write_engine && + (flags_write_some_set & HA_HAS_OWN_BINLOGGING)) my_error((error= ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE), MYF(0)); - } + else if (multi_engine && flags_some_set & HA_HAS_OWN_BINLOGGING) + lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE); /* both statement-only and row-only engines involved */ - if ((flags_all_set & (HA_BINLOG_STMT_CAPABLE | HA_BINLOG_ROW_CAPABLE)) == 0) + if ((flags_write_all_set & (HA_BINLOG_STMT_CAPABLE | HA_BINLOG_ROW_CAPABLE)) == 0) { /* 1. Error: Binary logging impossible since both row-incapable @@ -3742,7 +3753,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) my_error((error= ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE), MYF(0)); } /* statement-only engines involved */ - else if ((flags_all_set & HA_BINLOG_ROW_CAPABLE) == 0) + else if ((flags_write_all_set & HA_BINLOG_ROW_CAPABLE) == 0) { if (lex->is_stmt_row_injection()) { @@ -3790,7 +3801,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) */ 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_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0) { /* 5. Error: Cannot modify table that uses a storage engine @@ -3818,7 +3829,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) else { if (lex->is_stmt_unsafe() || lex->is_stmt_row_injection() - || (flags_all_set & HA_BINLOG_STMT_CAPABLE) == 0) + || (flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0) { /* log in row format! */ set_current_stmt_binlog_format_row_if_mixed(); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 6da734592dc..65dbe48aaaf 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -52,7 +52,8 @@ Query_tables_list::binlog_stmt_unsafe_errcode[BINLOG_STMT_UNSAFE_COUNT] = ER_BINLOG_UNSAFE_UDF, ER_BINLOG_UNSAFE_SYSTEM_VARIABLE, ER_BINLOG_UNSAFE_SYSTEM_FUNCTION, - ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS + ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS, + ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE }; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 7ec87806ea5..45a86464b5a 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1141,6 +1141,12 @@ public: */ BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS, + /** + Mixing self-logging and non-self-logging engines in a statement + is unsafe. + */ + BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE, + /* The last element of this enumeration type. */ BINLOG_STMT_UNSAFE_COUNT }; -- cgit v1.2.1 From 41c642e634f8d7b8d6aef4b4c94783c96c2be711 Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Wed, 31 Mar 2010 14:22:47 +0100 Subject: BUG#51291 Unfortunate effect around variable binlog_direct_non_transactional_updates BUG#46364 introduced the flag binlog_direct_non_transactional_updates which would make N-changes to be written to the binary log upon committing the statement when "ON". On the other hand, when "OFF" the option was supposed to mimic the behavior in 5.1. However, the implementation was not mimicking the behavior correctly and the following bugs popped up: Case #1: N-changes executed within a transaction would go into the S-cache. When later in the same transaction a T-change occurs, N-changes following it were written to the T-cache instead of the S-cache. In some cases, this raises problems. For example, a Table_map_log_event being written initially into the S-cache, together with the initial N-changes, would be absent from the T-cache. This would log N-changes orphaned from a Table_map_log_event (thence discarded at the slave). (MIXED and ROW) Case #2: When rolling back a transaction, the N-changes that might be in the T-cache were disregarded and truncated along with the T-changes. (MIXED and ROW) Case #3: When a MIXED statement (TN) is ahead of any other T-changes in the transaction and it fails, it is kept in the T-cache until the transaction ends. This is not the case in 5.1 or Betony (5.5.2). In these, the failed TN statement would be written to the binlog at the same instant it had failed and not deferred until transaction end. (SBR) To fix these problems, we have decided to do what follows: For Case #1 and #2, we circumvent them: 1. by not letting binlog_direct_non_transactional_updates affect MIXED and RBR. These modes will keep the behavior provided by WL#2687. Although this will make Celosia to behave differently from 5.1, an execution will be always safe under such modes in the sense that slaves will never go out sync. In 5.1, using either MIXED or ROW while mixing N-statements and T-statements was not safe. For Case #3, we don't actually fix it. We: 1. keep it and make all MIXED statements whether they end up failing or not or whether they are up front in the transaction or after some transactional change to always be stored in the T-cache. This means that it is written to the binary log on transaction commit/rollback only. 2. We make the warning message even more specific about the MIXED statement and SBR. mysql-test/extra/rpl_tests/rpl_mixing_engines.test: Updated the test case to avoid checking inconsistencies between the master and slave when session.binlog_direct_non_transactional_updates is ON and the format is statement. In this scenario, they will diverge because a counter (within a triger) is incremented and associated to the issued statement. However, an n-statement is logged ahead of the transaction and thus is not executed by the same order in the slave and thus gets a different value from the counter. mysql-test/suite/binlog/r/binlog_multi_engine.result: Updated the test case with the new error ER_BINLOG_UNSAFE_MIXED_STATEMENT. mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result: Updated the test case with the new error ER_BINLOG_UNSAFE_MIXED_STATEMENT. mysql-test/suite/ndb/r/ndb_binlog_format.result: Updated the test case with the new error ER_BINLOG_UNSAFE_MIXED_STATEMENT. mysql-test/suite/rpl/r/rpl_concurrency_error.result: Updated the test case with the new error ER_BINLOG_UNSAFE_MIXED_STATEMENT. mysql-test/suite/rpl/r/rpl_stm_binlog_max_cache_size.result: Updated the test case with the new error ER_BINLOG_UNSAFE_MIXED_STATEMENT. mysql-test/suite/rpl/r/rpl_stm_mixing_engines.result: Updated the test case with the new error ER_BINLOG_UNSAFE_MIXED_STATEMENT. mysql-test/suite/rpl/r/rpl_stm_stop_middle_group.result: Updated the test case with the new error ER_BINLOG_UNSAFE_MIXED_STATEMENT. sql/log.cc: Checked if either a trx-cache or a non-trx-cache should be used. If bin_log_direct_non_trans_update is active or the format is either MIXED or ROW, the cache to be used depends on the flag is_transactional. When the format is STMT, the non-trx-cache should be used if the statement is non-transactional and the trx-cache is empty, i.e. if any transactional statement has not committed yet. Otherwise, the trx-cache should be used. sql/share/errmsg-utf8.txt: Added the new unsafe error ER_BINLOG_UNSAFE_MIXED_STATEMENT. sql/sql_class.cc: Started printing ER_BINLOG_UNSAFE_MIXED_STATEMENT, when there is a mixed-statement. Organized the names of the variables and added comments. sql/sql_lex.cc: Added the new unsafe error ER_BINLOG_UNSAFE_MIXED_STATEMENT. sql/sql_lex.h: Added the new unsafe error ER_BINLOG_UNSAFE_MIXED_STATEMENT. --- sql/log.cc | 30 ++++++++++++++++++---------- sql/share/errmsg-utf8.txt | 3 +++ sql/sql_class.cc | 51 +++++++++++++++++++++++++++++++++-------------- sql/sql_lex.cc | 3 ++- sql/sql_lex.h | 6 ++++++ 5 files changed, 66 insertions(+), 27 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index 75853aec485..3056c4c1748 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1631,7 +1631,10 @@ binlog_flush_stmt_cache(THD *thd, binlog_cache_mngr *cache_mngr) */ bool const is_transactional= FALSE; IO_CACHE *cache_log= &cache_mngr->stmt_cache.cache_log; - thd->binlog_flush_pending_rows_event(TRUE, is_transactional); + + if (thd->binlog_flush_pending_rows_event(TRUE, is_transactional)) + DBUG_RETURN(1); + Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE, TRUE, 0); if ((error= mysql_bin_log.write(thd, cache_log, &qev, cache_mngr->stmt_cache.has_incident()))) @@ -4180,7 +4183,7 @@ bool MYSQL_BIN_LOG::is_query_in_union(THD *thd, query_id_t query_id_param) } /** - This function checks if a transactional talbe was updated by the + This function checks if a transactional table was updated by the current transaction. @param thd The client thread that executed the current statement. @@ -4193,11 +4196,11 @@ trans_has_updated_trans_table(const THD* thd) binlog_cache_mngr *const cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); - return (cache_mngr ? my_b_tell (&cache_mngr->trx_cache.cache_log) : 0); + return (cache_mngr ? !cache_mngr->trx_cache.empty() : 0); } /** - This function checks if a transactional talbe was updated by the + This function checks if a transactional table was updated by the current statement. @param thd The client thread that executed the current statement. @@ -4209,7 +4212,8 @@ stmt_has_updated_trans_table(const THD *thd) { Ha_trx_info *ha_info; - for (ha_info= thd->transaction.stmt.ha_list; ha_info; ha_info= ha_info->next()) + for (ha_info= thd->transaction.stmt.ha_list; ha_info; + ha_info= ha_info->next()) { if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton) return (TRUE); @@ -4219,11 +4223,14 @@ stmt_has_updated_trans_table(const THD *thd) /** This function checks if either a trx-cache or a non-trx-cache should - be used. If @c bin_log_direct_non_trans_update is active, the cache - to be used depends on the flag @c is_transactional. + be used. If @c bin_log_direct_non_trans_update is active or the format + is either MIXED or ROW, the cache to be used depends on the flag @c + is_transactional. - Otherswise, we use the trx-cache if either the @c is_transactional - is true or the trx-cache is not empty. + On the other hand, if binlog_format is STMT or direct option is + OFF, the trx-cache should be used if and only if the statement is + transactional or the trx-cache is not empty. Otherwise, the + non-trx-cache should be used. @param thd The client thread. @param is_transactional The changes are related to a trx-table. @@ -4236,8 +4243,9 @@ bool use_trans_cache(const THD* thd, bool is_transactional) (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); return - (thd->variables.binlog_direct_non_trans_update ? is_transactional : - (cache_mngr->trx_cache.empty() && !is_transactional ? FALSE : TRUE)); + ((thd->variables.binlog_format != BINLOG_FORMAT_STMT || + thd->variables.binlog_direct_non_trans_update) ? is_transactional : + (is_transactional || cache_mngr->trx_cache.empty())); } /* diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 30d12e89ca0..60bf27499be 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6324,3 +6324,6 @@ ER_TOO_LONG_INDEX_COMMENT ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE eng "Mixing self-logging and non-self-logging engines in a statement is unsafe." + +ER_BINLOG_UNSAFE_MIXED_STATEMENT + eng "Statements that read from both transactional and non-transactional tables and write to any of them are unsafe." diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 436b9a587b0..2ab5d7f7be8 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3592,10 +3592,28 @@ int THD::decide_logging_format(TABLE_LIST *tables) handler::Table_flags flags_write_all_set= HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE; + /* + If different types of engines are about to be updated. + For example: Innodb and Falcon; Innodb and MyIsam. + */ my_bool multi_write_engine= FALSE; - my_bool multi_engine= FALSE; - my_bool trans_non_trans_multi_engine= FALSE; - my_bool all_trans_engines= TRUE; + /* + If different types of engines are about to be accessed + and any of them is about to be updated. For example: + Innodb and Falcon; Innodb and MyIsam. + */ + my_bool multi_access_engine= FALSE; + /* + If non-transactional and transactional engines are about + to be accessed and any of them is about to be updated. + For example: Innodb and MyIsam. + */ + my_bool trans_non_trans_access_engines= FALSE; + /* + If all engines that are about to be updated are + transactional. + */ + my_bool all_trans_write_engines= TRUE; TABLE* prev_write_table= NULL; TABLE* prev_access_table= NULL; @@ -3629,8 +3647,8 @@ int THD::decide_logging_format(TABLE_LIST *tables) if (prev_write_table && prev_write_table->file->ht != table->table->file->ht) multi_write_engine= TRUE; - all_trans_engines= all_trans_engines && - table->table->file->has_transactions(); + all_trans_write_engines= all_trans_write_engines && + table->table->file->has_transactions(); prev_write_table= table->table; flags_write_all_set &= flags; flags_write_some_set |= flags; @@ -3638,8 +3656,8 @@ int THD::decide_logging_format(TABLE_LIST *tables) flags_some_set |= flags; if (prev_access_table && prev_access_table->file->ht != table->table->file->ht) { - multi_engine= TRUE; - trans_non_trans_multi_engine= trans_non_trans_multi_engine || + multi_access_engine= TRUE; + trans_non_trans_access_engines= trans_non_trans_access_engines || (prev_access_table->file->has_transactions() != table->table->file->has_transactions()); } @@ -3650,9 +3668,9 @@ int THD::decide_logging_format(TABLE_LIST *tables) DBUG_PRINT("info", ("flags_write_some_set: 0x%llx", flags_write_some_set)); DBUG_PRINT("info", ("flags_some_set: 0x%llx", flags_some_set)); DBUG_PRINT("info", ("multi_write_engine: %d", multi_write_engine)); - DBUG_PRINT("info", ("multi_engine: %d", multi_engine)); - DBUG_PRINT("info", ("trans_non_trans_multi_engine: %d", - trans_non_trans_multi_engine)); + DBUG_PRINT("info", ("multi_access_engine: %d", multi_access_engine)); + DBUG_PRINT("info", ("trans_non_trans_access_engines: %d", + trans_non_trans_access_engines)); int error= 0; int unsafe_flags; @@ -3661,8 +3679,10 @@ int THD::decide_logging_format(TABLE_LIST *tables) Set the statement as unsafe if: . it is a mixed statement, i.e. access transactional and non-transactional - tables, and updates at least one; - or + tables, and update any of them; + + or: + . an early statement updated a transactional table; . and, the current statement updates a non-transactional table. @@ -3726,8 +3746,9 @@ int THD::decide_logging_format(TABLE_LIST *tables) isolation level but if we have pure repeatable read or serializable the lock history on the slave will be different from the master. */ - if (trans_non_trans_multi_engine || - (trans_has_updated_trans_table(this) && !all_trans_engines)) + if (!trans_non_trans_access_engines) + lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MIXED_STATEMENT); + else if (trans_has_updated_trans_table(this) && !all_trans_write_engines) lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS); /* @@ -3740,7 +3761,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) (flags_write_some_set & HA_HAS_OWN_BINLOGGING)) my_error((error= ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE), MYF(0)); - else if (multi_engine && flags_some_set & HA_HAS_OWN_BINLOGGING) + else if (multi_access_engine && flags_some_set & HA_HAS_OWN_BINLOGGING) lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE); /* both statement-only and row-only engines involved */ diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 65dbe48aaaf..d098a05c217 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -53,7 +53,8 @@ Query_tables_list::binlog_stmt_unsafe_errcode[BINLOG_STMT_UNSAFE_COUNT] = ER_BINLOG_UNSAFE_SYSTEM_VARIABLE, ER_BINLOG_UNSAFE_SYSTEM_FUNCTION, ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS, - ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE + ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE, + ER_BINLOG_UNSAFE_MIXED_STATEMENT, }; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 45a86464b5a..56d8acbc743 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1147,6 +1147,12 @@ public: */ BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE, + /** + Statements that read from both transactional and non-transactional + tables and write to any of them are unsafe. + */ + BINLOG_STMT_UNSAFE_MIXED_STATEMENT, + /* The last element of this enumeration type. */ BINLOG_STMT_UNSAFE_COUNT }; -- cgit v1.2.1