MDEV-4297 mysql --binary-mode

backport mysql --binary-mode (bug#11747577, bug#33048)
This commit is contained in:
Sergei Golubchik 2013-06-10 21:45:30 +02:00
parent 16807b5856
commit 2db4392bf4
7 changed files with 445 additions and 72 deletions

View File

@ -1,5 +1,5 @@
/* /*
Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2001, 2012, Oracle and/or its affiliates.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by

View File

@ -36,7 +36,7 @@ typedef struct st_line_buffer
extern LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file); extern LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file);
extern LINE_BUFFER *batch_readline_command(LINE_BUFFER *buffer, char * str); extern LINE_BUFFER *batch_readline_command(LINE_BUFFER *buffer, char * str);
extern char *batch_readline(LINE_BUFFER *buffer); extern char *batch_readline(LINE_BUFFER *buffer, bool binary_mode);
extern void batch_readline_end(LINE_BUFFER *buffer); extern void batch_readline_end(LINE_BUFFER *buffer);
#endif /* CLIENT_MY_READLINE_INCLUDED */ #endif /* CLIENT_MY_READLINE_INCLUDED */

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2000, 2012, Oracle and/or its affiliates. Copyright (c) 2000, 2012, Oracle and/or its affiliates.
Copyright (c) 2009, 2012, Monty Program Ab. Copyright (c) 2009, 2013, Monty Program Ab.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -152,6 +152,7 @@ static uint verbose=0,opt_silent=0,opt_mysql_port=0, opt_local_infile=0;
static uint my_end_arg; static uint my_end_arg;
static char * opt_mysql_unix_port=0; static char * opt_mysql_unix_port=0;
static int connect_flag=CLIENT_INTERACTIVE; static int connect_flag=CLIENT_INTERACTIVE;
static my_bool opt_binary_mode= FALSE;
static int interrupted_query= 0; static int interrupted_query= 0;
static char *current_host,*current_db,*current_user=0,*opt_password=0, static char *current_host,*current_db,*current_user=0,*opt_password=0,
*current_prompt=0, *delimiter_str= 0, *current_prompt=0, *delimiter_str= 0,
@ -1056,9 +1057,10 @@ static void initialize_readline (char *name);
static void fix_history(String *final_command); static void fix_history(String *final_command);
#endif #endif
static COMMANDS *find_command(char *name,char cmd_name); static COMMANDS *find_command(char *name);
static bool add_line(String &buffer,char *line,char *in_string, static COMMANDS *find_command(char cmd_name);
bool *ml_comment, bool truncated); static bool add_line(String &buffer, char *line, ulong line_length,
char *in_string, bool *ml_comment, bool truncated);
static void remove_cntrl(String &buffer); static void remove_cntrl(String &buffer);
static void print_table_data(MYSQL_RES *result); static void print_table_data(MYSQL_RES *result);
static void print_table_data_html(MYSQL_RES *result); static void print_table_data_html(MYSQL_RES *result);
@ -1077,6 +1079,45 @@ static sig_handler window_resize(int sig);
#endif #endif
const char DELIMITER_NAME[]= "delimiter";
const uint DELIMITER_NAME_LEN= sizeof(DELIMITER_NAME) - 1;
inline bool is_delimiter_command(char *name, ulong len)
{
/*
Delimiter command has a parameter, so the length of the whole command
is larger than DELIMITER_NAME_LEN. We don't care the parameter, so
only name(first DELIMITER_NAME_LEN bytes) is checked.
*/
return (len >= DELIMITER_NAME_LEN &&
!my_strnncoll(charset_info, (uchar*) name, DELIMITER_NAME_LEN,
(uchar *) DELIMITER_NAME, DELIMITER_NAME_LEN));
}
/**
Get the index of a command in the commands array.
@param cmd_char Short form command.
@return int
The index of the command is returned if it is found, else -1 is returned.
*/
inline int get_command_index(char cmd_char)
{
/*
All client-specific commands are in the first part of commands array
and have a function to implement it.
*/
for (uint i= 0; *commands[i].func; i++)
if (commands[i].cmd_char == cmd_char)
return i;
return -1;
}
static int delimiter_index= -1;
static int charset_index= -1;
static bool real_binary_mode= FALSE;
int main(int argc,char *argv[]) int main(int argc,char *argv[])
{ {
char buff[80]; char buff[80];
@ -1085,6 +1126,8 @@ int main(int argc,char *argv[])
DBUG_ENTER("main"); DBUG_ENTER("main");
DBUG_PROCESS(argv[0]); DBUG_PROCESS(argv[0]);
charset_index= get_command_index('C');
delimiter_index= get_command_index('d');
delimiter_str= delimiter; delimiter_str= delimiter;
default_prompt = my_strdup(getenv("MYSQL_PS1") ? default_prompt = my_strdup(getenv("MYSQL_PS1") ?
getenv("MYSQL_PS1") : getenv("MYSQL_PS1") :
@ -1598,6 +1641,13 @@ static struct my_option my_long_options[] =
"Default authentication client-side plugin to use.", "Default authentication client-side plugin to use.",
&opt_default_auth, &opt_default_auth, 0, &opt_default_auth, &opt_default_auth, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"binary-mode", 0,
"By default, ASCII '\\0' is disallowed and '\\r\\n' is translated to '\\n'. "
"This switch turns off both features, and also turns off parsing of all client"
"commands except \\C and DELIMITER, in non-interactive mode (for input "
"piped to mysql or loaded using the 'source' command). This is necessary "
"when processing output from mysqlbinlog that may contain blobs.",
&opt_binary_mode, &opt_binary_mode, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
}; };
@ -1878,24 +1928,59 @@ static int read_and_execute(bool interactive)
ulong line_number=0; ulong line_number=0;
bool ml_comment= 0; bool ml_comment= 0;
COMMANDS *com; COMMANDS *com;
ulong line_length= 0;
status.exit_status=1; status.exit_status=1;
real_binary_mode= !interactive && opt_binary_mode;
while (!aborted) while (!aborted)
{ {
if (!interactive) if (!interactive)
{ {
line=batch_readline(status.line_buff); /*
batch_readline can return 0 on EOF or error.
In that case, we need to double check that we have a valid
line before actually setting line_length to read_length.
*/
line= batch_readline(status.line_buff, real_binary_mode);
if (line)
{
line_length= status.line_buff->read_length;
/*
ASCII 0x00 is not allowed appearing in queries if it is not in binary
mode.
*/
if (!real_binary_mode && strlen(line) != line_length)
{
status.exit_status= 1;
String msg;
msg.append("ASCII '\\0' appeared in the statement, but this is not "
"allowed unless option --binary-mode is enabled and mysql is "
"run in non-interactive mode. Set --binary-mode to 1 if ASCII "
"'\\0' is expected. Query: '");
msg.append(glob_buffer);
msg.append(line);
msg.append("'.");
put_info(msg.c_ptr(), INFO_ERROR);
break;
}
/* /*
Skip UTF8 Byte Order Marker (BOM) 0xEFBBBF. Skip UTF8 Byte Order Marker (BOM) 0xEFBBBF.
Editors like "notepad" put this marker in Editors like "notepad" put this marker in
the very beginning of a text file when the very beginning of a text file when
you save the file using "Unicode UTF-8" format. you save the file using "Unicode UTF-8" format.
*/ */
if (line && !line_number && if (!line_number &&
(uchar) line[0] == 0xEF && (uchar) line[0] == 0xEF &&
(uchar) line[1] == 0xBB && (uchar) line[1] == 0xBB &&
(uchar) line[2] == 0xBF) (uchar) line[2] == 0xBF)
{
line+= 3; line+= 3;
// decrease the line length accordingly to the 3 bytes chopped
line_length -=3;
}
}
line_number++; line_number++;
if (!glob_buffer.length()) if (!glob_buffer.length())
status.query_start_line=line_number; status.query_start_line=line_number;
@ -1946,6 +2031,8 @@ static int read_and_execute(bool interactive)
*/ */
if (opt_outfile && line) if (opt_outfile && line)
fprintf(OUTFILE, "%s\n", line); fprintf(OUTFILE, "%s\n", line);
line_length= line ? strlen(line) : 0;
} }
// End of file or system error // End of file or system error
if (!line) if (!line)
@ -1962,7 +2049,7 @@ static int read_and_execute(bool interactive)
(We want to allow help, print and clear anywhere at line start (We want to allow help, print and clear anywhere at line start
*/ */
if ((named_cmds || glob_buffer.is_empty()) if ((named_cmds || glob_buffer.is_empty())
&& !ml_comment && !in_string && (com=find_command(line,0))) && !ml_comment && !in_string && (com= find_command(line)))
{ {
if ((*com->func)(&glob_buffer,line) > 0) if ((*com->func)(&glob_buffer,line) > 0)
break; break;
@ -1974,7 +2061,7 @@ static int read_and_execute(bool interactive)
#endif #endif
continue; continue;
} }
if (add_line(glob_buffer, line, &in_string, &ml_comment, if (add_line(glob_buffer, line, line_length, &in_string, &ml_comment,
status.line_buff ? status.line_buff->truncated : 0)) status.line_buff ? status.line_buff->truncated : 0))
break; break;
} }
@ -1996,38 +2083,84 @@ static int read_and_execute(bool interactive)
tmpbuf.free(); tmpbuf.free();
#endif #endif
/*
If the function is called by 'source' command, it will return to interactive
mode, so real_binary_mode should be FALSE. Otherwise, it will exit the
program, it is safe to set real_binary_mode to FALSE.
*/
real_binary_mode= FALSE;
return status.exit_status; return status.exit_status;
} }
static COMMANDS *find_command(char *name,char cmd_char) /**
It checks if the input is a short form command. It returns the command's
pointer if a command is found, else return NULL. Note that if binary-mode
is set, then only \C is searched for.
@param cmd_char A character of one byte.
@return
the command's pointer or NULL.
*/
static COMMANDS *find_command(char cmd_char)
{
DBUG_ENTER("find_command");
DBUG_PRINT("enter", ("cmd_char: %d", cmd_char));
int index= -1;
/*
In binary-mode, we disallow all mysql commands except '\C'
and DELIMITER.
*/
if (real_binary_mode)
{
if (cmd_char == 'C')
index= charset_index;
}
else
index= get_command_index(cmd_char);
if (index >= 0)
{
DBUG_PRINT("exit",("found command: %s", commands[index].name));
DBUG_RETURN(&commands[index]);
}
else
DBUG_RETURN((COMMANDS *) 0);
}
/**
It checks if the input is a long form command. It returns the command's
pointer if a command is found, else return NULL. Note that if binary-mode
is set, then only DELIMITER is searched for.
@param name A string.
@return
the command's pointer or NULL.
*/
static COMMANDS *find_command(char *name)
{ {
uint len; uint len;
char *end; char *end;
DBUG_ENTER("find_command"); DBUG_ENTER("find_command");
DBUG_PRINT("enter",("name: '%s' char: %d", name ? name : "NULL", cmd_char));
if (!name) DBUG_ASSERT(name != NULL);
{ DBUG_PRINT("enter", ("name: '%s'", name));
len=0;
end=0;
}
else
{
while (my_isspace(charset_info, *name)) while (my_isspace(charset_info, *name))
name++; name++;
/* /*
If there is an \\g in the row or if the row has a delimiter but If there is an \\g in the row or if the row has a delimiter but
this is not a delimiter command, let add_line() take care of this is not a delimiter command, let add_line() take care of
parsing the row and calling find_command() parsing the row and calling find_command().
*/ */
if (strstr(name, "\\g") || (strstr(name, delimiter) && if ((!real_binary_mode && strstr(name, "\\g")) ||
!(strlen(name) >= 9 && (strstr(name, delimiter) &&
!my_strnncoll(&my_charset_latin1, !is_delimiter_command(name, DELIMITER_NAME_LEN)))
(uchar*) name, 9,
(const uchar*) "delimiter",
9))))
DBUG_RETURN((COMMANDS *) 0); DBUG_RETURN((COMMANDS *) 0);
if ((end=strcont(name, " \t"))) if ((end=strcont(name, " \t")))
{ {
len=(uint) (end - name); len=(uint) (end - name);
@ -2038,28 +2171,43 @@ static COMMANDS *find_command(char *name,char cmd_char)
} }
else else
len= (uint) strlen(name); len= (uint) strlen(name);
int index= -1;
if (real_binary_mode)
{
if (is_delimiter_command(name, len))
index= delimiter_index;
}
else
{
/*
All commands are in the first part of commands array and have a function
to implement it.
*/
for (uint i= 0; commands[i].func; i++)
{
if (!my_strnncoll(&my_charset_latin1, (uchar*) name, len,
(uchar*) commands[i].name, len) &&
(commands[i].name[len] == '\0') &&
(!end || commands[i].takes_params))
{
index= i;
break;
}
}
} }
for (uint i= 0; commands[i].name; i++) if (index >= 0)
{ {
if (commands[i].func && DBUG_PRINT("exit", ("found command: %s", commands[index].name));
(((name && DBUG_RETURN(&commands[index]);
!my_strnncoll(&my_charset_latin1, (uchar*) name, len,
(uchar*) commands[i].name, len) &&
!commands[i].name[len] &&
(!end || (end && commands[i].takes_params)))) ||
(!name && commands[i].cmd_char == cmd_char)))
{
DBUG_PRINT("exit",("found command: %s", commands[i].name));
DBUG_RETURN(&commands[i]);
}
} }
DBUG_RETURN((COMMANDS *) 0); DBUG_RETURN((COMMANDS *) 0);
} }
static bool add_line(String &buffer,char *line,char *in_string, static bool add_line(String &buffer, char *line, ulong line_length,
bool *ml_comment, bool truncated) char *in_string, bool *ml_comment, bool truncated)
{ {
uchar inchar; uchar inchar;
char buff[80], *pos, *out; char buff[80], *pos, *out;
@ -2074,10 +2222,11 @@ static bool add_line(String &buffer,char *line,char *in_string,
if (status.add_to_history && line[0] && not_in_history(line)) if (status.add_to_history && line[0] && not_in_history(line))
add_history(line); add_history(line);
#endif #endif
char *end_of_line=line+(uint) strlen(line); char *end_of_line= line + line_length;
for (pos=out=line ; (inchar= (uchar) *pos) ; pos++) for (pos= out= line; pos < end_of_line; pos++)
{ {
inchar= (uchar) *pos;
if (!preserve_comments) if (!preserve_comments)
{ {
// Skip spaces at the beginning of a statement // Skip spaces at the beginning of a statement
@ -2117,7 +2266,7 @@ static bool add_line(String &buffer,char *line,char *in_string,
*out++= (char) inchar; *out++= (char) inchar;
continue; continue;
} }
if ((com=find_command(NullS,(char) inchar))) if ((com= find_command((char) inchar)))
{ {
// Flush previously accepted characters // Flush previously accepted characters
if (out != line) if (out != line)
@ -2193,7 +2342,7 @@ static bool add_line(String &buffer,char *line,char *in_string,
pos--; pos--;
if ((com= find_command(buffer.c_ptr(), 0))) if ((com= find_command(buffer.c_ptr())))
{ {
if ((*com->func)(&buffer, buffer.c_ptr()) > 0) if ((*com->func)(&buffer, buffer.c_ptr()) > 0)
@ -2312,9 +2461,7 @@ static bool add_line(String &buffer,char *line,char *in_string,
{ {
uint length=(uint) (out-line); uint length=(uint) (out-line);
if (!truncated && (length < 9 || if (!truncated && (!is_delimiter_command(line, length) ||
my_strnncoll (charset_info, (uchar *)line, 9,
(const uchar *) "delimiter", 9) ||
(*in_string || *ml_comment))) (*in_string || *ml_comment)))
{ {
/* /*

View File

@ -206,10 +206,8 @@ void print_annotate_event(PRINT_EVENT_INFO *print_event_info)
} }
} }
static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *, const char*);
const char* logname); static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *, const char*);
static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
const char* logname);
static Exit_status dump_log_entries(const char* logname); static Exit_status dump_log_entries(const char* logname);
static Exit_status safe_connect(); static Exit_status safe_connect();

View File

@ -54,7 +54,7 @@ LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file)
} }
char *batch_readline(LINE_BUFFER *line_buff) char *batch_readline(LINE_BUFFER *line_buff, bool binary_mode)
{ {
char *pos; char *pos;
ulong out_length; ulong out_length;
@ -63,8 +63,17 @@ char *batch_readline(LINE_BUFFER *line_buff)
if (!(pos=intern_read_line(line_buff, &out_length))) if (!(pos=intern_read_line(line_buff, &out_length)))
return 0; return 0;
if (out_length && pos[out_length-1] == '\n') if (out_length && pos[out_length-1] == '\n')
if (--out_length && pos[out_length-1] == '\r') /* Remove '\n' */ {
out_length--; /* Remove '\r' */ /*
On Windows platforms we also need to remove '\r', unconditionally. On
Unix-like platforms we only remove it if we are not on binary mode.
*/
/* Remove '\n' */
if (--out_length && IF_WIN(1,!binary_mode) && pos[out_length-1] == '\r')
/* Remove '\r' */
out_length--;
}
line_buff->read_length=out_length; line_buff->read_length=out_length;
pos[out_length]=0; pos[out_length]=0;
return pos; return pos;
@ -226,7 +235,7 @@ char *intern_read_line(LINE_BUFFER *buffer, ulong *out_length)
for (;;) for (;;)
{ {
pos=buffer->end_of_line; pos=buffer->end_of_line;
while (*pos != '\n' && *pos) while (*pos != '\n' && pos != buffer->end)
pos++; pos++;
if (pos == buffer->end) if (pos == buffer->end)
{ {

View File

@ -0,0 +1,50 @@
RESET MASTER;
# Bug#33048 Not able to recover binary/blob data correctly using mysqlbinlog
# --------------------------------------------------------------------------
# The test verify that 0x00 and 0x0D0A sequence can be handled correctly by
# mysql
CREATE TABLE `A
B` (c1 CHAR(100));
# It is a faked statement. ASCII 0 is in the original statement, it would
# make the test result to become a binary file which was difficult to get
# the diff result if the original query was logged in the result.
INSERT INTO `A\r\nB` VALUES("A\0B");
INSERT INTO `A
B` VALUES("A
B");
SELECT HEX(c1) FROM `A
B`;
HEX(c1)
410042
410D0A42
FLUSH LOGS;
DROP TABLE `A
B`;
RESET MASTER;
# '--exec mysql ...' without --binary-mode option
# It creates the table with a wrong table name and generates an error.
# (error output was suppressed to make the test case platform agnostic)
# It is not in binary_mode, so table name '0x410D0A42' can be translated to
# '0x410A42' by mysql depending on the OS - Windows or Unix-like.
DROP TABLE `TABLE_NAME_MASKED`;
# In binary_mode, table name '0x410D0A42' and string '0x410042' can be
# handled correctly.
RESET MASTER;
SELECT HEX(c1) FROM `A
B`;
HEX(c1)
410042
410D0A42
DROP TABLE `A
B`;
RESET MASTER;
include/assert.inc [Table and contents created through mysqltest match 0x610D0A62.]
include/assert.inc [Table and contents created while replaying binary log without --binary-mode set match 0x61(0D)0A62.]
include/assert.inc [Table and contents created while replaying binary log with --binary-mode set match 0x610D0A62.]

View File

@ -0,0 +1,169 @@
source include/have_binlog_format_mixed_or_statement.inc;
RESET MASTER;
--echo # Bug#33048 Not able to recover binary/blob data correctly using mysqlbinlog
--echo # --------------------------------------------------------------------------
--echo # The test verify that 0x00 and 0x0D0A sequence can be handled correctly by
--echo # mysql
--echo
# zero => 0x00, newline => 0x0D0A, A => 0x41, B => 0x42
# 0x410D0A42 => 'A\r\nB'
let $table_name_right= `SELECT 0x410D0A42`;
# 0x410A42 => 'A\nB'
let $table_name_wrong= `SELECT 0x410A42`;
# 0x410042 => 'A\0B'
let $char0= `SELECT 0x410042`;
eval CREATE TABLE `$table_name_right` (c1 CHAR(100));
--echo # It is a faked statement. ASCII 0 is in the original statement, it would
--echo # make the test result to become a binary file which was difficult to get
--echo # the diff result if the original query was logged in the result.
--echo INSERT INTO `A\r\nB` VALUES("A\0B");
--echo
--disable_query_log
eval INSERT INTO `$table_name_right` VALUES("$char0");
--enable_query_log
let $char0= $table_name_right;
eval INSERT INTO `$table_name_right` VALUES("$char0");
eval SELECT HEX(c1) FROM `$table_name_right`;
--echo
let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
FLUSH LOGS;
eval DROP TABLE `$table_name_right`;
--echo
let $MYSQLD_DATADIR= `SELECT @@datadir`;
--exec $MYSQL_BINLOG $MYSQLD_DATADIR/$binlog_file > $MYSQLTEST_VARDIR/tmp/my.sql
RESET MASTER;
--echo # '--exec mysql ...' without --binary-mode option
--echo # It creates the table with a wrong table name and generates an error.
--echo # (error output was suppressed to make the test case platform agnostic)
## disabling result log because the error message has the
## table name in the output which is one byte different ('\r')
## on unixes and windows.
--disable_result_log
--error 1
--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/my.sql 2>&1
--enable_result_log
--echo
--echo # It is not in binary_mode, so table name '0x410D0A42' can be translated to
--echo # '0x410A42' by mysql depending on the OS - Windows or Unix-like.
--replace_result $table_name_wrong TABLE_NAME_MASKED $table_name_right TABLE_NAME_MASKED
if (`SELECT CONVERT(@@VERSION_COMPILE_OS USING latin1) IN ('Win32', 'Win64', 'Windows')`)
{
eval DROP TABLE `$table_name_right`;
}
if (`SELECT CONVERT(@@VERSION_COMPILE_OS USING latin1) NOT IN ('Win32', 'Win64', 'Windows')`)
{
eval DROP TABLE `$table_name_wrong`;
}
--echo
--echo # In binary_mode, table name '0x410D0A42' and string '0x410042' can be
--echo # handled correctly.
RESET MASTER;
--exec $MYSQL --binary-mode test < $MYSQLTEST_VARDIR/tmp/my.sql
eval SELECT HEX(c1) FROM `$table_name_right`;
--echo
eval DROP TABLE `$table_name_right`;
#
# BUG#12794048 - MAIN.MYSQL_BINARY_MODE FAILS ON WINDOWS RELEASE BUILD
#
RESET MASTER;
#
# This test case tests if the table names and their values
# are handled properly. For that we check
#
# 0x610D0A62 => 'a\r\nb'
let $tbl= `SELECT 0x610D0A62`;
--disable_result_log
--disable_query_log
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
#### case #1: mysqltest
#### CREATE table and insert value through regular mysqltest session
--eval CREATE TABLE `$tbl` (c1 CHAR(100))
--eval INSERT INTO `$tbl` VALUES ("$tbl")
--let $table_name=`SELECT table_name FROM information_schema.tables WHERE table_schema='test'`
--let $tbl0= `SELECT HEX(table_name) FROM information_schema.tables WHERE table_schema='test'`
--let $val0= `SELECT HEX(c1) FROM `$table_name` LIMIT 1`
FLUSH LOGS;
--eval DROP TABLE `$table_name`;
#### case #2: mysql --binlog-mode=0
#### Replay through regular mysql client non-interactive mode
--let $MYSQLD_DATADIR= `SELECT @@datadir`
--let $prefix=`SELECT UUID()`
--let $binlog_uuid_filename= $MYSQLTEST_VARDIR/tmp/$prefix-bin.log
--copy_file $MYSQLD_DATADIR/$binlog_file $binlog_uuid_filename
RESET MASTER;
--exec $MYSQL_BINLOG $binlog_uuid_filename | $MYSQL
--let $table_name=`SELECT table_name FROM information_schema.tables WHERE table_schema='test'`
--let $tbl1= `SELECT hex(table_name) FROM information_schema.tables WHERE table_schema='test'`
--let $val1= `SELECT HEX(c1) FROM `$table_name` LIMIT 1`
--eval DROP TABLE `$table_name`;
#### case #3: mysql --binlog-mode=1
#### Replay through regular mysql client non-interactive mode and with binary mode set
RESET MASTER;
--exec $MYSQL_BINLOG $binlog_uuid_filename | $MYSQL --binary-mode
--let $table_name=`SELECT table_name FROM information_schema.tables WHERE table_schema='test'`
--let $tbl2= `SELECT hex(table_name) FROM information_schema.tables WHERE table_schema='test'`
--let $val2= `SELECT HEX(c1) FROM `$table_name` LIMIT 1`
--eval DROP TABLE `$table_name`;
--enable_result_log
--disable_query_log
##### OUTCOME
--let $assert_text= Table and contents created through mysqltest match 0x610D0A62.
--let $assert_cond= "$tbl0" = "610D0A62" AND "$val0" = "610D0A62"
--source include/assert.inc
--let $assert_text= Table and contents created while replaying binary log without --binary-mode set match 0x61(0D)0A62.
if (`SELECT CONVERT(@@VERSION_COMPILE_OS USING latin1) IN ('Win32', 'Win64', 'Windows')`)
{
--let $assert_cond= "$tbl1" = "610D0A62" AND "$val1" = "610D0A62"
}
if (`SELECT CONVERT(@@VERSION_COMPILE_OS USING latin1) NOT IN ('Win32', 'Win64', 'Windows')`)
{
--let $assert_cond= "$tbl1" = "610A62" AND "$val1" = "610A62"
}
--source include/assert.inc
--let $assert_text= Table and contents created while replaying binary log with --binary-mode set match 0x610D0A62.
--let $assert_cond= "$tbl2" = "610D0A62" AND "$val2" = "610D0A62"
--source include/assert.inc
RESET MASTER;
--remove_file $binlog_uuid_filename