summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/client_priv.h2
-rw-r--r--client/my_readline.h2
-rw-r--r--client/mysql.cc271
-rw-r--r--client/mysqlbinlog.cc6
-rw-r--r--client/readline.cc17
-rw-r--r--mysql-test/r/mysql_binary_mode.result50
-rw-r--r--mysql-test/t/mysql_binary_mode.test169
7 files changed, 445 insertions, 72 deletions
diff --git a/client/client_priv.h b/client/client_priv.h
index 70a9d129433..e206804d057 100644
--- a/client/client_priv.h
+++ b/client/client_priv.h
@@ -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
it under the terms of the GNU General Public License as published by
diff --git a/client/my_readline.h b/client/my_readline.h
index 11ace987b44..57537308fed 100644
--- a/client/my_readline.h
+++ b/client/my_readline.h
@@ -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_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);
#endif /* CLIENT_MY_READLINE_INCLUDED */
diff --git a/client/mysql.cc b/client/mysql.cc
index 3cd078ac1ce..2c8f7347840 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -1,6 +1,6 @@
/*
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
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 char * opt_mysql_unix_port=0;
static int connect_flag=CLIENT_INTERACTIVE;
+static my_bool opt_binary_mode= FALSE;
static int interrupted_query= 0;
static char *current_host,*current_db,*current_user=0,*opt_password=0,
*current_prompt=0, *delimiter_str= 0,
@@ -1056,9 +1057,10 @@ static void initialize_readline (char *name);
static void fix_history(String *final_command);
#endif
-static COMMANDS *find_command(char *name,char cmd_name);
-static bool add_line(String &buffer,char *line,char *in_string,
- bool *ml_comment, bool truncated);
+static COMMANDS *find_command(char *name);
+static COMMANDS *find_command(char cmd_name);
+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 print_table_data(MYSQL_RES *result);
static void print_table_data_html(MYSQL_RES *result);
@@ -1077,6 +1079,45 @@ static sig_handler window_resize(int sig);
#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[])
{
char buff[80];
@@ -1085,6 +1126,8 @@ int main(int argc,char *argv[])
DBUG_ENTER("main");
DBUG_PROCESS(argv[0]);
+ charset_index= get_command_index('C');
+ delimiter_index= get_command_index('d');
delimiter_str= delimiter;
default_prompt = my_strdup(getenv("MYSQL_PS1") ?
getenv("MYSQL_PS1") :
@@ -1598,6 +1641,13 @@ static struct my_option my_long_options[] =
"Default authentication client-side plugin to use.",
&opt_default_auth, &opt_default_auth, 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}
};
@@ -1878,24 +1928,59 @@ static int read_and_execute(bool interactive)
ulong line_number=0;
bool ml_comment= 0;
COMMANDS *com;
+ ulong line_length= 0;
status.exit_status=1;
+ real_binary_mode= !interactive && opt_binary_mode;
while (!aborted)
{
if (!interactive)
{
- line=batch_readline(status.line_buff);
/*
- Skip UTF8 Byte Order Marker (BOM) 0xEFBBBF.
- Editors like "notepad" put this marker in
- the very beginning of a text file when
- you save the file using "Unicode UTF-8" format.
+ 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.
*/
- if (line && !line_number &&
- (uchar) line[0] == 0xEF &&
- (uchar) line[1] == 0xBB &&
- (uchar) line[2] == 0xBF)
- line+= 3;
+ 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.
+ Editors like "notepad" put this marker in
+ the very beginning of a text file when
+ you save the file using "Unicode UTF-8" format.
+ */
+ if (!line_number &&
+ (uchar) line[0] == 0xEF &&
+ (uchar) line[1] == 0xBB &&
+ (uchar) line[2] == 0xBF)
+ {
+ line+= 3;
+ // decrease the line length accordingly to the 3 bytes chopped
+ line_length -=3;
+ }
+ }
line_number++;
if (!glob_buffer.length())
status.query_start_line=line_number;
@@ -1946,6 +2031,8 @@ static int read_and_execute(bool interactive)
*/
if (opt_outfile && line)
fprintf(OUTFILE, "%s\n", line);
+
+ line_length= line ? strlen(line) : 0;
}
// End of file or system error
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
*/
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)
break;
@@ -1974,7 +2061,7 @@ static int read_and_execute(bool interactive)
#endif
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))
break;
}
@@ -1996,70 +2083,131 @@ static int read_and_execute(bool interactive)
tmpbuf.free();
#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;
}
-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;
char *end;
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));
+
+ while (my_isspace(charset_info, *name))
+ name++;
+ /*
+ 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
+ parsing the row and calling find_command().
+ */
+ if ((!real_binary_mode && strstr(name, "\\g")) ||
+ (strstr(name, delimiter) &&
+ !is_delimiter_command(name, DELIMITER_NAME_LEN)))
+ DBUG_RETURN((COMMANDS *) 0);
+
+ if ((end=strcont(name, " \t")))
{
- len=0;
- end=0;
+ len=(uint) (end - name);
+ while (my_isspace(charset_info, *end))
+ end++;
+ if (!*end)
+ end= 0; // no arguments to function
+ }
+ else
+ len= (uint) strlen(name);
+
+ int index= -1;
+ if (real_binary_mode)
+ {
+ if (is_delimiter_command(name, len))
+ index= delimiter_index;
}
else
{
- while (my_isspace(charset_info,*name))
- name++;
/*
- 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
- parsing the row and calling find_command()
+ All commands are in the first part of commands array and have a function
+ to implement it.
*/
- if (strstr(name, "\\g") || (strstr(name, delimiter) &&
- !(strlen(name) >= 9 &&
- !my_strnncoll(&my_charset_latin1,
- (uchar*) name, 9,
- (const uchar*) "delimiter",
- 9))))
- DBUG_RETURN((COMMANDS *) 0);
- if ((end=strcont(name," \t")))
+ for (uint i= 0; commands[i].func; i++)
{
- len=(uint) (end - name);
- while (my_isspace(charset_info,*end))
- end++;
- if (!*end)
- end=0; // no arguments to function
+ 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;
+ }
}
- else
- len=(uint) strlen(name);
}
- for (uint i= 0; commands[i].name; i++)
+ if (index >= 0)
{
- if (commands[i].func &&
- (((name &&
- !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_PRINT("exit", ("found command: %s", commands[index].name));
+ DBUG_RETURN(&commands[index]);
}
DBUG_RETURN((COMMANDS *) 0);
}
-static bool add_line(String &buffer,char *line,char *in_string,
- bool *ml_comment, bool truncated)
+static bool add_line(String &buffer, char *line, ulong line_length,
+ char *in_string, bool *ml_comment, bool truncated)
{
uchar inchar;
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))
add_history(line);
#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)
{
// 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;
continue;
}
- if ((com=find_command(NullS,(char) inchar)))
+ if ((com= find_command((char) inchar)))
{
// Flush previously accepted characters
if (out != line)
@@ -2193,7 +2342,7 @@ static bool add_line(String &buffer,char *line,char *in_string,
pos--;
- if ((com= find_command(buffer.c_ptr(), 0)))
+ if ((com= find_command(buffer.c_ptr())))
{
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);
- if (!truncated && (length < 9 ||
- my_strnncoll (charset_info, (uchar *)line, 9,
- (const uchar *) "delimiter", 9) ||
+ if (!truncated && (!is_delimiter_command(line, length) ||
(*in_string || *ml_comment)))
{
/*
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index 387413cc5aa..d68b2a557e1 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -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,
- const char* logname);
-static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
- const char* logname);
+static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *, const char*);
+static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *, const char*);
static Exit_status dump_log_entries(const char* logname);
static Exit_status safe_connect();
diff --git a/client/readline.cc b/client/readline.cc
index 791a044e0e1..b6643b86356 100644
--- a/client/readline.cc
+++ b/client/readline.cc
@@ -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;
ulong out_length;
@@ -63,8 +63,17 @@ char *batch_readline(LINE_BUFFER *line_buff)
if (!(pos=intern_read_line(line_buff, &out_length)))
return 0;
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;
pos[out_length]=0;
return pos;
@@ -226,7 +235,7 @@ char *intern_read_line(LINE_BUFFER *buffer, ulong *out_length)
for (;;)
{
pos=buffer->end_of_line;
- while (*pos != '\n' && *pos)
+ while (*pos != '\n' && pos != buffer->end)
pos++;
if (pos == buffer->end)
{
diff --git a/mysql-test/r/mysql_binary_mode.result b/mysql-test/r/mysql_binary_mode.result
new file mode 100644
index 00000000000..cb230037108
--- /dev/null
+++ b/mysql-test/r/mysql_binary_mode.result
@@ -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.]
diff --git a/mysql-test/t/mysql_binary_mode.test b/mysql-test/t/mysql_binary_mode.test
new file mode 100644
index 00000000000..d454bfb7624
--- /dev/null
+++ b/mysql-test/t/mysql_binary_mode.test
@@ -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