From 84f933d15b16cba54c4b82b9f8dff75aed6bce72 Mon Sep 17 00:00:00 2001 From: Przemyslaw Skibinski Date: Fri, 1 Apr 2022 12:25:44 +0200 Subject: [PATCH] FB8-93: output symbolic errno for 'SHOW SLAVE STATUS' (#940) (#940) Summary: JIRA: https://jira.percona.com/browse/FB8-93 Reference Patch: https://github.com/facebook/mysql-5.6/commit/a2b0c32 Reference Patch: https://github.com/facebook/mysql-5.6/commit/e82ab5a Instead of just showing the errno when running SHOW SLAVE STATUS command, also printing the error name so that user won't have misunderstanding Pull Request resolved: https://github.com/facebook/mysql-5.6/pull/940 Reviewed By: lloyd Differential Revision: D13924591 Pulled By: lth --------------------------------------------------------------------------------------------- SHOW SLAVE STATUS shows real error Summary: In parallel replication SHOW SLAVE STATUS doesn't show the actual error. It actually creates the real error (Slave_reporting_capability::va_report) and set m_last_error right after setting coordinator error so we just need to reverse the order of the two and show the real error in coordinator. Accessing the last error is protected by err_lock and also fallback to previous message in case the error number is 0 and can't be trusted, just in case. Reviewed By: hermanlee, Pushapgl Differential Revision: D28925760 --- client/mysqldump.cc | 4 +- include/my_sys.h | 1 + include/mysys_err.h | 9 +- mysql-test/include/check-testcase.test | 3 +- mysql-test/r/disabled_replication.result | 2 +- mysys/errors.cc | 258 ++++++++++++++--------- sql/rpl_replica.cc | 13 ++ sql/rpl_rli_pdb.cc | 84 ++++---- utilities/perror.cc | 2 +- 9 files changed, 232 insertions(+), 144 deletions(-) diff --git a/client/mysqldump.cc b/client/mysqldump.cc index e34c16d8e423..96ccc068d1fb 100644 --- a/client/mysqldump.cc +++ b/client/mysqldump.cc @@ -5390,8 +5390,8 @@ static int do_show_slave_status(MYSQL *mysql_con) { const int n_master_host = 1; const int n_master_port = 3; const int n_master_log_file = 9; - const int n_master_log_pos = 21; - const int n_channel_name = 55; + const int n_master_log_pos = 21 + 1 /* Last_Symbolic_Errno */; + const int n_channel_name = 55 + 1 /* Last_Symbolic_Errno */; MYSQL_ROW row = mysql_fetch_row(slave); /* Since 5.7 is is possible that SSS returns multiple channels */ while (row) { diff --git a/include/my_sys.h b/include/my_sys.h index 3664e95b72b4..f18d001a0874 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -660,6 +660,7 @@ extern void my_osmaperr(unsigned long last_error); #endif extern const char *get_global_errmsg(int nr); +extern const char *get_global_errname(int nr); extern void wait_for_free_space(const char *filename, int errors); extern FILE *my_fopen(const char *filename, int Flags, myf MyFlags); extern FILE *my_fdopen(File fd, const char *filename, int Flags, myf MyFlags); diff --git a/include/mysys_err.h b/include/mysys_err.h index 2dace6be8909..5d34819f7530 100644 --- a/include/mysys_err.h +++ b/include/mysys_err.h @@ -27,12 +27,17 @@ @file include/mysys_err.h */ +struct my_glob_errors { + const char *errname; /* error name */ + const char *errdesc; /* error description */ +}; + #define GLOBERRS \ (EE_ERROR_LAST - EE_ERROR_FIRST + 1) /* Nr of global errors \ */ -#define EE(X) (globerrs[(X)-EE_ERROR_FIRST]) +#define EE(X) (globerrs[(X)-EE_ERROR_FIRST].errdesc) -extern const char *globerrs[]; /* my_error_messages is here */ +extern const struct my_glob_errors globerrs[]; /* my_error_messages is here */ /* Error message numbers in global map */ /* diff --git a/mysql-test/include/check-testcase.test b/mysql-test/include/check-testcase.test index 9d0484ce58dc..84c007a271fd 100644 --- a/mysql-test/include/check-testcase.test +++ b/mysql-test/include/check-testcase.test @@ -46,6 +46,7 @@ if ($tmp) { --echo Replicate_Wild_Do_Table # --echo Replicate_Wild_Ignore_Table # --echo Last_Errno 0 + --echo Last_Symbolic_Errno --echo Last_Error --echo Skip_Counter 0 --echo Exec_Source_Log_Pos # @@ -91,7 +92,7 @@ if ($tmp) { if (!$tmp) { # Note: after WL#5177, fields 13-18 shall not be filtered-out. - --replace_column 4 # 5 # 6 # 7 # 8 # 9 # 10 # 13 # 14 # 15 # 16 # 17 # 18 # 22 # 23 # 24 # 25 # 26 # 40 # 41 # 42 # 46 # 52 # 53 # 55 # 56 # + --replace_column 4 # 5 # 6 # 7 # 8 # 9 # 10 # 13 # 14 # 15 # 16 # 17 # 18 # 23 # 24 # 25 # 26 # 27 # 41 # 42 # 43 # 47 # 53 # 54 # 56 # 57 # query_vertical SHOW REPLICA STATUS; } diff --git a/mysql-test/r/disabled_replication.result b/mysql-test/r/disabled_replication.result index a3f22cd25c95..0f05dcdb59e2 100644 --- a/mysql-test/r/disabled_replication.result +++ b/mysql-test/r/disabled_replication.result @@ -1,5 +1,5 @@ SHOW SLAVE STATUS; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_UUID Master_Info_File SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Master_Retry_Count Master_Bind Last_IO_Error_Timestamp Last_SQL_Error_Timestamp Master_SSL_Crl Master_SSL_Crlpath Retrieved_Gtid_Set Executed_Gtid_Set Auto_Position Replicate_Rewrite_DB Channel_Name Master_TLS_Version Master_public_key_path Get_master_public_key Network_Namespace +Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Symbolic_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id Master_UUID Master_Info_File SQL_Delay SQL_Remaining_Delay Slave_SQL_Running_State Master_Retry_Count Master_Bind Last_IO_Error_Timestamp Last_SQL_Error_Timestamp Master_SSL_Crl Master_SSL_Crlpath Retrieved_Gtid_Set Executed_Gtid_Set Auto_Position Replicate_Rewrite_DB Channel_Name Master_TLS_Version Master_public_key_path Get_master_public_key Network_Namespace Warnings: Warning 1287 'SHOW SLAVE STATUS' is deprecated and will be removed in a future release. Please use SHOW REPLICA STATUS instead RESET SLAVE; diff --git a/mysys/errors.cc b/mysys/errors.cc index 432d0e2f5995..7ac93801f71e 100644 --- a/mysys/errors.cc +++ b/mysys/errors.cc @@ -41,106 +41,156 @@ #include "my_thread_local.h" #include "mysys_err.h" -const char *globerrs[GLOBERRS] = { - "Can't create/write to file '%s' (OS errno %d - %s)", - "Error reading file '%s' (OS errno %d - %s)", - "Error writing file '%s' (OS errno %d - %s)", - "Error on close of '%s' (OS errno %d - %s)", - "Out of memory (Needed %u bytes)", - "Error on delete of '%s' (OS errno %d - %s)", - "Error on rename of '%s' to '%s' (OS errno %d - %s)", - "", - "Unexpected EOF found when reading file '%s' (OS errno %d - %s)", - "Can't lock file (OS errno %d - %s)", - "Can't unlock file (OS errno %d - %s)", - "Can't read dir of '%s' (OS errno %d - %s)", - "Can't get stat of '%s' (OS errno %d - %s)", - "Can't change size of file (OS errno %d - %s)", - "Can't open stream from handle (OS errno %d - %s)", - "Can't get working directory (OS errno %d - %s)", - "Can't change dir to '%s' (OS errno %d - %s)", - "Warning: '%s' had %d links", - "Warning: %d files and %d streams are left open", - "Disk is full writing '%s' (OS errno %d - %s). Waiting for someone to free " - "space...", - "Can't create directory '%s' (OS errno %d - %s)", - "Character set '%s' is not a compiled character set and is not specified " - "in the '%s' file", - "Out of resources when opening file '%s' (OS errno %d - %s)", - "Can't read value for symlink '%s' (Error %d - %s)", - "Can't create symlink '%s' pointing at '%s' (Error %d - %s)", - "Error on realpath() on '%s' (Error %d - %s)", - "Can't sync file '%s' to disk (OS errno %d - %s)", - "Collation '%s' is not a compiled collation and is not specified in the " - "'%s' file", - "File '%s' not found (OS errno %d - %s)", - "File '%s' (fileno: %d) was not closed", - "Cannot change ownership of the file '%s' (OS errno %d - %s)", - "Cannot change permissions of the file '%s' (OS errno %d - %s)", - "Cannot seek in file '%s' (OS errno %d - %s)", - "Memory capacity exceeded (capacity %llu bytes)", - "Disk is full writing '%s' (OS errno %d - %s). Waiting for someone to free " - "space... Retry in %d secs. Message reprinted in %d secs.", - "Failed to create timer (OS errno %d).", - "Failed to delete timer (OS errno %d).", - "Failed to create timer queue (OS errno %d).", - "Failed to start timer notify thread.", - "Failed to create event to interrupt timer notifier thread (OS errno %d).", - "Failed to register timer event with queue (OS errno %d), exiting timer " - "notifier thread.", - "LoadLibrary(\"kernel32.dll\") failed: GetLastError returns %lu.", - "%s.", - "Failed to determine large page size.", - "Error in my_thread_global_end(): %d thread(s) did not exit.", - "Failed to create IO completion port (OS errno %d).", - "Failed to open required defaults file: %s", - "Fatal error in defaults handling. Program aborted!", - "Wrong '!%s' directive in config file %s at line %d.", - "Skipping '%s' directive as maximum include recursion level was" - " reached in file %s at line %d.", - "Wrong group definition in config file %s at line %d.", - "Found option without preceding group in config file %s at line %d.", - "%s should be readable/writable only by current user.", - "World-writable config file '%s' is ignored.", - "%s: Option '%s' was used, but is disabled.", - "%s: Option '-%c' was used, but is disabled.", - "Using a password on the command line interface can be insecure.", - "Unknown suffix '%c' used for variable '%s' (value '%s').", - "SSL error: %s from '%s'.", - "SSL error: %s.", - "%d %s.", - "Packets out of order (found %u, expected %u).", - "Unknown option to protocol: %s.", - "Failed to locate server public key '%s'.", - "Public key is not in Privacy Enhanced Mail format: '%s'.", - "%s.", - "unknown variable '%s'.", - "unknown option '--%s'.", - "%s: unknown option '-%c'.", - "%s: option '--%s' cannot take an argument.", - "%s: option '--%s' requires an argument.", - "%s: option '-%c' requires an argument.", - "%s: ignoring option '--%s' due to invalid value '%s'.", - "%s: Empty value for '%s' specified.", - "%s: Maximum value of '%s' cannot be set.", - "option '%s': boolean value '%s' was not recognized. Set to OFF.", - "%s: Error while setting value '%s' to '%s'.", - "Incorrect integer value: '%s'.", - "Incorrect unsigned integer value: '%s'.", - "option '%s': signed value %s adjusted to %s.", - "option '%s': unsigned value %s adjusted to %s.", - "option '%s': value %s adjusted to %s.", - "option '%s': value %g adjusted to %g.", - "Invalid decimal value for option '%s'.", - "%s.", - "Failed to reset before a primary ignorable character %s.", - "Failed to reset before a tertiary ignorable character %s.", - "Shift character out of range: %s.", - "Reset character out of range: %s.", - "Unknown LDML tag: '%.*s'.", - "Failed to reset before a secondary ignorable character %s.", - "Stopped processing the '%s' directive in file %s at line %d.", - "pthread_kill(thread_id:%lu, signal:%s) returned '%s'."}; +const struct my_glob_errors globerrs[GLOBERRS] = { + {"EE_CANTCREATEFILE", "Can't create/write to file '%s' (OS errno %d - %s)"}, + {"EE_READ", "Error reading file '%s' (OS errno %d - %s)"}, + {"EE_WRITE", "Error writing file '%s' (OS errno %d - %s)"}, + {"EE_BADCLOSE", "Error on close of '%s' (OS errno %d - %s)"}, + {"EE_OUTOFMEMORY", "Out of memory (Needed %u bytes)"}, + {"EE_DELETE", "Error on delete of '%s' (OS errno %d - %s)"}, + {"EE_LINK", "Error on rename of '%s' to '%s' (OS errno %d - %s)"}, + {"", ""}, + {"EE_EOFERR", + "Unexpected EOF found when reading file '%s' (OS errno %d - %s)"}, + {"EE_CANTLOCK", "Can't lock file (OS errno %d - %s)"}, + {"EE_CANTUNLOCK", "Can't unlock file (OS errno %d - %s)"}, + {"EE_DIR", "Can't read dir of '%s' (OS errno %d - %s)"}, + {"EE_STAT", "Can't get stat of '%s' (OS errno %d - %s)"}, + {"EE_CANT_CHSIZE", "Can't change size of file (OS errno %d - %s)"}, + {"EE_CANT_OPEN_STREAM", "Can't open stream from handle (OS errno %d - %s)"}, + {"EE_GETWD", "Can't get working directory (OS errno %d - %s)"}, + {"EE_SETWD", "Can't change dir to '%s' (OS errno %d - %s)"}, + {"EE_LINK_WARNING", "Warning: '%s' had %d links"}, + {"EE_OPEN_WARNING", "Warning: %d files and %d streams are left open"}, + {"EE_DISK_FULL", + "Disk is full writing '%s' (OS errno %d - %s). Waiting for someone to " + "free space..."}, + {"EE_CANT_MKDIR", "Can't create directory '%s' (OS errno %d - %s)"}, + {"EE_UNKNOWN_CHARSET", + "Character set '%s' is not a compiled character set and is not specified " + "in the '%s' file"}, + {"EE_OUT_OF_FILERESOURCES", + "Out of resources when opening file '%s' (OS errno %d - %s)"}, + {"EE_CANT_READLINK", "Can't read value for symlink '%s' (Error %d - %s)"}, + {"EE_CANT_SYMLINK", + "Can't create symlink '%s' pointing at '%s' (Error %d - %s)"}, + {"EE_REALPATH", "Error on realpath() on '%s' (Error %d - %s)"}, + {"EE_SYNC", "Can't sync file '%s' to disk (OS errno %d - %s)"}, + {"EE_UNKNOWN_COLLATION", + "Collation '%s' is not a compiled collation and is not specified in the " + "'%s' file"}, + {"EE_FILENOTFOUND", "File '%s' not found (OS errno %d - %s)"}, + {"EE_FILE_NOT_CLOSED", "File '%s' (fileno: %d) was not closed"}, + {"EE_CHANGE_OWNERSHIP", + "Cannot change ownership of the file '%s' (OS errno %d - %s)"}, + {"EE_CHANGE_PERMISSIONS", + "Cannot change permissions of the file '%s' (OS errno %d - %s)"}, + {"EE_CANT_SEEK", "Cannot seek in file '%s' (OS errno %d - %s)"}, + {"EE_CAPACITY_EXCEEDED", "Memory capacity exceeded (capacity %llu bytes)"}, + {"EE_DISK_FULL_WITH_RETRY_MSG", + "Disk is full writing '%s' (OS errno %d - %s). Waiting for someone to " + "free space... Retry in %d secs. Message reprinted in %d secs."}, + {"EE_FAILED_TO_CREATE_TIMER", "Failed to create timer (OS errno %d)."}, + {"EE_FAILED_TO_DELETE_TIMER", "Failed to delete timer (OS errno %d)."}, + {"EE_FAILED_TO_CREATE_TIMER_QUEUE", + "Failed to create timer queue (OS errno %d)."}, + {"EE_FAILED_TO_START_TIMER_NOTIFY_THREAD", + "Failed to start timer notify thread."}, + {"EE_FAILED_TO_CREATE_TIMER_NOTIFY_THREAD_INTERRUPT_EVENT", + "Failed to create event to interrupt timer notifier thread (OS errno " + "%d)."}, + {"EE_EXITING_TIMER_NOTIFY_THREAD", + "Failed to register timer event with queue (OS errno %d), exiting timer " + "notifier thread."}, + {"EE_WIN_LIBRARY_LOAD_FAILED", + "LoadLibrary(\"kernel32.dll\") failed: GetLastError returns %lu."}, + {"EE_WIN_RUN_TIME_ERROR_CHECK", "%s."}, + {"EE_FAILED_TO_DETERMINE_LARGE_PAGE_SIZE", + "Failed to determine large page size."}, + {"EE_FAILED_TO_KILL_ALL_THREADS", + "Error in my_thread_global_end(): %d thread(s) did not exit."}, + {"EE_FAILED_TO_CREATE_IO_COMPLETION_PORT", + "Failed to create IO completion port (OS errno %d)."}, + {"EE_FAILED_TO_OPEN_DEFAULTS_FILE", + "Failed to open required defaults file: %s"}, + {"EE_FAILED_TO_HANDLE_DEFAULTS_FILE", + "Fatal error in defaults handling. Program aborted!"}, + {"EE_WRONG_DIRECTIVE_IN_CONFIG_FILE", + "Wrong '!%s' directive in config file %s at line %d."}, + {"EE_SKIPPING_DIRECTIVE_DUE_TO_MAX_INCLUDE_RECURSION", + "Skipping '%s' directive as maximum include recursion level was" + " reached in file %s at line %d."}, + {"EE_INCORRECT_GRP_DEFINITION_IN_CONFIG_FILE", + "Wrong group definition in config file %s at line %d."}, + {"EE_OPTION_WITHOUT_GRP_IN_CONFIG_FILE", + "Found option without preceding group in config file %s at line %d."}, + {"EE_CONFIG_FILE_PERMISSION_ERROR", + "%s should be readable/writable only by current user."}, + {"EE_IGNORE_WORLD_WRITABLE_CONFIG_FILE", + "World-writable config file '%s' is ignored."}, + {"EE_USING_DISABLED_OPTION", "%s: Option '%s' was used, but is disabled."}, + {"EE_USING_DISABLED_SHORT_OPTION", + "%s: Option '-%c' was used, but is disabled."}, + {"EE_USING_PASSWORD_ON_CLI_IS_INSECURE", + "Using a password on the command line interface can be insecure."}, + {"EE_UNKNOWN_SUFFIX_FOR_VARIABLE", + "Unknown suffix '%c' used for variable '%s' (value '%s')."}, + {"EE_SSL_ERROR_FROM_FILE", "SSL error: %s from '%s'."}, + {"EE_SSL_ERROR", "SSL error: %s."}, + {"EE_NET_SEND_ERROR_IN_BOOTSTRAP", "%d %s."}, + {"EE_PACKETS_OUT_OF_ORDER", + "Packets out of order (found %u, expected %u)."}, + {"EE_UNKNOWN_PROTOCOL_OPTION", "Unknown option to protocol: %s."}, + {"EE_FAILED_TO_LOCATE_SERVER_PUBLIC_KEY", + "Failed to locate server public key '%s'."}, + {"EE_PUBLIC_KEY_NOT_IN_PEM_FORMAT", + "Public key is not in Privacy Enhanced Mail format: '%s'."}, + {"EE_DEBUG_INFO", "%s."}, + {"EE_UNKNOWN_VARIABLE", "unknown variable '%s'."}, + {"EE_UNKNOWN_OPTION", "unknown option '--%s'."}, + {"EE_UNKNOWN_SHORT_OPTION", "%s: unknown option '-%c'."}, + {"EE_OPTION_WITHOUT_ARGUMENT", + "%s: option '--%s' cannot take an argument."}, + {"EE_OPTION_REQUIRES_ARGUMENT", "%s: option '--%s' requires an argument."}, + {"EE_SHORT_OPTION_REQUIRES_ARGUMENT", + "%s: option '-%c' requires an argument."}, + {"EE_OPTION_IGNORED_DUE_TO_INVALID_VALUE", + "%s: ignoring option '--%s' due to invalid value '%s'."}, + {"EE_OPTION_WITH_EMPTY_VALUE", "%s: Empty value for '%s' specified."}, + {"EE_FAILED_TO_ASSIGN_MAX_VALUE_TO_OPTION", + "%s: Maximum value of '%s' cannot be set."}, + {"EE_INCORRECT_BOOLEAN_VALUE_FOR_OPTION", + "option '%s': boolean value '%s' was not recognized. Set to OFF."}, + {"EE_FAILED_TO_SET_OPTION_VALUE", + "%s: Error while setting value '%s' to '%s'."}, + {"EE_INCORRECT_INT_VALUE_FOR_OPTION", "Incorrect integer value: '%s'."}, + {"EE_INCORRECT_UINT_VALUE_FOR_OPTION", + "Incorrect unsigned integer value: '%s'."}, + {"EE_ADJUSTED_SIGNED_VALUE_FOR_OPTION", + "option '%s': signed value %s adjusted to %s."}, + {"EE_ADJUSTED_UNSIGNED_VALUE_FOR_OPTION", + "option '%s': unsigned value %s adjusted to %s."}, + {"EE_ADJUSTED_ULONGLONG_VALUE_FOR_OPTION", + "option '%s': value %s adjusted to %s."}, + {"EE_ADJUSTED_DOUBLE_VALUE_FOR_OPTION", + "option '%s': value %g adjusted to %g."}, + {"EE_INVALID_DECIMAL_VALUE_FOR_OPTION", + "Invalid decimal value for option '%s'."}, + {"EE_COLLATION_PARSER_ERROR", "%s."}, + {"EE_FAILED_TO_RESET_BEFORE_PRIMARY_IGNORABLE_CHAR", + "Failed to reset before a primary ignorable character %s."}, + {"EE_FAILED_TO_RESET_BEFORE_TERTIARY_IGNORABLE_CHAR", + "Failed to reset before a territory ignorable character %s."}, + {"EE_SHIFT_CHAR_OUT_OF_RANGE", "Shift character out of range: %s."}, + {"EE_RESET_CHAR_OUT_OF_RANGE", "Reset character out of range: %s."}, + {"EE_UNKNOWN_LDML_TAG", "Unknown LDML tag: '%.*s'."}, + {"EE_FAILED_TO_RESET_BEFORE_SECONDARY_IGNORABLE_CHAR", + "Failed to reset before a secondary ignorable character %s."}, + {"EE_FAILED_PROCESSING_DIRECTIVE", + "Stopped processing the '%s' directive in file %s at line %d."}, + {"EE_PTHREAD_KILL_FAILED", + "pthread_kill(thread_id:%lu, signal:%s) returned '%s'."}, +}; /* We cannot call my_error/my_printf_error here in this function. @@ -173,4 +223,10 @@ void wait_for_free_space(const char *filename, int errors) { } while (--time_to_sleep > 0 && !is_killed_hook(nullptr)); } -const char *get_global_errmsg(int nr) { return globerrs[nr - EE_ERROR_FIRST]; } +const char *get_global_errname(int nr) { + return globerrs[nr - EE_ERROR_FIRST].errname; +} + +const char *get_global_errmsg(int nr) { + return globerrs[nr - EE_ERROR_FIRST].errdesc; +} diff --git a/sql/rpl_replica.cc b/sql/rpl_replica.cc index 64201ad3104a..b5972e0996dd 100644 --- a/sql/rpl_replica.cc +++ b/sql/rpl_replica.cc @@ -99,6 +99,7 @@ #include "mysql/thread_type.h" #include "mysql_com.h" #include "mysqld_error.h" +#include "mysys_err.h" #include "pfs_thread_provider.h" #include "prealloced_array.h" #include "sql-common/net_ns.h" @@ -3349,6 +3350,7 @@ static void show_slave_status_metadata(mem_root_deque *field_list, field_list->push_back( new Item_empty_string("Replicate_Wild_Ignore_Table", 28)); field_list->push_back(new Item_return_int("Last_Errno", 4, MYSQL_TYPE_LONG)); + field_list->push_back(new Item_empty_string("Last_Symbolic_Errno", 20)); field_list->push_back(new Item_empty_string("Last_Error", 20)); field_list->push_back( new Item_return_int("Skip_Counter", 10, MYSQL_TYPE_LONG)); @@ -3504,6 +3506,17 @@ static bool show_slave_status_send_data(THD *thd, Master_info *mi, protocol->store(&tmp); protocol->store(mi->rli->last_error().number); + + if (mi->rli->last_error().number == 0) { + protocol->store("", &my_charset_bin); + } else if (mi->rli->last_error().number >= EE_ERROR_FIRST && + mi->rli->last_error().number <= EE_ERROR_LAST) { + protocol->store(get_global_errname(mi->rli->last_error().number), + &my_charset_bin); + } else { + protocol->store("regular sql errno", &my_charset_bin); + } + protocol->store(mi->rli->last_error().message, &my_charset_bin); protocol->store((uint32)mi->rli->slave_skip_counter); protocol->store((ulonglong)mi->rli->get_group_master_log_pos_info()); diff --git a/sql/rpl_rli_pdb.cc b/sql/rpl_rli_pdb.cc index 4b1e9c4ffdc4..bb09434c02cb 100644 --- a/sql/rpl_rli_pdb.cc +++ b/sql/rpl_rli_pdb.cc @@ -1567,33 +1567,62 @@ void Slave_worker::do_report(loglevel level, int err_code, const char *msg, gtid_next->to_string(global_sid_map, buff_gtid, true); + if (is_group_replication_applier_channel) { + snprintf(buff_coord, sizeof(buff_coord), + "Worker %u failed executing transaction '%s'", internal_id, + buff_gtid); + } else { + snprintf(buff_coord, sizeof(buff_coord), + "Worker %u failed executing transaction '%s' at " + "source log %s, end_log_pos %llu", + internal_id, buff_gtid, log_name, log_pos); + } + + /* + Error reporting by the worker. The worker updates its error fields as well + as reports the error in the log. + */ + this->va_report(level, err_code, buff_coord, msg, args); + if (level == ERROR_LEVEL && (!has_temporary_error(thd, err_code) || thd->get_transaction()->cannot_safely_rollback( Transaction_ctx::SESSION))) { char coordinator_errmsg[MAX_SLAVE_ERRMSG]; + const char *err_msg = nullptr; + + mysql_mutex_lock(&err_lock); + if (m_last_error.number) { + /* We know for sure there is an valid error */ + err_msg = m_last_error.message; + } else { + /* Fallback to generic error message just in case */ + err_msg = buff_coord; + } if (is_group_replication_applier_channel) { - snprintf(coordinator_errmsg, MAX_SLAVE_ERRMSG, - "Coordinator stopped because there were error(s) in the " - "worker(s). " - "The most recent failure being: Worker %u failed executing " - "transaction '%s'. See error log and/or " - "performance_schema.replication_applier_status_by_worker " - "table for " - "more details about this failure or others, if any.", - internal_id, buff_gtid); + my_snprintf_8bit( + nullptr, coordinator_errmsg, MAX_SLAVE_ERRMSG, + "Coordinator stopped because there were error(s) in the " + "worker(s). " + "The most recent failure being: %s; " + "See error log and/or " + "performance_schema.replication_applier_status_by_worker " + "table for " + "more details about this failure or others, if any.", + err_msg); } else { - snprintf(coordinator_errmsg, MAX_SLAVE_ERRMSG, - "Coordinator stopped because there were error(s) in the " - "worker(s). " - "The most recent failure being: Worker %u failed executing " - "transaction '%s' at source log %s, end_log_pos %llu. " - "See error log and/or " - "performance_schema.replication_applier_status_by_worker " - "table for " - "more details about this failure or others, if any.", - internal_id, buff_gtid, log_name, log_pos); + my_snprintf_8bit( + nullptr, coordinator_errmsg, MAX_SLAVE_ERRMSG, + "Coordinator stopped because there were error(s) in the " + "worker(s). " + "The most recent failure being: %s; " + "See error log and/or " + "performance_schema.replication_applier_status_by_worker " + "table for " + "more details about this failure or others, if any.", + err_msg); } + mysql_mutex_unlock(&err_lock); /* We want to update the errors in coordinator as well as worker. @@ -1605,23 +1634,6 @@ void Slave_worker::do_report(loglevel level, int err_code, const char *msg, */ c_rli->fill_coord_err_buf(level, err_code, coordinator_errmsg); } - - if (is_group_replication_applier_channel) { - snprintf(buff_coord, sizeof(buff_coord), - "Worker %u failed executing transaction '%s'", internal_id, - buff_gtid); - } else { - snprintf(buff_coord, sizeof(buff_coord), - "Worker %u failed executing transaction '%s' at " - "source log %s, end_log_pos %llu", - internal_id, buff_gtid, log_name, log_pos); - } - - /* - Error reporting by the worker. The worker updates its error fields as well - as reports the error in the log. - */ - this->va_report(level, err_code, buff_coord, msg, args); } #ifndef NDEBUG diff --git a/utilities/perror.cc b/utilities/perror.cc index 7811149d5ecf..30aaa05bfefa 100644 --- a/utilities/perror.cc +++ b/utilities/perror.cc @@ -145,7 +145,7 @@ int get_ER_error_msg_by_code(uint code, const char **name_ptr, /* handle "global errors" */ if ((code >= EE_ERROR_FIRST) && (code <= EE_ERROR_LAST)) { *name_ptr = nullptr; - *msg_ptr = globerrs[code - EE_ERROR_FIRST]; + *msg_ptr = EE(code); return 1; }