diff options
Diffstat (limited to 'client/mysqlbinlog.cc')
-rw-r--r-- | client/mysqlbinlog.cc | 286 |
1 files changed, 195 insertions, 91 deletions
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 3d06a21c243..7a4135ab649 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -63,11 +63,15 @@ void sql_print_error(const char *format, ...); static bool one_database=0, to_last_remote_log= 0, disable_log_bin= 0; static bool opt_hexdump= 0; +static bool opt_base64_output= 0; static const char* database= 0; static my_bool force_opt= 0, short_form= 0, remote_opt= 0; +static my_bool debug_info_flag, debug_check_flag; +static my_bool force_if_open_opt= 1; static ulonglong offset = 0; static const char* host = 0; static int port= 0; +static uint my_end_arg; static const char* sock= 0; static const char* user = 0; static char* pass = 0; @@ -84,6 +88,7 @@ static short binlog_flags = 0; static MYSQL* mysql = NULL; static const char* dirname_for_local_load= 0; static bool stop_passed= 0; +static my_bool file_not_closed_error= 0; /* check_header() will set the pointer below. @@ -293,7 +298,7 @@ File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le, int Load_log_processor::load_old_format_file(NET* net, const char*server_fname, uint server_fname_len, File file) { - char buf[FN_REFLEN+1]; + uchar buf[FN_REFLEN+1]; buf[0] = 0; memcpy(buf + 1, server_fname, server_fname_len + 1); if (my_net_write(net, buf, server_fname_len +2) || net_flush(net)) @@ -307,7 +312,7 @@ int Load_log_processor::load_old_format_file(NET* net, const char*server_fname, ulong packet_len = my_net_read(net); if (packet_len == 0) { - if (my_net_write(net, "", 0) || net_flush(net)) + if (my_net_write(net, (uchar*) "", 0) || net_flush(net)) { sql_print_error("Failed sending the ack packet"); return -1; @@ -331,7 +336,7 @@ int Load_log_processor::load_old_format_file(NET* net, const char*server_fname, sql_print_error("Illegal length of packet read from net"); return -1; } - if (my_write(file, (byte*) net->read_pos, + if (my_write(file, (uchar*) net->read_pos, (uint) packet_len, MYF(MY_WME|MY_NABP))) return -1; } @@ -376,7 +381,7 @@ int Load_log_processor::process_first_event(const char *bname, uint blen, File_name_record rec; DBUG_ENTER("Load_log_processor::process_first_event"); - if (!(fname= my_malloc(full_len,MYF(MY_WME)))) + if (!(fname= (char*) my_malloc(full_len,MYF(MY_WME)))) DBUG_RETURN(-1); memcpy(fname, target_dir_name, target_dir_name_len); @@ -395,7 +400,7 @@ int Load_log_processor::process_first_event(const char *bname, uint blen, rec.fname= fname; rec.event= ce; - if (set_dynamic(&file_names, (gptr)&rec, file_id)) + if (set_dynamic(&file_names, (uchar*)&rec, file_id)) { sql_print_error("Could not construct local filename %s%s", target_dir_name, bname); @@ -405,7 +410,7 @@ int Load_log_processor::process_first_event(const char *bname, uint blen, if (ce) ce->set_fname_outside_temp_buf(fname, strlen(fname)); - if (my_write(file, (byte*)block, block_len, MYF(MY_WME|MY_NABP))) + if (my_write(file, (uchar*)block, block_len, MYF(MY_WME|MY_NABP))) error= -1; if (my_close(file, MYF(MY_WME))) error= -1; @@ -444,7 +449,7 @@ int Load_log_processor::process(Append_block_log_event *ae) if (((file= my_open(fname, O_APPEND|O_BINARY|O_WRONLY,MYF(MY_WME))) < 0)) DBUG_RETURN(-1); - if (my_write(file,(byte*)ae->block,ae->block_len,MYF(MY_WME|MY_NABP))) + if (my_write(file,(uchar*)ae->block,ae->block_len,MYF(MY_WME|MY_NABP))) error= -1; if (my_close(file,MYF(MY_WME))) error= -1; @@ -473,6 +478,25 @@ static bool check_database(const char *log_dbname) } + +static int +write_event_header_and_base64(Log_event *ev, FILE *result_file, + PRINT_EVENT_INFO *print_event_info) +{ + IO_CACHE *head= &print_event_info->head_cache; + IO_CACHE *body= &print_event_info->body_cache; + DBUG_ENTER("write_event_header_and_base64"); + + /* Write header and base64 output to cache */ + ev->print_header(head, print_event_info, FALSE); + ev->print_base64(body, print_event_info, FALSE); + + /* Read data from cache and write to result file */ + DBUG_RETURN(copy_event_cache_to_file_and_reinit(head, result_file) || + copy_event_cache_to_file_and_reinit(body, result_file)); +} + + /* Process an event @@ -516,6 +540,9 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, start_datetime= 0; offset= 0; // print everything and protect against cycling rec_count } + if (server_id && (server_id != ev->server_id)) { + DBUG_RETURN(0); + } if (((my_time_t)(ev->when) >= stop_datetime) || (pos >= stop_position_mot)) { @@ -530,12 +557,20 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, else print_event_info->hexdump_from= pos; + print_event_info->base64_output= opt_base64_output; + + DBUG_PRINT("debug", ("event_type: %s", ev->get_type_str())); + switch (ev_type) { case QUERY_EVENT: if (check_database(((Query_log_event*)ev)->db)) goto end; - ev->print(result_file, print_event_info); + if (opt_base64_output) + write_event_header_and_base64(ev, result_file, print_event_info); + else + ev->print(result_file, print_event_info); break; + case CREATE_FILE_EVENT: { Create_file_log_event* ce= (Create_file_log_event*)ev; @@ -554,7 +589,12 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, filename and use LOCAL), prepared in the 'case EXEC_LOAD_EVENT' below. */ - ce->print(result_file, print_event_info, TRUE); + if (opt_base64_output) + { + write_event_header_and_base64(ce, result_file, print_event_info); + } + else + ce->print(result_file, print_event_info, TRUE); // If this binlog is not 3.23 ; why this test?? if (glob_description_event->binlog_version >= 3) @@ -594,8 +634,10 @@ Create_file event for file_id: %u\n",exv->file_id); case FORMAT_DESCRIPTION_EVENT: delete glob_description_event; glob_description_event= (Format_description_log_event*) ev; - print_event_info->common_header_len= glob_description_event->common_header_len; + print_event_info->common_header_len= + glob_description_event->common_header_len; ev->print(result_file, print_event_info); + ev->temp_buf= 0; // as the event ref is zeroed /* We don't want this event to be deleted now, so let's hide it (I (Guilhem) should later see if this triggers a non-serious Valgrind @@ -603,6 +645,12 @@ Create_file event for file_id: %u\n",exv->file_id); later. */ ev= 0; + if (!force_if_open_opt && + (glob_description_event->flags & LOG_EVENT_BINLOG_IN_USE_F)) + { + file_not_closed_error= 1; + DBUG_RETURN(1); + } break; case BEGIN_LOAD_QUERY_EVENT: ev->print(result_file, print_event_info); @@ -637,19 +685,34 @@ Begin_load_query event for file_id: %u\n", exlq->file_id); end: rec_count++; + /* + Destroy the log_event object. If reading from a remote host, + set the temp_buf to NULL so that memory isn't freed twice. + */ if (ev) + { + if (remote_opt) + ev->temp_buf= 0; delete ev; + } DBUG_RETURN(0); } static struct my_option my_long_options[] = { - + {"help", '?', "Display this help and exit.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef __NETWARE__ {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif + {"base64-output", OPT_BASE64_OUTPUT, + "Print all binlog entries using base64 encoding. " + "This is for debugging only. Logs produced using this option " + "should not be applied on production systems.", + (uchar**) &opt_base64_output, (uchar**) &opt_base64_output, 0, GET_BOOL, + NO_ARG, 0, 0, 0, 0, 0, 0}, /* mysqlbinlog needs charsets knowledge, to be able to convert a charset number found in binlog to a charset name (to be able to print things @@ -657,33 +720,43 @@ static struct my_option my_long_options[] = SET @`a`:=_cp850 0x4DFC6C6C6572 COLLATE `cp850_general_ci`; */ {"character-sets-dir", OPT_CHARSETS_DIR, - "Directory where character sets are.", (gptr*) &charsets_dir, - (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#ifndef DBUG_OFF - {"debug", '#', "Output debug log.", (gptr*) &default_dbug_option, - (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, -#endif + "Directory where character sets are.", (uchar**) &charsets_dir, + (uchar**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"database", 'd', "List entries for just this database (local log only).", - (gptr*) &database, (gptr*) &database, 0, GET_STR_ALLOC, REQUIRED_ARG, + (uchar**) &database, (uchar**) &database, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifndef DBUG_OFF + {"debug", '#', "Output debug log.", (uchar**) &default_dbug_option, + (uchar**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, +#endif + {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .", + (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", + (uchar**) &debug_info_flag, (uchar**) &debug_info_flag, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"disable-log-bin", 'D', "Disable binary log. This is useful, if you " "enabled --to-last-log and are sending the output to the same MySQL server. " "This way you could avoid an endless loop. You would also like to use it " "when restoring after a crash to avoid duplication of the statements you " "already have. NOTE: you will need a SUPER privilege to use this option.", - (gptr*) &disable_log_bin, (gptr*) &disable_log_bin, 0, GET_BOOL, + (uchar**) &disable_log_bin, (uchar**) &disable_log_bin, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"force-if-open", 'F', "Force if binlog was not closed properly.", + (uchar**) &force_if_open_opt, (uchar**) &force_if_open_opt, 0, GET_BOOL, NO_ARG, + 1, 0, 0, 0, 0, 0}, {"force-read", 'f', "Force reading unknown binlog events.", - (gptr*) &force_opt, (gptr*) &force_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + (uchar**) &force_opt, (uchar**) &force_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"help", '?', "Display this help and exit.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"hexdump", 'H', "Augment output with hexadecimal and ASCII event dump.", - (gptr*) &opt_hexdump, (gptr*) &opt_hexdump, 0, GET_BOOL, NO_ARG, + (uchar**) &opt_hexdump, (uchar**) &opt_hexdump, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"host", 'h', "Get the binlog from server.", (gptr*) &host, (gptr*) &host, + {"host", 'h', "Get the binlog from server.", (uchar**) &host, (uchar**) &host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"offset", 'o', "Skip the first N entries.", (gptr*) &offset, (gptr*) &offset, + {"local-load", 'l', "Prepare local temporary files for LOAD DATA INFILE in the specified directory.", + (uchar**) &dirname_for_local_load, (uchar**) &dirname_for_local_load, 0, + GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"offset", 'o', "Skip the first N entries.", (uchar**) &offset, (uchar**) &offset, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"password", 'p', "Password to connect to remote server.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, @@ -693,33 +766,33 @@ static struct my_option my_long_options[] = "/etc/services, " #endif "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - (gptr*) &port, (gptr*) &port, 0, GET_INT, REQUIRED_ARG, + (uchar**) &port, (uchar**) &port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"position", 'j', "Deprecated. Use --start-position instead.", - (gptr*) &start_position, (gptr*) &start_position, 0, GET_ULL, + (uchar**) &start_position, (uchar**) &start_position, 0, GET_ULL, REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE, /* COM_BINLOG_DUMP accepts only 4 bytes for the position */ (ulonglong)(~(uint32)0), 0, 0, 0}, {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"result-file", 'r', "Direct output to a given file.", 0, 0, 0, GET_STR, - REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"read-from-remote-server", 'R', "Read binary logs from a MySQL server", - (gptr*) &remote_opt, (gptr*) &remote_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + (uchar**) &remote_opt, (uchar**) &remote_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"open_files_limit", OPT_OPEN_FILES_LIMIT, - "Used to reserve file descriptors for usage by this program", - (gptr*) &open_files_limit, (gptr*) &open_files_limit, 0, GET_ULONG, - REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0}, + {"result-file", 'r', "Direct output to a given file.", 0, 0, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"server-id", OPT_SERVER_ID, + "Extract only binlog entries created by the server having the given id.", + (uchar**) &server_id, (uchar**) &server_id, 0, GET_ULONG, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"set-charset", OPT_SET_CHARSET, - "Add 'SET NAMES character_set' to the output.", (gptr*) &charset, - (gptr*) &charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Add 'SET NAMES character_set' to the output.", (uchar**) &charset, + (uchar**) &charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"short-form", 's', "Just show the queries, no extra info.", - (gptr*) &short_form, (gptr*) &short_form, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + (uchar**) &short_form, (uchar**) &short_form, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"socket", 'S', "Socket file to use for connection.", - (gptr*) &sock, (gptr*) &sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, + (uchar**) &sock, (uchar**) &sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"start-datetime", OPT_START_DATETIME, "Start reading the binlog at first event having a datetime equal or " @@ -727,43 +800,44 @@ static struct my_option my_long_options[] = "in the local time zone, in any format accepted by the MySQL server " "for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 " "(you should probably use quotes for your shell to set it properly).", - (gptr*) &start_datetime_str, (gptr*) &start_datetime_str, + (uchar**) &start_datetime_str, (uchar**) &start_datetime_str, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"start-position", OPT_START_POSITION, + "Start reading the binlog at position N. Applies to the first binlog " + "passed on the command line.", + (uchar**) &start_position, (uchar**) &start_position, 0, GET_ULL, + REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE, + /* COM_BINLOG_DUMP accepts only 4 bytes for the position */ + (ulonglong)(~(uint32)0), 0, 0, 0}, {"stop-datetime", OPT_STOP_DATETIME, "Stop reading the binlog at first event having a datetime equal or " "posterior to the argument; the argument must be a date and time " "in the local time zone, in any format accepted by the MySQL server " "for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 " "(you should probably use quotes for your shell to set it properly).", - (gptr*) &stop_datetime_str, (gptr*) &stop_datetime_str, + (uchar**) &stop_datetime_str, (uchar**) &stop_datetime_str, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"start-position", OPT_START_POSITION, - "Start reading the binlog at position N. Applies to the first binlog " - "passed on the command line.", - (gptr*) &start_position, (gptr*) &start_position, 0, GET_ULL, - REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE, - /* COM_BINLOG_DUMP accepts only 4 bytes for the position */ - (ulonglong)(~(uint32)0), 0, 0, 0}, {"stop-position", OPT_STOP_POSITION, "Stop reading the binlog at position N. Applies to the last binlog " "passed on the command line.", - (gptr*) &stop_position, (gptr*) &stop_position, 0, GET_ULL, + (uchar**) &stop_position, (uchar**) &stop_position, 0, GET_ULL, REQUIRED_ARG, (ulonglong)(~(my_off_t)0), BIN_LOG_HEADER_SIZE, (ulonglong)(~(my_off_t)0), 0, 0, 0}, {"to-last-log", 't', "Requires -R. Will not stop at the end of the \ requested binlog but rather continue printing until the end of the last \ binlog of the MySQL server. If you send the output to the same MySQL server, \ that may lead to an endless loop.", - (gptr*) &to_last_remote_log, (gptr*) &to_last_remote_log, 0, GET_BOOL, + (uchar**) &to_last_remote_log, (uchar**) &to_last_remote_log, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"user", 'u', "Connect to the remote server as username.", - (gptr*) &user, (gptr*) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, + (uchar**) &user, (uchar**) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"local-load", 'l', "Prepare local temporary files for LOAD DATA INFILE in the specified directory.", - (gptr*) &dirname_for_local_load, (gptr*) &dirname_for_local_load, 0, - GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Print version and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"open_files_limit", OPT_OPEN_FILES_LIMIT, + "Used to reserve file descriptors for usage by this program", + (uchar**) &open_files_limit, (uchar**) &open_files_limit, 0, GET_ULONG, + REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -797,7 +871,7 @@ static void die(const char* fmt, ...) va_end(args); cleanup(); /* We cannot free DBUG, it is used in global destructors after exit(). */ - my_end(MY_DONT_FREE_DBUG); + my_end(my_end_arg | MY_DONT_FREE_DBUG); exit(1); } @@ -805,7 +879,7 @@ static void die(const char* fmt, ...) static void print_version() { - printf("%s Ver 3.2 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE); + printf("%s Ver 3.3 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE); NETWARE_SET_SCREEN_MODE(1); } @@ -890,14 +964,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), remote_opt= 1; break; case OPT_MYSQL_PROTOCOL: - { - if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0) - { - fprintf(stderr, "Unknown option to protocol: %s\n", argument); - exit(1); - } + opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib, + opt->name); break; - } case OPT_START_DATETIME: start_datetime= convert_str_to_timestamp(start_datetime_str); break; @@ -926,7 +995,10 @@ static int parse_args(int *argc, char*** argv) load_defaults("my",load_default_groups,argc,argv); if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); - + if (debug_info_flag) + my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO; + if (debug_check_flag) + my_end_arg= MY_CHECK_ERROR; return 0; } @@ -955,19 +1027,22 @@ static int dump_log_entries(const char* logname) { int rc; PRINT_EVENT_INFO print_event_info; + + if (!print_event_info.init_ok()) + return 1; /* Set safe delimiter, to dump things like CREATE PROCEDURE safely */ fprintf(result_file, "DELIMITER /*!*/;\n"); - strcpy(print_event_info.delimiter, "/*!*/;"); + strmov(print_event_info.delimiter, "/*!*/;"); rc= (remote_opt ? dump_remote_log_entries(&print_event_info, logname) : dump_local_log_entries(&print_event_info, logname)); /* Set delimiter back to semicolon */ fprintf(result_file, "DELIMITER ;\n"); - strcpy(print_event_info.delimiter, ";"); + strmov(print_event_info.delimiter, ";"); return rc; } @@ -1017,6 +1092,7 @@ static int check_master_version(MYSQL *mysql_arg, break; case '4': *description_event= new Format_description_log_event(3); + break; case '5': /* The server is soon going to send us its Format_description log @@ -1042,7 +1118,7 @@ static int dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info, const char* logname) { - char buf[128]; + uchar buf[128]; ulong len; uint logname_len; NET* net; @@ -1078,7 +1154,7 @@ could be out of memory"); int4store(buf, (uint32)start_position); int2store(buf + BIN_LOG_HEADER_SIZE, binlog_flags); - size_s tlen = strlen(logname); + size_t tlen = strlen(logname); if (tlen > UINT_MAX) { fprintf(stderr,"Log name too long\n"); @@ -1120,6 +1196,12 @@ could be out of memory"); error= 1; goto err; } + /* + If reading from a remote host, ensure the temp_buf for the + Log_event class is pointing to the incoming stream. + */ + if (remote_opt) + ev->register_temp_buf((char*) net->read_pos + 1); Log_event_type type= ev->get_type_code(); if (glob_description_event->binlog_version >= 3 || @@ -1226,17 +1308,23 @@ err: static void check_header(IO_CACHE* file, Format_description_log_event **description_event) { - byte header[BIN_LOG_HEADER_SIZE]; - byte buf[PROBE_HEADER_LEN]; + uchar header[BIN_LOG_HEADER_SIZE]; + uchar buf[PROBE_HEADER_LEN]; my_off_t tmp_pos, pos; *description_event= new Format_description_log_event(3); pos= my_b_tell(file); my_b_seek(file, (my_off_t)0); if (my_b_read(file, header, sizeof(header))) + { + delete *description_event; die("Failed reading header; Probably an empty file"); + } if (memcmp(header, BINLOG_MAGIC, sizeof(header))) + { + delete *description_event; die("File is not a binary log file"); + } /* Imagine we are running with --start-position=1000. We still need @@ -1257,9 +1345,12 @@ static void check_header(IO_CACHE* file, if (my_b_read(file, buf, sizeof(buf))) { if (file->error) + { + delete *description_event; die("\ Could not read entry at offset %lu : Error in log format or read error", tmp_pos); + } /* Otherwise this is just EOF : this log currently contains 0-2 events. Maybe it's going to be filled in the next @@ -1295,13 +1386,19 @@ Could not read entry at offset %lu : Error in log format or read error", break; else if (buf[4] == FORMAT_DESCRIPTION_EVENT) /* This is 5.0 */ { + Format_description_log_event *new_description_event; my_b_seek(file, tmp_pos); /* seek back to event's start */ - if (!(*description_event= (Format_description_log_event*) + if (!(new_description_event= (Format_description_log_event*) Log_event::read_log_event(file, *description_event))) /* EOF can't be hit here normally, so it's a real error */ + { + delete *description_event; die("Could not read a Format_description_log_event event \ at offset %lu ; this could be a log format error or read error", tmp_pos); + } + delete *description_event; + *description_event= new_description_event; DBUG_PRINT("info",("Setting description_event")); } else if (buf[4] == ROTATE_EVENT) @@ -1310,8 +1407,11 @@ at offset %lu ; this could be a log format error or read error", my_b_seek(file, tmp_pos); /* seek back to event's start */ if (!(ev= Log_event::read_log_event(file, *description_event))) /* EOF can't be hit here normally, so it's a real error */ + { + delete *description_event; die("Could not read a Rotate_log_event event at offset %lu ;" " this could be a log format error or read error", tmp_pos); + } delete ev; } else @@ -1327,7 +1427,7 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, { File fd = -1; IO_CACHE cache,*file= &cache; - byte tmp_buff[BIN_LOG_HEADER_SIZE]; + uchar tmp_buff[BIN_LOG_HEADER_SIZE]; int error= 0; if (logname && logname[0] != '-') @@ -1345,15 +1445,12 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, else // reading from stdin; { /* - Bug fix: #23735 - Author: Chuck Bell - Description: - Windows opens stdin in text mode by default. Certain characters - such as CTRL-Z are interpeted as events and the read() method - will stop. CTRL-Z is the EOF marker in Windows. to get past this - you have to open stdin in binary mode. Setmode() is used to set - stdin in binary mode. Errors on setting this mode result in - halting the function and printing an error message to stderr. + Windows opens stdin in text mode by default. Certain characters + such as CTRL-Z are interpeted as events and the read() method + will stop. CTRL-Z is the EOF marker in Windows. to get past this + you have to open stdin in binary mode. Setmode() is used to set + stdin in binary mode. Errors on setting this mode result in + halting the function and printing an error message to stderr. */ #if defined (__WIN__) || (_WIN64) if (_setmode(fileno(stdin), O_BINARY) == -1) @@ -1361,8 +1458,7 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, fprintf(stderr, "Could not set binary mode on stdin.\n"); return 1; } -#endif - +#endif if (init_io_cache(file, fileno(stdin), 0, READ_CACHE, (my_off_t) 0, 0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE))) return 1; @@ -1370,7 +1466,7 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, if (start_position) { /* skip 'start_position' characters from stdin */ - byte buff[IO_SIZE]; + uchar buff[IO_SIZE]; my_off_t length,tmp; for (length= start_position_mot ; length > 0 ; length-=tmp) { @@ -1385,7 +1481,10 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, } if (!glob_description_event || !glob_description_event->is_valid()) + { + delete glob_description_event; die("Invalid Format_description log event; could be out of memory"); + } if (!start_position && my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE)) { @@ -1436,7 +1535,7 @@ end: int main(int argc, char** argv) { - static char **defaults_argv; + char **defaults_argv; int exit_value= 0; ulonglong save_stop_position; MY_INIT(argv[0]); @@ -1534,7 +1633,17 @@ int main(int argc, char** argv) my_free_open_file_info(); load_processor.destroy(); /* We cannot free DBUG, it is used in global destructors after exit(). */ - my_end(MY_DONT_FREE_DBUG); + my_end(my_end_arg | MY_DONT_FREE_DBUG); + + if (file_not_closed_error) + { + fprintf(stderr, +"\nError: attempting to dump binlog '%s' which was not closed properly.\n" +"Most probably mysqld is still writting it, or crashed.\n" +"Your current options specify --disable-force-if-open\n" +"which means to abort on this problem.\n" +"You can rerun using --force-if-open to ignore this problem.\n\n", argv[-1]); + } exit(exit_value); DBUG_RETURN(exit_value); // Keep compilers happy } @@ -1546,12 +1655,7 @@ int main(int argc, char** argv) #include "my_decimal.h" #include "decimal.c" - -#if defined(__WIN__) && !defined(CMAKE_BUILD) -#include "my_decimal.cpp" -#include "log_event.cpp" -#else #include "my_decimal.cc" #include "log_event.cc" -#endif +#include "log_event_old.cc" |