diff --git a/mysql-test/suite/galera_3nodes/r/galera_toi_vote.result b/mysql-test/suite/galera_3nodes/r/galera_toi_vote.result index d8d3abe40e9..345fa92c13d 100644 --- a/mysql-test/suite/galera_3nodes/r/galera_toi_vote.result +++ b/mysql-test/suite/galera_3nodes/r/galera_toi_vote.result @@ -7,8 +7,9 @@ connection node_3; SET SESSION wsrep_on=OFF; DROP SCHEMA test; connection node_1; +SET SESSION lc_messages='fr_FR'; CREATE SCHEMA test; -ERROR HY000: Can't create database 'test'; database exists +ERROR HY000: Ne peut créer la base 'test'; elle existe déjà connection node_1; SET SESSION wsrep_sync_wait=0; connection node_2; diff --git a/mysql-test/suite/galera_3nodes/t/galera_toi_vote.test b/mysql-test/suite/galera_3nodes/t/galera_toi_vote.test index 6bc87cf8874..bd53c510cd4 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_toi_vote.test +++ b/mysql-test/suite/galera_3nodes/t/galera_toi_vote.test @@ -24,6 +24,9 @@ DROP SCHEMA test; # This should fail on nodes 1 and 2 and succeed on node 3 --connection node_1 +# Make error message on source node different by changing locale +# It should still agree with node 2 +SET SESSION lc_messages='fr_FR'; --error ER_DB_CREATE_EXISTS CREATE SCHEMA test; diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc index 513e17b3045..0ec8e6e7f47 100644 --- a/sql/wsrep_applier.cc +++ b/sql/wsrep_applier.cc @@ -82,7 +82,9 @@ wsrep_get_apply_format(THD* thd) return thd->wsrep_rgi->rli->relay_log.description_event_for_exec; } -void wsrep_store_error(const THD* const thd, wsrep::mutable_buffer& dst) +void wsrep_store_error(const THD* const thd, + wsrep::mutable_buffer& dst, + bool const include_msg) { Diagnostics_area::Sql_condition_iterator it= thd->get_stmt_da()->sql_conditions(); @@ -100,8 +102,16 @@ void wsrep_store_error(const THD* const thd, wsrep::mutable_buffer& dst) uint const err_code= cond->get_sql_errno(); const char* const err_str= cond->get_message_text(); - slider+= my_snprintf(slider, buf_end - slider, " %s, Error_code: %d;", - err_str, err_code); + if (include_msg) + { + slider+= snprintf(slider, buf_end - slider, " %s, Error_code: %d;", + err_str, err_code); + } + else + { + slider+= snprintf(slider, buf_end - slider, " Error_code: %d;", + err_code); + } } if (slider != dst.data()) diff --git a/sql/wsrep_applier.h b/sql/wsrep_applier.h index fefca306a70..e633b1b9bf2 100644 --- a/sql/wsrep_applier.h +++ b/sql/wsrep_applier.h @@ -35,7 +35,21 @@ int wsrep_apply_events(THD* thd, #define WSREP_ERR_FAILED 6 // Operation failed for some internal reason #define WSREP_ERR_ABORTED 7 // Operation was aborted externally -void wsrep_store_error(const THD* thd, wsrep::mutable_buffer& buf); +/* Loops over THD diagnostic area and concatenates all error messages + * and error codes to a single continuous buffer to create a unique + * but consistent failure signature which provider can use for voting + * between the nodes in the cluster. + * + * @param thd THD context + * @param dst buffer to store the signature + * @param include_msg whether to use MySQL error message in addition to + * MySQL error code. Note that in the case of a TOI + * operation the message may be not consistent between + * the nodes e.g. due to a different client locale setting + * and should be omitted */ +void wsrep_store_error(const THD* thd, + wsrep::mutable_buffer& buf, + bool include_msg); class Format_description_log_event; void wsrep_set_apply_format(THD*, Format_description_log_event*); diff --git a/sql/wsrep_high_priority_service.cc b/sql/wsrep_high_priority_service.cc index 7eb3f07849a..2c0e2e643fa 100644 --- a/sql/wsrep_high_priority_service.cc +++ b/sql/wsrep_high_priority_service.cc @@ -123,14 +123,15 @@ static void wsrep_setup_uk_and_fk_checks(THD* thd) static int apply_events(THD* thd, Relay_log_info* rli, const wsrep::const_buffer& data, - wsrep::mutable_buffer& err) + wsrep::mutable_buffer& err, + bool const include_msg) { int const ret= wsrep_apply_events(thd, rli, data.data(), data.size()); if (ret || wsrep_thd_has_ignored_error(thd)) { if (ret) { - wsrep_store_error(thd, err); + wsrep_store_error(thd, err, include_msg); } wsrep_dump_rbr_buf_with_header(thd, data.data(), data.size()); } @@ -427,7 +428,7 @@ int Wsrep_high_priority_service::apply_toi(const wsrep::ws_meta& ws_meta, #endif thd->set_time(); - int ret= apply_events(thd, m_rli, data, err); + int ret= apply_events(thd, m_rli, data, err, false); wsrep_thd_set_ignored_error(thd, false); trans_commit(thd); @@ -595,7 +596,7 @@ int Wsrep_applier_service::apply_write_set(const wsrep::ws_meta& ws_meta, #endif /* ENABLED_DEBUG_SYNC */ wsrep_setup_uk_and_fk_checks(thd); - int ret= apply_events(thd, m_rli, data, err); + int ret= apply_events(thd, m_rli, data, err, true); thd->close_temporary_tables(); if (!ret && !(ws_meta.flags() & wsrep::provider::flag::commit)) @@ -764,7 +765,7 @@ int Wsrep_replayer_service::apply_write_set(const wsrep::ws_meta& ws_meta, ws_meta, thd->wsrep_sr().fragments()); } - ret= ret || apply_events(thd, m_rli, data, err); + ret= ret || apply_events(thd, m_rli, data, err, true); thd->close_temporary_tables(); if (!ret && !(ws_meta.flags() & wsrep::provider::flag::commit)) { diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index e584c2cc144..6bb879a0367 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -2489,7 +2489,10 @@ static void wsrep_TOI_end(THD *thd) { if (thd->is_error() && !wsrep_must_ignore_error(thd)) { - wsrep_store_error(thd, err); + /* use only error code, for the message can be inconsistent + * between the nodes due to differing lc_message settings + * in client session and server applier thread */ + wsrep_store_error(thd, err, false); } int const ret= client_state.leave_toi_local(err);