summaryrefslogtreecommitdiff
path: root/client/mysqlbinlog.cc
diff options
context:
space:
mode:
Diffstat (limited to 'client/mysqlbinlog.cc')
-rw-r--r--client/mysqlbinlog.cc722
1 files changed, 529 insertions, 193 deletions
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index a88c93516b5..71a08132e9f 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -34,9 +34,11 @@
#define TABLE TABLE_CLIENT
#include "client_priv.h"
#include <my_time.h>
+#include <sslopt-vars.h>
/* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */
#include "sql_priv.h"
#include "log_event.h"
+#include "compat56.h"
#include "sql_common.h"
#include "my_dir.h"
#include <welcome_copyright_notice.h> // ORACLE_WELCOME_COPYRIGHT_NOTICE
@@ -48,6 +50,8 @@
#include "mysqld.h"
+#include <algorithm>
+
Rpl_filter *binlog_filter= 0;
#define BIN_LOG_HEADER_SIZE 4
@@ -67,9 +71,12 @@ ulong bytes_sent = 0L, bytes_received = 0L;
ulong mysqld_net_retry_count = 10L;
ulong open_files_limit;
ulong opt_binlog_rows_event_max_size;
-uint test_flags = 0;
+ulonglong test_flags = 0;
+ulong opt_binlog_rows_event_max_encoded_size= MAX_MAX_ALLOWED_PACKET;
static uint opt_protocol= 0;
static FILE *result_file;
+static char *result_file_name= 0;
+static const char *output_prefix= "";
#ifndef DBUG_OFF
static const char* default_dbug_option = "d:t:o,/tmp/mysqlbinlog.trace";
@@ -93,6 +100,8 @@ static 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 my_bool opt_raw_mode= 0, opt_stop_never= 0;
+static ulong opt_stop_never_slave_server_id= 0;
static my_bool opt_verify_binlog_checksum= 1;
static ulonglong offset = 0;
static char* host = 0;
@@ -102,7 +111,7 @@ static const char* sock= 0;
static char *opt_plugindir= 0, *opt_default_auth= 0;
#ifdef HAVE_SMEM
-static char *shared_memory_base_name= 0;
+static const char *shared_memory_base_name= 0;
#endif
static char* user = 0;
static char* pass = 0;
@@ -117,7 +126,6 @@ static ulonglong start_position, stop_position;
static char *start_datetime_str, *stop_datetime_str;
static my_time_t start_datetime= 0, stop_datetime= MY_TIME_T_MAX;
static ulonglong rec_count= 0;
-static short binlog_flags = 0;
static MYSQL* mysql = NULL;
static const char* dirname_for_local_load= 0;
static bool opt_skip_annotate_row_events= 0;
@@ -139,7 +147,9 @@ enum Exit_status {
/** An error occurred and execution should stop. */
ERROR_STOP,
/** No error occurred but execution should stop. */
- OK_STOP
+ OK_STOP,
+ /** No error occurred - end of file reached. */
+ OK_EOF,
};
/**
@@ -277,8 +287,8 @@ public:
int init()
{
- return init_dynamic_array(&file_names, sizeof(File_name_record),
- 100, 100);
+ return my_init_dynamic_array(&file_names, sizeof(File_name_record),
+ 100, 100, MYF(0));
}
void init_by_dir_name(const char *dir)
@@ -804,7 +814,12 @@ write_event_header_and_base64(Log_event *ev, FILE *result_file,
/* Write header and base64 output to cache */
ev->print_header(head, print_event_info, FALSE);
- ev->print_base64(body, print_event_info, FALSE);
+
+ DBUG_ASSERT(print_event_info->base64_output_mode == BASE64_OUTPUT_ALWAYS);
+
+ ev->print_base64(body, print_event_info,
+ print_event_info->base64_output_mode !=
+ BASE64_OUTPUT_DECODE_ROWS);
/* Read data from cache and write to result file */
if (copy_event_cache_to_file_and_reinit(head, result_file) ||
@@ -843,7 +858,9 @@ static bool print_base64(PRINT_EVENT_INFO *print_event_info, Log_event *ev)
return 1;
}
ev->print(result_file, print_event_info);
- return print_event_info->head_cache.error == -1;
+ return
+ print_event_info->head_cache.error == -1 ||
+ print_event_info->body_cache.error == -1;
}
@@ -1228,6 +1245,9 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
case WRITE_ROWS_EVENT:
case DELETE_ROWS_EVENT:
case UPDATE_ROWS_EVENT:
+ case WRITE_ROWS_EVENT_V1:
+ case UPDATE_ROWS_EVENT_V1:
+ case DELETE_ROWS_EVENT_V1:
{
Rows_log_event *e= (Rows_log_event*) ev;
if (print_row_event(print_event_info, ev, e->get_table_id(),
@@ -1245,6 +1265,9 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
goto err;
break;
}
+ case START_ENCRYPTION_EVENT:
+ glob_description_event->start_decryption((Start_encryption_log_event*)ev);
+ /* fall through */
default:
print_skip_replication_statement(print_event_info, ev);
ev->print(result_file, print_event_info);
@@ -1362,8 +1385,14 @@ static struct my_option my_options[] =
{"read-from-remote-server", 'R', "Read binary logs from a MySQL server.",
&remote_opt, &remote_opt, 0, GET_BOOL, NO_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},
+ {"raw", 0, "Requires -R. Output raw binlog data instead of SQL "
+ "statements. Output files named after server logs.",
+ &opt_raw_mode, &opt_raw_mode, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
+ 0, 0},
+ {"result-file", 'r', "Direct output to a given file. With --raw this is a "
+ "prefix for the file names.",
+ &result_file_name, &result_file_name, 0, GET_STR, REQUIRED_ARG,
+ 0, 0, 0, 0, 0, 0},
{"server-id", 0,
"Extract only binlog entries created by the server having the given id.",
&server_id, &server_id, 0, GET_ULONG,
@@ -1386,6 +1415,7 @@ static struct my_option my_options[] =
{"socket", 'S', "The socket file to use for connection.",
&sock, &sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0,
0, 0},
+#include <sslopt-longopts.h>
{"start-datetime", OPT_START_DATETIME,
"Start reading the binlog at first event having a datetime equal or "
"posterior to the argument; the argument must be a date and time "
@@ -1399,8 +1429,11 @@ static struct my_option my_options[] =
"passed on the command line.",
&start_position, &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},
+ /*
+ COM_BINLOG_DUMP accepts only 4 bytes for the position
+ so remote log reading has lower limit.
+ */
+ (ulonglong)(0xffffffffffffffffULL), 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 "
@@ -1409,6 +1442,14 @@ static struct my_option my_options[] =
"(you should probably use quotes for your shell to set it properly).",
&stop_datetime_str, &stop_datetime_str,
0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"stop-never", 0, "Wait for more data from the server "
+ "instead of stopping at the end of the last log. Implies --to-last-log.",
+ &opt_stop_never, &opt_stop_never, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"stop-never-slave-server-id", 0,
+ "The slave server_id used for --read-from-remote-server --stop-never.",
+ &opt_stop_never_slave_server_id, &opt_stop_never_slave_server_id, 0,
+ GET_ULONG, REQUIRED_ARG, 0, 0, 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.",
@@ -1439,6 +1480,15 @@ that may lead to an endless loop.",
"This value must be a multiple of 256.",
&opt_binlog_rows_event_max_size, &opt_binlog_rows_event_max_size, 0,
GET_ULONG, REQUIRED_ARG, UINT_MAX, 256, ULONG_MAX, 0, 256, 0},
+#ifndef DBUG_OFF
+ {"debug-binlog-row-event-max-encoded-size", 0,
+ "The maximum size of base64-encoded rows-event in one BINLOG pseudo-query "
+ "instance. When the computed actual size exceeds the limit "
+ "the BINLOG's argument string is fragmented in two.",
+ &opt_binlog_rows_event_max_encoded_size,
+ &opt_binlog_rows_event_max_encoded_size, 0,
+ GET_ULONG, REQUIRED_ARG, UINT_MAX/4, 256, ULONG_MAX, 0, 256, 0},
+#endif
{"verify-binlog-checksum", 'c', "Verify checksum binlog events.",
(uchar**) &opt_verify_binlog_checksum, (uchar**) &opt_verify_binlog_checksum,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -1527,6 +1577,8 @@ static void cleanup()
my_free(host);
my_free(user);
my_free(const_cast<char*>(dirname_for_local_load));
+ my_free(start_datetime_str);
+ my_free(stop_datetime_str);
delete binlog_filter;
delete glob_description_event;
@@ -1558,13 +1610,14 @@ the mysql command line client.\n\n");
static my_time_t convert_str_to_timestamp(const char* str)
{
- int was_cut;
+ MYSQL_TIME_STATUS status;
MYSQL_TIME l_time;
long dummy_my_timezone;
uint dummy_in_dst_time_gap;
+
/* We require a total specification (date AND time) */
- if (str_to_datetime(str, (uint) strlen(str), &l_time, 0, &was_cut) !=
- MYSQL_TIMESTAMP_DATETIME || was_cut)
+ if (str_to_datetime(str, (uint) strlen(str), &l_time, 0, &status) ||
+ l_time.time_type != MYSQL_TIMESTAMP_DATETIME || status.warnings)
{
error("Incorrect date and time argument: %s", str);
exit(1);
@@ -1590,6 +1643,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
DBUG_PUSH(argument ? argument : default_dbug_option);
break;
#endif
+#include <sslopt-case.h>
case 'd':
one_database = 1;
break;
@@ -1608,16 +1662,16 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
else
tty_password=1;
break;
- case 'r':
- if (!(result_file = my_fopen(argument, O_WRONLY | O_BINARY, MYF(MY_WME))))
- exit(1);
- break;
case 'R':
remote_opt= 1;
break;
case OPT_MYSQL_PROTOCOL:
- opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
- opt->name);
+ if ((opt_protocol= find_type_with_warning(argument, &sql_protocol_typelib,
+ opt->name)) <= 0)
+ {
+ sf_leaking_memory= 1; /* no memory leak reports here */
+ exit(1);
+ }
break;
case OPT_START_DATETIME:
start_datetime= convert_str_to_timestamp(start_datetime_str);
@@ -1630,8 +1684,15 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
opt_base64_output_mode= BASE64_OUTPUT_ALWAYS;
else
{
- opt_base64_output_mode= (enum_base64_output_mode)
- (find_type_or_exit(argument, &base64_output_mode_typelib, opt->name)-1);
+ int val;
+
+ if ((val= find_type_with_warning(argument, &base64_output_mode_typelib,
+ opt->name)) <= 0)
+ {
+ sf_leaking_memory= 1; /* no memory leak reports here */
+ exit(1);
+ }
+ opt_base64_output_mode= (enum_base64_output_mode) (val - 1);
}
break;
case OPT_REWRITE_DB: // db_from->db_to
@@ -1707,13 +1768,20 @@ static int parse_args(int *argc, char*** argv)
{
int ho_error;
- result_file = stdout;
if ((ho_error=handle_options(argc, argv, my_options, get_one_option)))
exit(ho_error);
if (debug_info_flag)
my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
- if (debug_check_flag)
+ else if (debug_check_flag)
my_end_arg= MY_CHECK_ERROR;
+ if (start_position > UINT_MAX32 && remote_opt)
+ {
+ /* Here we just emulate old behaviour of option limit handling */
+ fprintf(stderr, "Warning: option 'start-position': unsigned value %llu "
+ "adjusted to 4294967295 (limitation of the client-server protocol)",
+ start_position);
+ start_position= UINT_MAX32;
+ }
return 0;
}
@@ -1739,6 +1807,18 @@ static Exit_status safe_connect()
return ERROR_STOP;
}
+#ifdef HAVE_OPENSSL
+ if (opt_use_ssl)
+ {
+ mysql_ssl_set(mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
+ opt_ssl_capath, opt_ssl_cipher);
+ mysql_options(mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl);
+ mysql_options(mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath);
+ }
+ mysql_options(mysql,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
+ (char*)&opt_ssl_verify_server_cert);
+#endif /*HAVE_OPENSSL*/
+
if (opt_plugindir && *opt_plugindir)
mysql_options(mysql, MYSQL_PLUGIN_DIR, opt_plugindir);
@@ -1752,6 +1832,9 @@ static Exit_status safe_connect()
mysql_options(mysql, MYSQL_SHARED_MEMORY_BASE_NAME,
shared_memory_base_name);
#endif
+ mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
+ mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "program_name", "mysqlbinlog");
if (!mysql_real_connect(mysql, host, user, pass, 0, port, sock, 0))
{
error("Failed on connect: %s", mysql_error(mysql));
@@ -1786,7 +1869,8 @@ static Exit_status dump_log_entries(const char* logname)
Set safe delimiter, to dump things
like CREATE PROCEDURE safely
*/
- fprintf(result_file, "DELIMITER /*!*/;\n");
+ if (!opt_raw_mode)
+ fprintf(result_file, "DELIMITER /*!*/;\n");
strmov(print_event_info.delimiter, "/*!*/;");
print_event_info.verbose= short_form ? 0 : verbose;
@@ -1795,7 +1879,8 @@ static Exit_status dump_log_entries(const char* logname)
dump_local_log_entries(&print_event_info, logname));
/* Set delimiter back to semicolon */
- fprintf(result_file, "DELIMITER ;\n");
+ if (!opt_raw_mode)
+ fprintf(result_file, "DELIMITER ;\n");
strmov(print_event_info.delimiter, ";");
return rc;
}
@@ -1815,7 +1900,7 @@ static Exit_status check_master_version()
{
MYSQL_RES* res = 0;
MYSQL_ROW row;
- const char* version;
+ uint version;
if (mysql_query(mysql, "SELECT VERSION()") ||
!(res = mysql_store_result(mysql)))
@@ -1831,7 +1916,7 @@ static Exit_status check_master_version()
goto err;
}
- if (!(version = row[0]))
+ if (!(version = atoi(row[0])))
{
error("Could not find server version: "
"Master reported NULL for the version.");
@@ -1849,15 +1934,29 @@ static Exit_status check_master_version()
"Master returned '%s'", mysql_error(mysql));
goto err;
}
+
+ /*
+ Announce our capabilities to the server, so it will send us all the events
+ that we know about.
+ */
+ if (mysql_query(mysql, "SET @mariadb_slave_capability="
+ STRINGIFY_ARG(MARIA_SLAVE_CAPABILITY_MINE)))
+ {
+ error("Could not inform master about capability. Master returned '%s'",
+ mysql_error(mysql));
+ goto err;
+ }
+
delete glob_description_event;
- switch (*version) {
- case '3':
+ switch (version) {
+ case 3:
glob_description_event= new Format_description_log_event(1);
break;
- case '4':
+ case 4:
glob_description_event= new Format_description_log_event(3);
break;
- case '5':
+ case 5:
+ case 10:
/*
The server is soon going to send us its Format_description log
event, unless it is a 5.0 server with 3.23 or 4.0 binlogs.
@@ -1869,7 +1968,7 @@ static Exit_status check_master_version()
default:
glob_description_event= NULL;
error("Could not find server version: "
- "Master reported unrecognized MySQL version '%s'.", version);
+ "Master reported unrecognized MySQL version '%s'.", row[0]);
goto err;
}
if (!glob_description_event || !glob_description_event->is_valid())
@@ -1887,6 +1986,247 @@ err:
}
+static Exit_status handle_event_text_mode(PRINT_EVENT_INFO *print_event_info,
+ ulong *len,
+ const char* logname,
+ uint logname_len, my_off_t old_off)
+{
+ const char *error_msg;
+ Log_event *ev;
+ NET *net= &mysql->net;
+ DBUG_ENTER("handle_event_text_mode");
+
+ if (net->read_pos[5] == ANNOTATE_ROWS_EVENT)
+ {
+ if (!(ev= read_remote_annotate_event(net->read_pos + 1, *len - 1,
+ &error_msg)))
+ {
+ error("Could not construct annotate event object: %s", error_msg);
+ DBUG_RETURN(ERROR_STOP);
+ }
+ }
+ else
+ {
+ if (!(ev= Log_event::read_log_event((const char*) net->read_pos + 1 ,
+ *len - 1, &error_msg,
+ glob_description_event,
+ opt_verify_binlog_checksum)))
+ {
+ error("Could not construct log event object: %s", error_msg);
+ DBUG_RETURN(ERROR_STOP);
+ }
+ /*
+ If reading from a remote host, ensure the temp_buf for the
+ Log_event class is pointing to the incoming stream.
+ */
+ ev->register_temp_buf((char *) net->read_pos + 1, FALSE);
+ }
+
+ Log_event_type type= ev->get_type_code();
+ if (glob_description_event->binlog_version >= 3 ||
+ (type != LOAD_EVENT && type != CREATE_FILE_EVENT))
+ {
+ /*
+ If this is a Rotate event, maybe it's the end of the requested binlog;
+ in this case we are done (stop transfer).
+ This is suitable for binlogs, not relay logs (but for now we don't read
+ relay logs remotely because the server is not able to do that). If one
+ day we read relay logs remotely, then we will have a problem with the
+ detection below: relay logs contain Rotate events which are about the
+ binlogs, so which would trigger the end-detection below.
+ */
+ if (type == ROTATE_EVENT)
+ {
+ Rotate_log_event *rev= (Rotate_log_event *)ev;
+ /*
+ If this is a fake Rotate event, and not about our log, we can stop
+ transfer. If this a real Rotate event (so it's not about our log,
+ it's in our log describing the next log), we print it (because it's
+ part of our log) and then we will stop when we receive the fake one
+ soon.
+ */
+ if (rev->when == 0)
+ {
+ *len= 1; // fake Rotate, so don't increment old_off
+ if (!to_last_remote_log)
+ {
+ if ((rev->ident_len != logname_len) ||
+ memcmp(rev->new_log_ident, logname, logname_len))
+ {
+ delete ev;
+ DBUG_RETURN(OK_EOF);
+ }
+ /*
+ Otherwise, this is a fake Rotate for our log, at the very
+ beginning for sure. Skip it, because it was not in the original
+ log. If we are running with to_last_remote_log, we print it,
+ because it serves as a useful marker between binlogs then.
+ */
+ delete ev;
+ DBUG_RETURN(OK_CONTINUE);
+ }
+ }
+ }
+ else if (type == FORMAT_DESCRIPTION_EVENT)
+ {
+ /*
+ This could be an fake Format_description_log_event that server
+ (5.0+) automatically sends to a slave on connect, before sending
+ a first event at the requested position. If this is the case,
+ don't increment old_off. Real Format_description_log_event always
+ starts from BIN_LOG_HEADER_SIZE position.
+ */
+ if (old_off != BIN_LOG_HEADER_SIZE)
+ *len= 1; // fake event, don't increment old_off
+ }
+ Exit_status retval= process_event(print_event_info, ev, old_off, logname);
+ if (retval != OK_CONTINUE)
+ DBUG_RETURN(retval);
+ }
+ else
+ {
+ Load_log_event *le= (Load_log_event*)ev;
+ const char *old_fname= le->fname;
+ uint old_len= le->fname_len;
+ File file;
+ Exit_status retval;
+ char fname[FN_REFLEN+1];
+
+ if ((file= load_processor.prepare_new_file_for_old_format(le,fname)) < 0)
+ {
+ DBUG_RETURN(ERROR_STOP);
+ }
+
+ retval= process_event(print_event_info, ev, old_off, logname);
+ if (retval != OK_CONTINUE)
+ {
+ my_close(file,MYF(MY_WME));
+ DBUG_RETURN(retval);
+ }
+ retval= load_processor.load_old_format_file(net,old_fname,old_len,file);
+ my_close(file,MYF(MY_WME));
+ if (retval != OK_CONTINUE)
+ DBUG_RETURN(retval);
+ }
+
+ DBUG_RETURN(OK_CONTINUE);
+}
+
+
+static char out_file_name[FN_REFLEN + 1];
+
+static Exit_status handle_event_raw_mode(PRINT_EVENT_INFO *print_event_info,
+ ulong *len,
+ const char* logname, uint logname_len)
+{
+ const char *error_msg;
+ const unsigned char *read_pos= mysql->net.read_pos + 1;
+ Log_event_type type;
+ DBUG_ENTER("handle_event_raw_mode");
+ DBUG_ASSERT(opt_raw_mode && remote_opt);
+
+ type= (Log_event_type) read_pos[EVENT_TYPE_OFFSET];
+
+ if (type == HEARTBEAT_LOG_EVENT)
+ DBUG_RETURN(OK_CONTINUE);
+
+ if (type == ROTATE_EVENT || type == FORMAT_DESCRIPTION_EVENT)
+ {
+ Log_event *ev;
+ if (!(ev= Log_event::read_log_event((const char*) read_pos ,
+ *len - 1, &error_msg,
+ glob_description_event,
+ opt_verify_binlog_checksum)))
+ {
+ error("Could not construct %s event object: %s",
+ type == ROTATE_EVENT ? "rotate" : "format description", error_msg);
+ DBUG_RETURN(ERROR_STOP);
+ }
+ /*
+ If reading from a remote host, ensure the temp_buf for the
+ Log_event class is pointing to the incoming stream.
+ */
+ ev->register_temp_buf((char *) read_pos, FALSE);
+
+ if (type == ROTATE_EVENT)
+ {
+ Exit_status ret_val= OK_CONTINUE;
+ Rotate_log_event *rev= (Rotate_log_event *)ev;
+ char *pe= strmake(out_file_name, output_prefix, sizeof(out_file_name)-1);
+ strmake(pe, rev->new_log_ident, sizeof(out_file_name) - (pe-out_file_name));
+
+ /*
+ If this is a fake Rotate event, and not about our log, we can stop
+ transfer. If this a real Rotate event (so it's not about our log,
+ it's in our log describing the next log), we print it (because it's
+ part of our log) and then we will stop when we receive the fake one
+ soon.
+ */
+ if (rev->when == 0)
+ {
+ if (!to_last_remote_log)
+ {
+ if ((rev->ident_len != logname_len) ||
+ memcmp(rev->new_log_ident, logname, logname_len))
+ {
+ ret_val= OK_EOF;
+ }
+ /*
+ Otherwise, this is a fake Rotate for our log, at the very
+ beginning for sure. Skip it, because it was not in the original
+ log. If we are running with to_last_remote_log, we print it,
+ because it serves as a useful marker between binlogs then.
+ */
+ }
+ *len= 1; // fake Rotate, so don't increment old_off
+ ev->temp_buf= 0;
+ delete ev;
+ DBUG_RETURN(ret_val);
+ }
+ ev->temp_buf= 0;
+ delete ev;
+ }
+ else /* if (type == FORMAT_DESCRIPTION_EVENT) */
+ {
+ DBUG_ASSERT(type == FORMAT_DESCRIPTION_EVENT);
+
+ if (result_file)
+ my_fclose(result_file, MYF(0));
+
+ if (!(result_file= my_fopen(out_file_name,
+ O_WRONLY | O_BINARY, MYF(MY_WME))))
+ {
+ error("Could not create output log file: %s", out_file_name);
+ DBUG_RETURN(ERROR_STOP);
+ }
+ /* TODO - add write error simulation here */
+
+ if (my_fwrite(result_file, (const uchar *) BINLOG_MAGIC,
+ BIN_LOG_HEADER_SIZE, MYF(MY_NABP)))
+ {
+ error("Could not write into log file '%s'", out_file_name);
+ DBUG_RETURN(ERROR_STOP);
+ }
+
+ delete glob_description_event;
+ glob_description_event= (Format_description_log_event*) ev;
+ print_event_info->common_header_len=
+ glob_description_event->common_header_len;
+ ev->temp_buf= 0;
+ /* We do not want to delete the event here. */
+ }
+ }
+
+ if (my_fwrite(result_file, read_pos, *len - 1, MYF(MY_NABP)))
+ {
+ error("Could not write into log file '%s'", out_file_name);
+ DBUG_RETURN(ERROR_STOP);
+ }
+
+ DBUG_RETURN(OK_CONTINUE);
+}
+
+
/**
Requests binlog dump from a remote server and prints the events it
receives.
@@ -1909,8 +2249,9 @@ static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
uint logname_len;
NET* net;
my_off_t old_off= start_position_mot;
- char fname[FN_REFLEN+1];
Exit_status retval= OK_CONTINUE;
+ short binlog_flags = 0;
+ ulong slave_id;
DBUG_ENTER("dump_remote_log_entries");
/*
@@ -1929,19 +2270,31 @@ static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
COM_BINLOG_DUMP accepts only 4 bytes for the position, so we are forced to
cast to uint32.
*/
+ DBUG_ASSERT(start_position <= UINT_MAX32);
int4store(buf, (uint32)start_position);
if (!opt_skip_annotate_row_events)
binlog_flags|= BINLOG_SEND_ANNOTATE_ROWS_EVENT;
+ if (!opt_stop_never)
+ binlog_flags|= BINLOG_DUMP_NON_BLOCK;
+
int2store(buf + BIN_LOG_HEADER_SIZE, binlog_flags);
size_t tlen = strlen(logname);
- if (tlen > UINT_MAX)
+ if (tlen > sizeof(buf) - 10)
{
error("Log name too long.");
DBUG_RETURN(ERROR_STOP);
}
logname_len = (uint) tlen;
- int4store(buf + 6, 0);
+ if (opt_stop_never)
+ {
+ DBUG_ASSERT(to_last_remote_log);
+ slave_id= (opt_stop_never_slave_server_id == 0) ?
+ 1 : opt_stop_never_slave_server_id;
+ }
+ else
+ slave_id= 0;
+ int4store(buf + 6, slave_id);
memcpy(buf + 10, logname, logname_len);
if (simple_command(mysql, COM_BINLOG_DUMP, buf, logname_len + 10, 1))
{
@@ -1951,9 +2304,6 @@ static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
for (;;)
{
- const char *error_msg;
- Log_event *ev;
-
len= cli_safe_read(mysql);
if (len == packet_error)
{
@@ -1964,115 +2314,23 @@ static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
break; // end of data
DBUG_PRINT("info",( "len: %lu net->read_pos[5]: %d\n",
len, net->read_pos[5]));
- if (net->read_pos[5] == ANNOTATE_ROWS_EVENT)
+ if (opt_raw_mode)
{
- if (!(ev= read_remote_annotate_event(net->read_pos + 1, len - 1,
- &error_msg)))
- {
- error("Could not construct annotate event object: %s", error_msg);
- DBUG_RETURN(ERROR_STOP);
- }
+ retval= handle_event_raw_mode(print_event_info, &len,
+ logname, logname_len);
}
else
{
- if (!(ev= Log_event::read_log_event((const char*) net->read_pos + 1 ,
- len - 1, &error_msg,
- glob_description_event,
- opt_verify_binlog_checksum)))
- {
- error("Could not construct log event object: %s", error_msg);
- DBUG_RETURN(ERROR_STOP);
- }
- /*
- If reading from a remote host, ensure the temp_buf for the
- Log_event class is pointing to the incoming stream.
- */
- ev->register_temp_buf((char *) net->read_pos + 1, FALSE);
+ retval= handle_event_text_mode(print_event_info, &len,
+ logname, logname_len, old_off);
}
-
- Log_event_type type= ev->get_type_code();
- if (glob_description_event->binlog_version >= 3 ||
- (type != LOAD_EVENT && type != CREATE_FILE_EVENT))
+ if (retval != OK_CONTINUE)
{
- /*
- If this is a Rotate event, maybe it's the end of the requested binlog;
- in this case we are done (stop transfer).
- This is suitable for binlogs, not relay logs (but for now we don't read
- relay logs remotely because the server is not able to do that). If one
- day we read relay logs remotely, then we will have a problem with the
- detection below: relay logs contain Rotate events which are about the
- binlogs, so which would trigger the end-detection below.
- */
- if (type == ROTATE_EVENT)
- {
- Rotate_log_event *rev= (Rotate_log_event *)ev;
- /*
- If this is a fake Rotate event, and not about our log, we can stop
- transfer. If this a real Rotate event (so it's not about our log,
- it's in our log describing the next log), we print it (because it's
- part of our log) and then we will stop when we receive the fake one
- soon.
- */
- if (rev->when == 0)
- {
- if (!to_last_remote_log)
- {
- if ((rev->ident_len != logname_len) ||
- memcmp(rev->new_log_ident, logname, logname_len))
- {
- delete ev;
- DBUG_RETURN(OK_CONTINUE);
- }
- /*
- Otherwise, this is a fake Rotate for our log, at the very
- beginning for sure. Skip it, because it was not in the original
- log. If we are running with to_last_remote_log, we print it,
- because it serves as a useful marker between binlogs then.
- */
- delete ev;
- continue;
- }
- len= 1; // fake Rotate, so don't increment old_off
- }
- }
- else if (type == FORMAT_DESCRIPTION_EVENT)
- {
- /*
- This could be an fake Format_description_log_event that server
- (5.0+) automatically sends to a slave on connect, before sending
- a first event at the requested position. If this is the case,
- don't increment old_off. Real Format_description_log_event always
- starts from BIN_LOG_HEADER_SIZE position.
- */
- if (old_off != BIN_LOG_HEADER_SIZE)
- len= 1; // fake event, don't increment old_off
- }
- Exit_status retval= process_event(print_event_info, ev, old_off, logname);
- if (retval != OK_CONTINUE)
- DBUG_RETURN(retval);
+ if (retval == OK_EOF)
+ break;
+ DBUG_RETURN(retval);
}
- else
- {
- Load_log_event *le= (Load_log_event*)ev;
- const char *old_fname= le->fname;
- uint old_len= le->fname_len;
- File file;
- Exit_status retval;
-
- if ((file= load_processor.prepare_new_file_for_old_format(le,fname)) < 0)
- DBUG_RETURN(ERROR_STOP);
- retval= process_event(print_event_info, ev, old_off, logname);
- if (retval != OK_CONTINUE)
- {
- my_close(file,MYF(MY_WME));
- DBUG_RETURN(retval);
- }
- retval= load_processor.load_old_format_file(net,old_fname,old_len,file);
- my_close(file,MYF(MY_WME));
- if (retval != OK_CONTINUE)
- DBUG_RETURN(retval);
- }
/*
Let's adjust offset for remote log as for local log to produce
similar text and to have --stop-position to work identically.
@@ -2218,7 +2476,7 @@ static Exit_status check_header(IO_CACHE* file,
Format_description_log_event *new_description_event;
my_b_seek(file, tmp_pos); /* seek back to event's start */
if (!(new_description_event= (Format_description_log_event*)
- Log_event::read_log_event(file, glob_description_event,
+ Log_event::read_log_event(file, 0, glob_description_event,
opt_verify_binlog_checksum)))
/* EOF can't be hit here normally, so it's a real error */
{
@@ -2252,7 +2510,7 @@ static Exit_status check_header(IO_CACHE* file,
{
Log_event *ev;
my_b_seek(file, tmp_pos); /* seek back to event's start */
- if (!(ev= Log_event::read_log_event(file, glob_description_event,
+ if (!(ev= Log_event::read_log_event(file, 0, glob_description_event,
opt_verify_binlog_checksum)))
{
/* EOF can't be hit here normally, so it's a real error */
@@ -2312,7 +2570,7 @@ static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
/* read from stdin */
/*
Windows opens stdin in text mode by default. Certain characters
- such as CTRL-Z are interpeted as events and the read() method
+ such as CTRL-Z are interpreted 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
@@ -2340,7 +2598,7 @@ static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
my_off_t length,tmp;
for (length= start_position_mot ; length > 0 ; length-=tmp)
{
- tmp=min(length,sizeof(buff));
+ tmp= MY_MIN(length,sizeof(buff));
if (my_b_read(file, buff, (uint) tmp))
{
error("Failed reading from file.");
@@ -2366,7 +2624,7 @@ static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
char llbuff[21];
my_off_t old_off = my_b_tell(file);
- Log_event* ev = Log_event::read_log_event(file, glob_description_event,
+ Log_event* ev = Log_event::read_log_event(file, 0, glob_description_event,
opt_verify_binlog_checksum);
if (!ev)
{
@@ -2424,27 +2682,26 @@ int main(int argc, char** argv)
my_init_time(); // for time functions
tzset(); // set tzname
- init_alloc_root(&s_mem_root, 16384, 0);
- if (load_defaults("my", load_groups, &argc, &argv))
- exit(1);
+ init_alloc_root(&s_mem_root, 16384, 0, MYF(0));
+ load_defaults_or_exit("my", load_groups, &argc, &argv);
+ defaults_argv= argv;
if (!(binlog_filter= new Rpl_filter))
{
error("Failed to create Rpl_filter");
- exit(1);
+ goto err;
}
- defaults_argv= argv;
parse_args(&argc, (char***)&argv);
if (!argc || opt_version)
{
- if (!argc)
+ if (!opt_version)
+ {
usage();
- cleanup();
- free_defaults(defaults_argv);
- my_end(my_end_arg);
- exit(!opt_version);
+ retval= ERROR_STOP;
+ }
+ goto err;
}
if (opt_base64_output_mode == BASE64_OUTPUT_UNSPEC)
@@ -2459,45 +2716,91 @@ int main(int argc, char** argv)
my_set_max_open_files(open_files_limit);
+ if (opt_stop_never)
+ to_last_remote_log= TRUE;
+
+ if (opt_raw_mode)
+ {
+ if (!remote_opt)
+ {
+ error("The --raw mode only works with --read-from-remote-server");
+ exit(1);
+ }
+ if (one_database)
+ warning("The --database option is ignored in raw mode");
+
+ if (stop_position != (ulonglong)(~(my_off_t)0))
+ warning("The --stop-position option is ignored in raw mode");
+
+ if (stop_datetime != MY_TIME_T_MAX)
+ warning("The --stop-datetime option is ignored in raw mode");
+ result_file= 0;
+ if (result_file_name)
+ output_prefix= result_file_name;
+ }
+ else
+ {
+ if (result_file_name)
+ {
+ if (!(result_file= my_fopen(result_file_name,
+ O_WRONLY | O_BINARY, MYF(MY_WME))))
+ {
+ error("Could not create log file '%s'", result_file_name);
+ exit(1);
+ }
+ }
+ else
+ result_file= stdout;
+ }
+
MY_TMPDIR tmpdir;
tmpdir.list= 0;
if (!dirname_for_local_load)
{
if (init_tmpdir(&tmpdir, 0))
- exit(1);
+ {
+ retval= ERROR_STOP;
+ goto err;
+ }
dirname_for_local_load= my_strdup(my_tmpdir(&tmpdir), MY_WME);
}
if (load_processor.init())
- exit(1);
+ {
+ retval= ERROR_STOP;
+ goto err;
+ }
if (dirname_for_local_load)
load_processor.init_by_dir_name(dirname_for_local_load);
else
load_processor.init_by_cur_dir();
- fprintf(result_file, "/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;\n");
-
- fprintf(result_file,
- "/*!40019 SET @@session.max_insert_delayed_threads=0*/;\n");
+ if (!opt_raw_mode)
+ {
+ fprintf(result_file, "/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;\n");
- if (disable_log_bin)
fprintf(result_file,
- "/*!32316 SET @OLD_SQL_LOG_BIN=@@SQL_LOG_BIN, SQL_LOG_BIN=0*/;\n");
+ "/*!40019 SET @@session.max_insert_delayed_threads=0*/;\n");
- /*
- In mysqlbinlog|mysql, don't want mysql to be disconnected after each
- transaction (which would be the case with GLOBAL.COMPLETION_TYPE==2).
- */
- fprintf(result_file,
- "/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,"
- "COMPLETION_TYPE=0*/;\n");
+ if (disable_log_bin)
+ fprintf(result_file,
+ "/*!32316 SET @OLD_SQL_LOG_BIN=@@SQL_LOG_BIN, SQL_LOG_BIN=0*/;\n");
- if (charset)
+ /*
+ In mysqlbinlog|mysql, don't want mysql to be disconnected after each
+ transaction (which would be the case with GLOBAL.COMPLETION_TYPE==2).
+ */
fprintf(result_file,
- "\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
- "\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
- "\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
- "\n/*!40101 SET NAMES %s */;\n", charset);
+ "/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,"
+ "COMPLETION_TYPE=0*/;\n");
+
+ if (charset)
+ fprintf(result_file,
+ "\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
+ "\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
+ "\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
+ "\n/*!40101 SET NAMES %s */;\n", charset);
+ }
for (save_stop_position= stop_position, stop_position= ~(my_off_t)0 ;
(--argc >= 0) ; )
@@ -2511,27 +2814,30 @@ int main(int argc, char** argv)
start_position= BIN_LOG_HEADER_SIZE;
}
- /*
- Issue a ROLLBACK in case the last printed binlog was crashed and had half
- of transaction.
- */
- fprintf(result_file,
- "# End of log file\nROLLBACK /* added by mysqlbinlog */;\n"
- "/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;\n");
- if (disable_log_bin)
- fprintf(result_file, "/*!32316 SET SQL_LOG_BIN=@OLD_SQL_LOG_BIN*/;\n");
-
- if (charset)
+ if (!opt_raw_mode)
+ {
+ /*
+ Issue a ROLLBACK in case the last printed binlog was crashed and had half
+ of transaction.
+ */
fprintf(result_file,
- "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n"
- "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n"
- "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n");
-
- fprintf(result_file, "/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;\n");
+ "# End of log file\nROLLBACK /* added by mysqlbinlog */;\n"
+ "/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;\n");
+ if (disable_log_bin)
+ fprintf(result_file, "/*!32316 SET SQL_LOG_BIN=@OLD_SQL_LOG_BIN*/;\n");
+
+ if (charset)
+ fprintf(result_file,
+ "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n"
+ "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n"
+ "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n");
+
+ fprintf(result_file, "/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;\n");
+ }
if (tmpdir.list)
free_tmpdir(&tmpdir);
- if (result_file != stdout)
+ if (result_file && result_file != stdout)
my_fclose(result_file, MYF(0));
cleanup();
free_annotate_event();
@@ -2539,12 +2845,20 @@ int main(int argc, char** argv)
free_defaults(defaults_argv);
my_free_open_file_info();
load_processor.destroy();
+ mysql_server_end();
/* We cannot free DBUG, it is used in global destructors after exit(). */
my_end(my_end_arg | MY_DONT_FREE_DBUG);
exit(retval == ERROR_STOP ? 1 : 0);
/* Keep compilers happy. */
DBUG_RETURN(retval == ERROR_STOP ? 1 : 0);
+
+err:
+ cleanup();
+ free_defaults(defaults_argv);
+ my_end(my_end_arg);
+ exit(retval == ERROR_STOP ? 1 : 0);
+ DBUG_RETURN(retval == ERROR_STOP ? 1 : 0);
}
@@ -2553,6 +2867,27 @@ void *sql_alloc(size_t size)
return alloc_root(&s_mem_root, size);
}
+uint e_key_get_latest_version_func(uint) { return 1; }
+uint e_key_get_func(uint, uint, uchar*, uint*) { return 1; }
+uint e_ctx_size_func(uint, uint) { return 1; }
+int e_ctx_init_func(void *, const uchar*, uint, const uchar*, uint,
+ int, uint, uint) { return 1; }
+int e_ctx_update_func(void *, const uchar*, uint, uchar*, uint*) { return 1; }
+int e_ctx_finish_func(void *, uchar*, uint*) { return 1; }
+uint e_encrypted_length_func(uint, uint, uint) { return 1; }
+
+uint dummy1() { return 1; }
+struct encryption_service_st encryption_handler=
+{
+ e_key_get_latest_version_func,
+ e_key_get_func,
+ e_ctx_size_func,
+ e_ctx_init_func,
+ e_ctx_update_func,
+ e_ctx_finish_func,
+ e_encrypted_length_func
+};
+
/*
We must include this here as it's compiled with different options for
the server
@@ -2569,3 +2904,4 @@ void *sql_alloc(size_t size)
#include "sql_string.cc"
#include "sql_list.cc"
#include "rpl_filter.cc"
+#include "compat56.cc"