diff options
Diffstat (limited to 'client')
-rw-r--r-- | client/CMakeLists.txt | 4 | ||||
-rw-r--r-- | client/Makefile.am | 7 | ||||
-rw-r--r-- | client/client_priv.h | 6 | ||||
-rw-r--r-- | client/get_password.c | 4 | ||||
-rw-r--r-- | client/mysql.cc | 217 | ||||
-rw-r--r-- | client/mysql_upgrade.c | 80 | ||||
-rw-r--r-- | client/mysqladmin.cc | 144 | ||||
-rw-r--r-- | client/mysqlbinlog.cc | 150 | ||||
-rw-r--r-- | client/mysqlcheck.c | 66 | ||||
-rw-r--r-- | client/mysqldump.c | 18 | ||||
-rw-r--r-- | client/mysqlimport.c | 4 | ||||
-rw-r--r-- | client/mysqlshow.c | 2 | ||||
-rw-r--r-- | client/mysqlslap.c | 170 | ||||
-rw-r--r-- | client/mysqltest.cc | 316 | ||||
-rw-r--r-- | client/sql_string.h | 3 |
15 files changed, 858 insertions, 333 deletions
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index e39e8d7178a..52fd378689e 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -72,3 +72,7 @@ ENDIF(WIN32) SET_TARGET_PROPERTIES (mysqlcheck mysqldump mysqlimport mysql_upgrade mysqlshow mysqlslap PROPERTIES HAS_CXX TRUE) +ADD_DEFINITIONS(-DHAVE_DLOPEN) + +INSTALL(TARGETS mysql mysqltest mysqlcheck mysqldump mysqlimport mysql_upgrade mysqlshow + mysqlbinlog mysqladmin mysqlslap echo DESTINATION bin COMPONENT runtime) diff --git a/client/Makefile.am b/client/Makefile.am index 393573a061e..96e763772dd 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -99,8 +99,8 @@ mysql_upgrade_SOURCES= mysql_upgrade.c \ # Fix for mit-threads DEFS = -DMYSQL_CLIENT_NO_THREADS \ - -DDEFAULT_MYSQL_HOME="\"$(prefix)\"" \ - -DMYSQL_DATADIR="\"$(localstatedir)\"" + -DDEFAULT_MYSQL_HOME='"$(prefix)"' \ + -DMYSQL_DATADIR='"$(localstatedir)"' sql_src=log_event.h sql_priv.h rpl_constants.h \ rpl_tblmap.h rpl_tblmap.cc \ @@ -108,7 +108,8 @@ sql_src=log_event.h sql_priv.h rpl_constants.h \ log_event_old.h log_event_old.cc \ rpl_record_old.h rpl_record_old.cc \ rpl_utility.h rpl_utility.cc \ - transaction.h sql_const.h + transaction.h sql_const.h \ + sql_list.h rpl_filter.h sql_list.cc rpl_filter.cc strings_src=decimal.c dtoa.c link_sources: diff --git a/client/client_priv.h b/client/client_priv.h index e7911fc31f7..c543dd4efa2 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -84,7 +84,11 @@ enum options_client OPT_DEBUG_INFO, OPT_DEBUG_CHECK, OPT_COLUMN_TYPES, OPT_ERROR_LOG_FILE, OPT_WRITE_BINLOG, OPT_DUMP_DATE, OPT_INIT_COMMAND, - OPT_MAX_CLIENT_OPTION + OPT_ABORT_SOURCE_ON_ERROR, + OPT_REWRITE_DB, + OPT_PLUGIN_DIR, + OPT_DEFAULT_PLUGIN, + OPT_MAX_CLIENT_OPTION /* should be always the last */ }; /** diff --git a/client/get_password.c b/client/get_password.c index ea024f76fb6..c6653183f48 100644 --- a/client/get_password.c +++ b/client/get_password.c @@ -113,7 +113,7 @@ static void get_password(char *to,uint length,int fd, my_bool echo) for (;;) { - char tmp; + uchar tmp; if (my_read(fd,&tmp,1,MYF(0)) != 1) break; if (tmp == '\b' || (int) tmp == 127) @@ -138,7 +138,7 @@ static void get_password(char *to,uint length,int fd, my_bool echo) fputc('*',stderr); fflush(stderr); } - *(pos++) = tmp; + *(pos++)= (char) tmp; } while (pos != to && isspace(pos[-1]) == ' ') pos--; /* Allow dummy space at end */ diff --git a/client/mysql.cc b/client/mysql.cc index b61a751198a..208b5b3288c 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1,4 +1,6 @@ -/* Copyright 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (C) 2000-2009 MySQL AB + Copyright 2000, 2010, Oracle and/or its affiliates. All rights reserved. + Copyright 2000-2010 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 @@ -14,7 +16,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define COPYRIGHT_NOTICE "\ -Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.\n\ This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\ and you are welcome to modify and redistribute it under the GPL v2 license\n" @@ -48,7 +49,7 @@ and you are welcome to modify and redistribute it under the GPL v2 license\n" #include <locale.h> #endif -const char *VER= "14.14"; +const char *VER= "14.16"; /* Don't try to make a nice table if the data is too big */ #define MAX_COLUMN_LENGTH 1024 @@ -86,8 +87,9 @@ extern "C" { #include <term.h> #endif #endif -#endif +#endif /* defined(HAVE_CURSES_H) && defined(HAVE_TERM_H) */ +#undef bcmp // Fix problem with new readline #if defined(__WIN__) #include <conio.h> #else @@ -95,7 +97,6 @@ extern "C" { #define HAVE_READLINE #define USE_POPEN #endif - //int vidattr(long unsigned int attrs); // Was missing in sun curses } #if !defined(HAVE_VIDATTR) @@ -143,16 +144,18 @@ static my_bool ignore_errors=0,wait_flag=0,quick=0, opt_secure_auth= 0, default_pager_set= 0, opt_sigint_ignore= 0, auto_vertical_output= 0, - show_warnings= 0, executing_query= 0, interrupted_query= 0, + show_warnings= 0, executing_query= 0, ignore_spaces= 0; -static my_bool debug_info_flag, debug_check_flag; +static my_bool debug_info_flag, debug_check_flag, batch_abort_on_error; static my_bool column_types_flag; static my_bool preserve_comments= 0; +static my_bool in_com_source, aborted= 0; static ulong opt_max_allowed_packet, opt_net_buffer_length; 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 int interrupted_query= 0; static char *current_host,*current_db,*current_user=0,*opt_password=0, *current_prompt=0, *delimiter_str= 0, *default_charset= (char*) MYSQL_AUTODETECT_CHARSET_NAME, @@ -166,6 +169,7 @@ static int wait_time = 5; static STATUS status; static ulong select_limit,max_join_size,opt_connect_timeout=0; static char mysql_charsets_dir[FN_REFLEN+1]; +static char *opt_plugin_dir= 0, *opt_default_auth; static const char *xmlmeta[] = { "&", "&", "<", "<", @@ -1022,7 +1026,7 @@ static const char *load_default_groups[]= { "mysql","client",0 }; static int embedded_server_arg_count= 0; static char *embedded_server_args[MAX_SERVER_ARGS]; static const char *embedded_server_groups[]= -{ "server", "embedded", "mysql_SERVER", 0 }; +{ "server", "embedded", "mysql_SERVER", "mariadb_SERVER", 0 }; #ifdef HAVE_READLINE /* @@ -1078,9 +1082,10 @@ int main(int argc,char *argv[]) delimiter_str= delimiter; default_prompt = my_strdup(getenv("MYSQL_PS1") ? getenv("MYSQL_PS1") : - "mysql> ",MYF(MY_WME)); + "\\N [\\d]> ",MYF(MY_WME)); current_prompt = my_strdup(default_prompt,MYF(MY_WME)); prompt_counter=0; + aborted= 0; outfile[0]=0; // no (default) outfile strmov(pager, "stdout"); // the default, if --pager wasn't given @@ -1169,10 +1174,11 @@ int main(int argc,char *argv[]) window_resize(0); #endif - put_info("Welcome to the MySQL monitor. Commands end with ; or \\g.", + put_info("Welcome to the MariaDB monitor. Commands end with ; or \\g.", INFO_INFO); sprintf((char*) glob_buffer.ptr(), - "Your MySQL connection id is %lu\nServer version: %s\n", + "Your %s connection id is %lu\nServer version: %s\n", + mysql_get_server_name(&mysql), mysql_thread_id(&mysql), server_version_string(&mysql)); put_info((char*) glob_buffer.ptr(),INFO_INFO); @@ -1285,15 +1291,16 @@ sig_handler mysql_end(int sig) /* This function handles sigint calls If query is in process, kill query + If 'source' is executed, abort source command no query in process, terminate like previous behavior */ + sig_handler handle_sigint(int sig) { char kill_buffer[40]; MYSQL *kill_mysql= NULL; /* terminate if no query being executed, or we already tried interrupting */ - /* terminate if no query being executed, or we already tried interrupting */ if (!executing_query || (interrupted_query == 2)) { tee_fprintf(stdout, "Ctrl-C -- exit!\n"); @@ -1308,6 +1315,7 @@ sig_handler handle_sigint(int sig) goto err; } + /* First time try to kill the query, second time the connection */ interrupted_query++; /* mysqld < 5 does not understand KILL QUERY, skip to KILL CONNECTION */ @@ -1318,11 +1326,15 @@ sig_handler handle_sigint(int sig) sprintf(kill_buffer, "KILL %s%lu", (interrupted_query == 1) ? "QUERY " : "", mysql_thread_id(&mysql)); - tee_fprintf(stdout, "Ctrl-C -- sending \"%s\" to server ...\n", kill_buffer); + if (verbose) + tee_fprintf(stdout, "Ctrl-C -- sending \"%s\" to server ...\n", + kill_buffer); mysql_real_query(kill_mysql, kill_buffer, (uint) strlen(kill_buffer)); mysql_close(kill_mysql); - tee_fprintf(stdout, "Ctrl-C -- query aborted.\n"); - + tee_fprintf(stdout, "Ctrl-C -- query killed. Continuing normally.\n"); + interrupted_query= 0; + if (in_com_source) + aborted= 1; // Abort source command return; err: @@ -1334,7 +1346,6 @@ err: handler called mysql_end(). */ mysql_thread_end(); - return; #else mysql_end(sig); #endif @@ -1357,6 +1368,10 @@ static struct my_option my_long_options[] = 0, 0, 0, 0, 0}, {"help", 'I', "Synonym for -?", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"abort-source-on-error", OPT_ABORT_SOURCE_ON_ERROR, + "Abort 'source filename' operations in case of errors", + &batch_abort_on_error, &batch_abort_on_error, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"auto-rehash", OPT_AUTO_REHASH, "Enable automatic rehashing. One doesn't need to use 'rehash' to get table " "and field completion, but startup and reconnecting may take a longer time. " @@ -1413,7 +1428,7 @@ static struct my_option my_long_options[] = {"vertical", 'E', "Print the output of a query (rows) vertically.", &vertical, &vertical, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"force", 'f', "Continue even if we get an SQL error.", + {"force", 'f', "Continue even if we get an SQL error. Sets abort-source-on-error to 0", &ignore_errors, &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"named-commands", 'G', @@ -1564,6 +1579,13 @@ static struct my_option my_long_options[] = {"show-warnings", OPT_SHOW_WARNINGS, "Show warnings after every statement.", &show_warnings, &show_warnings, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.", + (uchar**) &opt_plugin_dir, (uchar**) &opt_plugin_dir, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"default_auth", OPT_PLUGIN_DIR, + "Default authentication client-side plugin to use.", + (uchar**) &opt_default_auth, (uchar**) &opt_default_auth, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -1747,6 +1769,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), #endif break; #include <sslopt-case.h> + case 'f': + batch_abort_on_error= 0; + break; case 'V': usage(1); exit(0); @@ -1830,7 +1855,7 @@ static int read_and_execute(bool interactive) String buffer; #endif - char *line; + char *line= 0; char in_string=0; ulong line_number=0; bool ml_comment= 0; @@ -1838,7 +1863,7 @@ static int read_and_execute(bool interactive) bool truncated= 0; status.exit_status=1; - for (;;) + while (!aborted) { if (!interactive) { @@ -1996,12 +2021,12 @@ static COMMANDS *find_command(char *name,char cmd_char) for (uint i= 0; commands[i].name; i++) { 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))) + (((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]); @@ -2159,16 +2184,21 @@ static bool add_line(String &buffer,char *line,char *in_string, } buffer.length(0); } - else if (!*ml_comment && (!*in_string && (inchar == '#' || - (inchar == '-' && pos[1] == '-' && - /* - The third byte is either whitespace or is the - end of the line -- which would occur only - because of the user sending newline -- which is - itself whitespace and should also match. - */ - (my_isspace(charset_info,pos[2]) || - !pos[2]))))) + else if (!*ml_comment && + (!*in_string && + (inchar == '#' || + (inchar == '-' && pos[1] == '-' && + /* + The third byte is either whitespace or is the end of + the line -- which would occur only because of the + user sending newline -- which is itself whitespace + and should also match. + We also ignore lines starting with '--', even if there + isn't a whitespace after. (This makes it easier to run + mysql-test-run cases through the client) + */ + ((my_isspace(charset_info,pos[2]) || !pos[2]) || + (buffer.is_empty() && out == line)))))) { // Flush previously accepted characters if (out != line) @@ -2855,13 +2885,8 @@ com_help(String *buffer __attribute__((unused)), return com_server_help(buffer,line,help_arg); } - put_info("\nFor information about MySQL products and services, visit:\n" - " http://www.mysql.com/\n" - "For developer information, including the MySQL Reference Manual, " - "visit:\n" - " http://dev.mysql.com/\n" - "To buy MySQL Enterprise support, training, or other products, visit:\n" - " https://shop.mysql.com/\n", INFO_INFO); + put_info("\nGeneral information about MariaDB can be found at\n" + "http://askmonty.org/wiki/index.php/Manual:Contents\n", INFO_INFO); put_info("List of all MySQL commands:", INFO_INFO); if (!named_cmds) put_info("Note that all text commands must be first on line and end with ';'",INFO_INFO); @@ -3858,8 +3883,9 @@ static int com_edit(String *buffer,char *line __attribute__((unused))) { char filename[FN_REFLEN],buff[160]; - int fd,tmp; + int fd,tmp,error; const char *editor; + MY_STAT stat_arg; if ((fd=create_temp_file(filename,NullS,"sql", O_CREAT | O_WRONLY, MYF(MY_WME))) < 0) @@ -3875,10 +3901,14 @@ com_edit(String *buffer,char *line __attribute__((unused))) !(editor = (char *)getenv("VISUAL"))) editor = "vi"; strxmov(buff,editor," ",filename,NullS); - if(system(buff) == -1) + if ((error= system(buff))) + { + char errmsg[100]; + sprintf(errmsg, "Command '%.40s' failed", buff); + put_info(errmsg, INFO_ERROR, 0, NullS); goto err; + } - MY_STAT stat_arg; if (!my_stat(filename,&stat_arg,MYF(MY_WME))) goto err; if ((fd = my_open(filename,O_RDONLY, MYF(MY_WME))) < 0) @@ -3961,7 +3991,7 @@ static int com_connect(String *buffer, char *line) { char *tmp, buff[256]; - bool save_rehash= opt_rehash; + my_bool save_rehash= opt_rehash; int error; bzero(buff, sizeof(buff)); @@ -4018,6 +4048,7 @@ static int com_source(String *buffer, char *line) int error; STATUS old_status; FILE *sql_file; + my_bool save_ignore_errors; /* Skip space from file name */ while (my_isspace(charset_info,*line)) @@ -4049,16 +4080,27 @@ static int com_source(String *buffer, char *line) /* Save old status */ old_status=status; + save_ignore_errors= ignore_errors; bfill((char*) &status,sizeof(status),(char) 0); status.batch=old_status.batch; // Run in batch mode status.line_buff=line_buff; status.file_name=source_name; glob_buffer.length(0); // Empty command buffer + ignore_errors= !batch_abort_on_error; + in_com_source= 1; error= read_and_execute(false); + ignore_errors= save_ignore_errors; status=old_status; // Continue as before + in_com_source= aborted= 0; my_fclose(sql_file,MYF(0)); batch_readline_end(line_buff); + /* + If we got an error during source operation, don't abort the client + if ignore_errors is set + */ + if (error && ignore_errors) + error= -1; // Ignore error return error; } @@ -4247,6 +4289,57 @@ char *get_arg(char *line, my_bool get_next_arg) } +/** + An example of mysql_authentication_dialog_ask callback. + + The C function with the name "mysql_authentication_dialog_ask", if exists, + will be used by the "dialog" client authentication plugin when user + input is needed. This function should be of mysql_authentication_dialog_ask_t + type. If the function does not exists, a built-in implementation will be + used. + + @param mysql mysql + @param type type of the input + 1 - normal string input + 2 - password string + @param prompt prompt + @param buf a buffer to store the use input + @param buf_len the length of the buffer + + @retval a pointer to the user input string. + It may be equal to 'buf' or to 'mysql->password'. + In all other cases it is assumed to be an allocated + string, and the "dialog" plugin will free() it. +*/ + +extern "C" char *mysql_authentication_dialog_ask(MYSQL *mysql, int type, + const char *prompt, + char *buf, int buf_len) +{ + char *s=buf; + + fputs("[mariadb] ", stdout); + fputs(prompt, stdout); + fputs(" ", stdout); + + if (type == 2) /* password */ + { + s= get_tty_password(""); + strnmov(buf, s, buf_len); + buf[buf_len-1]= 0; + my_free(s, MYF(0)); + } + else + { + if (!fgets(buf, buf_len-1, stdin)) + buf[0]= 0; + else if (buf[0] && (s= strend(buf))[-1] == '\n') + s[-1]= 0; + } + + return buf; +} + static int sql_real_connect(char *host,char *database,char *user,char *password, uint silent) @@ -4294,7 +4387,13 @@ sql_real_connect(char *host,char *database,char *user,char *password, } mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); - + + if (opt_plugin_dir && *opt_plugin_dir) + mysql_options(&mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir); + + if (opt_default_auth && *opt_default_auth) + mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); + if (!mysql_real_connect(&mysql, host, user, password, database, opt_mysql_port, opt_mysql_unix_port, connect_flag | CLIENT_MULTI_STATEMENTS)) @@ -4411,6 +4510,7 @@ com_status(String *buffer __attribute__((unused)), tee_fprintf(stdout, "Using outfile:\t\t'%s'\n", opt_outfile ? outfile : ""); #endif tee_fprintf(stdout, "Using delimiter:\t%s\n", delimiter); + tee_fprintf(stdout, "Server:\t\t\t%s\n", mysql_get_server_name(&mysql)); tee_fprintf(stdout, "Server version:\t\t%s\n", server_version_string(&mysql)); tee_fprintf(stdout, "Protocol version:\t%d\n", mysql_get_proto_info(&mysql)); tee_fprintf(stdout, "Connection:\t\t%s\n", mysql_get_host_info(&mysql)); @@ -4579,12 +4679,19 @@ put_info(const char *str,INFO_TYPE info_type, uint error, const char *sqlstate) if (error) { if (sqlstate) - (void) tee_fprintf(file, "ERROR %d (%s): ", error, sqlstate); + (void) tee_fprintf(file, "ERROR %d (%s)", error, sqlstate); else - (void) tee_fprintf(file, "ERROR %d: ", error); + (void) tee_fprintf(file, "ERROR %d", error); } else - tee_puts("ERROR: ", file); + tee_fputs("ERROR", file); + if (status.query_start_line && line_numbers) + { + (void) fprintf(file," at line %lu",status.query_start_line); + if (status.file_name) + (void) fprintf(file," in file: '%s'", status.file_name); + } + tee_fputs(": ", file); } else vidattr(A_BOLD); @@ -4593,7 +4700,7 @@ put_info(const char *str,INFO_TYPE info_type, uint error, const char *sqlstate) } if (unbuffered) fflush(file); - return info_type == INFO_ERROR ? -1 : 0; + return info_type == INFO_ERROR ? (ignore_errors ? -1 : 1): 0; } @@ -4730,7 +4837,7 @@ static void mysql_end_timer(ulong start_time,char *buff) strmov(strend(buff),")"); } -static const char* construct_prompt() +static const char *construct_prompt() { processed_prompt.free(); // Erase the old prompt time_t lclock = time(NULL); // Get the date struct @@ -4759,6 +4866,12 @@ static const char* construct_prompt() case 'd': processed_prompt.append(current_db ? current_db : "(none)"); break; + case 'N': + if (connected) + processed_prompt.append(mysql_get_server_name(&mysql)); + else + processed_prompt.append("unknown"); + break; case 'h': { const char *prompt; diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index 882350f813b..cd1c9bb27d3 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -1,4 +1,5 @@ /* Copyright (C) 2000 MySQL AB + Copyright (C) 2010 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 @@ -17,7 +18,7 @@ #include <sslopt-vars.h> #include "../scripts/mysql_fix_privilege_tables_sql.c" -#define VER "1.1" +#define VER "1.2" #ifdef HAVE_SYS_WAIT_H #include <sys/wait.h> @@ -34,9 +35,10 @@ 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, +static my_bool opt_force, debug_info_flag, debug_check_flag, opt_systables_only; -static uint my_end_arg= 0; +static my_bool opt_not_used; /* For compatiblity */ +static uint my_end_arg= 0, opt_verbose; static char *opt_user= (char*)"root"; static DYNAMIC_STRING ds_args; @@ -61,12 +63,14 @@ static struct my_option my_long_options[]= { {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"basedir", 'b', "Not used by mysql_upgrade. Only for backward compatibility.", + {"basedir", 'b', + "Not used by mysql_upgrade. Only for backward compatibility.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"character-sets-dir", OPT_CHARSETS_DIR, - "Directory for character set files.", 0, - 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"compress", OPT_COMPRESS, "Use compression in server/client protocol.", + "Not used by mysql_upgrade. Only for backward compatibility.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + {"compress", OPT_COMPRESS, + "Not used by mysql_upgrade. Only for backward compatibility.", ¬_used, ¬_used, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"datadir", 'd', "Not used by mysql_upgrade. Only for backward compatibility.", @@ -79,18 +83,17 @@ static struct my_option my_long_options[]= &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.", - &debug_check_flag, &debug_check_flag, 0, - GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + &debug_check_flag, &debug_check_flag, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"debug-info", 'T', "Print some debug info at exit.", &debug_info_flag, &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"default-character-set", OPT_DEFAULT_CHARSET, - "Set the default character set.", 0, - 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Not used by mysql_upgrade. Only for backward compatibility.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"force", 'f', "Force execution of mysqlcheck even if mysql_upgrade " "has already been executed for the current version of MySQL.", - &opt_force, &opt_force, 0, - GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"host",'h', "Connect to host.", 0, + &opt_force, &opt_force, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"host", 'h', "Connect to host.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"password", 'p', "Password to use when connecting to server. If password is not given," @@ -115,6 +118,8 @@ static struct my_option my_long_options[]= "Base name of shared memory.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif + {"silent", 's', "Print less information", &opt_silent, + &opt_silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"socket", 'S', "The socket file to use for connection.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #include <sslopt-longopts.h> @@ -127,8 +132,7 @@ static struct my_option my_long_options[]= {"user", 'u', "User for login if not current user.", &opt_user, &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"verbose", 'v', "Display more output about the process.", - &opt_verbose, &opt_verbose, 0, - GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + &opt_not_used, &opt_not_used, 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.", @@ -174,7 +178,7 @@ static void verbose(const char *fmt, ...) { va_list args; - if (!opt_verbose) + if (opt_silent) return; /* Print the verbose message */ @@ -270,6 +274,18 @@ get_one_option(int optid, const struct my_option *opt, /* FALLTHROUGH */ case 'v': /* --verbose */ + opt_verbose++; + if (argument == disabled_my_option) + { + opt_verbose= 0; + opt_silent= 1; + } + add_option= 0; + break; + case 's': + opt_verbose= 0; + add_option= 0; + break; case 'f': /* --force */ add_option= FALSE; break; @@ -430,7 +446,8 @@ static void find_tool(char *tool_executable_name, const char *tool_name, len, self_name, FN_LIBCHAR, tool_name); } - verbose("Looking for '%s' as: %s", tool_name, tool_executable_name); + if (opt_verbose) + verbose("Looking for '%s' as: %s", tool_name, tool_executable_name); /* Make sure it can be executed @@ -500,7 +517,7 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res, "--database=mysql", "--batch", /* Turns off pager etc. */ force ? "--force": "--skip-force", - ds_res ? "--silent": "", + ds_res || opt_silent ? "--silent": "", "<", query_file_path, "2>&1", @@ -582,7 +599,6 @@ static int upgrade_already_done(void) FILE *in; char upgrade_info_file[FN_REFLEN]= {0}; char buf[sizeof(MYSQL_SERVER_VERSION)+1]; - char *res; if (get_upgrade_info_file_name(upgrade_info_file)) return 0; /* Could not get filename => not sure */ @@ -590,19 +606,15 @@ static int upgrade_already_done(void) if (!(in= my_fopen(upgrade_info_file, O_RDONLY, MYF(0)))) return 0; /* Could not open file => not sure */ - /* - Read from file, don't care if it fails since it - will be detected by the strncmp - */ bzero(buf, sizeof(buf)); - res= fgets(buf, sizeof(buf), in); + if (!fgets(buf, sizeof(buf), in)) + { + /* Ignore, will be detected by strncmp() below */ + } my_fclose(in, MYF(0)); - if (!res) - return 0; /* Could not read from file => not sure */ - - return (strncmp(res, MYSQL_SERVER_VERSION, + return (strncmp(buf, MYSQL_SERVER_VERSION, sizeof(MYSQL_SERVER_VERSION)-1)==0); } @@ -658,6 +670,8 @@ static void create_mysql_upgrade_info_file(void) static void print_conn_args(const char *tool_name) { + if (opt_verbose < 2) + return; if (conn_args.str[0]) verbose("Running '%s' with connection arguments: %s", tool_name, conn_args.str); @@ -673,6 +687,7 @@ static void print_conn_args(const char *tool_name) static int run_mysqlcheck_upgrade(void) { + verbose("Phase 2/3: Checking and upgrading tables"); print_conn_args("mysqlcheck"); return run_tool(mysqlcheck_path, NULL, /* Send output from mysqlcheck directly to screen */ @@ -681,6 +696,8 @@ static int run_mysqlcheck_upgrade(void) "--check-upgrade", "--all-databases", "--auto-repair", + !opt_silent || opt_verbose ? "--verbose": "", + opt_silent ? "--silent": "", opt_write_binlog ? "--write-binlog" : "--skip-write-binlog", NULL); } @@ -688,6 +705,7 @@ static int run_mysqlcheck_upgrade(void) static int run_mysqlcheck_fixnames(void) { + verbose("Phase 1/3: Fixing table and database names"); print_conn_args("mysqlcheck"); return run_tool(mysqlcheck_path, NULL, /* Send output from mysqlcheck directly to screen */ @@ -696,6 +714,8 @@ static int run_mysqlcheck_fixnames(void) "--all-databases", "--fix-db-names", "--fix-table-names", + opt_verbose ? "--verbose": "", + opt_silent ? "--silent": "", opt_write_binlog ? "--write-binlog" : "--skip-write-binlog", NULL); } @@ -765,7 +785,7 @@ static int run_sql_fix_privilege_tables(void) if (init_dynamic_string(&ds_result, "", 512, 512)) die("Out of memory"); - verbose("Running 'mysql_fix_privilege_tables'..."); + verbose("Phase 3/3: Running 'mysql_fix_privilege_tables'..."); run_query(mysql_fix_privilege_tables, &ds_result, /* Collect result */ TRUE); diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index 69381b749a1..f164a7d039f 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -24,7 +24,7 @@ #include <mysql.h> #include <sql_common.h> -#define ADMIN_VERSION "8.42" +#define ADMIN_VERSION "9.0" #define MAX_MYSQL_VAR 512 #define SHUTDOWN_DEF_TIMEOUT 3600 /* Wait for shutdown */ #define MAX_TRUNC_LENGTH 3 @@ -97,7 +97,10 @@ enum commands { ADMIN_FLUSH_HOSTS, ADMIN_FLUSH_TABLES, ADMIN_PASSWORD, ADMIN_PING, ADMIN_EXTENDED_STATUS, ADMIN_FLUSH_STATUS, ADMIN_FLUSH_PRIVILEGES, ADMIN_START_SLAVE, ADMIN_STOP_SLAVE, - ADMIN_FLUSH_THREADS, ADMIN_OLD_PASSWORD + ADMIN_FLUSH_THREADS, ADMIN_OLD_PASSWORD, ADMIN_FLUSH_SLOW_LOG, + ADMIN_FLUSH_TABLE_STATISTICS, ADMIN_FLUSH_INDEX_STATISTICS, + ADMIN_FLUSH_USER_STATISTICS, ADMIN_FLUSH_CLIENT_STATISTICS, + ADMIN_FLUSH_ALL_STATUS, ADMIN_FLUSH_ALL_STATISTICS }; static const char *command_names[]= { "create", "drop", "shutdown", @@ -107,7 +110,10 @@ static const char *command_names[]= { "flush-hosts", "flush-tables", "password", "ping", "extended-status", "flush-status", "flush-privileges", "start-slave", "stop-slave", - "flush-threads","old-password", + "flush-threads", "old-password", "flush-slow-log", + "flush-table-statistics", "flush-index-statistics", + "flush-user-statistics", "flush-client-statistics", + "flush-all-status", "flush-all-statistics", NullS }; @@ -572,11 +578,12 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) If this behaviour is ever changed, Docs should be notified. */ - struct rand_struct rand_st; + struct my_rnd_struct rand_st; for (; argc > 0 ; argv++,argc--) { - switch (find_type(argv[0],&command_typelib,2)) { + int command; + switch ((command= find_type(argv[0],&command_typelib,2))) { case ADMIN_CREATE: { char buff[FN_REFLEN+20]; @@ -653,7 +660,11 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) if (mysql_refresh(mysql, (uint) ~(REFRESH_GRANT | REFRESH_STATUS | REFRESH_READ_LOCK | REFRESH_SLAVE | - REFRESH_MASTER))) + REFRESH_MASTER | REFRESH_TABLE_STATS | + REFRESH_INDEX_STATS | + REFRESH_USER_STATS | + REFRESH_SLOW_QUERY_LOG | + REFRESH_CLIENT_STATS))) { my_printf_error(0, "refresh failed; error: '%s'", error_flags, mysql_error(mysql)); @@ -671,7 +682,8 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) case ADMIN_VER: new_line=1; print_version(); - puts("Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc."); + puts("Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc,\n" + "2009 Monty Program Ab"); puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n"); printf("Server version\t\t%s\n", mysql_get_server_info(mysql)); printf("Protocol version\t%d\n", mysql_get_proto_info(mysql)); @@ -847,9 +859,19 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) } case ADMIN_FLUSH_LOGS: { - if (mysql_refresh(mysql,REFRESH_LOG)) + if (mysql_query(mysql,"flush logs")) { - my_printf_error(0, "refresh failed; error: '%s'", error_flags, + my_printf_error(0, "flush failed; error: '%s'", error_flags, + mysql_error(mysql)); + return -1; + } + break; + } + case ADMIN_FLUSH_SLOW_LOG: + { + if (mysql_query(mysql,"flush slow query logs")) + { + my_printf_error(0, "flush failed; error: '%s'", error_flags, mysql_error(mysql)); return -1; } @@ -859,7 +881,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) { if (mysql_query(mysql,"flush hosts")) { - my_printf_error(0, "refresh failed; error: '%s'", error_flags, + my_printf_error(0, "flush failed; error: '%s'", error_flags, mysql_error(mysql)); return -1; } @@ -869,7 +891,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) { if (mysql_query(mysql,"flush tables")) { - my_printf_error(0, "refresh failed; error: '%s'", error_flags, + my_printf_error(0, "flush failed; error: '%s'", error_flags, mysql_error(mysql)); return -1; } @@ -879,7 +901,71 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) { if (mysql_query(mysql,"flush status")) { - my_printf_error(0, "refresh failed; error: '%s'", error_flags, + my_printf_error(0, "flush failed; error: '%s'", error_flags, + mysql_error(mysql)); + return -1; + } + break; + } + case ADMIN_FLUSH_TABLE_STATISTICS: + { + if (mysql_query(mysql,"flush table_statistics")) + { + my_printf_error(0, "flush failed; error: '%s'", error_flags, + mysql_error(mysql)); + return -1; + } + break; + } + case ADMIN_FLUSH_INDEX_STATISTICS: + { + if (mysql_query(mysql,"flush index_statistics")) + { + my_printf_error(0, "flush failed; error: '%s'", error_flags, + mysql_error(mysql)); + return -1; + } + break; + } + case ADMIN_FLUSH_USER_STATISTICS: + { + if (mysql_query(mysql,"flush user_statistics")) + { + my_printf_error(0, "flush failed; error: '%s'", error_flags, + mysql_error(mysql)); + return -1; + } + break; + } + case ADMIN_FLUSH_CLIENT_STATISTICS: + { + if (mysql_query(mysql,"flush client_statistics")) + { + my_printf_error(0, "flush failed; error: '%s'", error_flags, + mysql_error(mysql)); + return -1; + } + break; + } + case ADMIN_FLUSH_ALL_STATISTICS: + { + if (mysql_query(mysql, + "flush table_statistics,index_statistics," + "user_statistics,client_statistics")) + { + my_printf_error(0, "flush failed; error: '%s'", error_flags, + mysql_error(mysql)); + return -1; + } + break; + } + case ADMIN_FLUSH_ALL_STATUS: + { + if (mysql_query(mysql, + "flush status,table_statistics,index_statistics," + "user_statistics,client_statistics")) + { + my_printf_error(0, "flush failed; error: '%s'", error_flags, mysql_error(mysql)); return -1; } @@ -893,7 +979,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) char *typed_password= NULL, *verified= NULL; /* Do initialization the same way as we do in mysqld */ start_time=time((time_t*) 0); - randominit(&rand_st,(ulong) start_time,(ulong) start_time/2); + my_rnd_init(&rand_st,(ulong) start_time,(ulong) start_time/2); if (argc < 1) { @@ -1070,7 +1156,8 @@ static void print_version(void) static void usage(void) { print_version(); - puts("Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc."); + puts("Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc,\n" + "2009 Monty Program Ab"); puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n"); puts("Administration program for the mysqld daemon."); printf("Usage: %s [OPTIONS] command command....\n", my_progname); @@ -1078,16 +1165,23 @@ static void usage(void) my_print_variables(my_long_options); print_defaults("my",load_default_groups); puts("\nWhere command is a one or more of: (Commands may be shortened)\n\ - create databasename Create a new database\n\ - debug Instruct server to write debug information to log\n\ - drop databasename Delete a database and all its tables\n\ - extended-status Gives an extended status message from the server\n\ - flush-hosts Flush all cached hosts\n\ - flush-logs Flush all logs\n\ - flush-status Clear status variables\n\ - flush-tables Flush all tables\n\ - flush-threads Flush the thread cache\n\ - flush-privileges Reload grant tables (same as reload)\n\ + create databasename Create a new database\n\ + debug Instruct server to write debug information to log\n\ + drop databasename Delete a database and all its tables\n\ + extended-status Gives an extended status message from the server\n\ + flush-all-statistics Flush all statistics tables\n\ + flush-all-status Flush status and statistics\n\ + flush-client-statistics Flush client statistics\n\ + flush-hosts Flush all cached hosts\n\ + flush-index-statistics Flush index statistics\n\ + flush-logs Flush all logs\n\ + flush-privileges Reload grant tables (same as reload)\n\ + flush-slow-log Flush slow query log\n\ + flush-status Clear status variables\n\ + flush-table-statistics Clear table statistics\n\ + flush-tables Flush all tables\n\ + flush-threads Flush the thread cache\n\ + flush-user-statistics Flush user statistics\n\ kill id,id,... Kill mysql threads"); #if MYSQL_VERSION_ID >= 32200 puts("\ @@ -1377,7 +1471,7 @@ static my_bool wait_pidfile(char *pidfile, time_t last_modified, struct stat *pidfile_status) { char buff[FN_REFLEN]; - int error= 1; + my_bool error= 1; uint count= 0; DBUG_ENTER("wait_pidfile"); diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 277c2d62544..a8f96a1089d 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -35,6 +35,15 @@ #include "log_event.h" #include "sql_common.h" +/* Needed for Rpl_filter */ +CHARSET_INFO* system_charset_info= &my_charset_utf8_general_ci; + +#include "sql_string.h" // needed for Rpl_filter +#include "sql_list.h" // needed for Rpl_filter +#include "rpl_filter.h" + +Rpl_filter *binlog_filter; + #define BIN_LOG_HEADER_SIZE 4 #define PROBE_HEADER_LEN (EVENT_LEN_OFFSET+4) @@ -436,7 +445,7 @@ Exit_status Load_log_processor::process_first_event(const char *bname, ptr= fname + target_dir_name_len; memcpy(ptr,bname,blen); ptr+= blen; - ptr+= sprintf(ptr, "-%x", file_id); + ptr+= my_sprintf(ptr, (ptr, "-%x", file_id)); if ((file= create_unique_file(fname,ptr)) < 0) { @@ -626,6 +635,42 @@ static bool shall_skip_database(const char *log_dbname) /** + Print "use <db>" statement when current db is to be changed. + + We have to control emiting USE statements according to rewrite-db options. + We have to do it here (see process_event() below) and to suppress + producing USE statements by corresponding log event print-functions. +*/ + +void print_use_stmt(PRINT_EVENT_INFO* pinfo, const char* db, size_t db_len) +{ + // pinfo->db is the current db. + // If current db is the same as required db, do nothing. + if (!db || !memcmp(pinfo->db, db, db_len + 1)) + return; + + // Current db and required db are different. + // Check for rewrite rule for required db. (Note that in a rewrite rule + // neither db_from nor db_to part can be empty). + size_t len_to= 0; + const char *db_to= binlog_filter->get_rewrite_db(db, &len_to); + + // If there is no rewrite rule for db (in this case len_to is left = 0), + // printing of the corresponding USE statement is left for log event + // print-function. + if (!len_to) + return; + + // In case of rewrite rule print USE statement for db_to + fprintf(result_file, "use %s%s\n", db_to, pinfo->delimiter); + + // Copy the *original* db to pinfo to suppress emiting + // of USE stmts by log_event print-functions. + memcpy(pinfo->db, db, db_len + 1); +} + + +/** Prints the given event in base64 format. The header is printed to the head cache and the body is printed to @@ -736,9 +781,11 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, switch (ev_type) { case QUERY_EVENT: - if (!((Query_log_event*)ev)->is_trans_keyword() && - shall_skip_database(((Query_log_event*)ev)->db)) + { + Query_log_event *qe= (Query_log_event*)ev; + if (!qe->is_trans_keyword() && shall_skip_database(qe->db)) goto end; + print_use_stmt(print_event_info, qe->db, qe->db_len); if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS) { if ((retval= write_event_header_and_base64(ev, result_file, @@ -749,6 +796,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, else ev->print(result_file, print_event_info); break; + } case CREATE_FILE_EVENT: { @@ -876,6 +924,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, if (!shall_skip_database(exlq->db)) { + print_use_stmt(print_event_info, exlq->db, exlq->db_len); if (fname) { convert_path_to_forward_slashes(fname); @@ -899,6 +948,13 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, destroy_evt= FALSE; goto end; } + size_t len_to= 0; + const char* db_to= binlog_filter->get_rewrite_db(map->get_db_name(), &len_to); + if (len_to && map->rewrite_db(db_to, len_to, glob_description_event)) + { + error("Could not rewrite database name"); + goto err; + } } case WRITE_ROWS_EVENT: case DELETE_ROWS_EVENT: @@ -983,14 +1039,16 @@ err: retval= ERROR_STOP; end: rec_count++; + /* - Destroy the log_event object. If reading from a remote host, - set the temp_buf to NULL so that memory isn't freed twice. + Destroy the log_event object. + MariaDB MWL#36: mainline does this: + If reading from a remote host, + set the temp_buf to NULL so that memory isn't freed twice. + We no longer do that, we use Rpl_filter::event_owns_temp_buf instead. */ if (ev) { - if (remote_opt) - ev->temp_buf= 0; if (destroy_evt) /* destroy it later if not set (ignored table map) */ delete ev; } @@ -1147,6 +1205,10 @@ that may lead to an endless loop.", "Used to reserve file descriptors for use by this program.", &open_files_limit, &open_files_limit, 0, GET_ULONG, REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0}, + {"rewrite-db", OPT_REWRITE_DB, + "Updates to a database with a different name than the original. \ +Example: rewrite-db='from->to'.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -1330,6 +1392,53 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), (find_type_or_exit(argument, &base64_output_mode_typelib, opt->name)-1); } break; + case OPT_REWRITE_DB: // db_from->db_to + { + /* See also handling of OPT_REPLICATE_REWRITE_DB in sql/mysqld.cc */ + char* ptr; + char* key= argument; // db-from + char* val; // db-to + + // Where key begins + while (*key && my_isspace(&my_charset_latin1, *key)) + key++; + + // Where val begins + if (!(ptr= strstr(argument, "->"))) + { + sql_print_error("Bad syntax in rewrite-db: missing '->'!\n"); + return 1; + } + val= ptr + 2; + while (*val && my_isspace(&my_charset_latin1, *val)) + val++; + + // Write \0 and skip blanks at the end of key + *ptr-- = 0; + while (my_isspace(&my_charset_latin1, *ptr) && ptr > argument) + *ptr-- = 0; + + if (!*key) + { + sql_print_error("Bad syntax in rewrite-db: empty db-from!\n"); + return 1; + } + + // Skip blanks at the end of val + ptr= val; + while (*ptr && !my_isspace(&my_charset_latin1, *ptr)) + ptr++; + *ptr= 0; + + if (!*val) + { + sql_print_error("Bad syntax in rewrite-db: empty db-to!\n"); + return 1; + } + + binlog_filter->add_db_rewrite(key, val); + break; + } case 'v': if (argument == disabled_my_option) verbose= 0; @@ -1374,6 +1483,10 @@ static int parse_args(int *argc, char*** argv) */ static Exit_status safe_connect() { + /* Close and old connections to MySQL */ + if (mysql) + mysql_close(mysql); + mysql= mysql_init(NULL); if (!mysql) @@ -1599,7 +1712,7 @@ static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info, If reading from a remote host, ensure the temp_buf for the Log_event class is pointing to the incoming stream. */ - ev->register_temp_buf((char *) net->read_pos + 1); + ev->register_temp_buf((char *) net->read_pos + 1, FALSE); Log_event_type type= ev->get_type_code(); if (glob_description_event->binlog_version >= 3 || @@ -1999,6 +2112,8 @@ end: return retval; } +/* Used in sql_alloc(). Inited and freed in main() */ +MEM_ROOT s_mem_root; int main(int argc, char** argv) { @@ -2011,8 +2126,16 @@ int main(int argc, char** argv) my_init_time(); // for time functions + init_alloc_root(&s_mem_root, 16384, 0); + if (!(binlog_filter= new Rpl_filter)) + { + error("Failed to create Rpl_filter"); + exit(1); + } + if (load_defaults("my", load_default_groups, &argc, &argv)) exit(1); + defaults_argv= argv; parse_args(&argc, (char***)&argv); @@ -2100,6 +2223,8 @@ int main(int argc, char** argv) if (result_file != stdout) my_fclose(result_file, MYF(0)); cleanup(); + delete binlog_filter; + free_root(&s_mem_root, MYF(0)); free_defaults(defaults_argv); my_free_open_file_info(); load_processor.destroy(); @@ -2111,6 +2236,12 @@ int main(int argc, char** argv) DBUG_RETURN(retval == ERROR_STOP ? 1 : 0); } + +void *sql_alloc(size_t size) +{ + return alloc_root(&s_mem_root, size); +} + /* We must include this here as it's compiled with different options for the server @@ -2122,3 +2253,6 @@ int main(int argc, char** argv) #include "log_event.cc" #include "log_event_old.cc" #include "rpl_utility.cc" +#include "sql_string.cc" +#include "sql_list.cc" +#include "rpl_filter.cc" diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index ce733e57db6..aeaead924c9 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -1,4 +1,6 @@ -/* Copyright (C) 2000 MySQL AB, 2009 Sun Microsystems, Inc +/* Copyright (C) 2000 MySQL AB & Jani Tolonen + Copyright (C) 2009 Sun Microsystems, Inc + Copyright (C) 2010 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 @@ -15,7 +17,7 @@ /* By Jani Tolonen, 2001-04-20, MySQL Development Team */ -#define CHECK_VERSION "2.5.0" +#define CHECK_VERSION "2.6.0" #include "client_priv.h" #include <m_ctype.h> @@ -67,8 +69,8 @@ static struct my_option my_long_options[] = &opt_auto_repair, &opt_auto_repair, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"character-sets-dir", OPT_CHARSETS_DIR, - "Directory for character set files.", &charsets_dir, - &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Directory for character set files.", (char**) &charsets_dir, + (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"check", 'c', "Check table for errors.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"check-only-changed", 'C', @@ -216,24 +218,26 @@ static void usage(void) { print_version(); puts("By Jani Tolonen, 2001-04-20, MySQL Development Team.\n"); - puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n"); + puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,"); puts("and you are welcome to modify and redistribute it under the GPL license.\n"); + printf("Usage: %s [OPTIONS] database [tables]\n", my_progname); + printf("OR %s [OPTIONS] --databases DB1 [DB2 DB3...]\n", + my_progname); + printf("OR %s [OPTIONS] --all-databases\n\n", my_progname); puts("This program can be used to CHECK (-c, -m, -C), REPAIR (-r), ANALYZE (-a),"); puts("or OPTIMIZE (-o) tables. Some of the options (like -e or -q) can be"); puts("used at the same time. Not all options are supported by all storage engines."); - puts("Please consult the MySQL manual for latest information about the"); - puts("above. The options -c, -r, -a, and -o are exclusive to each other, which"); + puts("The options -c, -r, -a, and -o are exclusive to each other, which"); puts("means that the last option will be used, if several was specified.\n"); - puts("The option -c will be used by default, if none was specified. You"); - puts("can change the default behavior by making a symbolic link, or"); + puts("The option -c (--check) will be used by default, if none was specified."); + puts("You can change the default behavior by making a symbolic link, or"); puts("copying this file somewhere with another name, the alternatives are:"); puts("mysqlrepair: The default option will be -r"); puts("mysqlanalyze: The default option will be -a"); puts("mysqloptimize: The default option will be -o\n"); - printf("Usage: %s [OPTIONS] database [tables]\n", my_progname); - printf("OR %s [OPTIONS] --databases DB1 [DB2 DB3...]\n", - my_progname); - printf("OR %s [OPTIONS] --all-databases\n", my_progname); + puts("Please consult the MariaDB/MySQL knowledgebase at"); + puts("http://kb.askmonty.org/v/mysqlcheck for latest information about"); + puts("this program."); print_defaults("my", load_default_groups); my_print_help(my_long_options); my_print_variables(my_long_options); @@ -406,6 +410,8 @@ static int process_all_databases() MYF(0), mysql_error(sock)); return 1; } + if (verbose) + printf("Processing databases\n"); while ((row = mysql_fetch_row(tableres))) { if (process_one_db(row[0])) @@ -419,6 +425,8 @@ static int process_all_databases() static int process_databases(char **db_names) { int result = 0; + if (verbose) + printf("Processing databases\n"); for ( ; *db_names ; db_names++) { if (process_one_db(*db_names)) @@ -511,6 +519,7 @@ static int process_all_tables_in_db(char *database) MYSQL_RES *res; MYSQL_ROW row; uint num_columns; + my_bool system_database= 0; LINT_INIT(res); if (use_db(database)) @@ -524,6 +533,9 @@ static int process_all_tables_in_db(char *database) return 1; } + if (!strcmp(database, "mysql") || !strcmp(database, "MYSQL")) + system_database= 1; + num_columns= mysql_num_fields(res); if (opt_all_in_1 && what_to_do != DO_UPGRADE) @@ -566,6 +578,10 @@ static int process_all_tables_in_db(char *database) /* Skip views if we don't perform renaming. */ if ((what_to_do != DO_UPGRADE) && (num_columns == 2) && (strcmp(row[1], "VIEW") == 0)) continue; + if (system_database && + (!strcmp(row[0], "general_log") || + !strcmp(row[0], "slow_log"))) + continue; /* Skip logging tables */ handle_request_for_tables(row[0], fixed_name_length(row[0])); } @@ -614,6 +630,8 @@ static int fix_database_storage_name(const char *name) static int process_one_db(char *database) { + if (verbose) + puts(database); if (what_to_do == DO_UPGRADE) { int rc= 0; @@ -696,7 +714,8 @@ static int handle_request_for_tables(char *tables, uint length) if (opt_all_in_1) { /* No backticks here as we added them before */ - query_length= sprintf(query, "%s TABLE %s %s", op, tables, options); + query_length= my_sprintf(query, + (query, "%s TABLE %s %s", op, tables, options)); } else { @@ -723,7 +742,7 @@ static void print_result() { MYSQL_RES *res; MYSQL_ROW row; - char prev[NAME_LEN*2+2]; + char prev[(NAME_LEN+9)*2+2]; uint i; my_bool found_error=0; @@ -753,7 +772,15 @@ static void print_result() printf("%-50s %s", row[0], row[3]); else if (!status && changed) { - printf("%s\n%-9s: %s", row[0], row[2], row[3]); + /* + If the error message includes REPAIR TABLE, we assume it means + we have to run upgrade on it. In this case we write a nicer message + than "Please do "REPAIR TABLE""... + */ + if (!strcmp(row[2],"error") && strinstr(row[3],"REPAIR TABLE") != 0) + printf("%-50s %s", row[0], "Needs upgrade"); + else + printf("%s\n%-9s: %s", row[0], row[2], row[3]); if (strcmp(row[2],"note")) found_error=1; } @@ -772,7 +799,7 @@ static void print_result() static int dbConnect(char *host, char *user, char *passwd) { DBUG_ENTER("dbConnect"); - if (verbose) + if (verbose > 1) { fprintf(stderr, "# Connecting to %s...\n", host ? host : "localhost"); } @@ -804,7 +831,7 @@ static int dbConnect(char *host, char *user, char *passwd) static void dbDisconnect(char *host) { - if (verbose) + if (verbose > 1) fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost"); mysql_close(sock); } /* dbDisconnect */ @@ -848,7 +875,8 @@ int main(int argc, char **argv) if (!opt_write_binlog) { - if (disable_binlog()) { + if (disable_binlog()) + { first_error= 1; goto end; } diff --git a/client/mysqldump.c b/client/mysqldump.c index ac704f152de..626ce1dede7 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -212,8 +212,8 @@ static struct my_option my_long_options[] = &opt_slave_apply, &opt_slave_apply, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"character-sets-dir", OPT_CHARSETS_DIR, - "Directory for character set files.", &charsets_dir, - &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Directory for character set files.", (char**) &charsets_dir, + (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"comments", 'i', "Write additional information.", &opt_comments, &opt_comments, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, @@ -250,8 +250,8 @@ static struct my_option my_long_options[] = {"debug", '#', "This is a non-debug version. Catch this and exit.", 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0}, #else - {"debug", '#', "Output debug log.", &default_dbug_option, - &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"debug", '#', "Output debug log.", (char**) &default_dbug_option, + (char**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.", &debug_check_flag, &debug_check_flag, 0, @@ -974,7 +974,7 @@ static int get_options(int *argc, char ***argv) static void DB_error(MYSQL *mysql_arg, const char *when) { DBUG_ENTER("DB_error"); - maybe_die(EX_MYSQLERR, "Got error: %d: %s %s", + maybe_die(EX_MYSQLERR, "Got error: %d: \"%s\" %s", mysql_errno(mysql_arg), mysql_error(mysql_arg), when); DBUG_VOID_RETURN; } @@ -1399,6 +1399,7 @@ static void free_resources() if (md_result_file && md_result_file != stdout) my_fclose(md_result_file, MYF(0)); my_free(opt_password); + my_free(current_host); if (my_hash_inited(&ignore_table)) my_hash_free(&ignore_table); if (extended_insert) @@ -4206,7 +4207,7 @@ static char *get_actual_table_name(const char *old_table_name, MEM_ROOT *root) } mysql_free_result(table_res); } - DBUG_PRINT("exit", ("new_table_name: %s", name)); + DBUG_PRINT("exit", ("new_table_name: %s", val_or_null(name))); DBUG_RETURN(name); } @@ -4928,6 +4929,7 @@ static my_bool get_view_structure(char *table, char* db) field= mysql_fetch_field_direct(table_res, 0); if (strcmp(field->name, "View") != 0) { + mysql_free_result(table_res); switch_character_set_results(mysql, default_charset); verbose_msg("-- It's base table, skipped\n"); DBUG_RETURN(0); @@ -4937,8 +4939,10 @@ static my_bool get_view_structure(char *table, char* db) if (path) { if (!(sql_file= open_sql_file_for_table(table, O_WRONLY))) + { + mysql_free_result(table_res); DBUG_RETURN(1); - + } write_header(sql_file, db); } diff --git a/client/mysqlimport.c b/client/mysqlimport.c index 3d71e437e40..593d43c0c80 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -68,8 +68,8 @@ static char *shared_memory_base_name=0; static struct my_option my_long_options[] = { {"character-sets-dir", OPT_CHARSETS_DIR, - "Directory for character set files.", &charsets_dir, - &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Directory for character set files.", (char**) &charsets_dir, + (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"default-character-set", OPT_DEFAULT_CHARSET, "Set the default character set.", &default_charset, &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, diff --git a/client/mysqlshow.c b/client/mysqlshow.c index bb05400e0d8..3cc551d2092 100644 --- a/client/mysqlshow.c +++ b/client/mysqlshow.c @@ -161,7 +161,7 @@ int main(int argc, char **argv) static struct my_option my_long_options[] = { {"character-sets-dir", 'c', "Directory for character set files.", - &charsets_dir, &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, + (char**) &charsets_dir, (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"default-character-set", OPT_DEFAULT_CHARSET, "Set the default character set.", &default_charset, diff --git a/client/mysqlslap.c b/client/mysqlslap.c index e605e2d522c..6d93bd73efe 100644 --- a/client/mysqlslap.c +++ b/client/mysqlslap.c @@ -292,6 +292,25 @@ static int gettimeofday(struct timeval *tp, void *tzp) } #endif +void set_mysql_connect_options(MYSQL *mysql) +{ + if (opt_compress) + mysql_options(mysql,MYSQL_OPT_COMPRESS,NullS); +#ifdef HAVE_OPENSSL + if (opt_use_ssl) + mysql_ssl_set(mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, + opt_ssl_capath, opt_ssl_cipher); +#endif + if (opt_protocol) + mysql_options(mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); +#ifdef HAVE_SMEM + if (shared_memory_base_name) + mysql_options(mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); +#endif + mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset); +} + + int main(int argc, char **argv) { MYSQL mysql; @@ -327,20 +346,7 @@ int main(int argc, char **argv) exit(1); } mysql_init(&mysql); - if (opt_compress) - mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS); -#ifdef HAVE_OPENSSL - if (opt_use_ssl) - mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, - opt_ssl_capath, opt_ssl_cipher); -#endif - if (opt_protocol) - mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); -#ifdef HAVE_SMEM - if (shared_memory_base_name) - mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); -#endif - mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); + set_mysql_connect_options(&mysql); if (!opt_only_print) { @@ -450,7 +456,16 @@ void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr) /* First we create */ if (create_statements) + { + /* + If we have an --engine option, then we indicate + create_schema() to add the engine type to the DDL. + */ + if (eptr) + create_statements->type= CREATE_TABLE_TYPE; + create_schema(mysql, create_schema_string, create_statements, eptr); + } /* If we generated GUID we need to build a list of them from creation that @@ -464,10 +479,10 @@ void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr) if (commit_rate) run_query(mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0")); - if (pre_system) - if ((sysret= system(pre_system)) != 0) - fprintf(stderr, "Warning: Execution of pre_system option returned %d.\n", - sysret); + if (pre_system && (sysret= system(pre_system)) != 0) + fprintf(stderr, + "Warning: Execution of pre_system option returned %d.\n", + sysret); /* Pre statements are always run after all other logic so they can @@ -481,11 +496,10 @@ void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr) if (post_statements) run_statements(mysql, post_statements); - if (post_system) - if ((sysret= system(post_system)) != 0) - fprintf(stderr, "Warning: Execution of post_system option returned %d.\n", - sysret); - + if (post_system && (sysret= system(post_system)) != 0) + fprintf(stderr, + "Warning: Execution of post_system option returned %d.\n", + sysret); /* We are finished with this run */ if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary) drop_primary_key_list(); @@ -530,7 +544,7 @@ static struct my_option my_long_options[] = 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"auto-generate-sql-load-type", OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE, "Specify test load type: mixed, update, write, key, or read; default is mixed.", - &auto_generate_sql_type, &auto_generate_sql_type, + (char**) &auto_generate_sql_type, (char**) &auto_generate_sql_type, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"auto-generate-sql-secondary-indexes", OPT_SLAP_AUTO_GENERATE_SECONDARY_INDEXES, @@ -561,13 +575,13 @@ static struct my_option my_long_options[] = &opt_compress, &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"concurrency", 'c', "Number of clients to simulate for query to run.", - &concurrency_str, &concurrency_str, 0, GET_STR, + (char**) &concurrency_str, (char**) &concurrency_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"create", OPT_SLAP_CREATE_STRING, "File or string to use create tables.", &create_string, &create_string, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"create-schema", OPT_CREATE_SLAP_SCHEMA, "Schema to run tests in.", - &create_schema_string, &create_schema_string, 0, GET_STR, + (char**) &create_schema_string, (char**) &create_schema_string, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"csv", OPT_SLAP_CSV, "Generate CSV output to named file or to stdout if no file is named.", @@ -577,7 +591,7 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0}, #else {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", - &default_dbug_option, &default_dbug_option, 0, GET_STR, + (char**) &default_dbug_option, (char**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.", @@ -587,14 +601,17 @@ static struct my_option my_long_options[] = &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"delimiter", 'F', "Delimiter to use in SQL statements supplied in file or command line.", - &delimiter, &delimiter, 0, GET_STR, REQUIRED_ARG, + (char**) &delimiter, (char**) &delimiter, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"detach", OPT_SLAP_DETACH, "Detach (close and reopen) connections after X number of requests.", &detach_rate, &detach_rate, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"engine", 'e', "Storage engine to use for creating the table.", - &default_engine, &default_engine, 0, + {"engine", 'e', + "Comma separated list of storage engines to use for creating the table." + " The test is run for each engine. You can also specify an option for an " + "engine after a `:', like memory:max_row=2300", + &default_engine, &default_engine, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"host", 'h', "Connect to host.", &host, &host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -602,11 +619,11 @@ static struct my_option my_long_options[] = &iterations, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, {"number-char-cols", 'x', "Number of VARCHAR columns to create in table if specifying --auto-generate-sql.", - &num_char_cols_opt, &num_char_cols_opt, 0, GET_STR, REQUIRED_ARG, + (char**) &num_char_cols_opt, (char**) &num_char_cols_opt, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"number-int-cols", 'y', "Number of INT columns to create in table if specifying --auto-generate-sql.", - &num_int_cols_opt, &num_int_cols_opt, 0, GET_STR, REQUIRED_ARG, + (char**) &num_int_cols_opt, (char**) &num_int_cols_opt, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"number-of-queries", OPT_MYSQL_NUMBER_OF_QUERY, "Limit each client to this number of queries (this is not exact).", @@ -958,6 +975,7 @@ build_update_string(void) ptr->type= UPDATE_TYPE_REQUIRES_PREFIX ; else ptr->type= UPDATE_TYPE; + strmov(ptr->string, update_string.str); dynstr_free(&update_string); DBUG_RETURN(ptr); @@ -973,8 +991,8 @@ build_update_string(void) static statement * build_insert_string(void) { - char buf[HUGE_STRING_LENGTH]; - unsigned int col_count; + char buf[HUGE_STRING_LENGTH]; + unsigned int col_count; statement *ptr; DYNAMIC_STRING insert_string; DBUG_ENTER("build_insert_string"); @@ -1064,8 +1082,8 @@ build_insert_string(void) static statement * build_select_string(my_bool key) { - char buf[HUGE_STRING_LENGTH]; - unsigned int col_count; + char buf[HUGE_STRING_LENGTH]; + unsigned int col_count; statement *ptr; static DYNAMIC_STRING query_string; DBUG_ENTER("build_select_string"); @@ -1117,6 +1135,7 @@ build_select_string(my_bool key) ptr->type= SELECT_TYPE_REQUIRES_PREFIX; else ptr->type= SELECT_TYPE; + strmov(ptr->string, query_string.str); dynstr_free(&query_string); DBUG_RETURN(ptr); @@ -1175,8 +1194,6 @@ get_options(int *argc,char ***argv) exit(1); } - - if (auto_generate_sql && num_of_query && auto_actual_queries) { fprintf(stderr, @@ -1217,6 +1234,7 @@ get_options(int *argc,char ***argv) num_int_cols= atoi(str->string); if (str->option) num_int_cols_index= atoi(str->option); + option_cleanup(str); } @@ -1229,6 +1247,7 @@ get_options(int *argc,char ***argv) num_char_cols_index= atoi(str->option); else num_char_cols_index= 0; + option_cleanup(str); } @@ -1463,6 +1482,7 @@ get_options(int *argc,char ***argv) if (tty_password) opt_password= get_tty_password(NullS); + DBUG_RETURN(0); } @@ -1477,6 +1497,7 @@ static int run_query(MYSQL *mysql, const char *query, int len) if (verbose >= 3) printf("%.*s;\n", len, query); + return mysql_real_query(mysql, query, len); } @@ -1592,18 +1613,6 @@ create_schema(MYSQL *mysql, const char *db, statement *stmt, } } - if (engine_stmt) - { - len= snprintf(query, HUGE_STRING_LENGTH, "set storage_engine=`%s`", - engine_stmt->string); - if (run_query(mysql, query, len)) - { - fprintf(stderr,"%s: Cannot set default engine: %s\n", my_progname, - mysql_error(mysql)); - exit(1); - } - } - count= 0; after_create= stmt; @@ -1617,8 +1626,21 @@ limit_not_met: { char buffer[HUGE_STRING_LENGTH]; - snprintf(buffer, HUGE_STRING_LENGTH, "%s %s", ptr->string, - engine_stmt->option); + snprintf(buffer, HUGE_STRING_LENGTH, "%s Engine = %s %s", + ptr->string, engine_stmt->string, engine_stmt->option); + if (run_query(mysql, buffer, strlen(buffer))) + { + fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n", + my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql)); + exit(1); + } + } + else if (engine_stmt && engine_stmt->string && ptr->type == CREATE_TABLE_TYPE) + { + char buffer[HUGE_STRING_LENGTH]; + + snprintf(buffer, HUGE_STRING_LENGTH, "%s Engine = %s", + ptr->string, engine_stmt->string); if (run_query(mysql, buffer, strlen(buffer))) { fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n", @@ -1652,6 +1674,7 @@ drop_schema(MYSQL *mysql, const char *db) { char query[HUGE_STRING_LENGTH]; int len; + DBUG_ENTER("drop_schema"); len= snprintf(query, HUGE_STRING_LENGTH, "DROP SCHEMA IF EXISTS `%s`", db); @@ -1788,6 +1811,7 @@ pthread_handler_t run_task(void *p) my_progname, mysql_error(mysql)); exit(0); } + set_mysql_connect_options(mysql); if (mysql_thread_init()) { @@ -1828,7 +1852,6 @@ limit_not_met: my_progname, mysql_error(mysql)); exit(0); } - if (slap_connect(mysql)) goto end; } @@ -1884,10 +1907,17 @@ limit_not_met: { if (mysql_field_count(mysql)) { - result= mysql_store_result(mysql); - while ((row = mysql_fetch_row(result))) - counter++; - mysql_free_result(result); + if ((result= mysql_store_result(mysql))) + { + while ((row = mysql_fetch_row(result))) + counter++; + mysql_free_result(result); + } + else + { + fprintf(stderr,"%s: Error in mysql_store_result(): %d %s\n", + my_progname, mysql_errno(mysql), mysql_error(mysql)); + } } } while(mysql_next_result(mysql) == 0); queries++; @@ -1933,17 +1963,27 @@ parse_option(const char *origin, option_string **stmt, char delm) uint count= 0; /* We know that there is always one */ for (tmp= *sptr= (option_string *)my_malloc(sizeof(option_string), - MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); (retstr= strchr(ptr, delm)); tmp->next= (option_string *)my_malloc(sizeof(option_string), - MYF(MY_ZEROFILL|MY_FAE|MY_WME)), + MYF(MY_ZEROFILL|MY_FAE|MY_WME)), tmp= tmp->next) { - char buffer[HUGE_STRING_LENGTH]; + /* + Initialize buffer, because otherwise an + --engine=<storage_engine>:<option>,<eng1>,<eng2> + will crash. + */ + char buffer[HUGE_STRING_LENGTH]= ""; char *buffer_ptr; count++; strncpy(buffer, ptr, (size_t)(retstr - ptr)); + /* + Handle --engine=memory:max_row=200 cases, or more general speaking + --engine=<storage_engine>:<options>, which will be translated to + Engine = storage_engine option. + */ if ((buffer_ptr= strchr(buffer, ':'))) { char *option_ptr; @@ -1964,13 +2004,15 @@ parse_option(const char *origin, option_string **stmt, char delm) tmp->length= (size_t)(retstr - ptr); } + /* Skip delimiter delm */ ptr+= retstr - ptr + 1; if (isspace(*ptr)) ptr++; + count++; } - if (ptr != origin+length) + if (ptr != origin + length) { char *origin_ptr; @@ -1979,7 +2021,7 @@ parse_option(const char *origin, option_string **stmt, char delm) char *option_ptr; tmp->length= (size_t)(origin_ptr - ptr); - tmp->string= my_strndup(origin, tmp->length, MYF(MY_FAE)); + tmp->string= my_strndup(ptr, tmp->length, MYF(MY_FAE)); option_ptr= (char *)ptr + 1 + tmp->length; @@ -2029,7 +2071,7 @@ parse_delimiter(const char *script, statement **stmt, char delm) if (ptr != script+length) { tmp->string= my_strndup(ptr, (uint)((script + length) - ptr), - MYF(MY_FAE)); + MYF(MY_FAE)); tmp->length= (size_t)((script + length) - ptr); count++; } @@ -2087,6 +2129,7 @@ print_conclusions_csv(conclusions *con) { char buffer[HUGE_STRING_LENGTH]; const char *ptr= auto_generate_sql_type ? auto_generate_sql_type : "query"; + snprintf(buffer, HUGE_STRING_LENGTH, "%s,%s,%ld.%03ld,%ld.%03ld,%ld.%03ld,%d,%llu\n", con->engine ? con->engine : "", /* Storage engine we ran against */ @@ -2173,6 +2216,7 @@ slap_connect(MYSQL *mysql) int x, connect_error= 1; for (x= 0; x < 10; x++) { + set_mysql_connect_options(mysql); if (mysql_real_connect(mysql, host, user, opt_password, create_schema_string, opt_mysql_port, diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 611f7f02be4..3eea6b997c8 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -36,6 +36,7 @@ #include "client_priv.h" #include <mysql_version.h> #include <mysqld_error.h> +#include <sql_common.h> #include <m_ctype.h> #include <my_dir.h> #include <hash.h> @@ -87,7 +88,8 @@ enum { OPT_PS_PROTOCOL=OPT_MAX_CLIENT_OPTION, OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL, OPT_MAX_CONNECT_RETRIES, OPT_MAX_CONNECTIONS, OPT_MARK_PROGRESS, OPT_LOG_DIR, - OPT_TAIL_LINES, OPT_RESULT_FORMAT_VERSION + OPT_TAIL_LINES, OPT_RESULT_FORMAT_VERSION, + OPT_MY_CONNECT_TIMEOUT }; static int record= 0, opt_sleep= -1; @@ -101,6 +103,7 @@ static int opt_max_connect_retries; static int opt_result_format_version; static int opt_max_connections= DEFAULT_MAX_CONN; static my_bool opt_compress= 0, silent= 0, verbose= 0; +static int opt_connect_timeout= -1; static my_bool debug_info_flag= 0, debug_check_flag= 0; static my_bool tty_password= 0; static my_bool opt_mark_progress= 0; @@ -114,6 +117,7 @@ static my_bool display_result_vertically= FALSE, display_result_lower= FALSE, static my_bool disable_query_log= 0, disable_result_log= 0; static my_bool disable_connect_log= 1; static my_bool disable_warnings= 0; +static my_bool prepare_warnings_enabled= 0; static my_bool disable_info= 1; static my_bool abort_on_error= 1; static my_bool server_initialized= 0; @@ -134,6 +138,9 @@ static char delimiter[MAX_DELIMITER_LENGTH]= ";"; static uint delimiter_length= 1; static char TMPDIR[FN_REFLEN]; +static char global_subst_from[200]; +static char global_subst_to[200]; +static char *global_subst= NULL; /* Block stack */ enum block_cmd { @@ -200,6 +207,10 @@ static void init_re(void); static int match_re(my_regex_t *, char *); static void free_re(void); +static int replace(DYNAMIC_STRING *ds_str, + const char *search_str, ulong search_len, + const char *replace_str, ulong replace_len); + static uint opt_protocol=0; DYNAMIC_ARRAY q_lines; @@ -311,6 +322,7 @@ enum enum_commands { Q_SEND_SHUTDOWN, Q_SHUTDOWN_SERVER, Q_RESULT_FORMAT_VERSION, Q_MOVE_FILE, Q_REMOVE_FILES_WILDCARD, Q_SEND_EVAL, + Q_ENABLE_PREPARE_WARNINGS, Q_DISABLE_PREPARE_WARNINGS, Q_UNKNOWN, /* Unknown command. */ Q_COMMENT, /* Comments, ignored. */ Q_COMMENT_WITH_COMMAND, @@ -411,6 +423,8 @@ const char *command_names[]= "move_file", "remove_files_wildcard", "send_eval", + "enable_prepare_warnings", + "disable_prepare_warnings", 0 }; @@ -543,7 +557,7 @@ public: { DBUG_ENTER("LogFile::open"); DBUG_PRINT("enter", ("dir: '%s', name: '%s'", - dir, name)); + val_or_null(dir), val_or_null(name))); if (!name) { m_file= stdout; @@ -609,14 +623,14 @@ public: lines++; int show_offset= 0; - char buf[256]; + char buf[256+1]; /* + zero termination for DBUG_PRINT */ size_t bytes; bool found_bof= false; /* Search backward in file until "lines" newline has been found */ while (lines && !found_bof) { - show_offset-= sizeof(buf); + show_offset-= sizeof(buf)-1; while(fseek(m_file, show_offset, SEEK_END) != 0 && show_offset < 0) { found_bof= true; @@ -624,7 +638,7 @@ public: show_offset++; } - if ((bytes= fread(buf, 1, sizeof(buf), m_file)) <= 0) + if ((bytes= fread(buf, 1, sizeof(buf)-1, m_file)) <= 0) { // ferror=0 will happen here if no queries executed yet if (ferror(m_file)) @@ -634,6 +648,7 @@ public: DBUG_VOID_RETURN; } + IF_DBUG(buf[bytes]= '\0';) DBUG_PRINT("info", ("Read %lu bytes from file, buf: %s", (unsigned long)bytes, buf)); @@ -678,8 +693,10 @@ public: } } - while ((bytes= fread(buf, 1, sizeof(buf), m_file)) > 0) - fwrite(buf, 1, bytes, stderr); + while ((bytes= fread(buf, 1, sizeof(buf)-1, m_file)) > 0) + if (bytes != fwrite(buf, 1, bytes, stderr)) + die("Failed to write to '%s', errno: %d", + m_file_name, errno); if (!lines) { @@ -716,6 +733,10 @@ void handle_no_error(struct st_command*); #define EMB_READ_QUERY_RESULT 2 #define EMB_END_CONNECTION 3 +/* workaround for MySQL BUG#57491 */ +#undef MY_WME +#define MY_WME 0 + /* attributes of the query thread */ pthread_attr_t cn_thd_attrib; @@ -1152,7 +1173,8 @@ void check_command_args(struct st_command *command, DBUG_VOID_RETURN; } -void handle_command_error(struct st_command *command, uint error) +void handle_command_error(struct st_command *command, uint error, + int sys_errno) { DBUG_ENTER("handle_command_error"); DBUG_PRINT("enter", ("error: %d", error)); @@ -1168,13 +1190,14 @@ void handle_command_error(struct st_command *command, uint error) if (i >= 0) { - DBUG_PRINT("info", ("command \"%.*s\" failed with expected error: %d", - command->first_word_len, command->query, error)); + DBUG_PRINT("info", ("command \"%.*s\" failed with expected error: %u, errno: %d", + command->first_word_len, command->query, error, + sys_errno)); DBUG_VOID_RETURN; } if (command->expected_errors.count > 0) - die("command \"%.*s\" failed with wrong error: %d", - command->first_word_len, command->query, error); + die("command \"%.*s\" failed with wrong error: %u, errno: %d", + command->first_word_len, command->query, error, sys_errno); } else if (command->expected_errors.err[0].type == ERR_ERRNO && command->expected_errors.err[0].code.errnum != 0) @@ -1317,15 +1340,6 @@ void die(const char *fmt, ...) DBUG_ENTER("die"); DBUG_PRINT("enter", ("start_lineno: %d", start_lineno)); - /* - Protect against dying twice - first time 'die' is called, try to write log files - second time, just exit - */ - if (dying) - cleanup_and_exit(1); - dying= 1; - /* Print the error message */ fprintf(stderr, "mysqltest: "); if (cur_file && cur_file != file_stack) @@ -1344,6 +1358,15 @@ void die(const char *fmt, ...) fprintf(stderr, "\n"); fflush(stderr); + /* + Protect against dying twice + first time 'die' is called, try to write log files + second time, just exit + */ + if (dying) + cleanup_and_exit(1); + dying= 1; + log_file.show_tail(opt_tail_lines); /* @@ -1364,6 +1387,7 @@ void abort_not_supported_test(const char *fmt, ...) DBUG_ENTER("abort_not_supported_test"); /* Print include filestack */ + fflush(stdout); fprintf(stderr, "The test '%s' is not supported by this installation\n", file_stack->file_name); fprintf(stderr, "Detected in file %s at line %d\n", @@ -1755,49 +1779,69 @@ enum compare_files_result_enum { */ -int compare_files2(File fd, const char* filename2) +int compare_files2(File fd1, const char* filename2) { int error= RESULT_OK; File fd2; - size_t len, len2; - char buff[512], buff2[512]; + size_t fd1_length, fd2_length; + DYNAMIC_STRING fd1_result, fd2_result; if ((fd2= my_open(filename2, O_RDONLY, MYF(0))) < 0) { - my_close(fd, MYF(0)); + my_close(fd1, MYF(0)); die("Failed to open second file: '%s'", filename2); } - while((len= my_read(fd, (uchar*)&buff, - sizeof(buff), MYF(0))) > 0) - { - if ((len2= my_read(fd2, (uchar*)&buff2, - sizeof(buff2), MYF(0))) < len) - { - /* File 2 was smaller */ - error= RESULT_LENGTH_MISMATCH; - break; - } - if (len2 > len) - { - /* File 1 was smaller */ - error= RESULT_LENGTH_MISMATCH; - break; - } - if ((memcmp(buff, buff2, len))) - { - /* Content of this part differed */ - error= RESULT_CONTENT_MISMATCH; - break; - } + + fd1_length= (size_t) my_seek(fd1, 0, SEEK_END, MYF(0)); + fd2_length= (size_t) my_seek(fd2, 0, SEEK_END, MYF(0)); + + if (init_dynamic_string(&fd1_result, 0, fd1_length, 0) || + init_dynamic_string(&fd2_result, 0, fd2_length, 0)) + die("Out of memory when allocating data for result"); + + fd1_result.length= fd1_length; + fd2_result.length= fd2_length; + + (void) my_seek(fd1, 0, SEEK_SET, MYF(0)); + (void) my_seek(fd2, 0, SEEK_SET, MYF(0)); + if (my_read(fd1, (uchar*) fd1_result.str, fd1_length, MYF(MY_WME | MY_NABP))) + die("Error when reading data from result file"); + if (my_read(fd2, (uchar*) fd2_result.str, fd2_length, MYF(MY_WME | MY_NABP))) + die("Error when reading data from result file"); + + if (global_subst && + (fd1_length != fd2_length || + memcmp(fd1_result.str, fd2_result.str, fd1_length))) + { + /** + @todo MARIA_HACK + This serves for when a test is run with --default-storage-engine=X + where X is not MyISAM: tests using SHOW CREATE TABLE will always fail + because SHOW CREATE TABLE prints X instead of MyISAM. With + --global-subst=X,MyISAM , such trivial differences are eliminated and + test may be reported as passing. + --global-subst is only a quick way to run a lot of existing tests + with Maria and find bugs; it is not good enough for reaching the main + trees when Maria is merged into them. + --global-subst should be removed. + */ + uint global_subst_from_len= strlen(global_subst_from); + uint global_subst_to_len= strlen(global_subst_to); + while (replace(&fd1_result, + global_subst_from, global_subst_from_len, + global_subst_to, global_subst_to_len) == 0) + /* do nothing */ ; + /* let's compare again to see if it is ok now */ } - if (!error && my_read(fd2, (uchar*)&buff2, - sizeof(buff2), MYF(0)) > 0) - { - /* File 1 was smaller */ + + if (fd1_result.length != fd2_result.length) error= RESULT_LENGTH_MISMATCH; - } + else if ((memcmp(fd1_result.str, fd2_result.str, fd1_result.length))) + error= RESULT_CONTENT_MISMATCH; my_close(fd2, MYF(0)); + dynstr_free(&fd1_result); + dynstr_free(&fd2_result); return error; } @@ -1865,7 +1909,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) { my_close(fd, MYF(0)); /* Remove the temporary file */ - my_delete(temp_file_path, MYF(0)); + my_delete(temp_file_path, MYF(MY_WME)); die("Failed to write file '%s'", temp_file_path); } @@ -1873,7 +1917,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) my_close(fd, MYF(0)); /* Remove the temporary file */ - my_delete(temp_file_path, MYF(0)); + my_delete(temp_file_path, MYF(MY_WME)); DBUG_RETURN(error); } @@ -1917,7 +1961,7 @@ void check_result() if (access(reject_file, W_OK) == 0) { /* Result file directory is writable, save reject file there */ - fn_format(reject_file, result_file_name, NULL, + fn_format(reject_file, result_file_name, "", ".reject", MY_REPLACE_EXT); } else @@ -3090,8 +3134,8 @@ void do_remove_file(struct st_command *command) ' '); DBUG_PRINT("info", ("removing file: %s", ds_filename.str)); - error= my_delete(ds_filename.str, MYF(0)) != 0; - handle_command_error(command, error); + 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; } @@ -3109,7 +3153,7 @@ void do_remove_file(struct st_command *command) void do_remove_files_wildcard(struct st_command *command) { - int error= 0; + int error= 0, sys_errno= 0; uint i; MY_DIR *dir_info; FILEINFO *file; @@ -3133,9 +3177,10 @@ void do_remove_files_wildcard(struct st_command *command) 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)))) + if (!(dir_info= my_dir(dirname, MYF(MY_DONT_SORT | MY_WANT_STAT | MY_WME)))) { error= 1; + sys_errno= my_errno; goto end; } init_dynamic_string(&ds_file_to_remove, dirname, 1024, 1024); @@ -3161,7 +3206,8 @@ void do_remove_files_wildcard(struct st_command *command) ds_file_to_remove.str[ds_directory.length + 1]= 0; dynstr_append(&ds_file_to_remove, file->name); DBUG_PRINT("info", ("removing file: %s", ds_file_to_remove.str)); - error= my_delete(ds_file_to_remove.str, MYF(0)) != 0; + if ((error= (my_delete(ds_file_to_remove.str, MYF(MY_WME)) != 0))) + sys_errno= my_errno; if (error) break; } @@ -3169,7 +3215,7 @@ void do_remove_files_wildcard(struct st_command *command) my_dirend(dir_info); end: - handle_command_error(command, error); + handle_command_error(command, error, sys_errno); dynstr_free(&ds_directory); dynstr_free(&ds_wild); dynstr_free(&ds_file_to_remove); @@ -3207,8 +3253,8 @@ void do_copy_file(struct st_command *command) DBUG_PRINT("info", ("Copy %s to %s", ds_from_file.str, ds_to_file.str)); error= (my_copy(ds_from_file.str, ds_to_file.str, - MYF(MY_DONT_OVERWRITE_FILE)) != 0); - handle_command_error(command, error); + MYF(MY_DONT_OVERWRITE_FILE | MY_WME)) != 0); + handle_command_error(command, error, my_errno); dynstr_free(&ds_from_file); dynstr_free(&ds_to_file); DBUG_VOID_RETURN; @@ -3243,8 +3289,8 @@ void do_move_file(struct st_command *command) DBUG_PRINT("info", ("Move %s to %s", ds_from_file.str, ds_to_file.str)); error= (my_rename(ds_from_file.str, ds_to_file.str, - MYF(0)) != 0); - handle_command_error(command, error); + MYF(disable_warnings ? 0 : MY_WME)) != 0); + handle_command_error(command, error, my_errno); dynstr_free(&ds_from_file); dynstr_free(&ds_to_file); DBUG_VOID_RETURN; @@ -3288,7 +3334,7 @@ void do_chmod_file(struct st_command *command) err_code= chmod(ds_file.str, mode); if (err_code < 0) err_code= 1; - handle_command_error(command, err_code); + handle_command_error(command, err_code, errno); dynstr_free(&ds_mode); dynstr_free(&ds_file); DBUG_VOID_RETURN; @@ -3321,7 +3367,7 @@ void do_file_exist(struct st_command *command) DBUG_PRINT("info", ("Checking for existence of file: %s", ds_filename.str)); error= (access(ds_filename.str, F_OK) != 0); - handle_command_error(command, error); + handle_command_error(command, error, errno); dynstr_free(&ds_filename); DBUG_VOID_RETURN; } @@ -3351,8 +3397,8 @@ void do_mkdir(struct st_command *command) ' '); DBUG_PRINT("info", ("creating directory: %s", ds_dirname.str)); - error= my_mkdir(ds_dirname.str, 0777, MYF(0)) != 0; - handle_command_error(command, error); + error= my_mkdir(ds_dirname.str, 0777, MYF(MY_WME)) != 0; + handle_command_error(command, error, my_errno); dynstr_free(&ds_dirname); DBUG_VOID_RETURN; } @@ -3372,7 +3418,7 @@ void do_rmdir(struct st_command *command) int error; static DYNAMIC_STRING ds_dirname; const struct command_arg rmdir_args[] = { - {"dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to remove"} + { "dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to remove" } }; DBUG_ENTER("do_rmdir"); @@ -3382,7 +3428,7 @@ void do_rmdir(struct st_command *command) DBUG_PRINT("info", ("removing directory: %s", ds_dirname.str)); error= rmdir(ds_dirname.str) != 0; - handle_command_error(command, error); + handle_command_error(command, error, errno); dynstr_free(&ds_dirname); DBUG_VOID_RETURN; } @@ -3458,7 +3504,7 @@ static void do_list_files(struct st_command *command) sizeof(list_files_args)/sizeof(struct command_arg), ' '); error= get_list_files(&ds_res, &ds_dirname, &ds_wild); - handle_command_error(command, error); + handle_command_error(command, error, my_errno); dynstr_free(&ds_dirname); dynstr_free(&ds_wild); DBUG_VOID_RETURN; @@ -3500,7 +3546,7 @@ static void do_list_files_write_file_command(struct st_command *command, init_dynamic_string(&ds_content, "", 1024, 1024); error= get_list_files(&ds_content, &ds_dirname, &ds_wild); - handle_command_error(command, error); + handle_command_error(command, error, my_errno); str_to_file2(ds_filename.str, ds_content.str, ds_content.length, append); dynstr_free(&ds_content); dynstr_free(&ds_filename); @@ -3724,7 +3770,7 @@ void do_cat_file(struct st_command *command) DBUG_PRINT("info", ("Reading from, file: %s", ds_filename.str)); error= cat_file(&ds_res, ds_filename.str); - handle_command_error(command, error); + handle_command_error(command, error, my_errno); dynstr_free(&ds_filename); DBUG_VOID_RETURN; } @@ -3770,9 +3816,10 @@ void do_diff_files(struct st_command *command) if ((error= compare_files(ds_filename.str, ds_filename2.str)) && match_expected_error(command, error, NULL) < 0) { - /* Compare of the two files failed, append them to output - so the failure can be analyzed, but only if it was not - expected to fail. + /* + Compare of the two files failed, append them to output + so the failure can be analyzed, but only if it was not + expected to fail. */ show_diff(&ds_res, ds_filename.str, ds_filename2.str); log_file.write(&ds_res); @@ -3782,7 +3829,7 @@ void do_diff_files(struct st_command *command) dynstr_free(&ds_filename); dynstr_free(&ds_filename2); - handle_command_error(command, error); + handle_command_error(command, error, -1); DBUG_VOID_RETURN; } @@ -3878,13 +3925,15 @@ void do_change_user(struct st_command *command) } if (!ds_user.length) + { dynstr_set(&ds_user, mysql->user); - if (!ds_passwd.length) - dynstr_set(&ds_passwd, mysql->passwd); + if (!ds_passwd.length) + dynstr_set(&ds_passwd, mysql->passwd); - if (!ds_db.length) - dynstr_set(&ds_db, mysql->db); + if (!ds_db.length) + dynstr_set(&ds_db, mysql->db); + } DBUG_PRINT("info",("connection: '%s' user: '%s' password: '%s' database: '%s'", cur_con->name, ds_user.str, ds_passwd.str, ds_db.str)); @@ -3988,7 +4037,7 @@ void do_perl(struct st_command *command) /* Remove the temporary file, but keep it if perl failed */ if (!error) - my_delete(temp_file_path, MYF(0)); + my_delete(temp_file_path, MYF(MY_WME)); /* Check for error code that indicates perl could not be started */ int exstat= WEXITSTATUS(error); @@ -4001,7 +4050,7 @@ void do_perl(struct st_command *command) abort_not_supported_test("perl not found in path"); #endif else - handle_command_error(command, exstat); + handle_command_error(command, exstat, my_errno); } dynstr_free(&ds_delimiter); DBUG_VOID_RETURN; @@ -4875,11 +4924,11 @@ char *get_string(char **to_ptr, char **from_ptr, } -void set_reconnect(MYSQL* mysql, int val) +void set_reconnect(MYSQL* mysql, my_bool val) { my_bool reconnect= val; DBUG_ENTER("set_reconnect"); - DBUG_PRINT("info", ("val: %d", val)); + DBUG_PRINT("info", ("val: %d", (int) val)); #if MYSQL_VERSION_ID < 50000 mysql->reconnect= reconnect; #else @@ -4949,7 +4998,7 @@ void select_connection(struct st_command *command) void do_close_connection(struct st_command *command) { - DBUG_ENTER("close_connection"); + DBUG_ENTER("do_close_connection"); struct st_connection *con; static DYNAMIC_STRING ds_connection; @@ -5022,6 +5071,7 @@ void do_close_connection(struct st_command *command) dynstr_append_mem(ds, ";\n", 2); } + dynstr_free(&ds_connection); DBUG_VOID_RETURN; } @@ -5314,7 +5364,8 @@ void do_connect(struct st_command *command) con_options= ds_options.str; while (*con_options) { - char* end; + size_t length; + char *end; /* Step past any spaces in beginning of option*/ while (*con_options && my_isspace(charset_info, *con_options)) con_options++; @@ -5322,13 +5373,14 @@ void do_connect(struct st_command *command) end= con_options; while (*end && !my_isspace(charset_info, *end)) end++; - if (!strncmp(con_options, "SSL", 3)) + length= (size_t) (end - con_options); + if (length == 3 && !strncmp(con_options, "SSL", 3)) con_ssl= 1; - else if (!strncmp(con_options, "COMPRESS", 8)) + else if (length == 8 && !strncmp(con_options, "COMPRESS", 8)) con_compress= 1; - else if (!strncmp(con_options, "PIPE", 4)) + else if (length == 4 && !strncmp(con_options, "PIPE", 4)) con_pipe= 1; - else if (!strncmp(con_options, "SHM", 3)) + else if (length == 3 && !strncmp(con_options, "SHM", 3)) con_shm= 1; else die("Illegal option to connect: %.*s", @@ -5368,6 +5420,9 @@ void do_connect(struct st_command *command) if (opt_charsets_dir) mysql_options(&con_slot->mysql, MYSQL_SET_CHARSET_DIR, opt_charsets_dir); + if (opt_connect_timeout >= 0) + mysql_options(&con_slot->mysql, MYSQL_OPT_CONNECT_TIMEOUT, + &opt_connect_timeout); #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) if (opt_use_ssl || con_ssl) @@ -5402,14 +5457,13 @@ void do_connect(struct st_command *command) mysql_options(&con_slot->mysql, MYSQL_SHARED_MEMORY_BASE_NAME, ds_shm.str); mysql_options(&con_slot->mysql, MYSQL_OPT_PROTOCOL, &protocol); } - else if(shared_memory_base_name) + else if (shared_memory_base_name) { mysql_options(&con_slot->mysql, MYSQL_SHARED_MEMORY_BASE_NAME, - shared_memory_base_name); + shared_memory_base_name); } #endif - /* Use default db name */ if (ds_database.length == 0) dynstr_set(&ds_database, opt_db); @@ -6195,6 +6249,9 @@ static struct my_option my_long_options[] = GET_INT, REQUIRED_ARG, 0, 0, 10000, 0, 0, 0}, {"test-file", 'x', "Read test from/in this file (default stdin).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"connect-timeout", OPT_MY_CONNECT_TIMEOUT, "Client connection timeout", + (uchar**) &opt_connect_timeout, (uchar**) &opt_connect_timeout, 0, + GET_INT, REQUIRED_ARG, -1, -1, 0, 0, 0, 0}, {"timer-file", 'm', "File where the timing in microseconds is stored.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"tmpdir", 't', "Temporary directory where sockets are put.", @@ -6406,6 +6463,15 @@ int parse_args(int argc, char **argv) if (debug_check_flag) my_end_arg= MY_CHECK_ERROR; + if (global_subst != NULL) + { + char *comma= strstr(global_subst, ","); + if (comma == NULL) + die("wrong --global-subst, must be X,Y"); + memcpy(global_subst_from, global_subst, (comma-global_subst)); + global_subst_from[comma-global_subst]= 0; + memcpy(global_subst_to, comma+1, strlen(comma)); + } if (!record) { @@ -7345,8 +7411,17 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, mysql_free_result(res); /* Free normal result set with meta data */ - /* Clear prepare warnings */ - dynstr_set(&ds_prepare_warnings, NULL); + /* + Normally, if there is a result set, we do not show warnings from the + prepare phase. This is because some warnings are generated both during + prepare and execute; this would generate different warning output + between normal and ps-protocol test runs. + + The --enable_prepare_warnings command can be used to change this so + that warnings from both the prepare and execute phase are shown. + */ + if (!disable_warnings && !prepare_warnings_enabled) + dynstr_set(&ds_prepare_warnings, NULL); } else { @@ -7359,7 +7434,6 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, Fetch info before fetching warnings, since it will be reset otherwise. */ - if (!disable_info) append_info(ds, mysql_stmt_affected_rows(stmt), mysql_info(mysql)); @@ -7394,14 +7468,6 @@ end: dynstr_free(&ds_execute_warnings); } - - /* Close the statement if - no reconnect, need new prepare */ - if (mysql->reconnect) - { - mysql_stmt_close(stmt); - cur_con->stmt= NULL; - } - /* We save the return code (mysql_stmt_errno(stmt)) from the last call sent to the server into the mysqltest builtin variable $mysql_errno. This @@ -7410,6 +7476,13 @@ end: var_set_errno(mysql_stmt_errno(stmt)); + /* Close the statement if reconnect, need new prepare */ + if (mysql->reconnect) + { + mysql_stmt_close(stmt); + cur_con->stmt= NULL; + } + DBUG_VOID_RETURN; } @@ -7571,7 +7644,6 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) } dynstr_free(&query_str); - } if (sp_protocol_enabled && @@ -7856,7 +7928,7 @@ void mark_progress(struct st_command* command __attribute__((unused)), die("Out of memory"); /* Milliseconds since start */ - end= longlong2str(timer, buf, 10); + end= longlong10_to_str(timer, buf, 10); dynstr_append_mem(&ds_progress, buf, (int)(end-buf)); dynstr_append_mem(&ds_progress, "\t", 1); @@ -7984,7 +8056,6 @@ static void init_signal_handling(void) #endif sigaction(SIGILL, &sa, NULL); sigaction(SIGFPE, &sa, NULL); - DBUG_VOID_RETURN; } @@ -7996,6 +8067,7 @@ int main(int argc, char **argv) my_bool q_send_flag= 0, abort_flag= 0; uint command_executed= 0, last_command_executed= 0; char save_file[FN_REFLEN]; + bool empty_result= FALSE; MY_INIT(argv[0]); save_file[0]= 0; @@ -8171,6 +8243,7 @@ int main(int argc, char **argv) verbose_msg("Start processing test commands from '%s' ...", cur_file->file_name); while (!read_command(&command) && !abort_flag) { + my_bool ok_to_do; int current_line_inc = 1, processed = 0; if (command->type == Q_UNKNOWN || command->type == Q_COMMENT_WITH_COMMAND) get_command_type(command); @@ -8188,7 +8261,7 @@ int main(int argc, char **argv) abort_on_error); /* delimiter needs to be executed so we can continue to parse */ - my_bool ok_to_do= cur_block->ok || command->type == Q_DELIMITER; + ok_to_do= cur_block->ok || command->type == Q_DELIMITER; /* Some commands need to be "done" the first time if they may get re-iterated over in a true context. This can only happen if there's @@ -8235,6 +8308,8 @@ int main(int argc, char **argv) case Q_DISABLE_CONNECT_LOG: disable_connect_log=1; break; case Q_ENABLE_WARNINGS: disable_warnings=0; break; case Q_DISABLE_WARNINGS: disable_warnings=1; break; + case Q_ENABLE_PREPARE_WARNINGS: prepare_warnings_enabled=1; break; + case Q_DISABLE_PREPARE_WARNINGS: prepare_warnings_enabled=0; break; case Q_ENABLE_INFO: disable_info=0; break; case Q_DISABLE_INFO: disable_info=1; break; case Q_ENABLE_METADATA: display_metadata=1; break; @@ -8427,12 +8502,12 @@ int main(int argc, char **argv) dynstr_append(&ds_res, "\n"); break; case Q_PING: - handle_command_error(command, mysql_ping(&cur_con->mysql)); + handle_command_error(command, mysql_ping(&cur_con->mysql), -1); break; case Q_SEND_SHUTDOWN: handle_command_error(command, mysql_shutdown(&cur_con->mysql, - SHUTDOWN_DEFAULT)); + SHUTDOWN_DEFAULT), -1); break; case Q_SHUTDOWN_SERVER: do_shutdown_server(command); @@ -8493,7 +8568,10 @@ int main(int argc, char **argv) abort_flag= 1; break; case Q_SKIP: - abort_not_supported_test("%s", command->first_argument); + /* Eval the query, thus replacing all environment variables */ + dynstr_set(&ds_res, 0); + do_eval(&ds_res, command->first_argument, command->end, FALSE); + abort_not_supported_test("%s",ds_res.str); break; case Q_RESULT: @@ -8561,8 +8639,6 @@ int main(int argc, char **argv) if (parsing_disabled) die("Test ended with parsing disabled"); - my_bool empty_result= FALSE; - /* The whole test has been executed _sucessfully_. Time to compare result or save it to record file. @@ -8643,7 +8719,7 @@ void timer_output(void) { char buf[32], *end; ulonglong timer= timer_now() - timer_start; - end= longlong2str(timer, buf, 10); + end= longlong10_to_str(timer, buf, 10); str_to_file(timer_file,buf, (int) (end-buf)); /* Timer has been written to the file, don't use it anymore */ timer_file= 0; @@ -8802,15 +8878,15 @@ void free_replace() typedef struct st_replace { - my_bool found; + int found; struct st_replace *next[256]; } REPLACE; typedef struct st_replace_found { - my_bool found; - char *replace_string; + int found; uint to_offset; int from_offset; + char *replace_string; } REPLACE_STRING; @@ -8842,7 +8918,7 @@ void replace_strings_append(REPLACE *rep, DYNAMIC_STRING* ds, } /* Found a string that needs to be replaced */ - DBUG_PRINT("info", ("found: %d, to_offset: %d, from_offset: %d, string: %s", + DBUG_PRINT("info", ("found: %d, to_offset: %u, from_offset: %d, string: %s", rep_str->found, rep_str->to_offset, rep_str->from_offset, rep_str->replace_string)); diff --git a/client/sql_string.h b/client/sql_string.h index bafc287c73e..b51e6b07e01 100644 --- a/client/sql_string.h +++ b/client/sql_string.h @@ -18,6 +18,9 @@ /* This file is originally from the mysql distribution. Coded by monty */ +#ifndef CLIENT_SQL_STRING_H +#define CLIENT_SQL_STRING_H + #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif |