diff options
Diffstat (limited to 'client')
-rw-r--r-- | client/client_priv.h | 2 | ||||
-rw-r--r-- | client/completion_hash.h | 7 | ||||
-rw-r--r-- | client/echo.c | 5 | ||||
-rw-r--r-- | client/get_password.c | 5 | ||||
-rw-r--r-- | client/my_readline.h | 2 | ||||
-rw-r--r-- | client/mysql.cc | 325 | ||||
-rw-r--r-- | client/mysql_plugin.c | 2 | ||||
-rw-r--r-- | client/mysql_upgrade.c | 71 | ||||
-rw-r--r-- | client/mysqladmin.cc | 2 | ||||
-rw-r--r-- | client/mysqlbinlog.cc | 200 | ||||
-rw-r--r-- | client/mysqlcheck.c | 91 | ||||
-rw-r--r-- | client/mysqldump.c | 21 | ||||
-rw-r--r-- | client/mysqltest.cc | 30 | ||||
-rw-r--r-- | client/readline.cc | 17 | ||||
-rw-r--r-- | client/sql_string.cc.dontuse | 4 | ||||
-rw-r--r-- | client/sql_string.h.dontuse | 3 |
16 files changed, 545 insertions, 242 deletions
diff --git a/client/client_priv.h b/client/client_priv.h index 8c713d73200..656c8fcf32a 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2001, 2011, 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/completion_hash.h b/client/completion_hash.h index 8e1b2d6e453..70c2cf1b371 100644 --- a/client/completion_hash.h +++ b/client/completion_hash.h @@ -1,4 +1,5 @@ -/* Copyright (C) 2000-2002 MySQL AB +/* Copyright (c) 2000-2002, 2006 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -12,8 +13,8 @@ You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA */ + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA */ #ifndef _HASH_ #define _HASH_ diff --git a/client/echo.c b/client/echo.c index e3d22edb3ae..2a3cb915d23 100644 --- a/client/echo.c +++ b/client/echo.c @@ -1,4 +1,5 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (c) 2000, 2007 MySQL AB + Use is subject to license terms 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 @@ -11,7 +12,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* echo is a replacement for the "echo" command builtin to cmd.exe diff --git a/client/get_password.c b/client/get_password.c index 09d307b5553..8a507d94e9b 100644 --- a/client/get_password.c +++ b/client/get_password.c @@ -1,4 +1,5 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (c) 2000, 2001, 2003, 2006, 2008 MySQL AB + Use is subject to license terms 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 @@ -11,7 +12,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* ** Ask for a password from tty 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 bb57c43674e..90310f85e95 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) 2000, 2013, Oracle and/or its affiliates. + 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} }; @@ -1635,7 +1685,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), { switch(optid) { case OPT_CHARSETS_DIR: - strmake(mysql_charsets_dir, argument, sizeof(mysql_charsets_dir) - 1); + strmake_buf(mysql_charsets_dir, argument); charsets_dir = mysql_charsets_dir; break; case OPT_DELIMITER: @@ -1648,7 +1698,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), /* Check that delimiter does not contain a backslash */ if (!strstr(argument, "\\")) { - strmake(delimiter, argument, sizeof(delimiter) - 1); + strmake_buf(delimiter, argument); } else { @@ -1680,7 +1730,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), if (argument && strlen(argument)) { default_pager_set= 1; - strmake(pager, argument, sizeof(pager) - 1); + strmake_buf(pager, argument); strmov(default_pager, pager); } else if (default_pager_set) @@ -1873,29 +1923,64 @@ static int read_and_execute(bool interactive) String buffer; #endif - char *line= 0; + char *line= NULL; char in_string=0; 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; @@ -1937,6 +2022,13 @@ static int read_and_execute(bool interactive) #else if (opt_outfile) fputs(prompt, OUTFILE); + /* + free the previous entered line. + Note: my_free() cannot be used here as the memory was allocated under + the readline/libedit library. + */ + if (line) + free(line); line= readline(prompt); #endif /* defined(__WIN__) */ @@ -1946,6 +2038,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 +2056,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 +2068,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; } @@ -1994,72 +2088,142 @@ static int read_and_execute(bool interactive) #if defined(__WIN__) buffer.free(); tmpbuf.free(); +#else + if (interactive) + /* + free the last entered line. + Note: my_free() cannot be used here as the memory was allocated under + the readline/libedit library. + */ + free(line); #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=(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) { - len=0; - end=0; + 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 +2238,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 +2282,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 +2358,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,17 +2477,17 @@ 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))) { /* Don't add a new line in case there's a DELIMITER command to be added to the glob buffer (e.g. on processing a line like "<command>;DELIMITER <non-eof>") : similar to how a new line is not added in the case when the DELIMITER is the first command - entered with an empty glob buffer. + entered with an empty glob buffer. However, if the delimiter is + part of a string or a comment, the new line should be added. (e.g. + SELECT '\ndelimiter\n';\n) */ *out++='\n'; length++; @@ -2959,7 +3124,7 @@ com_charset(String *buffer __attribute__((unused)), char *line) { char buff[256], *param; CHARSET_INFO * new_cs; - strmake(buff, line, sizeof(buff) - 1); + strmake_buf(buff, line); param= get_arg(buff, 0); if (!param || !*param) { @@ -3196,7 +3361,7 @@ static void init_tee(const char *file_name) return; } OUTFILE = new_outfile; - strmake(outfile, file_name, FN_REFLEN-1); + strmake_buf(outfile, file_name); tee_fprintf(stdout, "Logging to file '%s'\n", file_name); opt_outfile= 1; return; @@ -3826,7 +3991,7 @@ com_tee(String *buffer __attribute__((unused)), /* eliminate the spaces before the parameters */ while (my_isspace(charset_info,*param)) param++; - end= strmake(file_name, param, sizeof(file_name) - 1); + end= strmake_buf(file_name, param); /* remove end space from command line */ while (end > file_name && (my_isspace(charset_info,end[-1]) || my_iscntrl(charset_info,end[-1]))) @@ -3887,7 +4052,7 @@ com_pager(String *buffer __attribute__((unused)), } else { - end= strmake(pager_name, param, sizeof(pager_name)-1); + end= strmake_buf(pager_name, param); while (end > pager_name && (my_isspace(charset_info,end[-1]) || my_iscntrl(charset_info,end[-1]))) end--; @@ -4100,7 +4265,7 @@ static int com_source(String *buffer __attribute__((unused)), INFO_ERROR, 0); while (my_isspace(charset_info,*param)) param++; - end=strmake(source_name,param,sizeof(source_name)-1); + end=strmake_buf(source_name, param); while (end > source_name && (my_isspace(charset_info,end[-1]) || my_iscntrl(charset_info,end[-1]))) end--; @@ -4153,7 +4318,7 @@ com_delimiter(String *buffer __attribute__((unused)), char *line) { char buff[256], *tmp; - strmake(buff, line, sizeof(buff) - 1); + strmake_buf(buff, line); tmp= get_arg(buff, 0); if (!tmp || !*tmp) @@ -4170,7 +4335,7 @@ com_delimiter(String *buffer __attribute__((unused)), char *line) return 0; } } - strmake(delimiter, tmp, sizeof(delimiter) - 1); + strmake_buf(delimiter, tmp); delimiter_length= (int)strlen(delimiter); delimiter_str= delimiter; return 0; @@ -4184,7 +4349,7 @@ com_use(String *buffer __attribute__((unused)), char *line) int select_db; bzero(buff, sizeof(buff)); - strmake(buff, line, sizeof(buff) - 1); + strmake_buf(buff, line); tmp= get_arg(buff, 0); if (!tmp || !*tmp) { @@ -4728,7 +4893,13 @@ put_info(const char *str,INFO_TYPE info_type, uint error, const char *sqlstate) if (info_type == INFO_ERROR) { if (!opt_nobeep) + { +#ifdef _WIN32 + MessageBeep(MB_ICONWARNING); +#else putchar('\a'); /* This should make a bell */ +#endif + } vidattr(A_STANDOUT); if (error) { diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c index f4e3111b7b7..b6fa350b54a 100644 --- a/client/mysql_plugin.c +++ b/client/mysql_plugin.c @@ -12,7 +12,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include <m_string.h> diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index 9a3c56507e7..8b3f0fdec79 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -1,6 +1,6 @@ /* - Copyright (c) 2006, 2012, Oracle and/or its affiliates. - Copyright (C) 2010, 2012, Monty Program Ab. + Copyright (c) 2006, 2013, Oracle and/or its affiliates. + Copyright (c) 2010, 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 @@ -40,7 +40,7 @@ static char mysql_path[FN_REFLEN]; static char mysqlcheck_path[FN_REFLEN]; static my_bool opt_force, opt_verbose, debug_info_flag, debug_check_flag, - opt_systables_only; + opt_systables_only, opt_version_check; static my_bool opt_not_used, opt_silent; static uint my_end_arg= 0; static char *opt_user= (char*)"root"; @@ -150,6 +150,12 @@ static struct my_option my_long_options[]= &opt_not_used, &opt_not_used, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"version-check", 'k', "Run this program only if its \'server version\' " + "matches the version of the server to which it's connecting, (enabled by " + "default); use --skip-version-check to avoid this check. Note: the \'server " + "version\' of the program is the version of the MySQL server with which it " + "was built/distributed.", &opt_version_check, &opt_version_check, 0, + GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"write-binlog", OPT_WRITE_BINLOG, "All commands including mysqlcheck are binlogged. Enabled by default;" "use --skip-write-binlog when commands should not be sent to replication slaves.", @@ -291,6 +297,7 @@ get_one_option(int optid, const struct my_option *opt, my_progname, optid == 'b' ? "basedir" : "datadir"); /* FALLTHROUGH */ + case 'k': /* --version-check */ case 'v': /* --verbose */ opt_verbose++; if (argument == disabled_my_option) @@ -564,6 +571,8 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res, static int extract_variable_from_show(DYNAMIC_STRING* ds, char* value) { char *value_start, *value_end; + size_t len; + /* The query returns "datadir\t<datadir>\n", skip past the tab @@ -576,7 +585,9 @@ static int extract_variable_from_show(DYNAMIC_STRING* ds, char* value) if ((value_end= strchr(value_start, '\n')) == NULL) return 1; /* Unexpected result */ - strncpy(value, value_start, MY_MIN(FN_REFLEN, value_end-value_start)); + len= (size_t) MY_MIN(FN_REFLEN, value_end-value_start); + strncpy(value, value_start, len); + value[len]= '\0'; return 0; } @@ -874,6 +885,55 @@ static const char *load_default_groups[]= }; +/* Convert the specified version string into the numeric format. */ +static ulong STDCALL calc_server_version(char *some_version) +{ + uint major, minor, version; + char *point= some_version, *end_point; + major= (uint) strtoul(point, &end_point, 10); point=end_point+1; + minor= (uint) strtoul(point, &end_point, 10); point=end_point+1; + version= (uint) strtoul(point, &end_point, 10); + return (ulong) major * 10000L + (ulong)(minor * 100 + version); +} + +/** + Check if the server version matches with the server version mysql_upgrade + was compiled with. + + @return 0 match successful + 1 failed +*/ +static int check_version_match(void) +{ + DYNAMIC_STRING ds_version; + char version_str[NAME_CHAR_LEN + 1]; + + if (init_dynamic_string(&ds_version, NULL, NAME_CHAR_LEN, NAME_CHAR_LEN)) + die("Out of memory"); + + if (run_query("show variables like 'version'", + &ds_version, FALSE) || + extract_variable_from_show(&ds_version, version_str)) + { + dynstr_free(&ds_version); + return 1; /* Query failed */ + } + + dynstr_free(&ds_version); + + if (calc_server_version((char *) version_str) != MYSQL_VERSION_ID) + { + fprintf(stderr, "Error: Server version (%s) does not match with the " + "version of\nthe server (%s) with which this program was built/" + "distributed. You can\nuse --skip-version-check to skip this " + "check.\n", version_str, MYSQL_SERVER_VERSION); + return 1; + } + else + return 0; +} + + int main(int argc, char **argv) { char self_name[FN_REFLEN]; @@ -938,6 +998,9 @@ int main(int argc, char **argv) die(NULL); } + if (opt_version_check && check_version_match()) + die("Upgrade failed"); + /* Run "mysqlcheck" and "mysql_fix_privilege_tables.sql" */ diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index a45c3b85596..9a8901435c8 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* maintaince of mysql databases */ diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 32c02d03f37..31a1d583c4f 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1,6 +1,6 @@ /* - Copyright (c) 2000, 2012, Oracle and/or its affiliates. - Copyright (c) 2009, 2012, Monty Program Ab + Copyright (c) 2000, 2013, Oracle and/or its affiliates. + 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 @@ -37,6 +37,7 @@ /* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */ #include "sql_priv.h" #include "log_event.h" +#include "compat56.h" #include "sql_common.h" #include "my_dir.h" #include <welcome_copyright_notice.h> // ORACLE_WELCOME_COPYRIGHT_NOTICE @@ -206,10 +207,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(); @@ -818,6 +817,98 @@ write_event_header_and_base64(Log_event *ev, FILE *result_file, } +static bool print_base64(PRINT_EVENT_INFO *print_event_info, Log_event *ev) +{ + /* + 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 && + opt_base64_output_mode != BASE64_OUTPUT_DECODE_ROWS) + { + const char* type_str= ev->get_type_str(); + if (opt_base64_output_mode == BASE64_OUTPUT_NEVER) + error("--base64-output=never specified, but binlog contains a " + "%s event which must be printed in base64.", + type_str); + else + error("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); + return 1; + } + ev->print(result_file, print_event_info); + return print_event_info->head_cache.error == -1; +} + + +static bool print_row_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, + ulong table_id, bool is_stmt_end) +{ + Table_map_log_event *ignored_map= + print_event_info->m_table_map_ignored.get_table(table_id); + bool skip_event= (ignored_map != NULL); + + /* + end of statement check: + i) destroy/free ignored maps + ii) if skip event + a) since we are skipping the last event, + append END-MARKER(') to body cache (if required) + + b) flush cache now + */ + if (is_stmt_end) + { + /* + Now is safe to clear ignored map (clear_tables will also + delete original table map events stored in the map). + */ + if (print_event_info->m_table_map_ignored.count() > 0) + print_event_info->m_table_map_ignored.clear_tables(); + + /* + If there is a kept Annotate event and all corresponding + rbr-events were filtered away, the Annotate event was not + freed and it is just the time to do it. + */ + free_annotate_event(); + + /* + One needs to take into account an event that gets + filtered but was last event in the statement. If this is + the case, previous rows events that were written into + IO_CACHEs still need to be copied from cache to + result_file (as it would happen in ev->print(...) if + event was not skipped). + */ + if (skip_event) + { + // append END-MARKER(') with delimiter + IO_CACHE *const body_cache= &print_event_info->body_cache; + if (my_b_tell(body_cache)) + my_b_printf(body_cache, "'%s\n", print_event_info->delimiter); + + // flush cache + if ((copy_event_cache_to_file_and_reinit(&print_event_info->head_cache, result_file) || + copy_event_cache_to_file_and_reinit(&print_event_info->body_cache, result_file))) + return 1; + } + } + + /* skip the event check */ + if (skip_event) + return 0; + + return print_base64(print_event_info, ev); +} + + /** Print the given event, and either delete it or delegate the deletion to someone else. @@ -1130,86 +1221,29 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, error("Could not rewrite database name"); goto err; } + if (print_base64(print_event_info, ev)) + goto err; + break; } case WRITE_ROWS_EVENT: case DELETE_ROWS_EVENT: case UPDATE_ROWS_EVENT: + { + Rows_log_event *e= (Rows_log_event*) ev; + if (print_row_event(print_event_info, ev, e->get_table_id(), + e->get_flags(Rows_log_event::STMT_END_F))) + goto err; + break; + } case PRE_GA_WRITE_ROWS_EVENT: case PRE_GA_DELETE_ROWS_EVENT: case PRE_GA_UPDATE_ROWS_EVENT: { - if (ev_type != TABLE_MAP_EVENT) - { - Rows_log_event *e= (Rows_log_event*) ev; - Table_map_log_event *ignored_map= - print_event_info->m_table_map_ignored.get_table(e->get_table_id()); - bool skip_event= (ignored_map != NULL); - - /* - end of statement check: - i) destroy/free ignored maps - ii) if skip event, flush cache now - */ - if (e->get_flags(Rows_log_event::STMT_END_F)) - { - /* - Now is safe to clear ignored map (clear_tables will also - delete original table map events stored in the map). - */ - if (print_event_info->m_table_map_ignored.count() > 0) - print_event_info->m_table_map_ignored.clear_tables(); - - /* - If there is a kept Annotate event and all corresponding - rbr-events were filtered away, the Annotate event was not - freed and it is just the time to do it. - */ - free_annotate_event(); - - /* - One needs to take into account an event that gets - filtered but was last event in the statement. If this is - the case, previous rows events that were written into - IO_CACHEs still need to be copied from cache to - result_file (as it would happen in ev->print(...) if - event was not skipped). - */ - if (skip_event) - { - if ((copy_event_cache_to_file_and_reinit(&print_event_info->head_cache, result_file) || - copy_event_cache_to_file_and_reinit(&print_event_info->body_cache, result_file))) - goto err; - } - } - - /* skip the event check */ - if (skip_event) - goto end; - } - /* - 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 && - opt_base64_output_mode != BASE64_OUTPUT_DECODE_ROWS) - { - const char* type_str= ev->get_type_str(); - if (opt_base64_output_mode == BASE64_OUTPUT_NEVER) - error("--base64-output=never specified, but binlog contains a " - "%s event which must be printed in base64.", - type_str); - else - error("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); + Old_rows_log_event *e= (Old_rows_log_event*) ev; + if (print_row_event(print_event_info, ev, e->get_table_id(), + e->get_flags(Old_rows_log_event::STMT_END_F))) goto err; - } - /* FALL THROUGH */ + break; } default: print_skip_replication_statement(print_event_info, ev); @@ -1516,13 +1550,14 @@ the mysql command line client.\n\n"); static my_time_t convert_str_to_timestamp(const char* str) { - int was_cut; + MYSQL_TIME_STATUS status; MYSQL_TIME l_time; long dummy_my_timezone; uint dummy_in_dst_time_gap; + /* We require a total specification (date AND time) */ - if (str_to_datetime(str, (uint) strlen(str), &l_time, 0, &was_cut) != - MYSQL_TIMESTAMP_DATETIME || was_cut) + if (str_to_datetime(str, (uint) strlen(str), &l_time, 0, &status) || + l_time.time_type != MYSQL_TIMESTAMP_DATETIME || status.warnings) { error("Incorrect date and time argument: %s", str); exit(1); @@ -2444,6 +2479,8 @@ int main(int argc, char** argv) else load_processor.init_by_cur_dir(); + fprintf(result_file, "/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;\n"); + fprintf(result_file, "/*!40019 SET @@session.max_insert_delayed_threads=0*/;\n"); @@ -2494,6 +2531,8 @@ int main(int argc, char** argv) "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n" "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n"); + fprintf(result_file, "/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;\n"); + if (tmpdir.list) free_tmpdir(&tmpdir); if (result_file != stdout) @@ -2533,3 +2572,4 @@ void *sql_alloc(size_t size) #include "sql_string.cc" #include "sql_list.cc" #include "rpl_filter.cc" +#include "compat56.cc" diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index f429837c1dd..e614d628630 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -18,7 +18,7 @@ /* By Jani Tolonen, 2001-04-20, MySQL Development Team */ -#define CHECK_VERSION "2.7.0" +#define CHECK_VERSION "2.7.1" #include "client_priv.h" #include <m_ctype.h> @@ -32,6 +32,10 @@ #define EX_USAGE 1 #define EX_MYSQLERR 2 +/* ALTER instead of repair. */ +#define MAX_ALTER_STR_SIZE 128 * 1024 +#define KEY_PARTITIONING_CHANGED_STR "KEY () partitioning changed" + static MYSQL mysql_connection, *sock = 0; static my_bool opt_alldbs = 0, opt_check_only_changed = 0, opt_extended = 0, opt_compress = 0, opt_databases = 0, opt_fast = 0, @@ -47,7 +51,7 @@ static char *opt_password = 0, *current_user = 0, *default_charset= 0, *current_host= 0; static char *opt_plugin_dir= 0, *opt_default_auth= 0; static int first_error = 0; -DYNAMIC_ARRAY tables4repair, tables4rebuild; +DYNAMIC_ARRAY tables4repair, tables4rebuild, alter_table_cmds; static char *shared_memory_base_name=0; static uint opt_protocol=0; @@ -620,6 +624,17 @@ static int process_all_tables_in_db(char *database) } /* process_all_tables_in_db */ +static int run_query(const char *query) +{ + if (mysql_query(sock, query)) + { + fprintf(stderr, "Failed to %s\n", query); + fprintf(stderr, "Error: %s\n", mysql_error(sock)); + return 1; + } + return 0; +} + static int fix_table_storage_name(const char *name) { @@ -630,12 +645,7 @@ static int fix_table_storage_name(const char *name) if (strncmp(name, "#mysql50#", 9)) DBUG_RETURN(1); sprintf(qbuf, "RENAME TABLE `%s` TO `%s`", name, name + 9); - if (mysql_query(sock, qbuf)) - { - fprintf(stderr, "Failed to %s\n", qbuf); - fprintf(stderr, "Error: %s\n", mysql_error(sock)); - rc= 1; - } + rc= run_query(qbuf); if (verbose) printf("%-50s %s\n", name, rc ? "FAILED" : "OK"); DBUG_RETURN(rc); @@ -650,12 +660,7 @@ static int fix_database_storage_name(const char *name) if (strncmp(name, "#mysql50#", 9)) DBUG_RETURN(1); sprintf(qbuf, "ALTER DATABASE `%s` UPGRADE DATA DIRECTORY NAME", name); - if (mysql_query(sock, qbuf)) - { - fprintf(stderr, "Failed to %s\n", qbuf); - fprintf(stderr, "Error: %s\n", mysql_error(sock)); - rc= 1; - } + rc= run_query(qbuf); if (verbose) printf("%-50s %s\n", name, rc ? "FAILED" : "OK"); DBUG_RETURN(rc); @@ -726,15 +731,7 @@ static int use_db(char *database) static int disable_binlog() { const char *stmt= "SET SQL_LOG_BIN=0"; - DBUG_ENTER("disable_binlog"); - - if (mysql_query(sock, stmt)) - { - fprintf(stderr, "Failed to %s\n", stmt); - fprintf(stderr, "Error: %s\n", mysql_error(sock)); - DBUG_RETURN(1); - } - DBUG_RETURN(0); + return run_query(stmt); } static int handle_request_for_tables(char *tables, uint length) @@ -821,6 +818,7 @@ static void print_result() MYSQL_RES *res; MYSQL_ROW row; char prev[(NAME_LEN+9)*2+2]; + char prev_alter[MAX_ALTER_STR_SIZE]; uint i; my_bool found_error=0, table_rebuild=0; DBUG_ENTER("print_result"); @@ -828,6 +826,7 @@ static void print_result() res = mysql_use_result(sock); prev[0] = '\0'; + prev_alter[0]= 0; for (i = 0; (row = mysql_fetch_row(res)); i++) { int changed = strcmp(prev, row[0]); @@ -844,12 +843,18 @@ static void print_result() strcmp(row[3],"OK")) { if (table_rebuild) - insert_dynamic(&tables4rebuild, (uchar*) prev); + { + if (prev_alter[0]) + insert_dynamic(&alter_table_cmds, (uchar*) prev_alter); + else + insert_dynamic(&tables4rebuild, (uchar*) prev); + } else insert_dynamic(&tables4repair, (uchar*) prev); } found_error=0; table_rebuild=0; + prev_alter[0]= 0; if (opt_silent) continue; } @@ -866,11 +871,30 @@ static void print_result() printf("%-50s %s", row[0], "Needs upgrade"); else printf("%s\n%-9s: %s", row[0], row[2], row[3]); - if (strcmp(row[2],"note")) + if (opt_auto_repair && strcmp(row[2],"note")) { - found_error=1; - if (opt_auto_repair && strstr(row[3], "ALTER TABLE") != NULL) + const char *alter_txt= strstr(row[3], "ALTER TABLE"); + found_error=1; + if (alter_txt) + { table_rebuild=1; + if (!strncmp(row[3], KEY_PARTITIONING_CHANGED_STR, + strlen(KEY_PARTITIONING_CHANGED_STR)) && + strstr(alter_txt, "PARTITION BY")) + { + if (strlen(alter_txt) >= MAX_ALTER_STR_SIZE) + { + printf("Error: Alter command too long (>= %d)," + " please do \"%s\" or dump/reload to fix it!\n", + MAX_ALTER_STR_SIZE, + alter_txt); + table_rebuild= 0; + prev_alter[0]= 0; + } + else + strcpy(prev_alter, alter_txt); + } + } } } else @@ -882,7 +906,12 @@ static void print_result() if (found_error && opt_auto_repair && what_to_do != DO_REPAIR) { if (table_rebuild) - insert_dynamic(&tables4rebuild, (uchar*) prev); + { + if (prev_alter[0]) + insert_dynamic(&alter_table_cmds, (uchar*) prev_alter); + else + insert_dynamic(&tables4rebuild, (uchar*) prev); + } else insert_dynamic(&tables4repair, (uchar*) prev); } @@ -1001,7 +1030,9 @@ int main(int argc, char **argv) (my_init_dynamic_array(&tables4repair, sizeof(char)*(NAME_LEN*2+2),16, 64, MYF(0)) || my_init_dynamic_array(&tables4rebuild, sizeof(char)*(NAME_LEN*2+2),16, - 64, MYF(0)))) + 64, MYF(0)) || + my_init_dynamic_array(&alter_table_cmds, MAX_ALTER_STR_SIZE, 0, + 1, MYF(0)))) goto end; if (opt_alldbs) @@ -1026,6 +1057,8 @@ int main(int argc, char **argv) } for (i = 0; i < tables4rebuild.elements ; i++) rebuild_table((char*) dynamic_array_ptr(&tables4rebuild, i)); + for (i = 0; i < alter_table_cmds.elements ; i++) + run_query((char*) dynamic_array_ptr(&alter_table_cmds, i)); } ret= test(first_error); diff --git a/client/mysqldump.c b/client/mysqldump.c index 1cf66fe3dd1..ef3b0ce1ca0 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2012, Oracle and/or its affiliates. + Copyright (c) 2000, 2013, Oracle and/or its affiliates. Copyright (c) 2010, 2013, Monty Program Ab. This program is free software; you can redistribute it and/or modify @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* mysqldump.c - Dump a tables contents and format to an ASCII file @@ -2300,7 +2300,6 @@ static uint dump_routines_for_db(char *db) const char *routine_type[]= {"FUNCTION", "PROCEDURE"}; char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3]; char *routine_name; - char *query_str; int i; FILE *sql_file= md_result_file; MYSQL_RES *routine_res, *routine_list_res; @@ -2394,17 +2393,6 @@ static uint dump_routines_for_db(char *db) fprintf(sql_file, "/*!50003 DROP %s IF EXISTS %s */;\n", routine_type[i], routine_name); - query_str= cover_definer_clause(row[2], strlen(row[2]), - C_STRING_WITH_LEN("50020"), - C_STRING_WITH_LEN("50003"), - C_STRING_WITH_LEN(" FUNCTION")); - - if (!query_str) - query_str= cover_definer_clause(row[2], strlen(row[2]), - C_STRING_WITH_LEN("50020"), - C_STRING_WITH_LEN("50003"), - C_STRING_WITH_LEN(" PROCEDURE")); - if (mysql_num_fields(routine_res) >= 6) { if (switch_db_collation(sql_file, db_name_buff, ";", @@ -2442,9 +2430,9 @@ static uint dump_routines_for_db(char *db) fprintf(sql_file, "DELIMITER ;;\n" - "/*!50003 %s */;;\n" + "%s ;;\n" "DELIMITER ;\n", - (const char *) (query_str != NULL ? query_str : row[2])); + (const char *) row[2]); restore_sql_mode(sql_file, ";"); @@ -2459,7 +2447,6 @@ static uint dump_routines_for_db(char *db) } } - my_free(query_str); } } /* end of routine printing */ mysql_free_result(routine_res); diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 9e4b9da54af..87d6c80917a 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. - Copyright (c) 2009, 2012, Monty Program Ab. +/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. + 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 @@ -63,8 +63,9 @@ #define SIGNAL_FMT "signal %d" #endif +#include <my_context.h> static my_bool non_blocking_api_enabled= 0; -#if !defined(EMBEDDED_LIBRARY) +#if !defined(EMBEDDED_LIBRARY) && !defined(MY_CONTEXT_DISABLE) #define WRAP_NONBLOCK_ENABLED non_blocking_api_enabled #include "../tests/nonblock-wrappers.h" #endif @@ -3590,7 +3591,7 @@ void do_remove_file(struct st_command *command) ' '); DBUG_PRINT("info", ("removing file: %s", ds_filename.str)); - error= my_delete_allow_opened(ds_filename.str, MYF(disable_warnings ? 0 : MY_WME)) != 0; + error= my_delete(ds_filename.str, MYF(disable_warnings ? 0 : MY_WME)) != 0; handle_command_error(command, error, my_errno); dynstr_free(&ds_filename); DBUG_VOID_RETURN; @@ -3633,7 +3634,6 @@ void do_remove_files_wildcard(struct st_command *command) fn_format(dirname, ds_directory.str, "", "", MY_UNPACK_FILENAME); DBUG_PRINT("info", ("listing directory: %s", dirname)); - /* Note that my_dir sorts the list if not given any flags */ if (!(dir_info= my_dir(dirname, MYF(MY_DONT_SORT | MY_WANT_STAT | MY_WME)))) { error= 1; @@ -3648,7 +3648,7 @@ void do_remove_files_wildcard(struct st_command *command) /* Set default wild chars for wild_compare, is changed in embedded mode */ set_wild_chars(1); - for (i= 0; i < (uint) dir_info->number_off_files; i++) + for (i= 0; i < (uint) dir_info->number_of_files; i++) { file= dir_info->dir_entry + i; /* Remove only regular files, i.e. no directories etc. */ @@ -3911,17 +3911,12 @@ static int get_list_files(DYNAMIC_STRING *ds, const DYNAMIC_STRING *ds_dirname, DBUG_ENTER("get_list_files"); DBUG_PRINT("info", ("listing directory: %s", ds_dirname->str)); - /* Note that my_dir sorts the list if not given any flags */ - if (!(dir_info= my_dir(ds_dirname->str, MYF(0)))) + if (!(dir_info= my_dir(ds_dirname->str, MYF(MY_WANT_SORT)))) DBUG_RETURN(1); set_wild_chars(1); - for (i= 0; i < (uint) dir_info->number_off_files; i++) + for (i= 0; i < (uint) dir_info->number_of_files; i++) { file= dir_info->dir_entry + i; - if (file->name[0] == '.' && - (file->name[1] == '\0' || - (file->name[1] == '.' && file->name[2] == '\0'))) - continue; /* . or .. */ if (ds_wild && ds_wild->length && wild_compare(file->name, ds_wild->str, 0)) continue; @@ -5956,8 +5951,10 @@ void do_connect(struct st_command *command) if (opt_connect_timeout) mysql_options(con_slot->mysql, MYSQL_OPT_CONNECT_TIMEOUT, (void *) &opt_connect_timeout); - - mysql_options(con_slot->mysql, MYSQL_OPT_NONBLOCK, 0); +#ifndef MY_CONTEXT_DISABLE + if (mysql_options(con_slot->mysql, MYSQL_OPT_NONBLOCK, 0)) + die("Failed to initialise non-blocking API"); +#endif if (opt_compress || con_compress) mysql_options(con_slot->mysql, MYSQL_OPT_COMPRESS, NullS); mysql_options(con_slot->mysql, MYSQL_OPT_LOCAL_INFILE, 0); @@ -6361,8 +6358,7 @@ void do_delimiter(struct st_command* command) if (!(*p)) die("Can't set empty delimiter"); - strmake(delimiter, p, sizeof(delimiter) - 1); - delimiter_length= strlen(delimiter); + delimiter_length= strmake_buf(delimiter, p) - delimiter; DBUG_PRINT("exit", ("delimiter: %s", delimiter)); command->last_argument= p + delimiter_length; 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/client/sql_string.cc.dontuse b/client/sql_string.cc.dontuse index 64219886dd0..9679197b207 100644 --- a/client/sql_string.cc.dontuse +++ b/client/sql_string.cc.dontuse @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2011, Oracle and/or its affiliates. + Copyright (c) 2000, 2013, 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 @@ -691,7 +691,7 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length) { if (from->Alloced_length >= from_length) return from; - if (from->alloced || !to || from == to) + if ((from->alloced && (from->Alloced_length != 0)) || !to || from == to) { (void) from->realloc(from_length); return from; diff --git a/client/sql_string.h.dontuse b/client/sql_string.h.dontuse index 67155ebcee7..94f844dc689 100644 --- a/client/sql_string.h.dontuse +++ b/client/sql_string.h.dontuse @@ -1,7 +1,7 @@ #ifndef SQL_STRING_INCLUDED #define SQL_STRING_INCLUDED -/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. 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 @@ -226,6 +226,7 @@ public: DBUG_ASSERT(!s.uses_buffer_owned_by(this)); free(); Ptr=s.Ptr ; str_length=s.str_length ; Alloced_length=s.Alloced_length; + str_charset=s.str_charset; alloced=0; } return *this; |