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 3300ff7a89ffdd49283c6a23ec247a996c308b30 Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Wed, 24 Feb 2010 12:45:15 +0000 Subject: BUG#51277 SUPER_ACL should be checked unconditionally (binlog_format and binlog_direct) SUPER_ACL should be checked unconditionally while verifying if the binlog_format or the binlog_direct_non_transactional_updates might be changed. Roughly speaking, both session values cannot be changed in the context of a transaction or a stored function. Note that changing the global value does not cause any effect until a new connection is created. So, we fixed the problem by first checking the permissions and right after further verifications are ignored if the global value is being updated. In this patch, we also re-structure the test case to make it more readable. --- sql/sys_vars.cc | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) (limited to 'sql') diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 8f71d27e8d4..d8bdf35fd51 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -240,6 +240,12 @@ static bool check_has_super(sys_var *self, THD *thd, set_var *var) } static bool binlog_format_check(sys_var *self, THD *thd, set_var *var) { + if (check_has_super(self, thd, var)) + return true; + + if (var->type == OPT_GLOBAL) + return false; + /* If RBR and open temporary tables, their CREATE TABLE may not be in the binlog, so we can't toggle to SBR in this connection. @@ -271,18 +277,12 @@ static bool binlog_format_check(sys_var *self, THD *thd, set_var *var) /* Make the session variable 'binlog_format' read-only inside a transaction. */ - if (thd->active_transaction() && (var->type == OPT_SESSION)) + if (thd->active_transaction()) { my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0)); return true; } - if (check_has_super(self, thd, var)) - return true; - if (var->type == OPT_GLOBAL || - (thd->variables.binlog_format == var->save_result.ulonglong_value)) - return false; - return false; } @@ -311,32 +311,31 @@ static Sys_var_enum Sys_binlog_format( static bool binlog_direct_check(sys_var *self, THD *thd, set_var *var) { + if (check_has_super(self, thd, var)) + return true; + + if (var->type == OPT_GLOBAL) + return false; + /* Makes the session variable 'binlog_direct_non_transactional_updates' - read-only inside a transaction. + read-only if within a procedure, trigger or function. */ - if (thd->active_transaction() && (var->type == OPT_SESSION)) + if (thd->in_sub_stmt) { - my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT, MYF(0)); - return 1; + my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT, MYF(0)); + return true; } /* Makes the session variable 'binlog_direct_non_transactional_updates' - read-only if within a procedure, trigger or function. + read-only inside a transaction. */ - if (thd->in_sub_stmt) + if (thd->active_transaction()) { - my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT, MYF(0)); - return 1; + my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT, MYF(0)); + return true; } - if (check_has_super(self, thd, var)) - return true; - if (var->type == OPT_GLOBAL || - (thd->variables.binlog_direct_non_trans_update == - static_cast(var->save_result.ulonglong_value))) - return false; - return false; } -- cgit v1.2.1 From 056e67054272571adeceb39d8d69b5f7950e517f Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Wed, 24 Mar 2010 20:15:06 +0100 Subject: Fix an issue with the IBM C++ compiler which was detected during the build of 5.5.3-m3. This requires version 9 of IBM C++ to help. More fixes will still be needed, it is very strict (or rather: a bit picky?) about templates. --- sql/mdl.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sql') diff --git a/sql/mdl.h b/sql/mdl.h index 124151798ae..2fb21a5aa18 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -15,6 +15,14 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#if defined(__IBMC__) || defined(__IBMCPP__) +/* Further down, "next_in_lock" and "next_in_context" have the same type, + and in "sql_plist.h" this leads to an identical signature, which causes + problems in function overloading. +*/ +#pragma namemangling(v5) +#endif + #include "sql_plist.h" #include -- cgit v1.2.1 From a086b2b0d352ad83c2b7adbbdfc5d22ba01334bd Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Thu, 25 Mar 2010 00:30:16 +0000 Subject: BUG#52202: mysqlbinlog_row* fail in daily-trunk on Sol10 x86_64 debug_max There was a buffer overrun when unpacking the date field. Incidentaly, this seems to affect only solaris x86_64 debug builds, but others platforms may be vulnerable as well. In particular, the buffer size used was not taking into consideration that the '\0' character would be written into it. We fix this by increasing the size of the buffer used to accommodate one extra byte (the one for the '\0'). --- sql/log_event.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index 6412f0047d1..f23e30f2024 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1717,8 +1717,8 @@ log_event_print_value(IO_CACHE *file, const uchar *ptr, { uint32 tmp= uint3korr(ptr); int part; - char buf[10]; - char *pos= &buf[10]; + char buf[11]; + char *pos= &buf[10]; // start from '\0' to the beginning /* Copied from field.cc */ *pos--=0; // End NULL -- 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 From e0328736bfc3bcb69699551d80afa931016b6c6b Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Thu, 1 Apr 2010 00:16:22 +0100 Subject: BUG#51291 Unfortunate effect around variable binlog_direct_non_transactional_updates Post-merge fix. --- sql/log.cc | 2 +- sql/sql_class.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index a83eca12481..248dc4b5265 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -4245,7 +4245,7 @@ bool use_trans_cache(const THD* thd, bool is_transactional) return ((thd->variables.binlog_format != BINLOG_FORMAT_STMT || thd->variables.binlog_direct_non_trans_update) ? is_transactional : - (is_transactional || cache_mngr->trx_cache.empty())); + (is_transactional || !cache_mngr->trx_cache.empty())); } /* diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ffceb2eabce..473518b91c1 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3748,7 +3748,7 @@ 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_access_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); -- cgit v1.2.1 From 6a5b47a40015acfaf348e89d80d7b114dd53b120 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 13 Apr 2010 11:38:28 +0200 Subject: Bug#51980 mysqld service crashes with a simple COUNT(DISTINCT) query over a view Problem: Segmentation fault in add_group_and_distinct_keys() when accessing field of what is assumed to be an Item_field object. Cause: In case of views, the item added to list by is_indexed_agg_distinct() was not of type Item_field, but Item_ref. Resolution: Add the real Item_field object, the one referred to by Item_ref object, to the list, instead. mysql-test/r/count_distinct.result: Results for test case for Bug#51980. mysql-test/t/count_distinct.test: Test case for Bug#51980. Table needs to contain at least two rows to avoid const table optimization. sql/sql_select.cc: Make sure it is the actual Item_field object that is pushed to the out_args list of is_indexed_agg_distinct(), and not Item_ref objects. --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7d379ab34de..62a51a32ca2 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4157,7 +4157,7 @@ is_indexed_agg_distinct(JOIN *join, List *out_args) optimization is applicable */ if (out_args) - out_args->push_back((Item_field *) expr); + out_args->push_back((Item_field *) expr->real_item()); result= true; } } -- cgit v1.2.1 From 3227ba706fac95367ed53a48966303bc996b1d7f Mon Sep 17 00:00:00 2001 From: Konstantin Osipov Date: Tue, 13 Apr 2010 19:04:45 +0400 Subject: Backport of: ChangeSet@1.2703, 2007-12-07 09:35:28-05:00, cmiller@zippy.cornsilk.net +40 -0 Bug#13174: SHA2 function Patch contributed from Bill Karwin, paper unnumbered CLA in Seattle Implement SHA2 functions. Chad added code to make it work with YaSSL. Also, he removed the (probable) bug of embedded server never using SSL-dependent functions. (libmysqld/Makefile.am didn't read ANY autoconf defs.) Function specification: SHA2( string cleartext, integer hash_length ) -> string hash, or NULL where hash_length is one of 224, 256, 384, or 512. If either is NULL or a length is unsupported, then the result is NULL. The resulting string is always the length of the hash_length parameter or is NULL. Include the canonical hash examples from the NIST in the test results. --- Polish and address concerns of reviewers. .bzrignore: Added libmysqld/sha2.cc to the ignore list. client/mysql.cc: Add condition to remove code for embedded server. client/mysqltest.cc: Add condition to remove code for embedded server. include/Makefile.am: New header file to header list. include/mysql_embed.h: Embedded servers can use SSL-library functions too! include/sha2.h: Compatibility layer to make YaSSL behave like OpenSSL. include/sslopt-case.h: Remove SSL-communication parameters from command lines. include/sslopt-longopts.h: Remove SSL-communication parameters from command lines. include/sslopt-vars.h: Don't declare variables that are only used in SSL communication, if we are compiling the embedded server. include/violite.h: Don't even compile the SSL-communication function if we're in the embedded server. --- Remove CPP condition indentation. libmysqld/CMakeLists.txt: Add new file to source list. libmysqld/Makefile.am: Include standard DEFS in embedded compilation. It's an undiscovered but that it's not there. Add new file to source list. libmysqld/examples/Makefile.am: Include autoconf DEFS. libmysqld/lib_sql.cc: Initialize SSL-related variables in embedded server. mysql-test/include/have_ssl_crypto_functs.inc: Distinguish between communication and crypto. Use the tristate value of "have_ssl" variable to know whether to test or not for SSL-provided crypto functions. mysql-test/r/func_digest.result: Test against the sample test vectors in the NIST Secure Hash Standard (http://csrc.nist.gov/cryptval/shs.htm) mysql-test/r/func_encrypt_nossl.result: Update results to the new error message text. mysql-test/r/have_ssl_is_yes_or_disabled_only.require: Distinguish between communication and crypto. Use the tristate value of "have_ssl" variable to know whether to test or not for SSL-provided crypto functions. mysql-test/suite/rpl/t/rpl_ssl.test: Distinguish between communication and crypto. mysql-test/suite/rpl/t/rpl_ssl1.test: Distinguish between communication and crypto. mysql-test/t/func_des_encrypt.test: Distinguish between communication and crypto. mysql-test/t/func_digest.test: Test against the sample test vectors in the NIST Secure Hash Standard (http://csrc.nist.gov/cryptval/shs.htm) Also, test that various parameters (legal and illegal) do what we expect. --- Distinguish between communication and crypto. mysql-test/t/func_encrypt.test: Distinguish between communication and crypto. mysql-test/t/openssl_1.test: Don't test SSL communication if we're in the embedded server. --- Distinguish between communication and crypto. mysql-test/t/ssl-big.test: Don't test SSL communication if we're in the embedded server. --- Distinguish between communication and crypto. mysql-test/t/ssl.test: Don't test SSL communication if we're in the embedded server. --- Distinguish between communication and crypto. mysql-test/t/ssl_8k_key.test: Don't test SSL communication if we're in the embedded server. --- Distinguish between communication and crypto. mysql-test/t/ssl_compress.test: Don't test SSL communication if we're in the embedded server. --- Distinguish between communication and crypto. mysql-test/t/ssl_connect.test: Don't test SSL communication if we're in the embedded server. --- Distinguish between communication and crypto. sql-common/client.c: SSL is useful for more functionality than just connecting. Test for whether we are not embedded server also. sql/CMakeLists.txt: Add new source file to source list so that we have access to SHA2 functions. sql/Makefile.am: Add new source file to source list so that we have access to SHA2 functions. sql/item_create.cc: Bootstrap the SHA2 function into the server. sql/item_strfunc.cc: Add new SHA2 Item class methods. Clean up two minor problems. --- Remove extraneous debugging. --- We must check nullness of a parameter only /after/ computing its value. sql/item_strfunc.h: Declare new SHA2 Item class. sql/mysqld.cc: For embedded server, don't refer to SSL-communications variables or values. --- Remove CPP condition indentation. sql/sha2.cc: Compatibility layer to make YaSSL behave like OpenSSL. --- Add comment for generated functions. sql/sql_acl.cc: For embedded server, don't refer to SSL-communications variables or values. sql/sql_connect.cc: SSL is useful for more functionality than just connecting. Test for whether we are not embedded server also. sql/sys_vars.cc: For embedded server, don't refer to SSL-communications variables or values. --- sql/CMakeLists.txt | 2 +- sql/Makefile.am | 3 +- sql/item_create.cc | 23 ++++++++ sql/item_strfunc.cc | 153 +++++++++++++++++++++++++++++++++++++++++++++++++--- sql/item_strfunc.h | 12 +++++ sql/mysqld.cc | 26 +++++---- sql/sha2.cc | 68 +++++++++++++++++++++++ sql/sql_acl.cc | 4 +- sql/sql_connect.cc | 10 ++-- sql/sys_vars.cc | 2 +- 10 files changed, 276 insertions(+), 27 deletions(-) create mode 100644 sql/sha2.cc (limited to 'sql') diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 31110c5e201..396c8b1fd27 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -41,7 +41,7 @@ ENDIF() SET (SQL_SOURCE ../sql-common/client.c derror.cc des_key_file.cc discover.cc ../libmysql/errmsg.c field.cc field_conv.cc - filesort.cc gstream.cc + filesort.cc gstream.cc sha2.cc ha_partition.cc handler.cc hash_filo.cc hash_filo.h sql_plugin_services.h hostname.cc init.cc item.cc item_buff.cc item_cmpfunc.cc diff --git a/sql/Makefile.am b/sql/Makefile.am index 696f608c879..93595a964eb 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -167,7 +167,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ sql_plugin.cc sql_binlog.cc \ sql_builtin.cc sql_tablespace.cc partition_info.cc \ sql_servers.cc event_parse_data.cc sql_signal.cc \ - rpl_handler.cc mdl.cc transaction.cc sql_audit.cc + rpl_handler.cc mdl.cc transaction.cc sql_audit.cc \ + sha2.cc nodist_mysqld_SOURCES = mini_client_errors.c pack.c client.c my_time.c my_user.c diff --git a/sql/item_create.cc b/sql/item_create.cc index beb7b40dc18..5f30a10d1e0 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -1834,6 +1834,19 @@ protected: }; +class Create_func_sha2 : public Create_func_arg2 +{ +public: + virtual Item* create(THD *thd, Item *arg1, Item *arg2); + + static Create_func_sha2 s_singleton; + +protected: + Create_func_sha2() {} + virtual ~Create_func_sha2() {} +}; + + class Create_func_sign : public Create_func_arg1 { public: @@ -4363,6 +4376,15 @@ Create_func_sha::create(THD *thd, Item *arg1) } +Create_func_sha2 Create_func_sha2::s_singleton; + +Item* +Create_func_sha2::create(THD *thd, Item *arg1, Item *arg2) +{ + return new (thd->mem_root) Item_func_sha2(arg1, arg2); +} + + Create_func_sign Create_func_sign::s_singleton; Item* @@ -4973,6 +4995,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("SEC_TO_TIME") }, BUILDER(Create_func_sec_to_time)}, { { C_STRING_WITH_LEN("SHA") }, BUILDER(Create_func_sha)}, { { C_STRING_WITH_LEN("SHA1") }, BUILDER(Create_func_sha)}, + { { C_STRING_WITH_LEN("SHA2") }, BUILDER(Create_func_sha2)}, { { C_STRING_WITH_LEN("SIGN") }, BUILDER(Create_func_sign)}, { { C_STRING_WITH_LEN("SIN") }, BUILDER(Create_func_sin)}, { { C_STRING_WITH_LEN("SLEEP") }, BUILDER(Create_func_sleep)}, diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 9ae15322265..32baae87c50 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -29,6 +29,8 @@ #pragma implementation // gcc: Class implementation #endif +/* May include caustic 3rd-party defs. Use early, so it can override nothing. */ +#include "sha2.h" #include "my_global.h" // HAVE_* @@ -94,9 +96,9 @@ String *Item_str_ascii_func::val_str(String *str) Used to generate a hexadecimal representation of a message digest. */ -static void array_to_hex(char *to, const char *str, uint len) +static void array_to_hex(char *to, const unsigned char *str, uint len) { - const char *str_end= str + len; + const unsigned char *str_end= str + len; for (; str != str_end; ++str) { *to++= _dig_vec_lower[((uchar) *str) >> 4]; @@ -175,7 +177,7 @@ String *Item_func_md5::val_str_ascii(String *str) null_value=1; return 0; } - array_to_hex((char *) str->ptr(), (const char*) digest, 16); + array_to_hex((char *) str->ptr(), digest, 16); str->length((uint) 32); return str; } @@ -216,7 +218,7 @@ String *Item_func_sha::val_str_ascii(String *str) if (!( str->alloc(SHA1_HASH_SIZE*2) || (mysql_sha1_result(&context,digest)))) { - array_to_hex((char *) str->ptr(), (const char*) digest, SHA1_HASH_SIZE); + array_to_hex((char *) str->ptr(), digest, SHA1_HASH_SIZE); str->length((uint) SHA1_HASH_SIZE*2); null_value=0; return str; @@ -240,6 +242,144 @@ void Item_func_sha::fix_length_and_dec() fix_length_and_charset(SHA1_HASH_SIZE * 2, default_charset()); } +String *Item_func_sha2::val_str(String *str) +{ + DBUG_ASSERT(fixed == 1); +#ifdef HAVE_OPENSSL + unsigned char digest_buf[SHA512_DIGEST_LENGTH]; + String *input_string; + unsigned char *input_ptr; + size_t input_len; + uint digest_length= 0; + + str->set_charset(&my_charset_bin); + + input_string= args[0]->val_str(str); + if (input_string == NULL) + { + null_value= TRUE; + return (String *) NULL; + } + + null_value= args[0]->null_value; + if (null_value) + return (String *) NULL; + + input_ptr= (unsigned char *) input_string->ptr(); + input_len= input_string->length(); + + switch ((uint) args[1]->val_int()) { +#ifndef OPENSSL_NO_SHA512 + case 512: + digest_length= SHA512_DIGEST_LENGTH; + (void) SHA512(input_ptr, input_len, digest_buf); + break; + case 384: + digest_length= SHA384_DIGEST_LENGTH; + (void) SHA384(input_ptr, input_len, digest_buf); + break; +#endif +#ifndef OPENSSL_NO_SHA256 + case 224: + digest_length= SHA224_DIGEST_LENGTH; + (void) SHA224(input_ptr, input_len, digest_buf); + break; + case 256: + case 0: // SHA-256 is the default + digest_length= SHA256_DIGEST_LENGTH; + (void) SHA256(input_ptr, input_len, digest_buf); + break; +#endif + default: + if (!args[1]->const_item()) + push_warning_printf(current_thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WRONG_PARAMETERS_TO_NATIVE_FCT, + ER(ER_WRONG_PARAMETERS_TO_NATIVE_FCT), "sha2"); + null_value= TRUE; + return NULL; + } + + /* + Since we're subverting the usual String methods, we must make sure that + the destination has space for the bytes we're about to write. + */ + str->realloc((uint) digest_length*2 + 1); /* Each byte as two nybbles */ + + /* Convert the large number to a string-hex representation. */ + array_to_hex((char *) str->ptr(), digest_buf, digest_length); + + /* We poked raw bytes in. We must inform the the String of its length. */ + str->length((uint) digest_length*2); /* Each byte as two nybbles */ + + null_value= FALSE; + return str; + +#else + push_warning_printf(current_thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_FEATURE_DISABLED, + ER(ER_FEATURE_DISABLED), + "sha2", "--with-ssl"); + null_value= TRUE; + return (String *) NULL; +#endif +} + + +void Item_func_sha2::fix_length_and_dec() +{ + maybe_null = 1; + max_length = 0; + +#if defined(HAVE_OPENSSL) + int sha_variant= args[1]->const_item() ? args[1]->val_int() : 512; + + switch (sha_variant) { +#ifndef OPENSSL_NO_SHA512 + case 512: + max_length= SHA512_DIGEST_LENGTH*2; + break; + case 384: + max_length= SHA384_DIGEST_LENGTH*2; + break; +#endif +#ifndef OPENSSL_NO_SHA256 + case 256: + case 0: // SHA-256 is the default + max_length= SHA256_DIGEST_LENGTH*2; + break; + case 224: + max_length= SHA224_DIGEST_LENGTH*2; + break; +#endif + default: + push_warning_printf(current_thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WRONG_PARAMETERS_TO_NATIVE_FCT, + ER(ER_WRONG_PARAMETERS_TO_NATIVE_FCT), "sha2"); + } + + /* + The SHA2() function treats its parameter as being a case sensitive. + Thus we set binary collation on it so different instances of SHA2() + will be compared properly. + */ + + args[0]->collation.set( + get_charset_by_csname( + args[0]->collation.collation->csname, + MY_CS_BINSORT, + MYF(0)), + DERIVATION_COERCIBLE); +#else + push_warning_printf(current_thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_FEATURE_DISABLED, + ER(ER_FEATURE_DISABLED), + "sha2", "--with-ssl"); +#endif +} /* Implementation of AES encryption routines */ @@ -510,7 +650,6 @@ String *Item_func_des_encrypt::val_str(String *str) return 0; // ENCRYPT(NULL) == NULL if ((res_length=res->length()) == 0) return &my_empty_string; - if (arg_count == 1) { /* Protect against someone doing FLUSH DES_KEY_FILE */ @@ -583,7 +722,7 @@ error: #else push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN, ER_FEATURE_DISABLED, ER(ER_FEATURE_DISABLED), - "des_encrypt","--with-openssl"); + "des_encrypt", "--with-ssl"); #endif /* HAVE_OPENSSL */ null_value=1; return 0; @@ -661,7 +800,7 @@ wrong_key: #else push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN, ER_FEATURE_DISABLED, ER(ER_FEATURE_DISABLED), - "des_decrypt","--with-openssl"); + "des_decrypt", "--with-ssl"); #endif /* HAVE_OPENSSL */ null_value=1; return 0; diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index e3008a5daab..7b7f8d3308a 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -82,6 +82,18 @@ public: const char *func_name() const { return "sha"; } }; +class Item_func_sha2 :public Item_str_func +{ +public: + Item_func_sha2(Item *a, Item *b) :Item_str_func(a, b) + { + collation.set(&my_charset_bin); + } + String *val_str(String *); + void fix_length_and_dec(); + const char *func_name() const { return "sha2"; } +}; + class Item_func_aes_encrypt :public Item_str_func { public: diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 2bc47849915..b35e2545a18 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -957,7 +957,9 @@ static void openssl_lock(int, openssl_lock_t *, const char *, int); static unsigned long openssl_id_function(); #endif char *des_key_file; +#ifndef EMBEDDED_LIBRARY struct st_VioSSLFd *ssl_acceptor_fd; +#endif #endif /* HAVE_OPENSSL */ /** @@ -1003,8 +1005,8 @@ static void clean_up_mutexes(void); static void wait_for_signal_thread_to_end(void); static void create_pid_file(); static void mysqld_exit(int exit_code) __attribute__((noreturn)); -static void end_ssl(); #endif +static void end_ssl(); #ifndef EMBEDDED_LIBRARY @@ -1524,9 +1526,7 @@ void clean_up(bool print_message) #endif delete binlog_filter; delete rpl_filter; -#ifndef EMBEDDED_LIBRARY end_ssl(); -#endif vio_end(); #ifdef USE_REGEX my_regex_end(); @@ -3916,11 +3916,10 @@ static void openssl_lock(int mode, openssl_lock_t *lock, const char *file, #endif /* HAVE_OPENSSL */ -#ifndef EMBEDDED_LIBRARY - static void init_ssl() { #ifdef HAVE_OPENSSL +#ifndef EMBEDDED_LIBRARY if (opt_use_ssl) { enum enum_ssl_init_error error= SSL_INITERR_NOERROR; @@ -3942,6 +3941,9 @@ static void init_ssl() { have_ssl= SHOW_OPTION_DISABLED; } +#else + have_ssl= SHOW_OPTION_DISABLED; +#endif /* ! EMBEDDED_LIBRARY */ if (des_key_file) load_des_key_file(des_key_file); #endif /* HAVE_OPENSSL */ @@ -3951,16 +3953,16 @@ static void init_ssl() static void end_ssl() { #ifdef HAVE_OPENSSL +#ifndef EMBEDDED_LIBRARY if (ssl_acceptor_fd) { free_vio_ssl_acceptor_fd(ssl_acceptor_fd); ssl_acceptor_fd= 0; } +#endif /* ! EMBEDDED_LIBRARY */ #endif /* HAVE_OPENSSL */ } -#endif /* EMBEDDED_LIBRARY */ - static int init_server_components() { @@ -6434,7 +6436,7 @@ static int show_table_definitions(THD *thd, SHOW_VAR *var, char *buff) return 0; } -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) /* Functions relying on CTX */ static int show_ssl_ctx_sess_accept(THD *thd, SHOW_VAR *var, char *buff) { @@ -6690,7 +6692,7 @@ static int show_ssl_get_cipher_list(THD *thd, SHOW_VAR *var, char *buff) return 0; } -#endif /* HAVE_OPENSSL */ +#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ /* @@ -6781,6 +6783,7 @@ SHOW_VAR status_vars[]= { {"Sort_rows", (char*) offsetof(STATUS_VAR, filesort_rows), SHOW_LONG_STATUS}, {"Sort_scan", (char*) offsetof(STATUS_VAR, filesort_scan_count), SHOW_LONG_STATUS}, #ifdef HAVE_OPENSSL +#ifndef EMBEDDED_LIBRARY {"Ssl_accept_renegotiates", (char*) &show_ssl_ctx_sess_accept_renegotiate, SHOW_FUNC}, {"Ssl_accepts", (char*) &show_ssl_ctx_sess_accept, SHOW_FUNC}, {"Ssl_callback_cache_hits", (char*) &show_ssl_ctx_sess_cb_hits, SHOW_FUNC}, @@ -6804,6 +6807,7 @@ SHOW_VAR status_vars[]= { {"Ssl_verify_depth", (char*) &show_ssl_get_verify_depth, SHOW_FUNC}, {"Ssl_verify_mode", (char*) &show_ssl_get_verify_mode, SHOW_FUNC}, {"Ssl_version", (char*) &show_ssl_get_version, SHOW_FUNC}, +#endif #endif /* HAVE_OPENSSL */ {"Table_locks_immediate", (char*) &locks_immediate, SHOW_LONG}, {"Table_locks_waited", (char*) &locks_waited, SHOW_LONG}, @@ -7103,8 +7107,10 @@ static int mysql_init_variables(void) #endif #ifdef HAVE_OPENSSL des_key_file = 0; +#ifndef EMBEDDED_LIBRARY ssl_acceptor_fd= 0; -#endif +#endif /* ! EMBEDDED_LIBRARY */ +#endif /* HAVE_OPENSSL */ #ifdef HAVE_SMEM shared_memory_base_name= default_shared_memory_base_name; #endif diff --git a/sql/sha2.cc b/sql/sha2.cc new file mode 100644 index 00000000000..1a9de86f2e0 --- /dev/null +++ b/sql/sha2.cc @@ -0,0 +1,68 @@ +/* Copyright (C) 2007 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +/** + @file + A compatibility layer to our built-in SSL implementation, to mimic the + oft-used external library, OpenSSL. +*/ + +#include +#include + +#ifdef HAVE_YASSL + +/* + If TaoCrypt::SHA512 or ::SHA384 are not defined (but ::SHA256 is), it's + probably that neither of config.h's SIZEOF_LONG or SIZEOF_LONG_LONG are + 64 bits long. At present, both OpenSSL and YaSSL require 64-bit integers + for SHA-512. (The SIZEOF_* definitions come from autoconf's config.h .) +*/ + +# define GEN_YASSL_SHA2_BRIDGE(size) \ +unsigned char* SHA##size(const unsigned char *input_ptr, size_t input_length, \ + char unsigned *output_ptr) { \ + TaoCrypt::SHA##size hasher; \ + \ + hasher.Update(input_ptr, input_length); \ + hasher.Final(output_ptr); \ + return(output_ptr); \ +} + + +/** + @fn SHA512 + @fn SHA384 + @fn SHA256 + @fn SHA224 + + Instantiate an hash object, fill in the cleartext value, compute the digest, + and extract the result from the object. + + (Generate the functions. See similar .h code for the prototypes.) +*/ +# ifndef OPENSSL_NO_SHA512 +GEN_YASSL_SHA2_BRIDGE(512); +GEN_YASSL_SHA2_BRIDGE(384); +# else +# warning Some SHA2 functionality is missing. See OPENSSL_NO_SHA512. +# endif +GEN_YASSL_SHA2_BRIDGE(256); +GEN_YASSL_SHA2_BRIDGE(224); + +# undef GEN_YASSL_SHA2_BRIDGE + +#endif /* HAVE_YASSL */ diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index a5e5b4ec2a1..f8be3ff6d4a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -929,7 +929,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, if (acl_user) { /* OK. User found and password checked continue validation */ -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) Vio *vio=thd->net.vio; SSL *ssl= (SSL*) vio->ssl_arg; X509 *cert; @@ -946,7 +946,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, case SSL_TYPE_NONE: // SSL is not required user_access= acl_user->access; break; -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) case SSL_TYPE_ANY: // Any kind of SSL is ok if (vio_type(vio) == VIO_TYPE_SSL) user_access= acl_user->access; diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index cfcf1754581..e2d0977def7 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -36,7 +36,7 @@ // reset_host_errors #include "sql_acl.h" // acl_getroot, NO_ACCESS, SUPER_ACL -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) /* Without SSL the handshake consists of one packet. This packet has both client capabilites and scrambled password. @@ -52,7 +52,7 @@ #define MIN_HANDSHAKE_SIZE 2 #else #define MIN_HANDSHAKE_SIZE 6 -#endif /* HAVE_OPENSSL */ +#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ /* Get structure for logging connection data for the current user @@ -654,6 +654,7 @@ bool init_new_connection_handler_thread() return 0; } +#ifndef EMBEDDED_LIBRARY /* Perform handshake, authorize client and update thd ACL variables. @@ -667,7 +668,6 @@ bool init_new_connection_handler_thread() > 0 error code (not sent to user) */ -#ifndef EMBEDDED_LIBRARY static int check_connection(THD *thd) { uint connect_errors= 0; @@ -749,7 +749,7 @@ static int check_connection(THD *thd) #ifdef HAVE_COMPRESS server_capabilites|= CLIENT_COMPRESS; #endif /* HAVE_COMPRESS */ -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) if (ssl_acceptor_fd) { server_capabilites |= CLIENT_SSL; /* Wow, SSL is available! */ @@ -827,7 +827,7 @@ static int check_connection(THD *thd) if (thd->client_capabilities & CLIENT_IGNORE_SPACE) thd->variables.sql_mode|= MODE_IGNORE_SPACE; -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities)); if (thd->client_capabilities & CLIENT_SSL) { diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 3cb1e90b124..ea86bcc227f 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1923,7 +1923,7 @@ static Sys_var_set Sys_sql_mode( sql_mode_names, DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_sql_mode), ON_UPDATE(fix_sql_mode)); -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) #define SSL_OPT(X) CMD_LINE(REQUIRED_ARG,X) #else #define SSL_OPT(X) NO_CMD_LINE -- cgit v1.2.1 From 4288e329dd9676494a9e3927e61492e975277112 Mon Sep 17 00:00:00 2001 From: Konstantin Osipov Date: Wed, 14 Apr 2010 01:56:19 +0400 Subject: A fix for Bug#11918 "SP does not accept variables in LIMIT clause" Allow stored procedure variables in LIMIT clause. Only allow variables of INTEGER types. Handle negative values by means of an implicit cast to UNSIGNED (similarly to prepared statement placeholders). Add tests. Make sure replication works by not doing NAME_CONST substitution for variables in LIMIT clause. Add replication tests. mysql-test/r/sp.result: Update results (Bug#11918). mysql-test/suite/rpl/r/rpl_sp.result: Update results (Bug#11918). mysql-test/suite/rpl/t/rpl_sp.test: Add a test case for Bug#11918. mysql-test/t/sp.test: Add a test case for Bug#11918. sql/item.cc: Mark sp variables in LIMIT clause (a hack for replication). sql/item.h: Mark sp variables in LIMIT clause (a hack for replication). sql/share/errmsg-utf8.txt: Add a new error message (a type mismatch for LIMIT clause parameter). sql/sp_head.cc: Binlog rewrite sp variables in LIMIT clause without NAME_CONST substitution. sql/sql_string.cc: Implement append_ulonglong method. sql/sql_string.h: Declare append_ulonglong(). sql/sql_yacc.yy: Support stored procedure variables in LIMIT. --- sql/item.cc | 4 +++- sql/item.h | 7 +++++++ sql/share/errmsg-utf8.txt | 3 +++ sql/sp_head.cc | 11 ++++++++++- sql/sql_string.cc | 10 ++++++++++ sql/sql_string.h | 1 + sql/sql_yacc.yy | 35 ++++++++++++++++++++++++++++++++++- 7 files changed, 68 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 209d5aa0197..4199f8a409a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1186,7 +1186,9 @@ Item_splocal::Item_splocal(const LEX_STRING &sp_var_name, enum_field_types sp_var_type, uint pos_in_q, uint len_in_q) :Item_sp_variable(sp_var_name.str, sp_var_name.length), - m_var_idx(sp_var_idx), pos_in_query(pos_in_q), len_in_query(len_in_q) + m_var_idx(sp_var_idx), + limit_clause_param(FALSE), + pos_in_query(pos_in_q), len_in_query(len_in_q) { maybe_null= TRUE; diff --git a/sql/item.h b/sql/item.h index 4241074c659..11b4199da2c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1302,6 +1302,13 @@ class Item_splocal :public Item_sp_variable, Item_result m_result_type; enum_field_types m_field_type; public: + /* + Is this variable a parameter in LIMIT clause. + Used only during NAME_CONST substitution, to not append + NAME_CONST to the resulting query and thus not break + the slave. + */ + bool limit_clause_param; /* Position of this reference to SP variable in the statement (the statement itself is in sp_instr_stmt::m_query). diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 517782cb0b4..3acf990e00d 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6327,3 +6327,6 @@ ER_LOCK_ABORTED ER_DATA_OUT_OF_RANGE 22003 eng "%s value is out of range in '%s'" + +ER_WRONG_SPVAR_TYPE_IN_LIMIT + eng "A variable of a non-integer type in LIMIT clause" diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 62d53888149..c91ba2a68b4 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -978,11 +978,20 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) res|= qbuf.append(cur + prev_pos, (*splocal)->pos_in_query - prev_pos); prev_pos= (*splocal)->pos_in_query + (*splocal)->len_in_query; + res|= (*splocal)->fix_fields(thd, (Item **) splocal); + if (res) + break; + + if ((*splocal)->limit_clause_param) + { + res|= qbuf.append_ulonglong((*splocal)->val_uint()); + continue; + } + /* append the spvar substitute */ res|= qbuf.append(STRING_WITH_LEN(" NAME_CONST('")); res|= qbuf.append((*splocal)->m_name.str, (*splocal)->m_name.length); res|= qbuf.append(STRING_WITH_LEN("',")); - res|= (*splocal)->fix_fields(thd, (Item **) splocal); if (res) break; diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 75e8ca30cf0..9fbc06b7529 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -405,6 +405,16 @@ bool String::append(const char *s) } + +bool String::append_ulonglong(ulonglong val) +{ + if (realloc(str_length+MAX_BIGINT_WIDTH+2)) + return TRUE; + char *end= (char*) longlong10_to_str(val, (char*) Ptr + str_length, 10); + str_length= end - Ptr; + return FALSE; +} + /* Append a string in the given charset to the string with character set recoding diff --git a/sql/sql_string.h b/sql/sql_string.h index f67d6de9a0f..debfb7aa9c6 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -267,6 +267,7 @@ public: bool append(const char *s); bool append(const char *s,uint32 arg_length); bool append(const char *s,uint32 arg_length, CHARSET_INFO *cs); + bool append_ulonglong(ulonglong val); bool append(IO_CACHE* file, uint32 arg_length); bool append_with_prefill(const char *s, uint32 arg_length, uint32 full_length, char fill_char); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 207e72404ef..a0d64e6a378 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9830,7 +9830,40 @@ limit_options: ; limit_option: - param_marker + ident + { + Item_splocal *splocal; + THD *thd= YYTHD; + LEX *lex= thd->lex; + Lex_input_stream *lip= & thd->m_parser_state->m_lip; + sp_variable_t *spv; + sp_pcontext *spc = lex->spcont; + if (spc && (spv = spc->find_variable(&$1))) + { + splocal= new (thd->mem_root) + Item_splocal($1, spv->offset, spv->type, + lip->get_tok_start() - lex->sphead->m_tmp_query, + lip->get_ptr() - lip->get_tok_start()); + if (splocal == NULL) + MYSQL_YYABORT; +#ifndef DBUG_OFF + splocal->m_sp= lex->sphead; +#endif + lex->safe_to_cache_query=0; + } + else + { + my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str); + MYSQL_YYABORT; + } + if (splocal->type() != Item::INT_ITEM) + { + my_error(ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0)); + MYSQL_YYABORT; + } + splocal->limit_clause_param= TRUE; + $$= splocal; + } | param_marker { ((Item_param *) $1)->limit_clause_param= TRUE; } -- cgit v1.2.1 From 8e7939167d3fd3482038fbc052672e049b52c667 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 15 Apr 2010 13:05:17 +0400 Subject: BUG#47059 - In audit plugin I cannot see the event subclasses, e.g.MYSQL_AUDIT_GENERAL_ERROR General audit API (MYSQL_AUDIT_GENERAL_CLASS) didn't expose event subclass to plugins. This patch exposes event subclass to plugins via struct mysql_event_general::event_subclass. This change is not compatible with existing general audit plugins. Audit interface major version has been incremented. include/mysql/plugin_audit.h: Expose event subclass to audit general plugins. plugin/audit_null/audit_null.c: Added distinct counters for general event sub-classes. Removed printf() from deinit(). One can easily see number of calls via status variables. To make code nicer, modified class mask to use macro instead of hardcoded number. Incremented audit plugin minor version. sql/sql_audit.cc: Expose event subclass to audit general plugins. --- sql/sql_audit.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/sql_audit.cc b/sql/sql_audit.cc index 5190cba64de..412de9225e8 100644 --- a/sql/sql_audit.cc +++ b/sql/sql_audit.cc @@ -65,6 +65,7 @@ static void general_class_handler(THD *thd, uint event_subtype, va_list ap) { mysql_event_general event; event.event_class= MYSQL_AUDIT_GENERAL_CLASS; + event.event_subclass= event_subtype; event.general_error_code= va_arg(ap, int); event.general_thread_id= thd ? thd->thread_id : 0; event.general_time= va_arg(ap, time_t); -- cgit v1.2.1 From 20f5c421e7a70fa4338da34ab123002cf9b00ad3 Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Tue, 20 Apr 2010 10:10:43 +0100 Subject: BUG#51894 Replication failure with SBR on DROP TEMPORARY TABLE inside a transaction BUG#52616 Temp table prevents switch binlog format from STATEMENT to ROW Before the WL#2687 and BUG#46364, every non-transactional change that happened after a transactional change was written to trx-cache and flushed upon committing the transaction. WL#2687 and BUG#46364 changed this behavior and non-transactional changes are now written to the binary log upon committing the statement. A binary log event is identified as transactional or non-transactional through a flag in the Log_event which is set taking into account the underlie storage engine on what it is stems from. In the current bug, this flag was not being set properly when the DROP TEMPORARY TABLE was executed. However, while fixing this bug we figured out that changes to temporary tables should be always written to the trx-cache if there is an on-going transaction. Otherwise, binlog events in the reversed order would be produced. Regarding concurrency, keeping changes to temporary tables in the trx-cache is also safe as temporary tables are only visible to the owner connection. In this patch, we classify the following statements as unsafe: 1 - INSERT INTO t_myisam SELECT * FROM t_myisam_temp 2 - INSERT INTO t_myisam_temp SELECT * FROM t_myisam 3 - CREATE TEMPORARY TABLE t_myisam_temp SELECT * FROM t_myisam On the other hand, the following statements are classified as safe: 1 - INSERT INTO t_innodb SELECT * FROM t_myisam_temp 2 - INSERT INTO t_myisam_temp SELECT * FROM t_innodb The patch also guarantees that transactions that have a DROP TEMPORARY are always written to the binary log regardless of the mode and the outcome: commit or rollback. In particular, the DROP TEMPORARY is extended with the IF EXISTS clause when the current statement logging format is set to row. Finally, the patch allows to switch from STATEMENT to MIXED/ROW when there are temporary tables but the contrary is not possible. mysql-test/extra/rpl_tests/rpl_binlog_max_cache_size.test: Updated the test case because CREATE TEMPORARY TABLE t_innodb_temp SELECT * FROM t_myisam is not unsafe. mysql-test/extra/rpl_tests/rpl_implicit_commit_binlog.test: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/extra/rpl_tests/rpl_innodb.test: Removed comments from the test case that became false after the patch. mysql-test/extra/rpl_tests/rpl_loaddata.test: Suppressed warning messages due to the following cases: 1 - INSERT INTO t_myisam SELECT * FROM t_myisam_temp 2 - INSERT INTO t_myisam_temp SELECT * FROM t_myisam mysql-test/include/ctype_utf8_table.inc: Suppressed warning messages due to the following cases: 1 - INSERT INTO t_myisam SELECT * FROM t_myisam_temp 2 - INSERT INTO t_myisam_temp SELECT * FROM t_myisam mysql-test/r/ctype_cp932_binlog_stm.result: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/suite/binlog/r/binlog_database.result: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/suite/binlog/r/binlog_innodb_row.result: Updated the result file. mysql-test/suite/binlog/r/binlog_multi_engine.result: Updated the unsafe message. mysql-test/suite/binlog/r/binlog_row_binlog.result: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/suite/binlog/r/binlog_row_drop_tmp_tbl.result: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/suite/binlog/r/binlog_stm_binlog.result: Updated the result file. mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/suite/binlog/t/binlog_tmp_table.test: Suppressed warning messages due to the following cases: 1 - INSERT INTO t_myisam SELECT * FROM t_myisam_temp 2 - INSERT INTO t_myisam_temp SELECT * FROM t_myisam mysql-test/suite/ndb/r/ndb_binlog_format.result: Updated the unsafe message. mysql-test/suite/rpl/r/rpl_concurrency_error.result: Updated the unsafe message. mysql-test/suite/rpl/r/rpl_mixed_binlog_max_cache_size.result: Updated the result file because CREATE TEMPORARY TABLE t_innodb_temp SELECT * FROM t_myisam is not unsafe. mysql-test/suite/rpl/r/rpl_mixed_implicit_commit_binlog.result: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/suite/rpl/r/rpl_mixed_mixing_engines.result: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/suite/rpl/r/rpl_mixed_row_innodb.result: Added some comments to ease the understanding of the result file. mysql-test/suite/rpl/r/rpl_non_direct_mixed_mixing_engines.result: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/suite/rpl/r/rpl_non_direct_row_mixing_engines.result: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/suite/rpl/r/rpl_non_direct_stm_mixing_engines.result: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/suite/rpl/r/rpl_row_drop.result: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/suite/rpl/r/rpl_row_implicit_commit_binlog.result: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/suite/rpl/r/rpl_row_mixing_engines.result: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/suite/rpl/r/rpl_stm_binlog_max_cache_size.result: Updated the result file because CREATE TEMPORARY TABLE t_innodb_temp SELECT * FROM t_myisam is not unsafe. mysql-test/suite/rpl/r/rpl_stm_implicit_commit_binlog.result: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/suite/rpl/r/rpl_stm_innodb.result: Added some comments to ease the understanding of the result file. mysql-test/suite/rpl/r/rpl_stm_mixing_engines.result: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/suite/rpl/r/rpl_stm_stop_middle_group.result: Updated the unsafe message. mysql-test/suite/rpl/r/rpl_temp_temporary.result: Added a test case. mysql-test/suite/rpl/t/rpl000013.test: Suppressed warning messages due to the following cases: 1 - INSERT INTO t_myisam SELECT * FROM t_myisam_temp 2 - INSERT INTO t_myisam_temp SELECT * FROM t_myisam 3 - CREATE TEMPORARY TABLE t_myisam_temp SELECT * FROM t_myisam mysql-test/suite/rpl/t/rpl_misc_functions.test: Suppressed warning messages. mysql-test/suite/rpl/t/rpl_temp_table.test: Suppressed warning messages due to the following cases: 1 - INSERT INTO t_myisam SELECT * FROM t_myisam_temp 2 - INSERT INTO t_myisam_temp SELECT * FROM t_myisam 3 - CREATE TEMPORARY TABLE t_myisam_temp SELECT * FROM t_myisam mysql-test/suite/rpl/t/rpl_temp_temporary.test: Added a test case. mysql-test/suite/rpl/t/rpl_temporary.test: Suppressed warning messages due to the following cases: 1 - INSERT INTO t_myisam SELECT * FROM t_myisam_temp 2 - INSERT INTO t_myisam_temp SELECT * FROM t_myisam 3 - CREATE TEMPORARY TABLE t_myisam_temp SELECT * FROM t_myisam mysql-test/suite/rpl_ndb/r/rpl_ndb_row_implicit_commit_binlog.result: Updated the test case due to the new rules: changes to temporary tables are written to the binary log in the boundaries of a transaction if there is any. mysql-test/suite/rpl_ndb/r/rpl_truncate_7ndb.result: Updated the test case to remove references to positions in the binary log. mysql-test/suite/rpl_ndb/t/rpl_truncate_7ndb.test: Updated the test case to remove references to positions in the binary log. mysql-test/t/create_select_tmp.test: Suppressed warning messages due to the following cases: 1 - INSERT INTO t_myisam SELECT * FROM t_myisam_temp 2 - INSERT INTO t_myisam_temp SELECT * FROM t_myisam 3 - CREATE TEMPORARY TABLE t_myisam_temp SELECT * FROM t_myisam mysql-test/t/ctype_cp932_binlog_stm.test: Suppressed warning messages due to the following cases: 1 - INSERT INTO t_myisam SELECT * FROM t_myisam_temp 2 - INSERT INTO t_myisam_temp SELECT * FROM t_myisam 3 - CREATE TEMPORARY TABLE t_myisam_temp SELECT * FROM t_myisam mysql-test/t/mysqlbinlog.test: Suppressed warning messages due to the following cases: 1 - INSERT INTO t_myisam SELECT * FROM t_myisam_temp 2 - INSERT INTO t_myisam_temp SELECT * FROM t_myisam 3 - CREATE TEMPORARY TABLE t_myisam_temp SELECT * FROM t_myisam sql/log.cc: Improved the code by creating several functions to hide decision on type of engine changed, commit/abort, etc: . stmt_has_updated_non_trans_table . trans_has_updated_non_trans_table . ending_trans Updated the binlog_rollback function and the use of the OPTION_KEEP_LOG which indincates when a temporary table was either created or dropped and as such the command must be logged if not in MIXED mode and even while rolling back the transaction. sql/log.h: Improved the code by creating several functions to hide decision on type of engine changed, commit/abort, etc. sql/log_event.cc: Removed the setting of the OPTION_KEEP_LOG as it is related to CREATE TEMPORARY and DROP TEMPORARY and not to the type of engine (i.e. transactional or non-transactional). sql/log_event_old.cc: Removed the setting of the OPTION_KEEP_LOG as it is related to CREATE TEMPORARY and DROP TEMPORARY and not to the type of engine (i.e. transactional or non-transactional). sql/share/errmsg-utf8.txt: Updated the unsafe message. sql/sql_class.cc: Classifies the following statements as unsafe: 1 - INSERT INTO t_myisam SELECT * FROM t_myisam_temp 2 - INSERT INTO t_myisam_temp SELECT * FROM t_myisam On the other hand, the following statements are classified as safe: 1 - INSERT INTO t_innodb SELECT * FROM t_myisam_temp 2 - INSERT INTO t_myisam_temp SELECT * FROM t_innodb sql/sql_class.h: It allows to switch from STATEMENT to MIXED/ROW when there are temporary tables but the contrary is not possible. sql/sql_table.cc: Fixed the case that a DROP/DROP TEMPORARY that affects a temporary table in MIXED mode is written as a DROP TEMPORARY TABLE IF EXISTS because the table may not exist in the slave and due to the IF EXISTS token an error will never happen while processing the statement in the slave. Removed a function that was not being used. --- sql/log.cc | 85 +++++++++++++++++++++++++++++++++++------------ sql/log.h | 3 ++ sql/log_event.cc | 23 ++++++------- sql/log_event_old.cc | 10 ------ sql/share/errmsg-utf8.txt | 2 +- sql/sql_class.cc | 77 +++++++++++++++++++++++++++++++++++++++--- sql/sql_class.h | 4 +-- sql/sql_table.cc | 67 ++++++++++++------------------------- 8 files changed, 173 insertions(+), 98 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index 92ffcc58961..18f812d96bf 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1576,7 +1576,7 @@ binlog_truncate_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr, bool all) inside a transaction, we reset the transaction cache. */ thd->binlog_remove_pending_rows_event(TRUE, is_transactional); - if (all || !thd->in_multi_stmt_transaction()) + if (ending_trans(thd, all)) { if (cache_mngr->trx_cache.has_incident()) error= mysql_bin_log.write_incident(thd, TRUE); @@ -1682,12 +1682,11 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) DBUG_ENTER("binlog_commit"); binlog_cache_mngr *const cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); - bool const in_transaction= thd->in_multi_stmt_transaction(); DBUG_PRINT("debug", ("all: %d, in_transaction: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s", all, - YESNO(in_transaction), + YESNO(thd->in_multi_stmt_transaction()), YESNO(thd->transaction.all.modified_non_trans_table), YESNO(thd->transaction.stmt.modified_non_trans_table))); @@ -1711,7 +1710,7 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) - We are in a transaction and a full transaction is committed. Otherwise, we accumulate the changes. */ - if (!in_transaction || all) + if (ending_trans(thd, all)) { Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE, TRUE, 0); error= binlog_flush_trx_cache(thd, cache_mngr, &qev); @@ -1789,29 +1788,28 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) { /* We flush the cache wrapped in a beging/rollback if: - . aborting a transcation that modified a non-transactional table or; - . aborting a statement that modified both transactional and - non-transctional tables but which is not in the boundaries of any - transaction; + . aborting a single or multi-statement transaction and; + . the format is STMT and non-trans engines were updated or; . the OPTION_KEEP_LOG is activate. */ - if (thd->variables.binlog_format == BINLOG_FORMAT_STMT && - ((all && thd->transaction.all.modified_non_trans_table) || - (!all && thd->transaction.stmt.modified_non_trans_table && - !thd->in_multi_stmt_transaction()) || - (thd->variables.option_bits & OPTION_KEEP_LOG))) + if (ending_trans(thd, all) && + ((thd->variables.option_bits & OPTION_KEEP_LOG) || + (trans_has_updated_non_trans_table(thd) && + thd->variables.binlog_format == BINLOG_FORMAT_STMT))) { Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE, TRUE, 0); error= binlog_flush_trx_cache(thd, cache_mngr, &qev); } /* - Otherwise, we simply truncate the cache as there is no change on - non-transactional tables as follows. + Truncate the cache if: + . aborting a single or multi-statement transaction or; + . the OPTION_KEEP_LOG is not activate and; + . the format is not STMT or no non-trans were updated. */ - else if (all || (!all && - (!thd->transaction.stmt.modified_non_trans_table || - !thd->in_multi_stmt_transaction() || - thd->variables.binlog_format != BINLOG_FORMAT_STMT))) + else if (ending_trans(thd, all) || + (!(thd->variables.option_bits & OPTION_KEEP_LOG) && + ((!stmt_has_updated_non_trans_table(thd) || + thd->variables.binlog_format != BINLOG_FORMAT_STMT)))) error= binlog_truncate_trx_cache(thd, cache_mngr, all); } @@ -1909,7 +1907,7 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) non-transactional table. Otherwise, truncate the binlog cache starting from the SAVEPOINT command. */ - if (unlikely(thd->transaction.all.modified_non_trans_table || + if (unlikely(trans_has_updated_non_trans_table(thd) || (thd->variables.option_bits & OPTION_KEEP_LOG))) { int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); @@ -4257,6 +4255,49 @@ bool use_trans_cache(const THD* thd, bool is_transactional) (is_transactional || !cache_mngr->trx_cache.empty())); } +/** + This function checks if a transaction, either a multi-statement + or a single statement transaction is about to commit or not. + + @param thd The client thread that executed the current statement. + @param all Committing a transaction (i.e. TRUE) or a statement + (i.e. FALSE). + @return + @c true if committing a transaction, otherwise @c false. +*/ +bool ending_trans(THD* thd, const bool all) +{ + return (all || (!all && !thd->in_multi_stmt_transaction())); +} + +/** + This function checks if a non-transactional table was updated by + the current transaction. + + @param thd The client thread that executed the current statement. + @return + @c true if a non-transactional table was updated, @c false + otherwise. +*/ +bool trans_has_updated_non_trans_table(const THD* thd) +{ + return (thd->transaction.all.modified_non_trans_table || + thd->transaction.stmt.modified_non_trans_table); +} + +/** + This function checks if a non-transactional table was updated by the + current statement. + + @param thd The client thread that executed the current statement. + @return + @c true if a non-transactional table was updated, @c false otherwise. +*/ +bool stmt_has_updated_non_trans_table(const THD* thd) +{ + return (thd->transaction.stmt.modified_non_trans_table); +} + /* These functions are placed in this file since they need access to binlog_hton, which has internal linkage. @@ -4539,7 +4580,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, { set_write_error(thd); if (check_write_error(thd) && cache_data && - thd->transaction.stmt.modified_non_trans_table) + stmt_has_updated_non_trans_table(thd)) cache_data->set_incident(); DBUG_RETURN(1); } @@ -4740,7 +4781,7 @@ unlock: { set_write_error(thd); if (check_write_error(thd) && cache_data && - thd->transaction.stmt.modified_non_trans_table) + stmt_has_updated_non_trans_table(thd)) cache_data->set_incident(); } } diff --git a/sql/log.h b/sql/log.h index 71c27f50f78..12e02969485 100644 --- a/sql/log.h +++ b/sql/log.h @@ -26,6 +26,9 @@ class Format_description_log_event; bool trans_has_updated_trans_table(const THD* thd); bool stmt_has_updated_trans_table(const THD *thd); bool use_trans_cache(const THD* thd, bool is_transactional); +bool ending_trans(THD* thd, const bool all); +bool trans_has_updated_non_trans_table(const THD* thd); +bool stmt_has_updated_non_trans_table(const THD* thd); /* Transaction Coordinator log - a base abstract class diff --git a/sql/log_event.cc b/sql/log_event.cc index fc097414726..3a52b72909a 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -679,6 +679,7 @@ Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans) server_id= thd->server_id; when= thd->start_time; cache_type= (using_trans || stmt_has_updated_trans_table(thd) + || thd->thread_specific_used ? Log_event::EVENT_TRANSACTIONAL_CACHE : Log_event::EVENT_STMT_CACHE); } @@ -2470,6 +2471,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, */ LEX *lex= thd->lex; bool implicit_commit= FALSE; + bool force_trans= FALSE; cache_type= Log_event::EVENT_INVALID_CACHE; switch (lex->sql_command) { @@ -2483,14 +2485,16 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, implicit_commit= TRUE; break; case SQLCOM_DROP_TABLE: - implicit_commit= !(lex->drop_temporary && thd->in_multi_stmt_transaction()); + force_trans= lex->drop_temporary && thd->in_multi_stmt_transaction(); + implicit_commit= !force_trans; 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 && - thd->is_current_stmt_binlog_format_row()); + force_trans= (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) && + thd->in_multi_stmt_transaction(); + implicit_commit= !force_trans && + !(lex->select_lex.item_list.elements && + thd->is_current_stmt_binlog_format_row()); break; case SQLCOM_SET_OPTION: implicit_commit= (lex->autocommit ? TRUE : FALSE); @@ -2548,7 +2552,8 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, } else { - cache_type= (using_trans || stmt_has_updated_trans_table(thd) + cache_type= ((using_trans || stmt_has_updated_trans_table(thd) || + force_trans || thd->thread_specific_used) ? Log_event::EVENT_TRANSACTIONAL_CACHE : Log_event::EVENT_STMT_CACHE); } @@ -7733,12 +7738,6 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) clear_all_errors(thd, const_cast(rli)); error= 0; } - - if (!use_trans_cache()) - { - DBUG_PRINT("info", ("Marked that we need to keep log")); - thd->variables.option_bits|= OPTION_KEEP_LOG; - } } // if (table) diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index a80e8f4b1a2..f6c5b5d1023 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -241,11 +241,6 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info DBUG_EXECUTE_IF("stop_slave_middle_group", const_cast(rli)->abort_slave= 1;); error= do_after_row_operations(table, error); - if (!ev->use_trans_cache()) - { - DBUG_PRINT("info", ("Marked that we need to keep log")); - ev_thd->variables.option_bits|= OPTION_KEEP_LOG; - } } if (error) @@ -1683,11 +1678,6 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli) DBUG_EXECUTE_IF("stop_slave_middle_group", const_cast(rli)->abort_slave= 1;); error= do_after_row_operations(rli, error); - if (!use_trans_cache()) - { - DBUG_PRINT("info", ("Marked that we need to keep log")); - thd->variables.option_bits|= OPTION_KEEP_LOG; - } } // if (table) if (error) diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 927de5adff4..1308ad0ebcf 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6335,4 +6335,4 @@ 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." + eng "Statements that read from both transactional (or a temporary table of any engine type) 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 d07bfdc6abf..88f67175d02 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3661,19 +3661,80 @@ 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; + /* + Every temporary table must be always written to the binary + log in transaction boundaries and as such we artificially + classify them as transactional. + + Indirectly, this avoids classifying a temporary table created + on a non-transactional engine as unsafe when it is modified + after any transactional table: + + BEGIN; + INSERT INTO innodb_t VALUES (1); + INSERT INTO myisam_t_temp VALUES (1); + COMMIT; + + BINARY LOG: + + BEGIN; + INSERT INTO innodb_t VALUES (1); + INSERT INTO myisam_t_temp VALUES (1); + COMMIT; + */ all_trans_write_engines= all_trans_write_engines && - table->table->file->has_transactions(); + (table->table->file->has_transactions() || + table->table->s->tmp_table); prev_write_table= table->table; 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) + /* + The mixture of non-transactional and transactional tables must + identified and classified as unsafe. However, a temporary table + must be always handled as a transactional table. Based on that, + we have the following statements classified as mixed and by + consequence as unsafe: + + 1: INSERT INTO myisam_t SELECT * FROM innodb_t; + + 2: INSERT INTO innodb_t SELECT * FROM myisam_t; + + 3: INSERT INTO myisam_t SELECT * FROM myisam_t_temp; + + 4: INSERT INTO myisam_t_temp SELECT * FROM myisam_t; + + 5: CREATE TEMPORARY TABLE myisam_t_temp SELECT * FROM mysiam_t; + + The following statements are not considered mixed and as such + are safe: + + 1: INSERT INTO innodb_t SELECT * FROM myisam_t_temp; + + 2: INSERT INTO myisam_t_temp SELECT * FROM innodb_t_temp; + */ + if (!trans_non_trans_access_engines && prev_access_table && + (lex->sql_command != SQLCOM_CREATE_TABLE || + (lex->sql_command == SQLCOM_CREATE_TABLE && + (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)))) { + my_bool prev_trans; + my_bool act_trans; + if (prev_access_table->s->tmp_table || table->table->s->tmp_table) + { + prev_trans= prev_access_table->s->tmp_table ? TRUE : + prev_access_table->file->has_transactions(); + act_trans= table->table->s->tmp_table ? TRUE : + table->table->file->has_transactions(); + } + else + { + prev_trans= prev_access_table->file->has_transactions(); + act_trans= table->table->file->has_transactions(); + } + trans_non_trans_access_engines= (prev_trans != act_trans); 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; } @@ -3710,6 +3771,12 @@ int THD::decide_logging_format(TABLE_LIST *tables) 2: INSERT INTO innodb_t SELECT * FROM myisam_t; + 3: INSERT INTO myisam_t SELECT * FROM myisam_t_temp; + + 4: INSERT INTO myisam_t_temp SELECT * FROM myisam_t; + + 5: CREATE TEMPORARY TABLE myisam_t_temp SELECT * FROM mysiam_t; + are classified as unsafe to ensure that in mixed mode the execution is completely safe and equivalent to the row mode. Consider the following statements and sessions (connections) to understand the reason: diff --git a/sql/sql_class.h b/sql/sql_class.h index 950db01d1cd..c75d91baada 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2531,11 +2531,11 @@ public: ("temporary_tables: %s, in_sub_stmt: %s, system_thread: %s", YESNO(temporary_tables), YESNO(in_sub_stmt), show_system_thread(system_thread))); - if ((temporary_tables == NULL) && (in_sub_stmt == 0)) + if (in_sub_stmt == 0) { if (variables.binlog_format == BINLOG_FORMAT_ROW) set_current_stmt_binlog_format_row(); - else + else if (temporary_tables == NULL) clear_current_stmt_binlog_format_row(); } DBUG_VOID_RETURN; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c3a39354ff1..709fee07aac 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1998,8 +1998,13 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, case 0: // removed temporary table tmp_table_deleted= 1; - if (thd->variables.binlog_format == BINLOG_FORMAT_MIXED && - thd->is_current_stmt_binlog_format_row()) + /* + One needs to always log any temporary table drop if the current + statement logging format is set to row. This happens because one + might have created a temporary table while the statement logging + format was statement and then switched to mixed or row format. + */ + if (thd->is_current_stmt_binlog_format_row()) { if (built_tmp_query.is_empty()) { @@ -2191,7 +2196,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, deleted one or more non-temporary tables (and no temporary tables). In this case, we can write the original query into the binary log. - */ + */ error |= write_bin_log(thd, !error, thd->query(), thd->query_length()); } else if (thd->is_current_stmt_binlog_format_row() && @@ -2218,11 +2223,12 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, } /* - One needs to always log any temporary table drop, if: - 1. thread logging format is mixed mode; AND - 2. current statement logging format is set to row. + One needs to always log any temporary table drop if the current + statement logging format is set to row. This happens because one + might have created a temporary table while the statement logging + format was statement and then switched to mixed or row format. */ - if (thd->variables.binlog_format == BINLOG_FORMAT_MIXED) + if (thd->is_current_stmt_binlog_format_row()) { /* In this case we have deleted some temporary tables but we are using @@ -2233,8 +2239,14 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, */ built_tmp_query.chop(); // Chop of the last comma built_tmp_query.append(" /* generated by server */"); - error|= write_bin_log(thd, !error, built_tmp_query.ptr(), built_tmp_query.length(), - thd->in_multi_stmt_transaction()); + /* + We cannot call the write_bin_log as we do not care about any errors + in the master as the statement is always DROP TEMPORARY TABLE IF EXISTS + and as such there will be no errors in the slave. + */ + error|= thd->binlog_query(THD::STMT_QUERY_TYPE, built_tmp_query.ptr(), + built_tmp_query.length(), FALSE, FALSE, FALSE, + 0); } } @@ -3749,43 +3761,6 @@ void sp_prepare_create_field(THD *thd, Create_field *sql_field) (void) prepare_blob_field(thd, sql_field); } - -/* - Write CREATE TABLE binlog - - SYNOPSIS - write_create_table_bin_log() - thd Thread object - create_info Create information - internal_tmp_table Set to 1 if this is an internal temporary table - - DESCRIPTION - This function only is called in mysql_create_table_no_lock and - mysql_create_table - - RETURN VALUES - NONE - */ -static inline int write_create_table_bin_log(THD *thd, - const HA_CREATE_INFO *create_info, - bool internal_tmp_table) -{ - /* - Don't write statement if: - - It is an internal temporary table, - - Row-based logging is used and it we are creating a temporary table, or - - The binary log is not open. - Otherwise, the statement shall be binlogged. - */ - if (!internal_tmp_table && - (!thd->is_current_stmt_binlog_format_row() || - (thd->is_current_stmt_binlog_format_row() && - !(create_info->options & HA_LEX_CREATE_TMP_TABLE)))) - return write_bin_log(thd, TRUE, thd->query(), thd->query_length()); - return 0; -} - - /* Create a table -- cgit v1.2.1