MDEV-4297 mysql --binary-mode
backport mysql --binary-mode (bug#11747577, bug#33048)
This commit is contained in:
parent
16807b5856
commit
2db4392bf4
@ -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
|
||||||
|
@ -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 */
|
||||||
|
237
client/mysql.cc
237
client/mysql.cc
@ -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)))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
50
mysql-test/r/mysql_binary_mode.result
Normal file
50
mysql-test/r/mysql_binary_mode.result
Normal 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.]
|
169
mysql-test/t/mysql_binary_mode.test
Normal file
169
mysql-test/t/mysql_binary_mode.test
Normal 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
|
Loading…
x
Reference in New Issue
Block a user