diff options
author | Alfranio Correia <alfranio.correia@sun.com> | 2010-03-31 14:30:24 +0100 |
---|---|---|
committer | Alfranio Correia <alfranio.correia@sun.com> | 2010-03-31 14:30:24 +0100 |
commit | 671f8768bbf437c4ef546a73ccec2d472485528a (patch) | |
tree | 76af6a16f7a21178e722d6b90b26529ef26255b4 /sql | |
parent | bd92aec362ebd5c65f3c3b8e99a7e35a5bafede1 (diff) | |
parent | 41c642e634f8d7b8d6aef4b4c94783c96c2be711 (diff) | |
download | mariadb-git-671f8768bbf437c4ef546a73ccec2d472485528a.tar.gz |
auto-merge mysql-trunk-bugfixing (local) --> mysql-trunk-bugfixing
Diffstat (limited to 'sql')
-rw-r--r-- | sql/log.cc | 30 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 6 | ||||
-rw-r--r-- | sql/sql_class.cc | 98 | ||||
-rw-r--r-- | sql/sql_lex.cc | 4 | ||||
-rw-r--r-- | sql/sql_lex.h | 12 |
5 files changed, 105 insertions, 45 deletions
diff --git a/sql/log.cc b/sql/log.cc index 279782d271b..a83eca12481 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 517782cb0b4..2b778abc97b 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6327,3 +6327,9 @@ ER_LOCK_ABORTED ER_DATA_OUT_OF_RANGE 22003 eng "%s value is out of range in '%s'" + +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 4b21bc283e2..ffceb2eabce 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3589,13 +3589,33 @@ 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_engine= FALSE; - my_bool mixed_engine= FALSE; - my_bool all_trans_engines= TRUE; + /* + If different types of engines are about to be updated. + For example: Innodb and Falcon; Innodb and MyIsam. + */ + my_bool multi_write_engine= FALSE; + /* + 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; @@ -3621,32 +3641,50 @@ 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; - all_trans_engines= all_trans_engines && - table->table->file->has_transactions(); + multi_write_engine= TRUE; + all_trans_write_engines= all_trans_write_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_access_engine= TRUE; + trans_non_trans_access_engines= trans_non_trans_access_engines || + (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_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; + /* 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. @@ -3710,32 +3748,26 @@ 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 || - (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); - 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_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 */ - 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 @@ -3744,7 +3776,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()) { @@ -3792,7 +3824,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 @@ -3820,7 +3852,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 14b5e160629..0f49abe9abd 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -52,7 +52,9 @@ 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, + ER_BINLOG_UNSAFE_MIXED_STATEMENT, }; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 0b27f73e763..7b655889a5f 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1143,6 +1143,18 @@ 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, + + /** + 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 }; |