Merge riska.(none):/home/sven/bkroot/5.1-new-rpl
into riska.(none):/home/sven/bk/b32407-5.1-new-rpl-mysqlbinlog_base64
This commit is contained in:
commit
8b22f0a1d1
@ -77,7 +77,7 @@ enum options_client
|
||||
OPT_SLAP_POST_SYSTEM,
|
||||
OPT_SLAP_COMMIT,
|
||||
OPT_SLAP_DETACH,
|
||||
OPT_MYSQL_REPLACE_INTO, OPT_BASE64_OUTPUT, OPT_SERVER_ID,
|
||||
OPT_MYSQL_REPLACE_INTO, OPT_BASE64_OUTPUT_MODE, OPT_SERVER_ID,
|
||||
OPT_FIX_TABLE_NAMES, OPT_FIX_DB_NAMES, OPT_SSL_VERIFY_SERVER_CERT,
|
||||
OPT_DEBUG_INFO, OPT_DEBUG_CHECK, OPT_COLUMN_TYPES, OPT_ERROR_LOG_FILE,
|
||||
OPT_WRITE_BINLOG, OPT_DUMP_DATE,
|
||||
|
@ -63,7 +63,12 @@ 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;
|
||||
const char *base64_output_mode_names[]= {"NEVER", "AUTO", "ALWAYS", NullS};
|
||||
TYPELIB base64_output_mode_typelib=
|
||||
{ array_elements(base64_output_mode_names) - 1, "",
|
||||
base64_output_mode_names, NULL };
|
||||
static enum_base64_output_mode opt_base64_output_mode= BASE64_OUTPUT_UNSPEC;
|
||||
static const char *opt_base64_output_mode_str= NullS;
|
||||
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;
|
||||
@ -96,7 +101,7 @@ static my_bool file_not_closed_error= 0;
|
||||
This is because the event will be created (alloced) in read_log_event()
|
||||
(which returns a pointer) in check_header().
|
||||
*/
|
||||
Format_description_log_event* glob_description_event;
|
||||
static Format_description_log_event* glob_description_event;
|
||||
|
||||
static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
|
||||
const char* logname);
|
||||
@ -557,7 +562,7 @@ 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;
|
||||
print_event_info->base64_output_mode= opt_base64_output_mode;
|
||||
|
||||
DBUG_PRINT("debug", ("event_type: %s", ev->get_type_str()));
|
||||
|
||||
@ -565,7 +570,7 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
|
||||
case QUERY_EVENT:
|
||||
if (check_database(((Query_log_event*)ev)->db))
|
||||
goto end;
|
||||
if (opt_base64_output)
|
||||
if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS)
|
||||
write_event_header_and_base64(ev, result_file, print_event_info);
|
||||
else
|
||||
ev->print(result_file, print_event_info);
|
||||
@ -589,7 +594,7 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
|
||||
filename and use LOCAL), prepared in the 'case EXEC_LOAD_EVENT'
|
||||
below.
|
||||
*/
|
||||
if (opt_base64_output)
|
||||
if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS)
|
||||
{
|
||||
write_event_header_and_base64(ce, result_file, print_event_info);
|
||||
}
|
||||
@ -678,6 +683,38 @@ Create_file event for file_id: %u\n",exv->file_id);
|
||||
Begin_load_query event for file_id: %u\n", exlq->file_id);
|
||||
break;
|
||||
}
|
||||
case TABLE_MAP_EVENT:
|
||||
case WRITE_ROWS_EVENT:
|
||||
case DELETE_ROWS_EVENT:
|
||||
case UPDATE_ROWS_EVENT:
|
||||
case PRE_GA_WRITE_ROWS_EVENT:
|
||||
case PRE_GA_DELETE_ROWS_EVENT:
|
||||
case PRE_GA_UPDATE_ROWS_EVENT:
|
||||
/*
|
||||
These events must be printed in base64 format, if printed.
|
||||
base64 format requires a FD event to be safe, so if no FD
|
||||
event has been printed, we give an error. Except if user
|
||||
passed --short-form, because --short-form disables printing
|
||||
row events.
|
||||
*/
|
||||
if (!print_event_info->printed_fd_event && !short_form)
|
||||
{
|
||||
/*
|
||||
todo: a lot to clean up here
|
||||
*/
|
||||
const char* type_str= ev->get_type_str();
|
||||
delete ev;
|
||||
if (opt_base64_output_mode == BASE64_OUTPUT_NEVER)
|
||||
die("--base64-output=never specified, but binlog contains a "
|
||||
"%s event which must be printed in base64.",
|
||||
type_str);
|
||||
else
|
||||
die("malformed binlog: it does not contain any "
|
||||
"Format_description_log_event. I now found a %s event, which is "
|
||||
"not safe to process without a Format_description_log_event.",
|
||||
type_str);
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
default:
|
||||
ev->print(result_file, print_event_info);
|
||||
}
|
||||
@ -707,12 +744,17 @@ static struct my_option my_long_options[] =
|
||||
{"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},
|
||||
{"base64-output", OPT_BASE64_OUTPUT_MODE,
|
||||
"Determine when the output statements should be base64-encoded BINLOG "
|
||||
"statements: 'never' disables it and works only for binlogs without "
|
||||
"row-based events; 'auto' is the default and prints base64 only when "
|
||||
"necessary (i.e., for row-based events and format description events); "
|
||||
"'always' prints base64 whenever possible. 'always' is for debugging "
|
||||
"only and should not be used in a production system. The default is "
|
||||
"'auto'. --base64-output is a short form for --base64-output=always."
|
||||
,(uchar**) &opt_base64_output_mode_str,
|
||||
(uchar**) &opt_base64_output_mode_str,
|
||||
0, GET_STR, OPT_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
|
||||
@ -788,7 +830,10 @@ static struct my_option my_long_options[] =
|
||||
{"set-charset", OPT_SET_CHARSET,
|
||||
"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.",
|
||||
{"short-form", 's', "Just show regular queries: no extra info and no "
|
||||
"row-based events. This is for testing only, and should not be used in "
|
||||
"production systems. If you want to suppress base64-output, consider "
|
||||
"using --base64-output=never instead.",
|
||||
(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.",
|
||||
@ -973,6 +1018,15 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
|
||||
case OPT_STOP_DATETIME:
|
||||
stop_datetime= convert_str_to_timestamp(stop_datetime_str);
|
||||
break;
|
||||
case OPT_BASE64_OUTPUT_MODE:
|
||||
if (argument == NULL)
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case 'V':
|
||||
print_version();
|
||||
exit(0);
|
||||
@ -1305,8 +1359,31 @@ err:
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Reads the @c Format_description_log_event from the beginning of the
|
||||
input file.
|
||||
|
||||
The @c Format_description_log_event is only read if it is outside
|
||||
the range specified with @c --start-position; otherwise, it will be
|
||||
seen later. If this is an old binlog, a fake @c
|
||||
Format_description_event is created. This also prints a @c
|
||||
Format_description_log_event to the output, unless we reach the
|
||||
--start-position range. In this case, it is assumed that a @c
|
||||
Format_description_log_event will be found when reading events the
|
||||
usual way.
|
||||
|
||||
@param file The file to which a @c Format_description_log_event will
|
||||
be printed.
|
||||
|
||||
@param description_event Pointer to the global @c
|
||||
Format_description_log_event pointer. This will be updated if a new
|
||||
Format_description_log_event is found.
|
||||
|
||||
@param print_event_info Context state needed to print events.
|
||||
*/
|
||||
static void check_header(IO_CACHE* file,
|
||||
Format_description_log_event **description_event)
|
||||
Format_description_log_event **description_event,
|
||||
PRINT_EVENT_INFO *print_event_info)
|
||||
{
|
||||
uchar header[BIN_LOG_HEADER_SIZE];
|
||||
uchar buf[PROBE_HEADER_LEN];
|
||||
@ -1369,10 +1446,12 @@ Could not read entry at offset %lu : Error in log format or read error",
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_PRINT("info",("buf[4]=%d", buf[4]));
|
||||
DBUG_PRINT("info",("buf[EVENT_TYPE_OFFSET=%d]=%d",
|
||||
EVENT_TYPE_OFFSET, buf[EVENT_TYPE_OFFSET]));
|
||||
/* always test for a Start_v3, even if no --start-position */
|
||||
if (buf[4] == START_EVENT_V3) /* This is 3.23 or 4.x */
|
||||
if (buf[EVENT_TYPE_OFFSET] == START_EVENT_V3)
|
||||
{
|
||||
/* This is 3.23 or 4.x */
|
||||
if (uint4korr(buf + EVENT_LEN_OFFSET) <
|
||||
(LOG_EVENT_MINIMAL_HEADER_LEN + START_V3_HEADER_LEN))
|
||||
{
|
||||
@ -1384,8 +1463,9 @@ Could not read entry at offset %lu : Error in log format or read error",
|
||||
}
|
||||
else if (tmp_pos >= start_position)
|
||||
break;
|
||||
else if (buf[4] == FORMAT_DESCRIPTION_EVENT) /* This is 5.0 */
|
||||
else if (buf[EVENT_TYPE_OFFSET] == 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 (!(new_description_event= (Format_description_log_event*)
|
||||
@ -1397,11 +1477,22 @@ Could not read entry at offset %lu : Error in log format or read error",
|
||||
at offset %lu ; this could be a log format error or read error",
|
||||
tmp_pos);
|
||||
}
|
||||
delete *description_event;
|
||||
*description_event= new_description_event;
|
||||
if (opt_base64_output_mode == BASE64_OUTPUT_AUTO
|
||||
|| opt_base64_output_mode == BASE64_OUTPUT_ALWAYS)
|
||||
/*
|
||||
process_event will delete *description_event and set it to
|
||||
the new one, so we should not do it ourselves in this
|
||||
case.
|
||||
*/
|
||||
process_event(print_event_info, new_description_event, tmp_pos);
|
||||
else
|
||||
{
|
||||
delete *description_event;
|
||||
*description_event= new_description_event;
|
||||
}
|
||||
DBUG_PRINT("info",("Setting description_event"));
|
||||
}
|
||||
else if (buf[4] == ROTATE_EVENT)
|
||||
else if (buf[EVENT_TYPE_OFFSET] == ROTATE_EVENT)
|
||||
{
|
||||
Log_event *ev;
|
||||
my_b_seek(file, tmp_pos); /* seek back to event's start */
|
||||
@ -1430,7 +1521,7 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
|
||||
uchar tmp_buff[BIN_LOG_HEADER_SIZE];
|
||||
int error= 0;
|
||||
|
||||
if (logname && logname[0] != '-')
|
||||
if (logname && strcmp(logname, "-") != 0)
|
||||
{
|
||||
if ((fd = my_open(logname, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0)
|
||||
return 1;
|
||||
@ -1440,7 +1531,7 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
|
||||
my_close(fd, MYF(MY_WME));
|
||||
return 1;
|
||||
}
|
||||
check_header(file, &glob_description_event);
|
||||
check_header(file, &glob_description_event, print_event_info);
|
||||
}
|
||||
else // reading from stdin;
|
||||
{
|
||||
@ -1462,7 +1553,7 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
|
||||
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;
|
||||
check_header(file, &glob_description_event);
|
||||
check_header(file, &glob_description_event, print_event_info);
|
||||
if (start_position)
|
||||
{
|
||||
/* skip 'start_position' characters from stdin */
|
||||
@ -1554,6 +1645,9 @@ int main(int argc, char** argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (opt_base64_output_mode == BASE64_OUTPUT_UNSPEC)
|
||||
opt_base64_output_mode= BASE64_OUTPUT_AUTO;
|
||||
|
||||
my_set_max_open_files(open_files_limit);
|
||||
|
||||
MY_TMPDIR tmpdir;
|
||||
|
@ -106,6 +106,7 @@ ROLLBACK /* added by mysqlbinlog */;
|
||||
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
|
||||
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
|
||||
DELIMITER /*!*/;
|
||||
ROLLBACK/*!*/;
|
||||
SET INSERT_ID=4/*!*/;
|
||||
use test/*!*/;
|
||||
SET TIMESTAMP=1579609946/*!*/;
|
||||
@ -152,6 +153,7 @@ ROLLBACK /* added by mysqlbinlog */;
|
||||
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
|
||||
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
|
||||
DELIMITER /*!*/;
|
||||
ROLLBACK/*!*/;
|
||||
SET INSERT_ID=4/*!*/;
|
||||
use test/*!*/;
|
||||
SET TIMESTAMP=1579609946/*!*/;
|
||||
@ -299,6 +301,7 @@ ROLLBACK /* added by mysqlbinlog */;
|
||||
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
|
||||
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
|
||||
DELIMITER /*!*/;
|
||||
ROLLBACK/*!*/;
|
||||
SET INSERT_ID=4/*!*/;
|
||||
use test/*!*/;
|
||||
SET TIMESTAMP=1579609946/*!*/;
|
||||
|
60
mysql-test/suite/binlog/r/binlog_base64_flag.result
Normal file
60
mysql-test/suite/binlog/r/binlog_base64_flag.result
Normal file
@ -0,0 +1,60 @@
|
||||
==== Test BUG#32407 ====
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
1
|
||||
==== Test BINLOG statement w/o FD event ====
|
||||
BINLOG '
|
||||
SVtYRxMBAAAAKQAAADQBAAAAABAAAAAAAAAABHRlc3QAAnQxAAEDAAE=
|
||||
SVtYRxcBAAAAIgAAAFYBAAAQABAAAAAAAAEAAf/+AgAAAA==
|
||||
';
|
||||
ERROR HY000: The BINLOG statement of type `Table_map` was not preceded by a format description BINLOG statement.
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
1
|
||||
==== Test BINLOG statement with FD event ====
|
||||
BINLOG '
|
||||
ODdYRw8BAAAAZgAAAGoAAAABAAQANS4xLjIzLXJjLWRlYnVnLWxvZwAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAA4N1hHEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC
|
||||
';
|
||||
BINLOG '
|
||||
TFtYRxMBAAAAKQAAAH8BAAAAABAAAAAAAAAABHRlc3QAAnQxAAEDAAE=
|
||||
TFtYRxcBAAAAIgAAAKEBAAAQABAAAAAAAAEAAf/+AwAAAA==
|
||||
';
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
1
|
||||
3
|
||||
==== Test --base64-output=never on a binlog with row events ====
|
||||
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
|
||||
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
|
||||
DELIMITER /*!*/;
|
||||
# at 4
|
||||
#ROLLBACK/*!*/;
|
||||
# at 102
|
||||
#use test/*!*/;
|
||||
SET TIMESTAMP=1196959712/*!*/;
|
||||
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1/*!*/;
|
||||
SET @@session.sql_mode=0/*!*/;
|
||||
/*!\C latin1 *//*!*/;
|
||||
SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/;
|
||||
create table t1 (a int) engine= myisam/*!*/;
|
||||
# at 203
|
||||
==== Test non-matching FD event and Row event ====
|
||||
BINLOG '
|
||||
4CdYRw8BAAAAYgAAAGYAAAAAAAQANS4xLjE1LW5kYi02LjEuMjQtZGVidWctbG9nAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAADgJ1hHEzgNAAgAEgAEBAQEEgAATwAEGggICAg=
|
||||
';
|
||||
BINLOG '
|
||||
Dl1YRxMBAAAAKQAAADQBAAAAABAAAAAAAAAABHRlc3QAAnQxAAEDAAE=
|
||||
Dl1YRxcBAAAAIgAAAFYBAAAQABAAAAAAAAEAAf/+BQAAAA==
|
||||
';
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
1
|
||||
3
|
||||
drop table t1;
|
BIN
mysql-test/suite/binlog/std_data/binlog-bug32407.000001
Normal file
BIN
mysql-test/suite/binlog/std_data/binlog-bug32407.000001
Normal file
Binary file not shown.
102
mysql-test/suite/binlog/t/binlog_base64_flag.test
Normal file
102
mysql-test/suite/binlog/t/binlog_base64_flag.test
Normal file
@ -0,0 +1,102 @@
|
||||
# This test case verifies that the mysqlbinlog --base64-output=X flags
|
||||
# work as expected, and that BINLOG statements with row events fail if
|
||||
# they are not preceded by BINLOG statements with Format description
|
||||
# events.
|
||||
#
|
||||
# See also BUG#32407.
|
||||
|
||||
|
||||
# Test to show BUG#32407. This reads a binlog created with the
|
||||
# mysql-5.1-telco-6.1 tree, specifically at the tag
|
||||
# mysql-5.1.15-ndb-6.1.23, and applies it to the database. The test
|
||||
# should fail before BUG#32407 was fixed and succeed afterwards.
|
||||
--echo ==== Test BUG#32407 ====
|
||||
|
||||
# The binlog contains row events equivalent to:
|
||||
# CREATE TABLE t1 (a int) engine = myisam
|
||||
# INSERT INTO t1 VALUES (1), (1)
|
||||
exec $MYSQL_BINLOG suite/binlog/std_data/binlog-bug32407.000001 | $MYSQL;
|
||||
# The above line should succeed and t1 should contain two ones
|
||||
select * from t1;
|
||||
|
||||
|
||||
# Test that a BINLOG statement encoding a row event fails unless a
|
||||
# Format_description_event as been supplied with an earlier BINLOG
|
||||
# statement.
|
||||
--echo ==== Test BINLOG statement w/o FD event ====
|
||||
|
||||
# This is a binlog statement consisting of one Table_map_log_event and
|
||||
# one Write_rows_log_event. Together, they correspond to the
|
||||
# following query:
|
||||
# INSERT INTO TABLE test.t1 VALUES (2)
|
||||
|
||||
error ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT;
|
||||
BINLOG '
|
||||
SVtYRxMBAAAAKQAAADQBAAAAABAAAAAAAAAABHRlc3QAAnQxAAEDAAE=
|
||||
SVtYRxcBAAAAIgAAAFYBAAAQABAAAAAAAAEAAf/+AgAAAA==
|
||||
';
|
||||
# The above line should fail and 2 should not be in the table
|
||||
select * from t1;
|
||||
|
||||
|
||||
# Test that it works to read a Format_description_log_event with a
|
||||
# BINLOG statement, followed by a row-event in base64 from the same
|
||||
# version.
|
||||
--echo ==== Test BINLOG statement with FD event ====
|
||||
|
||||
# This is a binlog statement containing a Format_description_log_event
|
||||
# from the same version as the Table_map and Write_rows_log_event.
|
||||
BINLOG '
|
||||
ODdYRw8BAAAAZgAAAGoAAAABAAQANS4xLjIzLXJjLWRlYnVnLWxvZwAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAA4N1hHEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC
|
||||
';
|
||||
|
||||
# This is a Table_map_log_event+Write_rows_log_event corresponding to:
|
||||
# INSERT INTO TABLE test.t1 VALUES (3)
|
||||
BINLOG '
|
||||
TFtYRxMBAAAAKQAAAH8BAAAAABAAAAAAAAAABHRlc3QAAnQxAAEDAAE=
|
||||
TFtYRxcBAAAAIgAAAKEBAAAQABAAAAAAAAEAAf/+AwAAAA==
|
||||
';
|
||||
# The above line should succeed and 3 should be in the table
|
||||
select * from t1;
|
||||
|
||||
|
||||
# Test that mysqlbinlog stops with an error message when the
|
||||
# --base64-output=never flag is used on a binlog with base64 events.
|
||||
--echo ==== Test --base64-output=never on a binlog with row events ====
|
||||
|
||||
# mysqlbinlog should fail
|
||||
--replace_regex /#[0-9][0-9][0-9][0-9][0-9][0-9] .*/#/
|
||||
error 1;
|
||||
exec $MYSQL_BINLOG --base64-output=never suite/binlog/std_data/binlog-bug32407.000001;
|
||||
# the above line should output the query log event and then stop
|
||||
|
||||
|
||||
# Test that the following fails cleanly: "First, read a
|
||||
# Format_description event which has N event types. Then, read an
|
||||
# event of type M>N"
|
||||
--echo ==== Test non-matching FD event and Row event ====
|
||||
|
||||
# This is the Format_description_log_event from
|
||||
# binlog-bug32407.000001, encoded in base64. It contains only the old
|
||||
# row events (number of event types is 22)
|
||||
BINLOG '
|
||||
4CdYRw8BAAAAYgAAAGYAAAAAAAQANS4xLjE1LW5kYi02LjEuMjQtZGVidWctbG9nAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAADgJ1hHEzgNAAgAEgAEBAQEEgAATwAEGggICAg=
|
||||
';
|
||||
|
||||
# The following is a Write_rows_log_event with event type 23, i.e.,
|
||||
# not supported by the Format_description_log_event above. It
|
||||
# corresponds to the following query:
|
||||
# INSERT INTO t1 VALUES (5)
|
||||
error 1149;
|
||||
BINLOG '
|
||||
Dl1YRxMBAAAAKQAAADQBAAAAABAAAAAAAAAABHRlc3QAAnQxAAEDAAE=
|
||||
Dl1YRxcBAAAAIgAAAFYBAAAQABAAAAAAAAEAAf/+BQAAAA==
|
||||
';
|
||||
# the above line should fail and 5 should not be in the binlog.
|
||||
select * from t1;
|
||||
|
||||
|
||||
# clean up
|
||||
drop table t1;
|
@ -9,3 +9,4 @@
|
||||
# Do not use any TAB characters for whitespace.
|
||||
#
|
||||
##############################################################################
|
||||
binlog_base64_flag : BUG#33247 2007-12-14 Sven: mysqlbinlog does not clean up after itself on termination. When compiled in debug mode, this test generates lots of warnings for memory leaks.
|
||||
|
@ -40,6 +40,10 @@ KEY `data` (`data`)
|
||||
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
|
||||
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
|
||||
BINLOG '
|
||||
O1ZVRw8BAAAAZgAAAGoAAAAAAAQANS4xLjIzLXJjLWRlYnVnLWxvZwAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAA7VlVHEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC
|
||||
'/*!*/;
|
||||
BINLOG '
|
||||
Bk3vRhO0AQAAOAAAALcLyQkAAJlXFwIAAAAABXRyYWNrAA12aXNpdHNfZXZlbnRzAAYJAwcPDwM=
|
||||
Bk3vRhe0AQAAWgAAABEMyQkQAJlXFwIAAAEABv/AIE4AvvVDAQZN70YAK0Rvd25sb2Fkcy9NeVNR
|
||||
TC00LjEvbXlzcWwtNC4xLjEyYS13aW4zMi56aXBPaAIC
|
||||
|
@ -155,6 +155,7 @@ c1 c3 c4 c5
|
||||
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
|
||||
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
|
||||
DELIMITER /*!*/;
|
||||
ROLLBACK/*!*/;
|
||||
use test/*!*/;
|
||||
SET TIMESTAMP=1000000000/*!*/;
|
||||
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1/*!*/;
|
||||
@ -295,6 +296,7 @@ ROLLBACK /* added by mysqlbinlog */;
|
||||
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
|
||||
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
|
||||
DELIMITER /*!*/;
|
||||
ROLLBACK/*!*/;
|
||||
use test/*!*/;
|
||||
SET TIMESTAMP=1000000000/*!*/;
|
||||
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1/*!*/;
|
||||
|
@ -39,6 +39,24 @@ CREATE TABLE `visits_events` (
|
||||
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
|
||||
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
|
||||
--delimiter /*!*/;
|
||||
|
||||
# at 4 (0x4)
|
||||
#071204 14:29:31 server id 1 end_log_pos 106
|
||||
# Position Timestamp Type Master ID Size Master Pos Flags
|
||||
# 4 3b 56 55 47 0f 01 00 00 00 66 00 00 00 6a 00 00 00 00 00
|
||||
# 17 04 00 35 2e 31 2e 32 33 2d 72 63 2d 64 65 62 75 |..5.1.23.rc.debu|
|
||||
# 27 67 2d 6c 6f 67 00 00 00 00 00 00 00 00 00 00 00 |g.log...........|
|
||||
# 37 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
# 47 00 00 00 00 3b 56 55 47 13 38 0d 00 08 00 12 00 |.....VUG.8......|
|
||||
# 57 04 04 04 04 12 00 00 53 00 04 1a 08 00 00 00 08 |.......S........|
|
||||
# 67 08 08 02 |...|
|
||||
# Start: binlog v 4, server v 5.1.23-rc-debug-log created 071204 14:29:31 at startup
|
||||
|
||||
BINLOG '
|
||||
O1ZVRw8BAAAAZgAAAGoAAAAAAAQANS4xLjIzLXJjLWRlYnVnLWxvZwAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAA7VlVHEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC
|
||||
'/*!*/;
|
||||
|
||||
# at 164170623
|
||||
# at 164170679
|
||||
#7918 3:59:2 server id 436 end_log_pos 164170679
|
||||
|
@ -42,7 +42,7 @@ select "--- Local --" as "";
|
||||
#
|
||||
|
||||
--replace_regex /[[:<:]][0-9]{6} [0-9 ][0-9]:[0-9]{2}:[0-9]{2}[[:>:]]/{yymmdd} {HH:MM:SS}/ /=[0-9]+ /={integer} / /# at [0-9]+/# at {pos}/ /(pos:?) [0-9]+/\1 {pos}/ /binlog v [0-9]+, server v [^ ]* created/binlog v #, server v ## created/
|
||||
--exec $MYSQL_BINLOG $MYSQLTEST_VARDIR/log/master-bin.000001
|
||||
--exec $MYSQL_BINLOG --base64-output=never $MYSQLTEST_VARDIR/log/master-bin.000001
|
||||
|
||||
--disable_query_log
|
||||
select "--- offset --" as "";
|
||||
|
210
sql/log_event.cc
210
sql/log_event.cc
@ -491,9 +491,9 @@ static void print_set_option(IO_CACHE* file, uint32 bits_changed,
|
||||
Log_event::get_type_str()
|
||||
*/
|
||||
|
||||
const char* Log_event::get_type_str()
|
||||
const char* Log_event::get_type_str(Log_event_type type)
|
||||
{
|
||||
switch(get_type_code()) {
|
||||
switch(type) {
|
||||
case START_EVENT_V3: return "Start_v3";
|
||||
case STOP_EVENT: return "Stop";
|
||||
case QUERY_EVENT: return "Query";
|
||||
@ -524,6 +524,11 @@ const char* Log_event::get_type_str()
|
||||
}
|
||||
}
|
||||
|
||||
const char* Log_event::get_type_str()
|
||||
{
|
||||
return get_type_str(get_type_code());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Log_event::Log_event()
|
||||
@ -1050,94 +1055,111 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
|
||||
DBUG_RETURN(NULL); // general sanity check - will fail on a partial read
|
||||
}
|
||||
|
||||
switch(buf[EVENT_TYPE_OFFSET]) {
|
||||
case QUERY_EVENT:
|
||||
ev = new Query_log_event(buf, event_len, description_event, QUERY_EVENT);
|
||||
break;
|
||||
case LOAD_EVENT:
|
||||
ev = new Load_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case NEW_LOAD_EVENT:
|
||||
ev = new Load_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case ROTATE_EVENT:
|
||||
ev = new Rotate_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
#ifdef HAVE_REPLICATION
|
||||
case SLAVE_EVENT: /* can never happen (unused event) */
|
||||
ev = new Slave_log_event(buf, event_len);
|
||||
break;
|
||||
#endif /* HAVE_REPLICATION */
|
||||
case CREATE_FILE_EVENT:
|
||||
ev = new Create_file_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case APPEND_BLOCK_EVENT:
|
||||
ev = new Append_block_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case DELETE_FILE_EVENT:
|
||||
ev = new Delete_file_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case EXEC_LOAD_EVENT:
|
||||
ev = new Execute_load_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case START_EVENT_V3: /* this is sent only by MySQL <=4.x */
|
||||
ev = new Start_log_event_v3(buf, description_event);
|
||||
break;
|
||||
case STOP_EVENT:
|
||||
ev = new Stop_log_event(buf, description_event);
|
||||
break;
|
||||
case INTVAR_EVENT:
|
||||
ev = new Intvar_log_event(buf, description_event);
|
||||
break;
|
||||
case XID_EVENT:
|
||||
ev = new Xid_log_event(buf, description_event);
|
||||
break;
|
||||
case RAND_EVENT:
|
||||
ev = new Rand_log_event(buf, description_event);
|
||||
break;
|
||||
case USER_VAR_EVENT:
|
||||
ev = new User_var_log_event(buf, description_event);
|
||||
break;
|
||||
case FORMAT_DESCRIPTION_EVENT:
|
||||
ev = new Format_description_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
#if defined(HAVE_REPLICATION)
|
||||
case PRE_GA_WRITE_ROWS_EVENT:
|
||||
ev = new Write_rows_log_event_old(buf, event_len, description_event);
|
||||
break;
|
||||
case PRE_GA_UPDATE_ROWS_EVENT:
|
||||
ev = new Update_rows_log_event_old(buf, event_len, description_event);
|
||||
break;
|
||||
case PRE_GA_DELETE_ROWS_EVENT:
|
||||
ev = new Delete_rows_log_event_old(buf, event_len, description_event);
|
||||
break;
|
||||
case WRITE_ROWS_EVENT:
|
||||
ev = new Write_rows_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case UPDATE_ROWS_EVENT:
|
||||
ev = new Update_rows_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case DELETE_ROWS_EVENT:
|
||||
ev = new Delete_rows_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case TABLE_MAP_EVENT:
|
||||
ev = new Table_map_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
#endif
|
||||
case BEGIN_LOAD_QUERY_EVENT:
|
||||
ev = new Begin_load_query_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case EXECUTE_LOAD_QUERY_EVENT:
|
||||
ev= new Execute_load_query_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case INCIDENT_EVENT:
|
||||
ev = new Incident_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
default:
|
||||
DBUG_PRINT("error",("Unknown event code: %d",
|
||||
(int) buf[EVENT_TYPE_OFFSET]));
|
||||
uint event_type= buf[EVENT_TYPE_OFFSET];
|
||||
if (event_type > description_event->number_of_event_types &&
|
||||
event_type != FORMAT_DESCRIPTION_EVENT)
|
||||
{
|
||||
/*
|
||||
It is unsafe to use the description_event if its post_header_len
|
||||
array does not include the event type.
|
||||
*/
|
||||
DBUG_PRINT("error", ("event type %d found, but the current "
|
||||
"Format_description_log_event supports only %d event "
|
||||
"types", event_type,
|
||||
description_event->number_of_event_types));
|
||||
ev= NULL;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(event_type) {
|
||||
case QUERY_EVENT:
|
||||
ev = new Query_log_event(buf, event_len, description_event, QUERY_EVENT);
|
||||
break;
|
||||
case LOAD_EVENT:
|
||||
ev = new Load_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case NEW_LOAD_EVENT:
|
||||
ev = new Load_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case ROTATE_EVENT:
|
||||
ev = new Rotate_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
#ifdef HAVE_REPLICATION
|
||||
case SLAVE_EVENT: /* can never happen (unused event) */
|
||||
ev = new Slave_log_event(buf, event_len);
|
||||
break;
|
||||
#endif /* HAVE_REPLICATION */
|
||||
case CREATE_FILE_EVENT:
|
||||
ev = new Create_file_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case APPEND_BLOCK_EVENT:
|
||||
ev = new Append_block_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case DELETE_FILE_EVENT:
|
||||
ev = new Delete_file_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case EXEC_LOAD_EVENT:
|
||||
ev = new Execute_load_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case START_EVENT_V3: /* this is sent only by MySQL <=4.x */
|
||||
ev = new Start_log_event_v3(buf, description_event);
|
||||
break;
|
||||
case STOP_EVENT:
|
||||
ev = new Stop_log_event(buf, description_event);
|
||||
break;
|
||||
case INTVAR_EVENT:
|
||||
ev = new Intvar_log_event(buf, description_event);
|
||||
break;
|
||||
case XID_EVENT:
|
||||
ev = new Xid_log_event(buf, description_event);
|
||||
break;
|
||||
case RAND_EVENT:
|
||||
ev = new Rand_log_event(buf, description_event);
|
||||
break;
|
||||
case USER_VAR_EVENT:
|
||||
ev = new User_var_log_event(buf, description_event);
|
||||
break;
|
||||
case FORMAT_DESCRIPTION_EVENT:
|
||||
ev = new Format_description_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
#if defined(HAVE_REPLICATION)
|
||||
case PRE_GA_WRITE_ROWS_EVENT:
|
||||
ev = new Write_rows_log_event_old(buf, event_len, description_event);
|
||||
break;
|
||||
case PRE_GA_UPDATE_ROWS_EVENT:
|
||||
ev = new Update_rows_log_event_old(buf, event_len, description_event);
|
||||
break;
|
||||
case PRE_GA_DELETE_ROWS_EVENT:
|
||||
ev = new Delete_rows_log_event_old(buf, event_len, description_event);
|
||||
break;
|
||||
case WRITE_ROWS_EVENT:
|
||||
ev = new Write_rows_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case UPDATE_ROWS_EVENT:
|
||||
ev = new Update_rows_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case DELETE_ROWS_EVENT:
|
||||
ev = new Delete_rows_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case TABLE_MAP_EVENT:
|
||||
ev = new Table_map_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
#endif
|
||||
case BEGIN_LOAD_QUERY_EVENT:
|
||||
ev = new Begin_load_query_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case EXECUTE_LOAD_QUERY_EVENT:
|
||||
ev= new Execute_load_query_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
case INCIDENT_EVENT:
|
||||
ev = new Incident_log_event(buf, event_len, description_event);
|
||||
break;
|
||||
default:
|
||||
DBUG_PRINT("error",("Unknown event code: %d",
|
||||
(int) buf[EVENT_TYPE_OFFSET]));
|
||||
ev= NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DBUG_PRINT("read_event", ("%s(type_code: %d; event_len: %d)",
|
||||
@ -2604,6 +2626,14 @@ void Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
|
||||
my_b_printf(&cache,"ROLLBACK%s\n", print_event_info->delimiter);
|
||||
#endif
|
||||
}
|
||||
if (temp_buf &&
|
||||
print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER &&
|
||||
!print_event_info->short_form)
|
||||
{
|
||||
my_b_printf(&cache, "BINLOG '\n");
|
||||
print_base64(&cache, print_event_info, FALSE);
|
||||
print_event_info->printed_fd_event= TRUE;
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
#endif /* MYSQL_CLIENT */
|
||||
@ -5050,7 +5080,7 @@ Create_file_log_event::Create_file_log_event(const char* buf, uint len,
|
||||
Load_log_event::get_data_size() +
|
||||
create_file_header_len + 1);
|
||||
if (len < block_offset)
|
||||
return;
|
||||
DBUG_VOID_RETURN;
|
||||
block = (char*)buf + block_offset;
|
||||
block_len = len - block_offset;
|
||||
}
|
||||
|
@ -567,6 +567,15 @@ class Format_description_log_event;
|
||||
class Relay_log_info;
|
||||
|
||||
#ifdef MYSQL_CLIENT
|
||||
enum enum_base64_output_mode {
|
||||
BASE64_OUTPUT_NEVER= 0,
|
||||
BASE64_OUTPUT_AUTO= 1,
|
||||
BASE64_OUTPUT_ALWAYS= 2,
|
||||
BASE64_OUTPUT_UNSPEC= 3,
|
||||
/* insert new output modes here */
|
||||
BASE64_OUTPUT_MODE_COUNT
|
||||
};
|
||||
|
||||
/*
|
||||
A structure for mysqlbinlog to know how to print events
|
||||
|
||||
@ -600,7 +609,8 @@ typedef struct st_print_event_info
|
||||
st_print_event_info()
|
||||
:flags2_inited(0), sql_mode_inited(0),
|
||||
auto_increment_increment(1),auto_increment_offset(1), charset_inited(0),
|
||||
lc_time_names_number(0), charset_database_number(0)
|
||||
lc_time_names_number(0), charset_database_number(0),
|
||||
base64_output_mode(BASE64_OUTPUT_UNSPEC), printed_fd_event(FALSE)
|
||||
{
|
||||
/*
|
||||
Currently we only use static PRINT_EVENT_INFO objects, so zeroed at
|
||||
@ -627,7 +637,14 @@ typedef struct st_print_event_info
|
||||
|
||||
/* Settings on how to print the events */
|
||||
bool short_form;
|
||||
bool base64_output;
|
||||
enum_base64_output_mode base64_output_mode;
|
||||
/*
|
||||
This is set whenever a Format_description_event is printed.
|
||||
Later, when an event is printed in base64, this flag is tested: if
|
||||
no Format_description_event has been seen, it is unsafe to print
|
||||
the base64 event, so an error message is generated.
|
||||
*/
|
||||
bool printed_fd_event;
|
||||
my_off_t hexdump_from;
|
||||
uint8 common_header_len;
|
||||
char delimiter[16];
|
||||
@ -936,7 +953,13 @@ public:
|
||||
const char **error,
|
||||
const Format_description_log_event
|
||||
*description_event);
|
||||
/* returns the human readable name of the event's type */
|
||||
/**
|
||||
Returns the human readable name of the given event type.
|
||||
*/
|
||||
static const char* get_type_str(Log_event_type type);
|
||||
/**
|
||||
Returns the human readable name of this event's type.
|
||||
*/
|
||||
const char* get_type_str();
|
||||
|
||||
/* Return start of query time or current time */
|
||||
|
@ -6116,3 +6116,6 @@ ER_CANT_CREATE_SROUTINE
|
||||
eng "Cannot create stored routine `%-.64s`. Check warnings"
|
||||
ER_SLAVE_AMBIGOUS_EXEC_MODE
|
||||
eng "Ambiguous slave modes combination. %s"
|
||||
|
||||
ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT
|
||||
eng "The BINLOG statement of type `%s` was not preceded by a format description BINLOG statement."
|
||||
|
308
sql/slave.cc
308
sql/slave.cc
@ -13,6 +13,17 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
|
||||
/**
|
||||
@addtogroup Replication
|
||||
@{
|
||||
|
||||
@file
|
||||
|
||||
@brief Code to run the io thread and the sql thread on the
|
||||
replication slave.
|
||||
*/
|
||||
|
||||
#include "mysql_priv.h"
|
||||
|
||||
#include <mysql.h>
|
||||
@ -33,10 +44,6 @@
|
||||
|
||||
#include "rpl_tblmap.h"
|
||||
|
||||
int queue_event(Master_info* mi,const char* buf,ulong event_len);
|
||||
static Log_event* next_event(Relay_log_info* rli);
|
||||
|
||||
|
||||
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
|
||||
|
||||
#define MAX_SLAVE_RETRY_PAUSE 5
|
||||
@ -132,6 +139,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
|
||||
const char* table_name, bool overwrite);
|
||||
static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi);
|
||||
static Log_event* next_event(Relay_log_info* rli);
|
||||
static int queue_event(Master_info* mi,const char* buf,ulong event_len);
|
||||
static int terminate_slave_thread(THD *thd,
|
||||
pthread_mutex_t* term_lock,
|
||||
pthread_cond_t* term_cond,
|
||||
@ -1757,6 +1765,175 @@ static int has_temporary_error(THD *thd)
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Applies the given event and advances the relay log position.
|
||||
|
||||
In essence, this function does:
|
||||
|
||||
@code
|
||||
ev->apply_event(rli);
|
||||
ev->update_pos(rli);
|
||||
@endcode
|
||||
|
||||
But it also does some maintainance, such as skipping events if
|
||||
needed and reporting errors.
|
||||
|
||||
If the @c skip flag is set, then it is tested whether the event
|
||||
should be skipped, by looking at the slave_skip_counter and the
|
||||
server id. The skip flag should be set when calling this from a
|
||||
replication thread but not set when executing an explicit BINLOG
|
||||
statement.
|
||||
|
||||
@retval 0 OK.
|
||||
|
||||
@retval 1 Error calling ev->apply_event().
|
||||
|
||||
@retval 2 No error calling ev->apply_event(), but error calling
|
||||
ev->update_pos().
|
||||
*/
|
||||
int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli,
|
||||
bool skip)
|
||||
{
|
||||
int exec_res= 0;
|
||||
|
||||
DBUG_ENTER("apply_event_and_update_pos");
|
||||
|
||||
DBUG_PRINT("exec_event",("%s(type_code: %d; server_id: %d)",
|
||||
ev->get_type_str(), ev->get_type_code(),
|
||||
ev->server_id));
|
||||
DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu",
|
||||
FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT),
|
||||
FLAGSTR(thd->options, OPTION_BEGIN),
|
||||
rli->last_event_start_time));
|
||||
|
||||
/*
|
||||
Execute the event to change the database and update the binary
|
||||
log coordinates, but first we set some data that is needed for
|
||||
the thread.
|
||||
|
||||
The event will be executed unless it is supposed to be skipped.
|
||||
|
||||
Queries originating from this server must be skipped. Low-level
|
||||
events (Format_description_log_event, Rotate_log_event,
|
||||
Stop_log_event) from this server must also be skipped. But for
|
||||
those we don't want to modify 'group_master_log_pos', because
|
||||
these events did not exist on the master.
|
||||
Format_description_log_event is not completely skipped.
|
||||
|
||||
Skip queries specified by the user in 'slave_skip_counter'. We
|
||||
can't however skip events that has something to do with the log
|
||||
files themselves.
|
||||
|
||||
Filtering on own server id is extremely important, to ignore
|
||||
execution of events created by the creation/rotation of the relay
|
||||
log (remember that now the relay log starts with its Format_desc,
|
||||
has a Rotate etc).
|
||||
*/
|
||||
|
||||
thd->server_id = ev->server_id; // use the original server id for logging
|
||||
thd->set_time(); // time the query
|
||||
thd->lex->current_select= 0;
|
||||
if (!ev->when)
|
||||
ev->when= my_time(0);
|
||||
ev->thd = thd; // because up to this point, ev->thd == 0
|
||||
|
||||
if (skip)
|
||||
{
|
||||
int reason= ev->shall_skip(rli);
|
||||
if (reason == Log_event::EVENT_SKIP_COUNT)
|
||||
--rli->slave_skip_counter;
|
||||
pthread_mutex_unlock(&rli->data_lock);
|
||||
if (reason == Log_event::EVENT_SKIP_NOT)
|
||||
exec_res= ev->apply_event(rli);
|
||||
#ifndef DBUG_OFF
|
||||
/*
|
||||
This only prints information to the debug trace.
|
||||
|
||||
TODO: Print an informational message to the error log?
|
||||
*/
|
||||
static const char *const explain[] = {
|
||||
// EVENT_SKIP_NOT,
|
||||
"not skipped",
|
||||
// EVENT_SKIP_IGNORE,
|
||||
"skipped because event should be ignored",
|
||||
// EVENT_SKIP_COUNT
|
||||
"skipped because event skip counter was non-zero"
|
||||
};
|
||||
DBUG_PRINT("info", ("OPTION_BEGIN: %d; IN_STMT: %d",
|
||||
thd->options & OPTION_BEGIN ? 1 : 0,
|
||||
rli->get_flag(Relay_log_info::IN_STMT)));
|
||||
DBUG_PRINT("skip_event", ("%s event was %s",
|
||||
ev->get_type_str(), explain[reason]));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
exec_res= ev->apply_event(rli);
|
||||
|
||||
DBUG_PRINT("info", ("apply_event error = %d", exec_res));
|
||||
if (exec_res == 0)
|
||||
{
|
||||
int error= ev->update_pos(rli);
|
||||
char buf[22];
|
||||
DBUG_PRINT("info", ("update_pos error = %d", error));
|
||||
DBUG_PRINT("info", ("group %s %s",
|
||||
llstr(rli->group_relay_log_pos, buf),
|
||||
rli->group_relay_log_name));
|
||||
DBUG_PRINT("info", ("event %s %s",
|
||||
llstr(rli->event_relay_log_pos, buf),
|
||||
rli->event_relay_log_name));
|
||||
/*
|
||||
The update should not fail, so print an error message and
|
||||
return an error code.
|
||||
|
||||
TODO: Replace this with a decent error message when merged
|
||||
with BUG#24954 (which adds several new error message).
|
||||
*/
|
||||
if (error)
|
||||
{
|
||||
rli->report(ERROR_LEVEL, ER_UNKNOWN_ERROR,
|
||||
"It was not possible to update the positions"
|
||||
" of the relay log information: the slave may"
|
||||
" be in an inconsistent state."
|
||||
" Stopped in %s position %s",
|
||||
rli->group_relay_log_name,
|
||||
llstr(rli->group_relay_log_pos, buf));
|
||||
DBUG_RETURN(2);
|
||||
}
|
||||
}
|
||||
|
||||
DBUG_RETURN(exec_res ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Top-level function for executing the next event from the relay log.
|
||||
|
||||
This function reads the event from the relay log, executes it, and
|
||||
advances the relay log position. It also handles errors, etc.
|
||||
|
||||
This function may fail to apply the event for the following reasons:
|
||||
|
||||
- The position specfied by the UNTIL condition of the START SLAVE
|
||||
command is reached.
|
||||
|
||||
- It was not possible to read the event from the log.
|
||||
|
||||
- The slave is killed.
|
||||
|
||||
- An error occurred when applying the event, and the event has been
|
||||
tried slave_trans_retries times. If the event has been retried
|
||||
fewer times, 0 is returned.
|
||||
|
||||
- init_master_info or init_relay_log_pos failed. (These are called
|
||||
if a failure occurs when applying the event.)</li>
|
||||
|
||||
- An error occurred when updating the binlog position.
|
||||
|
||||
@retval 0 The event was applied.
|
||||
|
||||
@retval 1 The event was not applied.
|
||||
*/
|
||||
static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
|
||||
{
|
||||
DBUG_ENTER("exec_relay_log_event");
|
||||
@ -1802,117 +1979,26 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
|
||||
}
|
||||
if (ev)
|
||||
{
|
||||
int const type_code= ev->get_type_code();
|
||||
int exec_res= 0;
|
||||
|
||||
DBUG_PRINT("exec_event",("%s(type_code: %d; server_id: %d)",
|
||||
ev->get_type_str(), type_code, ev->server_id));
|
||||
DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu",
|
||||
FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT),
|
||||
FLAGSTR(thd->options, OPTION_BEGIN),
|
||||
rli->last_event_start_time));
|
||||
|
||||
int exec_res= apply_event_and_update_pos(ev, thd, rli, TRUE);
|
||||
|
||||
/*
|
||||
Execute the event to change the database and update the binary
|
||||
log coordinates, but first we set some data that is needed for
|
||||
the thread.
|
||||
|
||||
The event will be executed unless it is supposed to be skipped.
|
||||
|
||||
Queries originating from this server must be skipped. Low-level
|
||||
events (Format_description_log_event, Rotate_log_event,
|
||||
Stop_log_event) from this server must also be skipped. But for
|
||||
those we don't want to modify 'group_master_log_pos', because
|
||||
these events did not exist on the master.
|
||||
Format_description_log_event is not completely skipped.
|
||||
|
||||
Skip queries specified by the user in 'slave_skip_counter'. We
|
||||
can't however skip events that has something to do with the log
|
||||
files themselves.
|
||||
|
||||
Filtering on own server id is extremely important, to ignore
|
||||
execution of events created by the creation/rotation of the relay
|
||||
log (remember that now the relay log starts with its Format_desc,
|
||||
has a Rotate etc).
|
||||
Format_description_log_event should not be deleted because it will be
|
||||
used to read info about the relay log's format; it will be deleted when
|
||||
the SQL thread does not need it, i.e. when this thread terminates.
|
||||
*/
|
||||
|
||||
thd->server_id = ev->server_id; // use the original server id for logging
|
||||
thd->set_time(); // time the query
|
||||
thd->lex->current_select= 0;
|
||||
if (!ev->when)
|
||||
ev->when= my_time(0);
|
||||
ev->thd = thd; // because up to this point, ev->thd == 0
|
||||
|
||||
int reason= ev->shall_skip(rli);
|
||||
if (reason == Log_event::EVENT_SKIP_COUNT)
|
||||
--rli->slave_skip_counter;
|
||||
pthread_mutex_unlock(&rli->data_lock);
|
||||
if (reason == Log_event::EVENT_SKIP_NOT)
|
||||
exec_res= ev->apply_event(rli);
|
||||
#ifndef DBUG_OFF
|
||||
/*
|
||||
This only prints information to the debug trace.
|
||||
|
||||
TODO: Print an informational message to the error log?
|
||||
*/
|
||||
static const char *const explain[] = {
|
||||
// EVENT_SKIP_NOT,
|
||||
"not skipped",
|
||||
// EVENT_SKIP_IGNORE,
|
||||
"skipped because event should be ignored",
|
||||
// EVENT_SKIP_COUNT
|
||||
"skipped because event skip counter was non-zero"
|
||||
};
|
||||
DBUG_PRINT("info", ("OPTION_BEGIN: %d; IN_STMT: %d",
|
||||
thd->options & OPTION_BEGIN ? 1 : 0,
|
||||
rli->get_flag(Relay_log_info::IN_STMT)));
|
||||
DBUG_PRINT("skip_event", ("%s event was %s",
|
||||
ev->get_type_str(), explain[reason]));
|
||||
#endif
|
||||
|
||||
DBUG_PRINT("info", ("apply_event error = %d", exec_res));
|
||||
if (exec_res == 0)
|
||||
{
|
||||
int error= ev->update_pos(rli);
|
||||
char buf[22];
|
||||
DBUG_PRINT("info", ("update_pos error = %d", error));
|
||||
DBUG_PRINT("info", ("group %s %s",
|
||||
llstr(rli->group_relay_log_pos, buf),
|
||||
rli->group_relay_log_name));
|
||||
DBUG_PRINT("info", ("event %s %s",
|
||||
llstr(rli->event_relay_log_pos, buf),
|
||||
rli->event_relay_log_name));
|
||||
/*
|
||||
The update should not fail, so print an error message and
|
||||
return an error code.
|
||||
|
||||
TODO: Replace this with a decent error message when merged
|
||||
with BUG#24954 (which adds several new error message).
|
||||
*/
|
||||
if (error)
|
||||
{
|
||||
rli->report(ERROR_LEVEL, ER_UNKNOWN_ERROR,
|
||||
"It was not possible to update the positions"
|
||||
" of the relay log information: the slave may"
|
||||
" be in an inconsistent state."
|
||||
" Stopped in %s position %s",
|
||||
rli->group_relay_log_name,
|
||||
llstr(rli->group_relay_log_pos, buf));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Format_description_log_event should not be deleted because it will be
|
||||
used to read info about the relay log's format; it will be deleted when
|
||||
the SQL thread does not need it, i.e. when this thread terminates.
|
||||
*/
|
||||
if (type_code != FORMAT_DESCRIPTION_EVENT)
|
||||
if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
|
||||
{
|
||||
DBUG_PRINT("info", ("Deleting the event after it has been executed"));
|
||||
delete ev;
|
||||
}
|
||||
|
||||
/*
|
||||
update_log_pos failed: this should not happen, so we don't
|
||||
retry.
|
||||
*/
|
||||
if (exec_res == 2)
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (slave_trans_retries)
|
||||
{
|
||||
int temp_err;
|
||||
@ -3051,7 +3137,7 @@ static int queue_old_event(Master_info *mi, const char *buf,
|
||||
any >=5.0.0 format.
|
||||
*/
|
||||
|
||||
int queue_event(Master_info* mi,const char* buf, ulong event_len)
|
||||
static int queue_event(Master_info* mi,const char* buf, ulong event_len)
|
||||
{
|
||||
int error= 0;
|
||||
ulong inc_pos;
|
||||
@ -3937,4 +4023,8 @@ template class I_List_iterator<i_string>;
|
||||
template class I_List_iterator<i_string_pair>;
|
||||
#endif
|
||||
|
||||
/**
|
||||
@} (end of group Replication)
|
||||
*/
|
||||
|
||||
#endif /* HAVE_REPLICATION */
|
||||
|
@ -187,6 +187,8 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
|
||||
void set_slave_thread_options(THD* thd);
|
||||
void set_slave_thread_default_charset(THD *thd, Relay_log_info const *rli);
|
||||
void rotate_relay_log(Master_info* mi);
|
||||
int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli,
|
||||
bool skip);
|
||||
|
||||
pthread_handler_t handle_slave_io(void *arg);
|
||||
pthread_handler_t handle_slave_sql(void *arg);
|
||||
|
@ -17,15 +17,14 @@
|
||||
#include "rpl_rli.h"
|
||||
#include "base64.h"
|
||||
|
||||
/*
|
||||
/**
|
||||
Execute a BINLOG statement
|
||||
|
||||
TODO: This currently assumes a MySQL 5.x binlog.
|
||||
When we'll have binlog with a different format, to execute the
|
||||
BINLOG command properly the server will need to know which format
|
||||
the BINLOG command's event is in. mysqlbinlog should then send
|
||||
the Format_description_log_event of the binlog it reads and the
|
||||
server thread should cache this format into
|
||||
To execute the BINLOG command properly the server needs to know
|
||||
which format the BINLOG command's event is in. Therefore, the first
|
||||
BINLOG statement seen must be a base64 encoding of the
|
||||
Format_description_log_event, as outputted by mysqlbinlog. This
|
||||
Format_description_log_event is cached in
|
||||
rli->description_event_for_exec.
|
||||
*/
|
||||
|
||||
@ -54,11 +53,24 @@ void mysql_client_binlog_statement(THD* thd)
|
||||
/*
|
||||
Allocation
|
||||
*/
|
||||
if (!thd->rli_fake)
|
||||
thd->rli_fake= new Relay_log_info;
|
||||
|
||||
const Format_description_log_event *desc=
|
||||
new Format_description_log_event(4);
|
||||
/*
|
||||
If we do not have a Format_description_event, we create a dummy
|
||||
one here. In this case, the first event we read must be a
|
||||
Format_description_event.
|
||||
*/
|
||||
my_bool have_fd_event= TRUE;
|
||||
if (!thd->rli_fake)
|
||||
{
|
||||
thd->rli_fake= new Relay_log_info;
|
||||
have_fd_event= FALSE;
|
||||
}
|
||||
if (thd->rli_fake && !thd->rli_fake->relay_log.description_event_for_exec)
|
||||
{
|
||||
thd->rli_fake->relay_log.description_event_for_exec=
|
||||
new Format_description_log_event(4);
|
||||
have_fd_event= FALSE;
|
||||
}
|
||||
|
||||
const char *error= 0;
|
||||
char *buf= (char *) my_malloc(decoded_len, MYF(MY_WME));
|
||||
@ -67,7 +79,9 @@ void mysql_client_binlog_statement(THD* thd)
|
||||
/*
|
||||
Out of memory check
|
||||
*/
|
||||
if (!(thd->rli_fake && desc && buf))
|
||||
if (!(thd->rli_fake &&
|
||||
thd->rli_fake->relay_log.description_event_for_exec &&
|
||||
buf))
|
||||
{
|
||||
my_error(ER_OUTOFMEMORY, MYF(0), 1); /* needed 1 bytes */
|
||||
goto end;
|
||||
@ -138,7 +152,28 @@ void mysql_client_binlog_statement(THD* thd)
|
||||
goto end;
|
||||
}
|
||||
|
||||
ev= Log_event::read_log_event(bufptr, event_len, &error, desc);
|
||||
/*
|
||||
If we have not seen any Format_description_event, then we must
|
||||
see one; it is the only statement that can be read in base64
|
||||
without a prior Format_description_event.
|
||||
*/
|
||||
if (!have_fd_event)
|
||||
{
|
||||
if (bufptr[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT)
|
||||
have_fd_event= TRUE;
|
||||
else
|
||||
{
|
||||
my_error(ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT,
|
||||
MYF(0),
|
||||
Log_event::get_type_str(
|
||||
(Log_event_type)bufptr[EVENT_TYPE_OFFSET]));
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
ev= Log_event::read_log_event(bufptr, event_len, &error,
|
||||
thd->rli_fake->relay_log.
|
||||
description_event_for_exec);
|
||||
|
||||
DBUG_PRINT("info",("binlog base64 err=%s", error));
|
||||
if (!ev)
|
||||
@ -174,11 +209,10 @@ void mysql_client_binlog_statement(THD* thd)
|
||||
Neither do we have to update the log positions, since that is
|
||||
not used at all: the rli_fake instance is used only for error
|
||||
reporting.
|
||||
*/
|
||||
*/
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
if (IF_DBUG(int err= ) ev->apply_event(thd->rli_fake))
|
||||
if (apply_event_and_update_pos(ev, thd, thd->rli_fake, FALSE))
|
||||
{
|
||||
DBUG_PRINT("info", ("apply_event() returned: %d", err));
|
||||
/*
|
||||
TODO: Maybe a better error message since the BINLOG statement
|
||||
now contains several events.
|
||||
@ -188,7 +222,14 @@ void mysql_client_binlog_statement(THD* thd)
|
||||
}
|
||||
#endif
|
||||
|
||||
delete ev;
|
||||
/*
|
||||
Format_description_log_event should not be deleted because it
|
||||
will be used to read info about the relay log's format; it
|
||||
will be deleted when the SQL thread does not need it,
|
||||
i.e. when this thread terminates.
|
||||
*/
|
||||
if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
|
||||
delete ev;
|
||||
ev= 0;
|
||||
}
|
||||
}
|
||||
@ -207,7 +248,6 @@ end:
|
||||
*/
|
||||
thd->net.no_send_ok= nsok;
|
||||
|
||||
delete desc;
|
||||
my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user