diff options
Diffstat (limited to 'client')
-rw-r--r--[-rwxr-xr-x] | client/CMakeLists.txt | 10 | ||||
-rw-r--r-- | client/Makefile.am | 101 | ||||
-rw-r--r-- | client/client_priv.h | 31 | ||||
-rw-r--r-- | client/get_password.c | 4 | ||||
-rw-r--r-- | client/mysql.cc | 219 | ||||
-rw-r--r-- | client/mysqladmin.cc | 84 | ||||
-rw-r--r-- | client/mysqlbinlog.cc | 164 | ||||
-rw-r--r-- | client/mysqlcheck.c | 92 | ||||
-rw-r--r-- | client/mysqldump.c | 493 | ||||
-rw-r--r-- | client/mysqlimport.c | 253 | ||||
-rw-r--r-- | client/mysqlmanager-pwgen.c | 160 | ||||
-rw-r--r-- | client/mysqlmanagerc.c | 173 | ||||
-rw-r--r-- | client/mysqlshow.c | 22 | ||||
-rw-r--r-- | client/mysqlslap.c | 2104 | ||||
-rw-r--r-- | client/mysqltest.c | 88 | ||||
-rw-r--r-- | client/sql_string.h | 2 |
16 files changed, 3239 insertions, 761 deletions
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 6e37d02ecd8..8ec8b0111b0 100755..100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -25,7 +25,6 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/extra/yassl/include ${CMAKE_SOURCE_DIR}/libmysql ${CMAKE_SOURCE_DIR}/regex - ${CMAKE_SOURCE_DIR}/mysys ${CMAKE_SOURCE_DIR}/sql ${CMAKE_SOURCE_DIR}/strings) @@ -83,20 +82,24 @@ ADD_EXECUTABLE(mysqlimport mysqlimport.c) TARGET_LINK_LIBRARIES(mysqlimport mysqlclient mysys dbug yassl taocrypt zlib wsock32) ADD_EXECUTABLE(mysql_upgrade mysql_upgrade.c ../mysys/my_getpagesize.c) -TARGET_LINK_LIBRARIES(mysql_upgrade mysqlclient mysys dbug yassl taocrypt zlib wsock32) +TARGET_LINK_LIBRARIES(mysql_upgrade mysqlclient dbug yassl taocrypt zlib wsock32) ADD_DEPENDENCIES(mysql_upgrade GenFixPrivs) ADD_EXECUTABLE(mysqlshow mysqlshow.c) TARGET_LINK_LIBRARIES(mysqlshow mysqlclient mysys dbug yassl taocrypt zlib wsock32) ADD_EXECUTABLE(mysqlbinlog mysqlbinlog.cc ../mysys/mf_tempdir.c ../mysys/my_new.cc - ../mysys/my_bit.c ../mysys/my_bitmap.c + ../mysys/my_bit.c ../mysys/my_bitmap.c ../mysys/my_vle.c ../mysys/base64.c) TARGET_LINK_LIBRARIES(mysqlbinlog mysqlclient dbug yassl taocrypt zlib wsock32) ADD_EXECUTABLE(mysqladmin mysqladmin.cc) TARGET_LINK_LIBRARIES(mysqladmin mysqlclient mysys dbug yassl taocrypt zlib wsock32) +ADD_EXECUTABLE(mysqlslap mysqlslap.c) +SET_SOURCE_FILES_PROPERTIES(mysqlslap.c PROPERTIES COMPILE_FLAGS "-DTHREADS") +TARGET_LINK_LIBRARIES(mysqlslap mysqlclient mysys yassl taocrypt zlib wsock32 dbug) + ADD_EXECUTABLE(echo echo.c) IF(EMBED_MANIFESTS) @@ -111,4 +114,3 @@ IF(EMBED_MANIFESTS) MYSQL_EMBED_MANIFEST("mysqladmin" "asInvoker") MYSQL_EMBED_MANIFEST("echo" "asInvoker") ENDIF(EMBED_MANIFESTS) - diff --git a/client/Makefile.am b/client/Makefile.am index c7663c7da82..2d8bd918734 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -1,64 +1,109 @@ # Copyright (C) 2000-2006 MySQL 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 # the Free Software Foundation; version 2 of the License. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # This file is public domain and comes with NO WARRANTY of any kind -#AUTOMAKE_OPTIONS = nostdinc +if THREAD_SAFE_CLIENT +LIBMYSQLCLIENT_LA = $(top_builddir)/libmysql_r/libmysqlclient_r.la +else +LIBMYSQLCLIENT_LA = $(top_builddir)/libmysql/libmysqlclient.la +endif + INCLUDES = -I$(top_builddir)/include \ -I$(top_srcdir)/include \ -I$(top_srcdir)/regex \ $(openssl_includes) + LIBS = @CLIENT_LIBS@ -LDADD= @CLIENT_EXTRA_LDFLAGS@ \ - $(top_builddir)/libmysql/libmysqlclient.la -bin_PROGRAMS = mysql mysqladmin mysqlcheck mysqlshow \ - mysqldump mysqlimport mysqltest mysqlbinlog \ - mysql_upgrade \ - mysqltestmanagerc mysqltestmanager-pwgen + +LDADD= @CLIENT_EXTRA_LDFLAGS@ $(CLIENT_THREAD_LIBS) \ + $(top_builddir)/libmysql/libmysqlclient.la + noinst_HEADERS = sql_string.h completion_hash.h my_readline.h \ client_priv.h -mysql_SOURCES = mysql.cc readline.cc sql_string.cc completion_hash.cc + +EXTRA_DIST = get_password.c CMakeLists.txt echo.c + +BUILT_SOURCES = link_sources + +CLEANFILES = $(BUILT_SOURCES) + +bin_PROGRAMS = mysql \ + mysqladmin \ + mysqlbinlog \ + mysqlcheck \ + mysqldump \ + mysqlimport \ + mysqlshow \ + mysqlslap \ + mysqltest \ + mysql_upgrade + +mysql_SOURCES = mysql.cc readline.cc sql_string.cc \ + completion_hash.cc +mysql_LDADD = @readline_link@ @TERMCAP_LIB@ \ + $(LDADD) $(CXXLDFLAGS) mysqladmin_SOURCES = mysqladmin.cc -mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD) $(CXXLDFLAGS) -mysqltest_SOURCES= mysqltest.c \ - $(top_srcdir)/mysys/my_getsystime.c \ - $(top_srcdir)/mysys/my_copy.c -mysqltest_LDADD = $(top_builddir)/regex/libregex.a $(LDADD) -mysqlbinlog_SOURCES = mysqlbinlog.cc \ +mysqlbinlog_SOURCES = mysqlbinlog.cc \ $(top_srcdir)/mysys/mf_tempdir.c \ - $(top_srcdir)/mysys/my_new.cc + $(top_srcdir)/mysys/my_new.cc \ + $(top_srcdir)/mysys/my_bit.c \ + $(top_srcdir)/mysys/my_bitmap.c \ + $(top_srcdir)/mysys/my_vle.c \ + $(top_srcdir)/mysys/base64.c mysqlbinlog_LDADD = $(LDADD) $(CXXLDFLAGS) -mysqltestmanager_pwgen_SOURCES = mysqlmanager-pwgen.c -mysqltestmanagerc_SOURCES= mysqlmanagerc.c -mysqlcheck_SOURCES= mysqlcheck.c -mysqlshow_SOURCES= mysqlshow.c -mysqldump_SOURCES= mysqldump.c my_user.c \ + +mysqldump_SOURCES= mysqldump.c \ + my_user.c \ $(top_srcdir)/mysys/mf_getdate.c -mysqlimport_SOURCES= mysqlimport.c + +mysqlimport_SOURCES= mysqlimport.c + +mysqlimport_LDADD = $(CXXLDFLAGS) $(CLIENT_THREAD_LIBS) \ + @CLIENT_EXTRA_LDFLAGS@ \ + $(LIBMYSQLCLIENT_LA) \ + $(top_builddir)/mysys/libmysys.a + +mysqlshow_SOURCES= mysqlshow.c + +mysqlslap_SOURCES= mysqlslap.c +mysqlslap_CFLAGS= -DTHREAD -UUNDEF_THREADS_HACK +mysqlslap_LDADD = $(CXXLDFLAGS) $(CLIENT_THREAD_LIBS) \ + @CLIENT_EXTRA_LDFLAGS@ \ + $(LIBMYSQLCLIENT_LA) \ + $(top_builddir)/mysys/libmysys.a + +mysqltest_SOURCES= mysqltest.c \ + $(top_srcdir)/mysys/my_getsystime.c \ + $(top_srcdir)/mysys/my_copy.c +mysqltest_LDADD = $(top_builddir)/regex/libregex.a $(LDADD) + mysql_upgrade_SOURCES= mysql_upgrade.c \ $(top_srcdir)/mysys/my_getpagesize.c -sql_src=log_event.h mysql_priv.h log_event.cc my_decimal.h my_decimal.cc -strings_src=decimal.c # Fix for mit-threads DEFS = -DUNDEF_THREADS_HACK \ -DDEFAULT_MYSQL_HOME="\"$(prefix)\"" \ -DDATADIR="\"$(localstatedir)\"" -EXTRA_DIST = get_password.c CMakeLists.txt echo.c +sql_src=log_event.h mysql_priv.h rpl_constants.h \ + log_event.cc my_decimal.h my_decimal.cc \ + log_event_old.h log_event_old.cc \ + rpl_record_old.h rpl_record_old.cc +strings_src=decimal.c link_sources: for f in $(sql_src) ; do \ @@ -71,7 +116,7 @@ link_sources: done; \ rm -f $(srcdir)/my_user.c; \ @LN_CP_F@ $(top_srcdir)/sql-common/my_user.c my_user.c; - + echo timestamp > link_sources; # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/client/client_priv.h b/client/client_priv.h index 418bf86f2c8..25241cc8c59 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -23,7 +23,13 @@ #include <errmsg.h> #include <my_getopt.h> -/* We have to define 'enum options' identical in all files to keep OS2 happy */ +#ifndef WEXITSTATUS +# ifdef __WIN__ +# define WEXITSTATUS(stat_val) (stat_val) +# else +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +# endif +#endif enum options_client { @@ -49,7 +55,26 @@ enum options_client OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING, #endif OPT_TRIGGERS, + OPT_MYSQL_ONLY_PRINT, + OPT_MYSQL_LOCK_DIRECTORY, + OPT_USE_THREADS, + OPT_IMPORT_USE_THREADS, + OPT_MYSQL_NUMBER_OF_QUERY, + OPT_MYSQL_PRESERVE_SCHEMA, OPT_IGNORE_TABLE,OPT_INSERT_IGNORE,OPT_SHOW_WARNINGS,OPT_DROP_DATABASE, - OPT_TZ_UTC, OPT_AUTO_CLOSE, OPT_SSL_VERIFY_SERVER_CERT, - OPT_DEBUG_INFO, OPT_ERROR_LOG_FILE + OPT_TZ_UTC, OPT_AUTO_CLOSE, OPT_CREATE_SLAP_SCHEMA, + OPT_SLAP_CSV, OPT_SLAP_CREATE_STRING, + OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE, OPT_SLAP_AUTO_GENERATE_WRITE_NUM, + OPT_SLAP_AUTO_GENERATE_ADD_AUTO, + OPT_SLAP_AUTO_GENERATE_GUID_PRIMARY, + OPT_SLAP_AUTO_GENERATE_EXECUTE_QUERIES, + OPT_SLAP_AUTO_GENERATE_SECONDARY_INDEXES, + OPT_SLAP_AUTO_GENERATE_UNIQUE_WRITE_NUM, + OPT_SLAP_AUTO_GENERATE_UNIQUE_QUERY_NUM, + OPT_SLAP_PRE_QUERY, + OPT_SLAP_POST_QUERY, + OPT_MYSQL_REPLACE_INTO, OPT_BASE64_OUTPUT, OPT_SERVER_ID, + OPT_FIX_TABLE_NAMES, OPT_FIX_DB_NAMES, OPT_SSL_VERIFY_SERVER_CERT, + OPT_DEBUG_INFO, OPT_COLUMN_TYPES, OPT_ERROR_LOG_FILE, OPT_WRITE_BINLOG, + OPT_MAX_CLIENT_OPTION }; diff --git a/client/get_password.c b/client/get_password.c index e7e6c850469..37761d5bb5d 100644 --- a/client/get_password.c +++ b/client/get_password.c @@ -63,7 +63,7 @@ /* were just going to fake it here and get input from the keyboard */ -char *get_tty_password(char *opt_message) +char *get_tty_password(const char *opt_message) { char to[80]; char *pos=to,*end=to+sizeof(to)-1; @@ -149,7 +149,7 @@ static void get_password(char *to,uint length,int fd,bool echo) #endif /* ! HAVE_GETPASS */ -char *get_tty_password(char *opt_message) +char *get_tty_password(const char *opt_message) { #ifdef HAVE_GETPASS char *passbuff; diff --git a/client/mysql.cc b/client/mysql.cc index 368fce30d67..31cb78de1fd 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -43,7 +43,7 @@ #include <locale.h> #endif -const char *VER= "14.12"; +const char *VER= "14.13"; /* Don't try to make a nice table if the data is too big */ #define MAX_COLUMN_LENGTH 1024 @@ -83,7 +83,7 @@ extern "C" { #endif #undef bcmp // Fix problem with new readline -#if defined( __WIN__) || defined(OS2) +#if defined( __WIN__) #include <conio.h> #elif !defined(__NETWARE__) #include <readline/readline.h> @@ -103,7 +103,7 @@ extern "C" { #define cmp_database(cs,A,B) strcmp((A),(B)) #endif -#if !defined( __WIN__) && !defined( OS2) && !defined(__NETWARE__) && (!defined(HAVE_mit_thread) || !defined(THREAD)) +#if !defined( __WIN__) && !defined(__NETWARE__) && !defined(THREAD) #define USE_POPEN #endif @@ -138,8 +138,8 @@ static my_bool info_flag=0,ignore_errors=0,wait_flag=0,quick=0, tty_password= 0, opt_nobeep=0, opt_reconnect=1, default_charset_used= 0, opt_secure_auth= 0, default_pager_set= 0, opt_sigint_ignore= 0, - show_warnings= 0; -static volatile int executing_query= 0, interrupted_query= 0; + show_warnings= 0, executing_query= 0, interrupted_query= 0; +static my_bool column_types_flag; 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 my_string opt_mysql_unix_port=0; @@ -342,8 +342,7 @@ static void end_timer(ulong start_time,char *buff); static void mysql_end_timer(ulong start_time,char *buff); static void nice_time(double sec,char *buff,bool part_second); static sig_handler mysql_end(int sig); -static sig_handler mysql_sigint(int sig); - +static sig_handler handle_sigint(int sig); int main(int argc,char *argv[]) { @@ -440,7 +439,7 @@ int main(int argc,char *argv[]) if (opt_sigint_ignore) signal(SIGINT, SIG_IGN); else - signal(SIGINT, mysql_sigint); // Catch SIGINT to clean up + signal(SIGINT, handle_sigint); // Catch SIGINT to clean up signal(SIGQUIT, mysql_end); // Catch SIGQUIT to clean up put_info("Welcome to the MySQL monitor. Commands end with ; or \\g.", @@ -504,28 +503,6 @@ int main(int argc,char *argv[]) #endif } -sig_handler mysql_sigint(int sig) -{ - char kill_buffer[40]; - MYSQL *kill_mysql= NULL; - - signal(SIGINT, mysql_sigint); - - /* terminate if no query being executed, or we already tried interrupting */ - if (!executing_query || interrupted_query++) - mysql_end(sig); - - kill_mysql= mysql_init(kill_mysql); - if (!mysql_real_connect(kill_mysql,current_host, current_user, opt_password, - "", opt_mysql_port, opt_mysql_unix_port,0)) - mysql_end(sig); - /* kill_buffer is always big enough because max length of %lu is 15 */ - sprintf(kill_buffer, "KILL /*!50000 QUERY */ %lu", mysql_thread_id(&mysql)); - mysql_real_query(kill_mysql, kill_buffer, strlen(kill_buffer)); - mysql_close(kill_mysql); - tee_fprintf(stdout, "Query aborted by Ctrl+C\n"); -} - sig_handler mysql_end(int sig) { mysql_close(&mysql); @@ -564,11 +541,40 @@ sig_handler mysql_end(int sig) my_free(current_prompt,MYF(MY_ALLOW_ZERO_PTR)); mysql_server_end(); free_defaults(defaults_argv); - my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); + my_end(info_flag ? MY_CHECK_ERROR : 0); exit(status.exit_status); } +/* + This function handles sigint calls + If query is in process, kill query + 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 */ + if (!executing_query || interrupted_query) + mysql_end(sig); + + kill_mysql= mysql_init(kill_mysql); + if (!mysql_real_connect(kill_mysql,current_host, current_user, opt_password, + "", opt_mysql_port, opt_mysql_unix_port,0)) + mysql_end(sig); + + /* kill_buffer is always big enough because max length of %lu is 15 */ + sprintf(kill_buffer, "KILL /*!50000 QUERY */ %lu", mysql_thread_id(&mysql)); + mysql_real_query(kill_mysql, kill_buffer, strlen(kill_buffer)); + mysql_close(kill_mysql); + tee_fprintf(stdout, "Query aborted by Ctrl+C\n"); + + interrupted_query= 1; +} + + static struct my_option my_long_options[] = { {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, @@ -591,12 +597,13 @@ static struct my_option my_long_options[] = {"character-sets-dir", OPT_CHARSETS_DIR, "Directory where character sets are.", (gptr*) &charsets_dir, (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"default-character-set", OPT_DEFAULT_CHARSET, - "Set the default character set.", (gptr*) &default_charset, - (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"column-type-info", OPT_COLUMN_TYPES, "Display column type information.", + (gptr*) &column_types_flag, (gptr*) &column_types_flag, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"compress", 'C', "Use compression in server/client protocol.", (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + #ifdef DBUG_OFF {"debug", '#', "This is a non-debug version. Catch this and exit", 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0}, @@ -604,8 +611,13 @@ static struct my_option my_long_options[] = {"debug", '#', "Output debug log", (gptr*) &default_dbug_option, (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif + {"debug-info", 'T', "Print some debug info at exit.", (gptr*) &info_flag, + (gptr*) &info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"database", 'D', "Database to use.", (gptr*) ¤t_db, (gptr*) ¤t_db, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"default-character-set", OPT_DEFAULT_CHARSET, + "Set the default character set.", (gptr*) &default_charset, + (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"delimiter", OPT_DELIMITER, "Delimiter to be used.", (gptr*) &delimiter_str, (gptr*) &delimiter_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"execute", 'e', "Execute command and quit. (Disables --force and history file)", 0, @@ -702,8 +714,6 @@ static struct my_option my_long_options[] = #include "sslopt-longopts.h" {"table", 't', "Output in table format.", (gptr*) &output_tables, (gptr*) &output_tables, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"debug-info", 'T', "Print some debug info at exit.", (gptr*) &info_flag, - (gptr*) &info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"tee", OPT_TEE, "Append everything into outfile. See interactive help (\\h) also. Does not work in batch mode. Disable with --disable-tee. This option is disabled by default.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -729,7 +739,7 @@ static struct my_option my_long_options[] = "Number of seconds before connection timeout.", (gptr*) &opt_connect_timeout, (gptr*) &opt_connect_timeout, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 3600*12, 0, - 0, 1}, + 0, 0}, {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET, "Max packet length to send to, or receive from server", (gptr*) &opt_max_allowed_packet, (gptr*) &opt_max_allowed_packet, 0, GET_ULONG, @@ -875,14 +885,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), opt_nopager= 1; break; case OPT_MYSQL_PROTOCOL: - { - if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0) - { - fprintf(stderr, "Unknown option to protocol: %s\n", argument); - exit(1); - } + opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib, + opt->name); break; - } break; case 'A': opt_rehash= 0; @@ -1021,7 +1026,7 @@ static int get_options(int argc, char **argv) static int read_and_execute(bool interactive) { -#if defined(OS2) || defined(__NETWARE__) +#if defined(__NETWARE__) char linebuffer[254]; String buffer; #endif @@ -1058,9 +1063,7 @@ static int read_and_execute(bool interactive) if (opt_outfile && glob_buffer.is_empty()) fflush(OUTFILE); - interrupted_query= 0; - -#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__) +#if defined( __WIN__) || defined(__NETWARE__) tee_fputs(prompt, stdout); #if defined(__NETWARE__) line=fgets(linebuffer, sizeof(linebuffer)-1, stdin); @@ -1071,7 +1074,7 @@ static int read_and_execute(bool interactive) if (p != NULL) *p = '\0'; } -#elif defined(__WIN__) +#else defined(__WIN__) if (!tmpbuf.is_alloced()) tmpbuf.alloc(65535); tmpbuf.length(0); @@ -1087,32 +1090,12 @@ static int read_and_execute(bool interactive) */ } while (tmpbuf.alloced_length() <= clen); line= buffer.c_ptr(); -#else /* OS2 */ - buffer.length(0); - /* _cgets() expects the buffer size - 3 as the first byte */ - linebuffer[0]= (char) sizeof(linebuffer) - 3; - do - { - line= _cgets(linebuffer); - buffer.append(line, (unsigned char)linebuffer[1]); - /* - If _cgets() gets an input line that is linebuffer[0] bytes - long, the next call to _cgets() will return immediately with - linebuffer[1] == 0, and it does the same thing for input that - is linebuffer[0]-1 bytes long. So it appears that even though - _cgets() replaces the newline (which is two bytes on Window) with - a nil, it still needs the space in the linebuffer for it. This is, - naturally, undocumented. - */ - } while ((unsigned char)linebuffer[0] <= - (unsigned char)linebuffer[1] + 1); - line= buffer.c_ptr(); #endif /* __NETWARE__ */ #else if (opt_outfile) fputs(prompt, OUTFILE); line= readline(prompt); -#endif /* defined( __WIN__) || defined(OS2) || defined(__NETWARE__) */ +#endif /* defined( __WIN__) || defined(__NETWARE__) */ /* When Ctrl+d or Ctrl+z is pressed, the line may be NULL on some OS @@ -1164,7 +1147,7 @@ static int read_and_execute(bool interactive) } } -#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__) +#if defined( __WIN__) || defined(__NETWARE__) buffer.free(); #endif #if defined( __WIN__) @@ -2030,6 +2013,7 @@ com_go(String *buffer,char *line __attribute__((unused))) uint error= 0; int err= 0; + interrupted_query= 0; if (!status.batch) { old_buffer= *buffer; // Save for edit command @@ -2065,9 +2049,7 @@ com_go(String *buffer,char *line __attribute__((unused))) } timer=start_timer(); - executing_query= 1; - error= mysql_real_query_for_lazy(buffer->ptr(),buffer->length()); #ifdef HAVE_READLINE @@ -2081,8 +2063,8 @@ com_go(String *buffer,char *line __attribute__((unused))) if (error) { - buffer->length(0); // Remove query on error executing_query= 0; + buffer->length(0); // Remove query on error return error; } error=0; @@ -2095,7 +2077,7 @@ com_go(String *buffer,char *line __attribute__((unused))) if (!(result=mysql_use_result(&mysql)) && mysql_field_count(&mysql)) { executing_query= 0; - return put_error(&mysql); + return put_error(&mysql); } } else @@ -2104,7 +2086,7 @@ com_go(String *buffer,char *line __attribute__((unused))) if (error) { executing_query= 0; - return error; + return error; } } @@ -2114,7 +2096,7 @@ com_go(String *buffer,char *line __attribute__((unused))) time_buff[0]=0; if (result) { - if (!mysql_num_rows(result) && ! quick && !info_flag) + if (!mysql_num_rows(result) && ! quick && !column_types_flag) { strmov(buff, "Empty set"); if (opt_xml) @@ -2179,9 +2161,6 @@ com_go(String *buffer,char *line __attribute__((unused))) fflush(stdout); mysql_free_result(result); } while (!(err= mysql_next_result(&mysql))); - - executing_query= 0; - if (err >= 1) error= put_error(&mysql); @@ -2196,6 +2175,7 @@ com_go(String *buffer,char *line __attribute__((unused))) (mysql.server_status & SERVER_STATUS_DB_DROPPED)) get_current_db(); + executing_query= 0; return error; /* New command follows */ } @@ -2267,32 +2247,32 @@ com_ego(String *buffer,char *line) static const char *fieldtype2str(enum enum_field_types type) { switch (type) { - case FIELD_TYPE_BIT: return "BIT"; - case FIELD_TYPE_BLOB: return "BLOB"; - case FIELD_TYPE_DATE: return "DATE"; - case FIELD_TYPE_DATETIME: return "DATETIME"; - case FIELD_TYPE_NEWDECIMAL: return "NEWDECIMAL"; - case FIELD_TYPE_DECIMAL: return "DECIMAL"; - case FIELD_TYPE_DOUBLE: return "DOUBLE"; - case FIELD_TYPE_ENUM: return "ENUM"; - case FIELD_TYPE_FLOAT: return "FLOAT"; - case FIELD_TYPE_GEOMETRY: return "GEOMETRY"; - case FIELD_TYPE_INT24: return "INT24"; - case FIELD_TYPE_LONG: return "LONG"; - case FIELD_TYPE_LONGLONG: return "LONGLONG"; - case FIELD_TYPE_LONG_BLOB: return "LONG_BLOB"; - case FIELD_TYPE_MEDIUM_BLOB: return "MEDIUM_BLOB"; - case FIELD_TYPE_NEWDATE: return "NEWDATE"; - case FIELD_TYPE_NULL: return "NULL"; - case FIELD_TYPE_SET: return "SET"; - case FIELD_TYPE_SHORT: return "SHORT"; - case FIELD_TYPE_STRING: return "STRING"; - case FIELD_TYPE_TIME: return "TIME"; - case FIELD_TYPE_TIMESTAMP: return "TIMESTAMP"; - case FIELD_TYPE_TINY: return "TINY"; - case FIELD_TYPE_TINY_BLOB: return "TINY_BLOB"; - case FIELD_TYPE_VAR_STRING: return "VAR_STRING"; - case FIELD_TYPE_YEAR: return "YEAR"; + case MYSQL_TYPE_BIT: return "BIT"; + case MYSQL_TYPE_BLOB: return "BLOB"; + case MYSQL_TYPE_DATE: return "DATE"; + case MYSQL_TYPE_DATETIME: return "DATETIME"; + case MYSQL_TYPE_NEWDECIMAL: return "NEWDECIMAL"; + case MYSQL_TYPE_DECIMAL: return "DECIMAL"; + case MYSQL_TYPE_DOUBLE: return "DOUBLE"; + case MYSQL_TYPE_ENUM: return "ENUM"; + case MYSQL_TYPE_FLOAT: return "FLOAT"; + case MYSQL_TYPE_GEOMETRY: return "GEOMETRY"; + case MYSQL_TYPE_INT24: return "INT24"; + case MYSQL_TYPE_LONG: return "LONG"; + case MYSQL_TYPE_LONGLONG: return "LONGLONG"; + case MYSQL_TYPE_LONG_BLOB: return "LONG_BLOB"; + case MYSQL_TYPE_MEDIUM_BLOB: return "MEDIUM_BLOB"; + case MYSQL_TYPE_NEWDATE: return "NEWDATE"; + case MYSQL_TYPE_NULL: return "NULL"; + case MYSQL_TYPE_SET: return "SET"; + case MYSQL_TYPE_SHORT: return "SHORT"; + case MYSQL_TYPE_STRING: return "STRING"; + case MYSQL_TYPE_TIME: return "TIME"; + case MYSQL_TYPE_TIMESTAMP: return "TIMESTAMP"; + case MYSQL_TYPE_TINY: return "TINY"; + case MYSQL_TYPE_TINY_BLOB: return "TINY_BLOB"; + case MYSQL_TYPE_VAR_STRING: return "VAR_STRING"; + case MYSQL_TYPE_YEAR: return "YEAR"; default: return "?-unknown-?"; } } @@ -2366,7 +2346,7 @@ print_table_data(MYSQL_RES *result) bool *num_flag; num_flag=(bool*) my_alloca(sizeof(bool)*mysql_num_fields(result)); - if (info_flag) + if (column_types_flag) { print_field_types(result); if (!mysql_num_rows(result)) @@ -2411,6 +2391,8 @@ print_table_data(MYSQL_RES *result) while ((cur= mysql_fetch_row(result))) { + if (interrupted_query) + break; ulong *lengths= mysql_fetch_lengths(result); (void) tee_fputs("| ", PAGER); mysql_field_seek(result, 0); @@ -2422,7 +2404,6 @@ print_table_data(MYSQL_RES *result) uint visible_length; uint extra_padding; - /* If this column may have a null value, use "NULL" for empty. */ if (cur[off] == NULL) { buffer= "NULL"; @@ -2516,6 +2497,8 @@ print_table_data_html(MYSQL_RES *result) } while ((cur = mysql_fetch_row(result))) { + if (interrupted_query) + break; ulong *lengths=mysql_fetch_lengths(result); (void) tee_fputs("<TR>", PAGER); for (uint i=0; i < mysql_num_fields(result); i++) @@ -2546,6 +2529,8 @@ print_table_data_xml(MYSQL_RES *result) fields = mysql_fetch_fields(result); while ((cur = mysql_fetch_row(result))) { + if (interrupted_query) + break; ulong *lengths=mysql_fetch_lengths(result); (void) tee_fputs("\n <row>\n", PAGER); for (uint i=0; i < mysql_num_fields(result); i++) @@ -2585,6 +2570,8 @@ print_table_data_vertically(MYSQL_RES *result) mysql_field_seek(result,0); for (uint row_count=1; (cur= mysql_fetch_row(result)); row_count++) { + if (interrupted_query) + break; mysql_field_seek(result,0); tee_fprintf(PAGER, "*************************** %d. row ***************************\n", row_count); @@ -3595,9 +3582,6 @@ void tee_fprintf(FILE *file, const char *fmt, ...) NETWARE_YIELD; va_start(args, fmt); (void) vfprintf(file, fmt, args); -#ifdef OS2 - fflush( file); -#endif va_end(args); if (opt_outfile) @@ -3613,9 +3597,6 @@ void tee_fputs(const char *s, FILE *file) { NETWARE_YIELD; fputs(s, file); -#ifdef OS2 - fflush( file); -#endif if (opt_outfile) fputs(s, OUTFILE); } @@ -3626,9 +3607,6 @@ void tee_puts(const char *s, FILE *file) NETWARE_YIELD; fputs(s, file); fputc('\n', file); -#ifdef OS2 - fflush(file); -#endif if (opt_outfile) { fputs(s, OUTFILE); @@ -3639,14 +3617,11 @@ void tee_puts(const char *s, FILE *file) void tee_putc(int c, FILE *file) { putc(c, file); -#ifdef OS2 - fflush( file); -#endif if (opt_outfile) putc(c, OUTFILE); } -#if defined( __WIN__) || defined( OS2) || defined(__NETWARE__) +#if defined( __WIN__) || defined(__NETWARE__) #include <time.h> #else #include <sys/times.h> @@ -3658,7 +3633,7 @@ void tee_putc(int c, FILE *file) static ulong start_timer(void) { -#if defined( __WIN__) || defined( OS2) || defined(__NETWARE__) +#if defined( __WIN__) || defined(__NETWARE__) return clock(); #else struct tms tms_tmp; diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index c7033f6914f..03b37f2ba3a 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -27,7 +27,7 @@ #include "../ndb/src/mgmclient/ndb_mgmclient.h" #endif -#define ADMIN_VERSION "8.41" +#define ADMIN_VERSION "8.42" #define MAX_MYSQL_VAR 256 #define SHUTDOWN_DEF_TIMEOUT 3600 /* Wait for shutdown */ #define MAX_TRUNC_LENGTH 3 @@ -40,7 +40,7 @@ ulonglong last_values[MAX_MYSQL_VAR]; static int interval=0; static my_bool option_force=0,interrupted=0,new_line=0, opt_compress=0, opt_relative=0, opt_verbose=0, opt_vertical=0, - tty_password=0; + tty_password= 0, info_flag= 0, opt_nobeep; static uint tcp_port = 0, option_wait = 0, option_silent=0, nr_iterations, opt_count_iterations= 0; static ulong opt_connect_timeout, opt_shutdown_timeout; @@ -54,6 +54,7 @@ static char *opt_ndb_connectstring=0; static char *shared_memory_base_name=0; #endif static uint opt_protocol=0; +static myf error_flags; /* flags to pass to my_printf_error, like ME_BELL */ /* When using extended-status relatively, ex_val_max_len is the estimated @@ -135,6 +136,8 @@ static struct my_option my_long_options[] = REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", (gptr*) &info_flag, + (gptr*) &info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"force", 'f', "Don't ask for confirmation on drop database; with multiple commands, continue even if an error occurs.", (gptr*) &option_force, (gptr*) &option_force, 0, GET_BOOL, NO_ARG, 0, 0, @@ -152,6 +155,8 @@ static struct my_option my_long_options[] = NO_ARG, 0, 0, 0, 0, 0, 0}, {"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"no-beep", 'b', "Turn off beep on error.", (gptr*) &opt_nobeep, + (gptr*) &opt_nobeep, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"password", 'p', "Password to use when connecting to server. If password is not given it's asked from the tty.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, @@ -282,15 +287,10 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), #endif break; case OPT_MYSQL_PROTOCOL: - { - if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0) - { - fprintf(stderr, "Unknown option to protocol: %s\n", argument); - exit(1); - } + opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib, + opt->name); break; } - } if (error) { usage(); @@ -350,6 +350,8 @@ int main(int argc,char *argv[]) #endif if (default_charset) mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); + error_flags= (myf)(opt_nobeep ? 0 : ME_BELL); + if (sql_connect(&mysql, option_wait)) { unsigned int err= mysql_errno(&mysql); @@ -411,7 +413,7 @@ int main(int argc,char *argv[]) my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); #endif free_defaults(save_argv); - my_end(0); + my_end(info_flag ? MY_CHECK_ERROR : 0); exit(error ? 1 : 0); return 0; } @@ -448,7 +450,7 @@ static my_bool sql_connect(MYSQL *mysql, uint wait) if (!host) host= (char*) LOCAL_HOST; my_printf_error(0,"connect to server at '%s' failed\nerror: '%s'", - MYF(ME_BELL), host, mysql_error(mysql)); + error_flags, host, mysql_error(mysql)); if (mysql_errno(mysql) == CR_CONNECTION_ERROR) { fprintf(stderr, @@ -523,14 +525,14 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) char buff[FN_REFLEN+20]; if (argc < 2) { - my_printf_error(0,"Too few arguments to create",MYF(ME_BELL)); + my_printf_error(0, "Too few arguments to create", error_flags); return 1; } sprintf(buff,"create database `%.*s`",FN_REFLEN,argv[1]); if (mysql_query(mysql,buff)) { my_printf_error(0,"CREATE DATABASE failed; error: '%-.200s'", - MYF(ME_BELL), mysql_error(mysql)); + error_flags, mysql_error(mysql)); return -1; } argc--; argv++; @@ -540,7 +542,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) { if (argc < 2) { - my_printf_error(0,"Too few arguments to drop",MYF(ME_BELL)); + my_printf_error(0, "Too few arguments to drop", error_flags); return 1; } if (drop_db(mysql,argv[1])) @@ -565,7 +567,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) if (mysql_shutdown(mysql, SHUTDOWN_DEFAULT)) { - my_printf_error(0,"shutdown failed; error: '%s'",MYF(ME_BELL), + my_printf_error(0, "shutdown failed; error: '%s'", error_flags, mysql_error(mysql)); return -1; } @@ -586,7 +588,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) case ADMIN_RELOAD: if (mysql_query(mysql,"flush privileges")) { - my_printf_error(0,"reload failed; error: '%s'",MYF(ME_BELL), + my_printf_error(0, "reload failed; error: '%s'", error_flags, mysql_error(mysql)); return -1; } @@ -597,7 +599,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) REFRESH_READ_LOCK | REFRESH_SLAVE | REFRESH_MASTER))) { - my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL), + my_printf_error(0, "refresh failed; error: '%s'", error_flags, mysql_error(mysql)); return -1; } @@ -605,7 +607,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) case ADMIN_FLUSH_THREADS: if (mysql_refresh(mysql,(uint) REFRESH_THREADS)) { - my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL), + my_printf_error(0, "refresh failed; error: '%s'", error_flags, mysql_error(mysql)); return -1; } @@ -649,7 +651,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) "show processlist")) || !(result = mysql_store_result(mysql))) { - my_printf_error(0,"process list failed; error: '%s'",MYF(ME_BELL), + my_printf_error(0, "process list failed; error: '%s'", error_flags, mysql_error(mysql)); return -1; } @@ -672,7 +674,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) char *pos; if (argc < 2) { - my_printf_error(0,"Too few arguments to 'kill'",MYF(ME_BELL)); + my_printf_error(0, "Too few arguments to 'kill'", error_flags); return 1; } pos=argv[1]; @@ -680,7 +682,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) { if (mysql_kill(mysql,(ulong) atol(pos))) { - my_printf_error(0,"kill failed on %ld; error: '%s'",MYF(ME_BELL), + my_printf_error(0, "kill failed on %ld; error: '%s'", error_flags, atol(pos), mysql_error(mysql)); error=1; } @@ -696,7 +698,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) case ADMIN_DEBUG: if (mysql_dump_debug_info(mysql)) { - my_printf_error(0,"debug failed; error: '%s'",MYF(ME_BELL), + my_printf_error(0, "debug failed; error: '%s'", error_flags, mysql_error(mysql)); return -1; } @@ -710,7 +712,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) if (mysql_query(mysql,"show /*!40003 GLOBAL */ variables") || !(res=mysql_store_result(mysql))) { - my_printf_error(0,"unable to show variables; error: '%s'",MYF(ME_BELL), + my_printf_error(0, "unable to show variables; error: '%s'", error_flags, mysql_error(mysql)); return -1; } @@ -732,7 +734,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) if (mysql_query(mysql, "show /*!50002 GLOBAL */ status") || !(res = mysql_store_result(mysql))) { - my_printf_error(0, "unable to show status; error: '%s'", MYF(ME_BELL), + my_printf_error(0, "unable to show status; error: '%s'", error_flags, mysql_error(mysql)); return -1; } @@ -782,7 +784,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) { if (mysql_refresh(mysql,REFRESH_LOG)) { - my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL), + my_printf_error(0, "refresh failed; error: '%s'", error_flags, mysql_error(mysql)); return -1; } @@ -792,7 +794,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'",MYF(ME_BELL), + my_printf_error(0, "refresh failed; error: '%s'", error_flags, mysql_error(mysql)); return -1; } @@ -802,7 +804,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'",MYF(ME_BELL), + my_printf_error(0, "refresh failed; error: '%s'", error_flags, mysql_error(mysql)); return -1; } @@ -812,7 +814,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) { if (mysql_query(mysql,"flush status")) { - my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL), + my_printf_error(0, "refresh failed; error: '%s'", error_flags, mysql_error(mysql)); return -1; } @@ -829,7 +831,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) if (argc < 2) { - my_printf_error(0,"Too few arguments to change password",MYF(ME_BELL)); + my_printf_error(0, "Too few arguments to change password", error_flags); return 1; } if (argv[1][0]) @@ -852,7 +854,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) if (mysql_query(mysql, "SHOW VARIABLES LIKE 'old_passwords'")) { my_printf_error(0, "Could not determine old_passwords setting from server; error: '%s'", - MYF(ME_BELL),mysql_error(mysql)); + error_flags, mysql_error(mysql)); return -1; } else @@ -863,7 +865,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) my_printf_error(0, "Could not get old_passwords setting from " "server; error: '%s'", - MYF(ME_BELL),mysql_error(mysql)); + error_flags, mysql_error(mysql)); return -1; } if (!mysql_num_rows(res)) @@ -888,7 +890,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) if (mysql_query(mysql,"set sql_log_off=1")) { my_printf_error(0, "Can't turn off logging; error: '%s'", - MYF(ME_BELL),mysql_error(mysql)); + error_flags, mysql_error(mysql)); return -1; } if (mysql_query(mysql,buff)) @@ -896,7 +898,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) if (mysql_errno(mysql)!=1290) { my_printf_error(0,"unable to change password; error: '%s'", - MYF(ME_BELL),mysql_error(mysql)); + error_flags, mysql_error(mysql)); return -1; } else @@ -910,7 +912,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) " with grant tables disabled (was started with" " --skip-grant-tables).\n" "Use: \"mysqladmin flush-privileges password '*'\"" - " instead", MYF(ME_BELL)); + " instead", error_flags); return -1; } } @@ -921,7 +923,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) case ADMIN_START_SLAVE: if (mysql_query(mysql, "START SLAVE")) { - my_printf_error(0, "Error starting slave: %s", MYF(ME_BELL), + my_printf_error(0, "Error starting slave: %s", error_flags, mysql_error(mysql)); return -1; } @@ -931,7 +933,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) case ADMIN_STOP_SLAVE: if (mysql_query(mysql, "STOP SLAVE")) { - my_printf_error(0, "Error stopping slave: %s", MYF(ME_BELL), + my_printf_error(0, "Error stopping slave: %s", error_flags, mysql_error(mysql)); return -1; } @@ -957,7 +959,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) else { my_printf_error(0,"mysqld doesn't answer to ping, error: '%s'", - MYF(ME_BELL),mysql_error(mysql)); + error_flags, mysql_error(mysql)); return -1; } } @@ -968,7 +970,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) { if (argc < 2) { - my_printf_error(0,"Too few arguments to ndb-mgm",MYF(ME_BELL)); + my_printf_error(0, "Too few arguments to ndb-mgm", error_flags); return 1; } { @@ -982,7 +984,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) break; #endif default: - my_printf_error(0,"Unknown command: '%-.60s'",MYF(ME_BELL),argv[0]); + my_printf_error(0, "Unknown command: '%-.60s'", error_flags, argv[0]); return 1; } } @@ -1060,7 +1062,7 @@ static int drop_db(MYSQL *mysql, const char *db) sprintf(name_buff,"drop database `%.*s`",FN_REFLEN,db); if (mysql_query(mysql,name_buff)) { - my_printf_error(0,"DROP DATABASE %s failed;\nerror: '%s'",MYF(ME_BELL), + my_printf_error(0, "DROP DATABASE %s failed;\nerror: '%s'", error_flags, db,mysql_error(mysql)); return 1; } @@ -1285,7 +1287,7 @@ static my_bool get_pidfile(MYSQL *mysql, char *pidfile) if (mysql_query(mysql, "SHOW VARIABLES LIKE 'pid_file'")) { - my_printf_error(0,"query failed; error: '%s'",MYF(ME_BELL), + my_printf_error(0, "query failed; error: '%s'", error_flags, mysql_error(mysql)); } result = mysql_store_result(mysql); diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index a371981e24d..033c55707fc 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -63,8 +63,10 @@ void sql_print_error(const char *format, ...); static bool one_database=0, to_last_remote_log= 0, disable_log_bin= 0; static bool opt_hexdump= 0; +static bool opt_base64_output= 0; static const char* database= 0; -static my_bool force_opt= 0, short_form= 0, remote_opt= 0; +static my_bool force_opt= 0, short_form= 0, remote_opt= 0, info_flag; +static my_bool force_if_open_opt= 1; static ulonglong offset = 0; static const char* host = 0; static int port= 0; @@ -84,6 +86,7 @@ static short binlog_flags = 0; static MYSQL* mysql = NULL; static const char* dirname_for_local_load= 0; static bool stop_passed= 0; +static my_bool file_not_closed_error= 0; /* check_header() will set the pointer below. @@ -473,6 +476,25 @@ static bool check_database(const char *log_dbname) } + +static int +write_event_header_and_base64(Log_event *ev, FILE *result_file, + PRINT_EVENT_INFO *print_event_info) +{ + IO_CACHE *head= &print_event_info->head_cache; + IO_CACHE *body= &print_event_info->body_cache; + DBUG_ENTER("write_event_header_and_base64"); + + /* Write header and base64 output to cache */ + ev->print_header(head, print_event_info, FALSE); + ev->print_base64(body, print_event_info, FALSE); + + /* Read data from cache and write to result file */ + DBUG_RETURN(copy_event_cache_to_file_and_reinit(head, result_file) || + copy_event_cache_to_file_and_reinit(body, result_file)); +} + + /* Process an event @@ -516,6 +538,9 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, start_datetime= 0; offset= 0; // print everything and protect against cycling rec_count } + if (server_id && (server_id != ev->server_id)) { + DBUG_RETURN(0); + } if (((my_time_t)(ev->when) >= stop_datetime) || (pos >= stop_position_mot)) { @@ -530,12 +555,20 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, else print_event_info->hexdump_from= pos; + print_event_info->base64_output= opt_base64_output; + + DBUG_PRINT("debug", ("event_type: %s", ev->get_type_str())); + switch (ev_type) { case QUERY_EVENT: if (check_database(((Query_log_event*)ev)->db)) goto end; - ev->print(result_file, print_event_info); + if (opt_base64_output) + write_event_header_and_base64(ev, result_file, print_event_info); + else + ev->print(result_file, print_event_info); break; + case CREATE_FILE_EVENT: { Create_file_log_event* ce= (Create_file_log_event*)ev; @@ -554,7 +587,12 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, filename and use LOCAL), prepared in the 'case EXEC_LOAD_EVENT' below. */ - ce->print(result_file, print_event_info, TRUE); + if (opt_base64_output) + { + write_event_header_and_base64(ce, result_file, print_event_info); + } + else + ce->print(result_file, print_event_info, TRUE); // If this binlog is not 3.23 ; why this test?? if (glob_description_event->binlog_version >= 3) @@ -594,7 +632,8 @@ Create_file event for file_id: %u\n",exv->file_id); case FORMAT_DESCRIPTION_EVENT: delete glob_description_event; glob_description_event= (Format_description_log_event*) ev; - print_event_info->common_header_len= glob_description_event->common_header_len; + print_event_info->common_header_len= + glob_description_event->common_header_len; ev->print(result_file, print_event_info); /* We don't want this event to be deleted now, so let's hide it (I @@ -603,6 +642,12 @@ Create_file event for file_id: %u\n",exv->file_id); later. */ ev= 0; + if (!force_if_open_opt && + (glob_description_event->flags & LOG_EVENT_BINLOG_IN_USE_F)) + { + file_not_closed_error= 1; + DBUG_RETURN(1); + } break; case BEGIN_LOAD_QUERY_EVENT: ev->print(result_file, print_event_info); @@ -645,11 +690,18 @@ end: static struct my_option my_long_options[] = { - + {"help", '?', "Display this help and exit.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef __NETWARE__ {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif + {"base64-output", OPT_BASE64_OUTPUT, + "Print all binlog entries using base64 encoding. " + "This is for debugging only. Logs produced using this option " + "should not be applied on production systems.", + (gptr*) &opt_base64_output, (gptr*) &opt_base64_output, 0, GET_BOOL, + NO_ARG, 0, 0, 0, 0, 0, 0}, /* mysqlbinlog needs charsets knowledge, to be able to convert a charset number found in binlog to a charset name (to be able to print things @@ -659,13 +711,15 @@ static struct my_option my_long_options[] = {"character-sets-dir", OPT_CHARSETS_DIR, "Directory where character sets are.", (gptr*) &charsets_dir, (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"database", 'd', "List entries for just this database (local log only).", + (gptr*) &database, (gptr*) &database, 0, GET_STR_ALLOC, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, #ifndef DBUG_OFF {"debug", '#', "Output debug log.", (gptr*) &default_dbug_option, (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif - {"database", 'd', "List entries for just this database (local log only).", - (gptr*) &database, (gptr*) &database, 0, GET_STR_ALLOC, REQUIRED_ARG, - 0, 0, 0, 0, 0, 0}, + {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", (gptr*) &info_flag, + (gptr*) &info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"disable-log-bin", 'D', "Disable binary log. This is useful, if you " "enabled --to-last-log and are sending the output to the same MySQL server. " "This way you could avoid an endless loop. You would also like to use it " @@ -673,16 +727,20 @@ static struct my_option my_long_options[] = "already have. NOTE: you will need a SUPER privilege to use this option.", (gptr*) &disable_log_bin, (gptr*) &disable_log_bin, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"force-if-open", 'F', "Force if binlog was not closed properly.", + (gptr*) &force_if_open_opt, (gptr*) &force_if_open_opt, 0, GET_BOOL, NO_ARG, + 1, 0, 0, 0, 0, 0}, {"force-read", 'f', "Force reading unknown binlog events.", (gptr*) &force_opt, (gptr*) &force_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"help", '?', "Display this help and exit.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"hexdump", 'H', "Augment output with hexadecimal and ASCII event dump.", (gptr*) &opt_hexdump, (gptr*) &opt_hexdump, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"host", 'h', "Get the binlog from server.", (gptr*) &host, (gptr*) &host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"local-load", 'l', "Prepare local temporary files for LOAD DATA INFILE in the specified directory.", + (gptr*) &dirname_for_local_load, (gptr*) &dirname_for_local_load, 0, + GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"offset", 'o', "Skip the first N entries.", (gptr*) &offset, (gptr*) &offset, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"password", 'p', "Password to connect to remote server.", @@ -698,15 +756,15 @@ static struct my_option my_long_options[] = {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"result-file", 'r', "Direct output to a given file.", 0, 0, 0, GET_STR, - REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"read-from-remote-server", 'R', "Read binary logs from a MySQL server", (gptr*) &remote_opt, (gptr*) &remote_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"open_files_limit", OPT_OPEN_FILES_LIMIT, - "Used to reserve file descriptors for usage by this program", - (gptr*) &open_files_limit, (gptr*) &open_files_limit, 0, GET_ULONG, - REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0}, + {"result-file", 'r', "Direct output to a given file.", 0, 0, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"server-id", OPT_SERVER_ID, + "Extract only binlog entries created by the server having the given id.", + (gptr*) &server_id, (gptr*) &server_id, 0, GET_ULONG, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"set-charset", OPT_SET_CHARSET, "Add 'SET NAMES character_set' to the output.", (gptr*) &charset, (gptr*) &charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -724,6 +782,13 @@ static struct my_option my_long_options[] = "(you should probably use quotes for your shell to set it properly).", (gptr*) &start_datetime_str, (gptr*) &start_datetime_str, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"start-position", OPT_START_POSITION, + "Start reading the binlog at position N. Applies to the first binlog " + "passed on the command line.", + (gptr*) &start_position, (gptr*) &start_position, 0, GET_ULL, + REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE, + /* COM_BINLOG_DUMP accepts only 4 bytes for the position */ + (ulonglong)(~(uint32)0), 0, 0, 0}, {"stop-datetime", OPT_STOP_DATETIME, "Stop reading the binlog at first event having a datetime equal or " "posterior to the argument; the argument must be a date and time " @@ -732,13 +797,6 @@ static struct my_option my_long_options[] = "(you should probably use quotes for your shell to set it properly).", (gptr*) &stop_datetime_str, (gptr*) &stop_datetime_str, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"start-position", OPT_START_POSITION, - "Start reading the binlog at position N. Applies to the first binlog " - "passed on the command line.", - (gptr*) &start_position, (gptr*) &start_position, 0, GET_ULL, - REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE, - /* COM_BINLOG_DUMP accepts only 4 bytes for the position */ - (ulonglong)(~(uint32)0), 0, 0, 0}, {"stop-position", OPT_STOP_POSITION, "Stop reading the binlog at position N. Applies to the last binlog " "passed on the command line.", @@ -754,11 +812,12 @@ that may lead to an endless loop.", {"user", 'u', "Connect to the remote server as username.", (gptr*) &user, (gptr*) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"local-load", 'l', "Prepare local temporary files for LOAD DATA INFILE in the specified directory.", - (gptr*) &dirname_for_local_load, (gptr*) &dirname_for_local_load, 0, - GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Print version and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"open_files_limit", OPT_OPEN_FILES_LIMIT, + "Used to reserve file descriptors for usage by this program", + (gptr*) &open_files_limit, (gptr*) &open_files_limit, 0, GET_ULONG, + REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -792,7 +851,7 @@ static void die(const char* fmt, ...) va_end(args); cleanup(); /* We cannot free DBUG, it is used in global destructors after exit(). */ - my_end(MY_DONT_FREE_DBUG); + my_end((info_flag ? MY_CHECK_ERROR : 0) | MY_DONT_FREE_DBUG); exit(1); } @@ -885,14 +944,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), remote_opt= 1; break; case OPT_MYSQL_PROTOCOL: - { - if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0) - { - fprintf(stderr, "Unknown option to protocol: %s\n", argument); - exit(1); - } + opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib, + opt->name); break; - } case OPT_START_DATETIME: start_datetime= convert_str_to_timestamp(start_datetime_str); break; @@ -950,6 +1004,9 @@ static int dump_log_entries(const char* logname) { int rc; PRINT_EVENT_INFO print_event_info; + + if (!print_event_info.init_ok()) + return 1; /* Set safe delimiter, to dump things like CREATE PROCEDURE safely @@ -1340,15 +1397,12 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, else // reading from stdin; { /* - Bug fix: #23735 - Author: Chuck Bell - Description: - Windows opens stdin in text mode by default. Certain characters - such as CTRL-Z are interpeted as events and the read() method - will stop. CTRL-Z is the EOF marker in Windows. to get past this - you have to open stdin in binary mode. Setmode() is used to set - stdin in binary mode. Errors on setting this mode result in - halting the function and printing an error message to stderr. + Windows opens stdin in text mode by default. Certain characters + such as CTRL-Z are interpeted as events and the read() method + will stop. CTRL-Z is the EOF marker in Windows. to get past this + you have to open stdin in binary mode. Setmode() is used to set + stdin in binary mode. Errors on setting this mode result in + halting the function and printing an error message to stderr. */ #if defined (__WIN__) || (_WIN64) if (_setmode(fileno(stdin), O_BINARY) == -1) @@ -1356,8 +1410,7 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, fprintf(stderr, "Could not set binary mode on stdin.\n"); return 1; } -#endif - +#endif if (init_io_cache(file, fileno(stdin), 0, READ_CACHE, (my_off_t) 0, 0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE))) return 1; @@ -1431,7 +1484,7 @@ end: int main(int argc, char** argv) { - static char **defaults_argv; + char **defaults_argv; int exit_value= 0; ulonglong save_stop_position; MY_INIT(argv[0]); @@ -1529,7 +1582,17 @@ int main(int argc, char** argv) my_free_open_file_info(); load_processor.destroy(); /* We cannot free DBUG, it is used in global destructors after exit(). */ - my_end(MY_DONT_FREE_DBUG); + my_end((info_flag ? MY_CHECK_ERROR : 0) | MY_DONT_FREE_DBUG); + + if (file_not_closed_error) + { + fprintf(stderr, +"\nError: attempting to dump binlog '%s' which was not closed properly.\n" +"Most probably mysqld is still writting it, or crashed.\n" +"Your current options specify --disable-force-if-open\n" +"which means to abort on this problem.\n" +"You can rerun using --force-if-open to ignore this problem.\n\n", argv[-1]); + } exit(exit_value); DBUG_RETURN(exit_value); // Keep compilers happy } @@ -1539,14 +1602,17 @@ int main(int argc, char** argv) the server */ +#if defined(__WIN__) && !defined(USING_CMAKE) #include "my_decimal.h" #include "decimal.c" - -#if defined(__WIN__) && !defined(CMAKE_BUILD) #include "my_decimal.cpp" #include "log_event.cpp" +#include "log_event_old.cpp" #else +#include "my_decimal.h" +#include "decimal.c" #include "my_decimal.cc" #include "log_event.cc" +#include "log_event_old.cc" #endif diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index b69e9201a28..43a938badbe 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -15,7 +15,7 @@ /* By Jani Tolonen, 2001-04-20, MySQL Development Team */ -#define CHECK_VERSION "2.4.4" +#define CHECK_VERSION "2.4.5" #include "client_priv.h" #include <m_ctype.h> @@ -33,7 +33,9 @@ static my_bool opt_alldbs = 0, opt_check_only_changed = 0, opt_extended = 0, opt_compress = 0, opt_databases = 0, opt_fast = 0, opt_medium_check = 0, opt_quick = 0, opt_all_in_1 = 0, opt_silent = 0, opt_auto_repair = 0, ignore_errors = 0, - tty_password = 0, opt_frm = 0, opt_upgrade= 0; + tty_password= 0, opt_frm= 0, info_flag= 0, + opt_fix_table_names= 0, opt_fix_db_names= 0, opt_upgrade= 0, + opt_write_binlog= 1; static uint verbose = 0, opt_mysql_port=0; static my_string opt_mysql_unix_port = 0; static char *opt_password = 0, *current_user = 0, @@ -47,7 +49,7 @@ static char *shared_memory_base_name=0; static uint opt_protocol=0; static CHARSET_INFO *charset_info= &my_charset_latin1; -enum operations {DO_CHECK, DO_REPAIR, DO_ANALYZE, DO_OPTIMIZE}; +enum operations { DO_CHECK, DO_REPAIR, DO_ANALYZE, DO_OPTIMIZE, DO_UPGRADE }; static struct my_option my_long_options[] = { @@ -94,12 +96,20 @@ static struct my_option my_long_options[] = {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif + {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", (gptr*) &info_flag, + (gptr*) &info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"default-character-set", OPT_DEFAULT_CHARSET, "Set the default character set.", (gptr*) &default_charset, (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"fast",'F', "Check only tables that haven't been closed properly.", (gptr*) &opt_fast, (gptr*) &opt_fast, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"fix-db-names", OPT_FIX_DB_NAMES, "Fix database names.", + (gptr*) &opt_fix_db_names, (gptr*) &opt_fix_db_names, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"fix-table-names", OPT_FIX_TABLE_NAMES, "Fix table names.", + (gptr*) &opt_fix_table_names, (gptr*) &opt_fix_table_names, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"force", 'f', "Continue even if we get an sql-error.", (gptr*) &ignore_errors, (gptr*) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -114,6 +124,10 @@ static struct my_option my_long_options[] = {"medium-check", 'm', "Faster than extended-check, but only finds 99.99 percent of all errors. Should be good enough for most cases.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"write-binlog", OPT_WRITE_BINLOG, + "Log ANALYZE, OPTIMIZE and REPAIR TABLE commands. Enabled by default; use --skip-write-binlog when commands should not be sent to replication slaves.", + (gptr*) &opt_write_binlog, (gptr*) &opt_write_binlog, 0, GET_BOOL, NO_ARG, + 1, 0, 0, 0, 0, 0}, {"optimize", 'o', "Optimize table.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"password", 'p', @@ -173,6 +187,7 @@ static int process_all_databases(); static int process_databases(char **db_names); static int process_selected_tables(char *db, char **table_names, int tables); static int process_all_tables_in_db(char *database); +static int process_one_db(char *database); static int use_db(char *database); static int handle_request_for_tables(char *tables, uint length); static int dbConnect(char *host, char *user,char *passwd); @@ -253,6 +268,15 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'o': what_to_do = DO_OPTIMIZE; break; + case OPT_FIX_DB_NAMES: + what_to_do= DO_UPGRADE; + default_charset= (char*) "utf8"; + opt_databases= 1; + break; + case OPT_FIX_TABLE_NAMES: + what_to_do= DO_UPGRADE; + default_charset= (char*) "utf8"; + break; case 'p': if (argument) { @@ -291,15 +315,10 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case 'V': print_version(); exit(0); case OPT_MYSQL_PROTOCOL: - { - if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0) - { - fprintf(stderr, "Unknown option to protocol: %s\n", argument); - exit(1); - } + opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib, + opt->name); break; } - } return 0; } @@ -375,7 +394,7 @@ static int process_all_databases() } while ((row = mysql_fetch_row(tableres))) { - if (process_all_tables_in_db(row[0])) + if (process_one_db(row[0])) result = 1; } return result; @@ -388,7 +407,7 @@ static int process_databases(char **db_names) int result = 0; for ( ; *db_names ; db_names++) { - if (process_all_tables_in_db(*db_names)) + if (process_one_db(*db_names)) result = 1; } return result; @@ -509,6 +528,43 @@ static int process_all_tables_in_db(char *database) } /* process_all_tables_in_db */ + +static int fix_object_name(const char *obj, const char *name) +{ + char qbuf[100 + NAME_LEN*4]; + int rc= 0; + if (strncmp(name, "#mysql50#", 9)) + return 1; + sprintf(qbuf, "RENAME %s `%s` TO `%s`", obj, name, name + 9); + if (mysql_query(sock, qbuf)) + { + fprintf(stderr, "Failed to %s\n", qbuf); + fprintf(stderr, "Error: %s\n", mysql_error(sock)); + rc= 1; + } + if (verbose) + printf("%-50s %s\n", name, rc ? "FAILED" : "OK"); + return rc; +} + + +static int process_one_db(char *database) +{ + if (what_to_do == DO_UPGRADE) + { + int rc= 0; + if (opt_fix_db_names && !strncmp(database,"#mysql50#", 9)) + { + rc= fix_object_name("DATABASE", database); + database+= 9; + } + if (rc || !opt_fix_table_names) + return rc; + } + return process_all_tables_in_db(database); +} + + static int use_db(char *database) { if (mysql_get_server_version(sock) >= 50003 && @@ -542,17 +598,19 @@ static int handle_request_for_tables(char *tables, uint length) if (opt_upgrade) end = strmov(end, " FOR UPGRADE"); break; case DO_REPAIR: - op = "REPAIR"; + op= (opt_write_binlog) ? "REPAIR" : "REPAIR NO_WRITE_TO_BINLOG"; if (opt_quick) end = strmov(end, " QUICK"); if (opt_extended) end = strmov(end, " EXTENDED"); if (opt_frm) end = strmov(end, " USE_FRM"); break; case DO_ANALYZE: - op = "ANALYZE"; + op= (opt_write_binlog) ? "ANALYZE" : "ANALYZE NO_WRITE_TO_BINLOG"; break; case DO_OPTIMIZE: - op = "OPTIMIZE"; + op= (opt_write_binlog) ? "OPTIMIZE" : "OPTIMIZE NO_WRITE_TO_BINLOG"; break; + case DO_UPGRADE: + return fix_object_name("TABLE", tables); } if (!(query =(char *) my_malloc((sizeof(char)*(length+110)), MYF(MY_WME)))) @@ -704,7 +762,7 @@ int main(int argc, char **argv) */ if (get_options(&argc, &argv)) { - my_end(0); + my_end(info_flag ? MY_CHECK_ERROR : 0); exit(EX_USAGE); } if (dbConnect(current_host, current_user, opt_password)) @@ -746,6 +804,6 @@ int main(int argc, char **argv) #ifdef HAVE_SMEM my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); #endif - my_end(0); + my_end(info_flag ? MY_CHECK_ERROR : 0); return(first_error!=0); } /* main */ diff --git a/client/mysqldump.c b/client/mysqldump.c index b334e8d9a11..fa25701eb91 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -29,14 +29,14 @@ ** master/autocommit code by Brian Aker <brian@tangent.org> ** SSL by ** Andrei Errapart <andreie@no.spam.ee> -** Tõnu Samuel <tonu@please.do.not.remove.this.spam.ee> +** Tõnu Samuel <tonu@please.do.not.remove.this.spam.ee> ** XML by Gary Huntress <ghuntress@mediaone.net> 10/10/01, cleaned up ** and adapted to mysqldump 05/11/01 by Jani Tolonen ** Added --single-transaction option 06/06/2002 by Peter Zaitsev ** 10 Jun 2003: SET NAMES and --no-set-names by Alexander Barkov */ -#define DUMP_VERSION "10.11" +#define DUMP_VERSION "10.12" #include <my_global.h> #include <my_sys.h> @@ -50,6 +50,7 @@ #include "mysql.h" #include "mysql_version.h" #include "mysqld_error.h" +#include "../sql/ha_ndbcluster_tables.h" /* Exit codes */ @@ -95,7 +96,10 @@ static my_bool verbose= 0, opt_no_create_info= 0, opt_no_data= 0, opt_single_transaction=0, opt_comments= 0, opt_compact= 0, opt_hex_blob=0, opt_order_by_primary=0, opt_ignore=0, opt_complete_insert= 0, opt_drop_database= 0, - opt_dump_triggers= 0, opt_routines=0, opt_tz_utc=1; + opt_replace_into= 0, + opt_dump_triggers= 0, opt_routines=0, opt_tz_utc=1, + opt_events= 0, + opt_alltspcs=0, opt_notspcs= 0; static ulong opt_max_allowed_packet, opt_net_buffer_length; static MYSQL mysql_connection,*mysql=0; static my_bool insert_pat_inited= 0, info_flag; @@ -149,7 +153,6 @@ static CHARSET_INFO *charset_info= &my_charset_latin1; const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace"; /* have we seen any VIEWs during table scanning? */ my_bool seen_views= 0; - const char *compatible_mode_names[]= { "MYSQL323", "MYSQL40", "POSTGRESQL", "ORACLE", "MSSQL", "DB2", @@ -180,6 +183,14 @@ static struct my_option my_long_options[] = "Dump all the databases. This will be same as --databases with all databases selected.", (gptr*) &opt_alldbs, (gptr*) &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"all-tablespaces", 'Y', + "Dump all the tablespaces.", + (gptr*) &opt_alltspcs, (gptr*) &opt_alltspcs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + 0, 0}, + {"no-tablespaces", 'y', + "Do not dump any tablespace information.", + (gptr*) &opt_notspcs, (gptr*) &opt_notspcs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + 0, 0}, {"add-drop-database", OPT_DROP_DATABASE, "Add a 'DROP DATABASE' before each create.", (gptr*) &opt_drop_database, (gptr*) &opt_drop_database, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -246,6 +257,9 @@ static struct my_option my_long_options[] = {"disable-keys", 'K', "'/*!40000 ALTER TABLE tb_name DISABLE KEYS */; and '/*!40000 ALTER TABLE tb_name ENABLE KEYS */; will be put in the output.", (gptr*) &opt_disable_keys, (gptr*) &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"events", 'E', "Dump events.", + (gptr*) &opt_events, (gptr*) &opt_events, 0, GET_BOOL, + NO_ARG, 0, 0, 0, 0, 0, 0}, {"extended-insert", 'e', "Allows utilization of the new, much faster INSERT syntax.", (gptr*) &extended_insert, (gptr*) &extended_insert, 0, GET_BOOL, NO_ARG, @@ -371,6 +385,9 @@ static struct my_option my_long_options[] = {"quote-names",'Q', "Quote table and column names with backticks (`).", (gptr*) &opt_quoted, (gptr*) &opt_quoted, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"replace", OPT_MYSQL_REPLACE_INTO, "Use REPLACE INTO instead of INSERT INTO.", + (gptr*) &opt_replace_into, (gptr*) &opt_replace_into, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + 0, 0}, {"result-file", 'r', "Direct output to a given file. This option should be used in MSDOS, because it prevents new line '\\n' from being converted to '\\r\\n' (carriage return + line feed).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -457,6 +474,10 @@ char check_if_ignore_table(const char *table_name, char *table_type); static char *primary_key_fields(const char *table_name); static my_bool get_view_structure(char *table, char* db); static my_bool dump_all_views_in_db(char *database); +static int dump_all_tablespaces(); +static int dump_tablespaces_for_tables(char *db, char **table_names, int tables); +static int dump_tablespaces_for_databases(char** databases); +static int dump_tablespaces(char* ts_where); #include <help_start.h> @@ -543,8 +564,10 @@ static void write_header(FILE *sql_file, char *db_name) if (opt_xml) { fputs("<?xml version=\"1.0\"?>\n", sql_file); - /* Schema reference. Allows use of xsi:nil for NULL values and - xsi:type to define an element's data type. */ + /* + Schema reference. Allows use of xsi:nil for NULL values and + xsi:type to define an element's data type. + */ fputs("<mysqldump ", sql_file); fputs("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", sql_file); @@ -784,14 +807,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; } case (int) OPT_MYSQL_PROTOCOL: - { - if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0) - { - fprintf(stderr, "Unknown option to protocol: %s\n", argument); - exit(1); - } - break; - } + opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib, + opt->name); + break; } return 0; } @@ -812,11 +830,15 @@ static int get_options(int *argc, char ***argv) (hash_get_key) get_table_key, (hash_free_key) free_table_ent, 0)) return(EX_EOM); - /* Don't copy cluster internal log tables */ + /* Don't copy internal log tables */ if (my_hash_insert(&ignore_table, (byte*) my_strdup("mysql.apply_status", MYF(MY_WME))) || my_hash_insert(&ignore_table, - (byte*) my_strdup("mysql.schema", MYF(MY_WME)))) + (byte*) my_strdup("mysql.schema", MYF(MY_WME))) || + my_hash_insert(&ignore_table, + (byte*) my_strdup("mysql.general_log", MYF(MY_WME))) || + my_hash_insert(&ignore_table, + (byte*) my_strdup("mysql.slow_log", MYF(MY_WME)))) return(EX_EOM); if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option))) @@ -1395,6 +1417,136 @@ static void print_xml_row(FILE *xml_file, const char *row_name, check_io(xml_file); } + +/* + create_delimiter + Generate a new (null-terminated) string that does not exist in query + and is therefore suitable for use as a query delimiter. Store this + delimiter in delimiter_buff . + + This is quite simple in that it doesn't even try to parse statements as an + interpreter would. It merely returns a string that is not in the query, which + is much more than adequate for constructing a delimiter. + + RETURN + ptr to the delimiter on Success + NULL on Failure +*/ +static char *create_delimiter(char *query, char *delimiter_buff, + int delimiter_max_size) +{ + int proposed_length; + char *presence; + + delimiter_buff[0]= ';'; /* start with one semicolon, and */ + + for (proposed_length= 2; proposed_length < delimiter_max_size; + delimiter_max_size++) { + + delimiter_buff[proposed_length-1]= ';'; /* add semicolons, until */ + delimiter_buff[proposed_length]= '\0'; + + presence = strstr(query, delimiter_buff); + if (presence == NULL) { /* the proposed delimiter is not in the query. */ + return delimiter_buff; + } + + } + return NULL; /* but if we run out of space, return nothing at all. */ +} + + +/* + dump_events_for_db + -- retrieves list of events for a given db, and prints out + the CREATE EVENT statement into the output (the dump). + + RETURN + 0 Success + 1 Error +*/ +static uint dump_events_for_db(char *db) +{ + char query_buff[QUERY_LENGTH]; + char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3]; + char *event_name; + char delimiter[QUERY_LENGTH], *delimit_test; + FILE *sql_file= md_result_file; + MYSQL_RES *event_res, *event_list_res; + MYSQL_ROW row, event_list_row; + DBUG_ENTER("dump_events_for_db"); + DBUG_PRINT("enter", ("db: '%s'", db)); + + mysql_real_escape_string(mysql, db_name_buff, db, strlen(db)); + + /* nice comments */ + if (opt_comments) + fprintf(sql_file, "\n--\n-- Dumping events for database '%s'\n--\n", db); + + /* + not using "mysql_query_with_error_report" because we may have not + enough privileges to lock mysql.events. + */ + if (lock_tables) + mysql_query(mysql, "LOCK TABLES mysql.event READ"); + + if (mysql_query_with_error_report(mysql, &event_list_res, "show events")) + DBUG_RETURN(0); + + strcpy(delimiter, ";"); + if (mysql_num_rows(event_list_res) > 0) + { + fprintf(sql_file, "/*!50106 SET @save_time_zone= @@TIME_ZONE */ ;\n"); + + while ((event_list_row= mysql_fetch_row(event_list_res)) != NULL) + { + event_name= quote_name(event_list_row[1], name_buff, 0); + DBUG_PRINT("info", ("retrieving CREATE EVENT for %s", name_buff)); + my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE EVENT %s", + event_name); + + if (mysql_query_with_error_report(mysql, &event_res, query_buff)) + DBUG_RETURN(1); + + while ((row= mysql_fetch_row(event_res)) != NULL) + { + /* + if the user has EXECUTE privilege he can see event names, but not the + event body! + */ + if (strlen(row[3]) != 0) + { + if (opt_drop) + fprintf(sql_file, "/*!50106 DROP EVENT IF EXISTS %s */%s\n", + event_name, delimiter); + + delimit_test= create_delimiter(row[3], delimiter, sizeof(delimiter)); + if (delimit_test == NULL) { + fprintf(stderr, "%s: Warning: Can't dump event '%s'\n", + event_name, my_progname); + DBUG_RETURN(1); + } + + fprintf(sql_file, "DELIMITER %s\n", delimiter); + fprintf(sql_file, "/*!50106 SET TIME_ZONE= '%s' */ %s\n", + row[2], delimiter); + fprintf(sql_file, "/*!50106 %s */ %s\n", row[3], delimiter); + } + } /* end of event printing */ + mysql_free_result(event_res); + + } /* end of list of events */ + fprintf(sql_file, "DELIMITER ;\n"); + fprintf(sql_file, "/*!50106 SET TIME_ZONE= @save_time_zone */ ;\n"); + } + mysql_free_result(event_list_res); + + if (lock_tables) + VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES")); + DBUG_RETURN(0); +} + + /* Print hex value for blob data. @@ -1432,7 +1584,7 @@ static void print_blob_as_hex(FILE *output_file, const char *str, ulong len) static uint dump_routines_for_db(char *db) { - char query_buff[512]; + char query_buff[QUERY_LENGTH]; const char *routine_type[]= {"FUNCTION", "PROCEDURE"}; char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3]; char *routine_name; @@ -1476,9 +1628,9 @@ static uint dump_routines_for_db(char *db) while ((routine_list_row= mysql_fetch_row(routine_list_res))) { + routine_name= quote_name(routine_list_row[1], name_buff, 0); DBUG_PRINT("info", ("retrieving CREATE %s for %s", routine_type[i], name_buff)); - routine_name= quote_name(routine_list_row[1], name_buff, 0); my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE %s %s", routine_type[i], routine_name); @@ -1598,8 +1750,8 @@ static uint get_table_structure(char *table, char *db, char *table_type, my_ulonglong num_fields; char *result_table, *opt_quoted_table; const char *insert_option; - char name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3]; - char table_buff2[NAME_LEN*2+3], query_buff[512]; + char name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3]; + char table_buff2[NAME_LEN*2+3], query_buff[QUERY_LENGTH]; FILE *sql_file= md_result_file; int len; MYSQL_RES *result; @@ -1803,7 +1955,10 @@ static uint get_table_structure(char *table, char *db, char *table_type, */ if (write_data) { - dynstr_append_checked(&insert_pat, "INSERT "); + if (opt_replace_into) + dynstr_append_checked(&insert_pat, "REPLACE "); + else + dynstr_append_checked(&insert_pat, "INSERT "); dynstr_append_checked(&insert_pat, insert_option); dynstr_append_checked(&insert_pat, "INTO "); dynstr_append_checked(&insert_pat, opt_quoted_table); @@ -1869,7 +2024,10 @@ static uint get_table_structure(char *table, char *db, char *table_type, if (write_data) { - dynstr_append_checked(&insert_pat, "INSERT "); + if (opt_replace_into) + dynstr_append_checked(&insert_pat, "REPLACE "); + else + dynstr_append_checked(&insert_pat, "INSERT "); dynstr_append_checked(&insert_pat, insert_option); dynstr_append_checked(&insert_pat, "INTO "); dynstr_append_checked(&insert_pat, result_table); @@ -2086,7 +2244,7 @@ static void dump_triggers_for_table(char *table, { char *result_table; char name_buff[NAME_LEN*4+3], table_buff[NAME_LEN*2+3]; - char query_buff[512]; + char query_buff[QUERY_LENGTH]; uint old_opt_compatible_mode=opt_compatible_mode; FILE *sql_file= md_result_file; MYSQL_RES *result; @@ -2565,7 +2723,7 @@ static void dump_table(char *table, char *db) dynstr_append_checked(&extended_row, "NULL"); else { - if (field->type == FIELD_TYPE_DECIMAL) + if (field->type == MYSQL_TYPE_DECIMAL) { /* add " signs around */ dynstr_append_checked(&extended_row, "'"); @@ -2634,7 +2792,7 @@ static void dump_table(char *table, char *db) else if (my_isalpha(charset_info, *ptr) || (*ptr == '-' && my_isalpha(charset_info, ptr[1]))) fputs("NULL", md_result_file); - else if (field->type == FIELD_TYPE_DECIMAL) + else if (field->type == MYSQL_TYPE_DECIMAL) { /* add " signs around */ fputc('\'', md_result_file); @@ -2768,6 +2926,256 @@ static char *getTableName(int reset) } /* getTableName */ +/* + dump all logfile groups and tablespaces +*/ + +static int dump_all_tablespaces() +{ + return dump_tablespaces(NULL); +} + +static int dump_tablespaces_for_tables(char *db, char **table_names, int tables) +{ + DYNAMIC_STRING where; + int r; + int i; + char name_buff[NAME_LEN*2+3]; + + mysql_real_escape_string(mysql, name_buff, db, strlen(db)); + + init_dynamic_string_checked(&where, " AND TABLESPACE_NAME IN (" + "SELECT DISTINCT TABLESPACE_NAME FROM" + " INFORMATION_SCHEMA.PARTITIONS" + " WHERE" + " TABLE_SCHEMA='", 256, 1024); + dynstr_append_checked(&where, name_buff); + dynstr_append_checked(&where, "' AND TABLE_NAME IN ("); + + for (i=0 ; i<tables ; i++) + { + mysql_real_escape_string(mysql, name_buff, + table_names[i], strlen(table_names[i])); + + dynstr_append_checked(&where, "'"); + dynstr_append_checked(&where, name_buff); + dynstr_append_checked(&where, "',"); + } + dynstr_trunc(&where, 1); + dynstr_append_checked(&where,"))"); + + DBUG_PRINT("info",("Dump TS for Tables where: %s",where.str)); + r= dump_tablespaces(where.str); + dynstr_free(&where); + return r; +} + +static int dump_tablespaces_for_databases(char** databases) +{ + DYNAMIC_STRING where; + int r; + int i; + + init_dynamic_string_checked(&where, " AND TABLESPACE_NAME IN (" + "SELECT DISTINCT TABLESPACE_NAME FROM" + " INFORMATION_SCHEMA.PARTITIONS" + " WHERE" + " TABLE_SCHEMA IN (", 256, 1024); + + for (i=0 ; databases[i]!=NULL ; i++) + { + char db_name_buff[NAME_LEN*2+3]; + mysql_real_escape_string(mysql, db_name_buff, + databases[i], strlen(databases[i])); + dynstr_append_checked(&where, "'"); + dynstr_append_checked(&where, db_name_buff); + dynstr_append_checked(&where, "',"); + } + dynstr_trunc(&where, 1); + dynstr_append_checked(&where,"))"); + + DBUG_PRINT("info",("Dump TS for DBs where: %s",where.str)); + r= dump_tablespaces(where.str); + dynstr_free(&where); + return r; +} + +static int dump_tablespaces(char* ts_where) +{ + MYSQL_ROW row; + MYSQL_RES *tableres; + char buf[FN_REFLEN]; + DYNAMIC_STRING sqlbuf; + int first= 0; + /* + The following are used for parsing the EXTRA field + */ + char extra_format[]= "UNDO_BUFFER_SIZE="; + char *ubs; + char *endsemi; + + init_dynamic_string_checked(&sqlbuf, + "SELECT LOGFILE_GROUP_NAME," + " FILE_NAME," + " TOTAL_EXTENTS," + " INITIAL_SIZE," + " ENGINE," + " EXTRA" + " FROM INFORMATION_SCHEMA.FILES" + " WHERE FILE_TYPE = 'UNDO LOG'" + " AND FILE_NAME IS NOT NULL", + 256, 1024); + if(ts_where) + { + dynstr_append_checked(&sqlbuf, + " AND LOGFILE_GROUP_NAME IN (" + "SELECT DISTINCT LOGFILE_GROUP_NAME" + " FROM INFORMATION_SCHEMA.FILES" + " WHERE FILE_TYPE = 'DATAFILE'" + ); + dynstr_append_checked(&sqlbuf, ts_where); + dynstr_append_checked(&sqlbuf, ")"); + } + dynstr_append_checked(&sqlbuf, + " GROUP BY LOGFILE_GROUP_NAME, FILE_NAME" + ", ENGINE" + " ORDER BY LOGFILE_GROUP_NAME"); + + if (mysql_query(mysql, sqlbuf.str) || + !(tableres = mysql_store_result(mysql))) + { + if (mysql_errno(mysql) == ER_BAD_TABLE_ERROR || + mysql_errno(mysql) == ER_BAD_DB_ERROR || + mysql_errno(mysql) == ER_UNKNOWN_TABLE) + { + fprintf(md_result_file, + "\n--\n-- Not dumping tablespaces as no INFORMATION_SCHEMA.FILES" + " table on this server\n--\n"); + check_io(md_result_file); + return 0; + } + + my_printf_error(0, "Error: Couldn't dump tablespaces %s", + MYF(0), mysql_error(mysql)); + return 1; + } + + buf[0]= 0; + while ((row= mysql_fetch_row(tableres))) + { + if (strcmp(buf, row[0]) != 0) + first= 1; + if (first) + { + if (!opt_xml && opt_comments) + { + fprintf(md_result_file,"\n--\n-- Logfile group: %s\n--\n", row[0]); + check_io(md_result_file); + } + fprintf(md_result_file, "\nCREATE"); + } + else + { + fprintf(md_result_file, "\nALTER"); + } + fprintf(md_result_file, + " LOGFILE GROUP %s\n" + " ADD UNDOFILE '%s'\n", + row[0], + row[1]); + if (first) + { + ubs= strstr(row[5],extra_format); + if(!ubs) + break; + ubs+= strlen(extra_format); + endsemi= strstr(ubs,";"); + if(endsemi) + endsemi[0]= '\0'; + fprintf(md_result_file, + " UNDO_BUFFER_SIZE %s\n", + ubs); + } + fprintf(md_result_file, + " INITIAL_SIZE %s\n" + " ENGINE=%s;\n", + row[3], + row[4]); + check_io(md_result_file); + if (first) + { + first= 0; + strxmov(buf, row[0], NullS); + } + } + dynstr_free(&sqlbuf); + init_dynamic_string_checked(&sqlbuf, + "SELECT DISTINCT TABLESPACE_NAME," + " FILE_NAME," + " LOGFILE_GROUP_NAME," + " EXTENT_SIZE," + " INITIAL_SIZE," + " ENGINE" + " FROM INFORMATION_SCHEMA.FILES" + " WHERE FILE_TYPE = 'DATAFILE'", + 256, 1024); + + if(ts_where) + dynstr_append_checked(&sqlbuf, ts_where); + + dynstr_append_checked(&sqlbuf, " ORDER BY TABLESPACE_NAME, LOGFILE_GROUP_NAME"); + + if (mysql_query_with_error_report(mysql, &tableres, sqlbuf.str)) + return 1; + + buf[0]= 0; + while ((row= mysql_fetch_row(tableres))) + { + if (strcmp(buf, row[0]) != 0) + first= 1; + if (first) + { + if (!opt_xml && opt_comments) + { + fprintf(md_result_file,"\n--\n-- Tablespace: %s\n--\n", row[0]); + check_io(md_result_file); + } + fprintf(md_result_file, "\nCREATE"); + } + else + { + fprintf(md_result_file, "\nALTER"); + } + fprintf(md_result_file, + " TABLESPACE %s\n" + " ADD DATAFILE '%s'\n", + row[0], + row[1]); + if (first) + { + fprintf(md_result_file, + " USE LOGFILE GROUP %s\n" + " EXTENT_SIZE %s\n", + row[2], + row[3]); + } + fprintf(md_result_file, + " INITIAL_SIZE %s\n" + " ENGINE=%s;\n", + row[4], + row[5]); + check_io(md_result_file); + if (first) + { + first= 0; + strxmov(buf, row[0], NullS); + } + } + + dynstr_free(&sqlbuf); + return 0; +} + static int dump_all_databases() { MYSQL_ROW row; @@ -2963,8 +3371,12 @@ static int dump_all_tables_in_db(char *database) init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024); for (numrows= 0 ; (table= getTableName(1)) ; numrows++) { - dynstr_append_checked(&query, quote_name(table, table_buff, 1)); - dynstr_append_checked(&query, " READ /*!32311 LOCAL */,"); + char *end= strmov(afterdot, table); + if (include_table(hash_key,end - hash_key)) + { + dynstr_append_checked(&query, quote_name(table, table_buff, 1)); + dynstr_append_checked(&query, " READ /*!32311 LOCAL */,"); + } } if (numrows && mysql_real_query(mysql, query.str, query.length-1)) DB_error(mysql, "when using LOCK TABLES"); @@ -2990,6 +3402,12 @@ static int dump_all_tables_in_db(char *database) dump_triggers_for_table(table, database); } } + if (opt_events && !opt_xml && + mysql_get_server_version(mysql) >= 50106) + { + DBUG_PRINT("info", ("Dumping events for database %s", database)); + dump_events_for_db(database); + } if (opt_routines && !opt_xml && mysql_get_server_version(mysql) >= 50009) { @@ -3118,14 +3536,14 @@ static char *get_actual_table_name(const char *old_table_name, MEM_ROOT *root) static int dump_selected_tables(char *db, char **table_names, int tables) { - char table_buff[NAME_LEN*+3]; + char table_buff[NAME_LEN*2+3]; DYNAMIC_STRING lock_tables_query; MEM_ROOT root; char **dump_tables, **pos, **end; DBUG_ENTER("dump_selected_tables"); if (init_dumping(db, init_dumping_tables)) - return 1; + DBUG_RETURN(1); init_alloc_root(&root, 8192, 0); if (!(dump_tables= pos= (char**) alloc_root(&root, tables * sizeof(char *)))) @@ -3186,6 +3604,12 @@ static int dump_selected_tables(char *db, char **table_names, int tables) for (pos= dump_tables; pos < end; pos++) get_view_structure(*pos, db); } + if (opt_events && !opt_xml && + mysql_get_server_version(mysql) >= 50106) + { + DBUG_PRINT("info", ("Dumping events for database %s", db)); + dump_events_for_db(db); + } /* obtain dump of routines (procs/functions) */ if (opt_routines && !opt_xml && mysql_get_server_version(mysql) >= 50009) @@ -3881,16 +4305,27 @@ int main(int argc, char **argv) if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */ goto err; + if (opt_alltspcs) + dump_all_tablespaces(); + if (opt_alldbs) + { + if (!opt_alltspcs && !opt_notspcs) + dump_all_tablespaces(); dump_all_databases(); + } else if (argc > 1 && !opt_databases) { /* Only one database and selected table(s) */ + if (!opt_alltspcs && !opt_notspcs) + dump_tablespaces_for_tables(*argv, (argv + 1), (argc -1)); dump_selected_tables(*argv, (argv + 1), (argc - 1)); } else { /* One or more databases, all tables */ + if (!opt_alltspcs && !opt_notspcs) + dump_tablespaces_for_databases(argv); dump_databases(argv); } diff --git a/client/mysqlimport.c b/client/mysqlimport.c index e7bf1cfd889..c037da9c0b9 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -24,10 +24,21 @@ ** * * ** ************************* */ -#define IMPORT_VERSION "3.5" +#define IMPORT_VERSION "3.6" #include "client_priv.h" #include "mysql_version.h" +#ifdef HAVE_LIBPTHREAD +#include <my_pthread.h> +#endif + + +/* Global Thread counter */ +uint counter; +#ifdef HAVE_LIBPTHREAD +pthread_mutex_t counter_mutex; +pthread_cond_t count_threshhold; +#endif static void db_error_with_table(MYSQL *mysql, char *table); static void db_error(MYSQL *mysql); @@ -38,8 +49,8 @@ static char *add_load_option(char *ptr,const char *object, static my_bool verbose=0,lock_tables=0,ignore_errors=0,opt_delete=0, replace=0,silent=0,ignore=0,opt_compress=0, opt_low_priority= 0, tty_password= 0; -static uint opt_local_file=0; -static MYSQL mysql_connection; +static my_bool info_flag= 0; +static uint opt_use_threads=0, opt_local_file=0; static char *opt_password=0, *current_user=0, *current_host=0, *current_db=0, *fields_terminated=0, *lines_terminated=0, *enclosed=0, *opt_enclosed=0, @@ -76,6 +87,8 @@ static struct my_option my_long_options[] = 0, 0, 0}, {"debug",'#', "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", (gptr*) &info_flag, + (gptr*) &info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"delete", 'd', "First delete all rows from table.", (gptr*) &opt_delete, (gptr*) &opt_delete, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"fields-terminated-by", OPT_FTB, @@ -107,8 +120,9 @@ static struct my_option my_long_options[] = REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"local", 'L', "Read all files through the client.", (gptr*) &opt_local_file, (gptr*) &opt_local_file, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"lock-tables", 'l', "Lock all tables for write.", (gptr*) &lock_tables, - (gptr*) &lock_tables, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"lock-tables", 'l', "Lock all tables for write (this disables threads).", + (gptr*) &lock_tables, (gptr*) &lock_tables, 0, GET_BOOL, NO_ARG, + 0, 0, 0, 0, 0, 0}, {"low-priority", OPT_LOW_PRIORITY, "Use LOW_PRIORITY when updating the table.", (gptr*) &opt_low_priority, (gptr*) &opt_low_priority, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -137,6 +151,11 @@ static struct my_option my_long_options[] = (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #include <sslopt-longopts.h> + {"use-threads", OPT_USE_THREADS, + "Load files in parallel. The argument is the number " + "of threads to use for loading data.", + (gptr*) &opt_use_threads, (gptr*) &opt_use_threads, 0, + GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifndef DONT_ALLOW_USER_CHANGE {"user", 'u', "User for login if not current user.", (gptr*) ¤t_user, (gptr*) ¤t_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -212,14 +231,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; #endif case OPT_MYSQL_PROTOCOL: - { - if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0) - { - fprintf(stderr, "Unknown option to protocol: %s\n", argument); - exit(1); - } + opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib, + opt->name); break; - } case '#': DBUG_PUSH(argument ? argument : "d:t:o"); break; @@ -269,7 +283,7 @@ static int get_options(int *argc, char ***argv) -static int write_to_table(char *filename, MYSQL *sock) +static int write_to_table(char *filename, MYSQL *mysql) { char tablename[FN_REFLEN], hard_path[FN_REFLEN], sql_statement[FN_REFLEN*16+256], *end; @@ -277,7 +291,7 @@ static int write_to_table(char *filename, MYSQL *sock) DBUG_PRINT("enter",("filename: %s",filename)); fn_format(tablename, filename, "", "", 1 | 2); /* removes path & ext. */ - if (! opt_local_file) + if (!opt_local_file) strmov(hard_path,filename); else my_load_path(hard_path, filename, NULL); /* filename includes the path */ @@ -286,10 +300,14 @@ static int write_to_table(char *filename, MYSQL *sock) { if (verbose) fprintf(stdout, "Deleting the old data from table %s\n", tablename); +#ifdef HAVE_SNPRINTF + snprintf(sql_statement, FN_REFLEN*16+256, "DELETE FROM %s", tablename); +#else sprintf(sql_statement, "DELETE FROM %s", tablename); - if (mysql_query(sock, sql_statement)) +#endif + if (mysql_query(mysql, sql_statement)) { - db_error_with_table(sock, tablename); + db_error_with_table(mysql, tablename); DBUG_RETURN(1); } } @@ -328,17 +346,17 @@ static int write_to_table(char *filename, MYSQL *sock) end= strmov(strmov(strmov(end, " ("), opt_columns), ")"); *end= '\0'; - if (mysql_query(sock, sql_statement)) + if (mysql_query(mysql, sql_statement)) { - db_error_with_table(sock, tablename); + db_error_with_table(mysql, tablename); DBUG_RETURN(1); } if (!silent) { - if (mysql_info(sock)) /* If NULL-pointer, print nothing */ + if (mysql_info(mysql)) /* If NULL-pointer, print nothing */ { fprintf(stdout, "%s.%s: %s\n", current_db, tablename, - mysql_info(sock)); + mysql_info(mysql)); } } DBUG_RETURN(0); @@ -346,7 +364,7 @@ static int write_to_table(char *filename, MYSQL *sock) -static void lock_table(MYSQL *sock, int tablecount, char **raw_tablename) +static void lock_table(MYSQL *mysql, int tablecount, char **raw_tablename) { DYNAMIC_STRING query; int i; @@ -361,72 +379,74 @@ static void lock_table(MYSQL *sock, int tablecount, char **raw_tablename) dynstr_append(&query, tablename); dynstr_append(&query, " WRITE,"); } - if (mysql_real_query(sock, query.str, query.length-1)) - db_error(sock); /* We shall countinue here, if --force was given */ + if (mysql_real_query(mysql, query.str, query.length-1)) + db_error(mysql); /* We shall countinue here, if --force was given */ } -static MYSQL *db_connect(char *host, char *database, char *user, char *passwd) +static MYSQL *db_connect(char *host, char *database, + char *user, char *passwd) { - MYSQL *sock; + MYSQL *mysql; if (verbose) fprintf(stdout, "Connecting to %s\n", host ? host : "localhost"); - mysql_init(&mysql_connection); + if (!(mysql= mysql_init(NULL))) + return 0; if (opt_compress) - mysql_options(&mysql_connection,MYSQL_OPT_COMPRESS,NullS); + mysql_options(mysql,MYSQL_OPT_COMPRESS,NullS); if (opt_local_file) - mysql_options(&mysql_connection,MYSQL_OPT_LOCAL_INFILE, + mysql_options(mysql,MYSQL_OPT_LOCAL_INFILE, (char*) &opt_local_file); #ifdef HAVE_OPENSSL if (opt_use_ssl) - mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, + mysql_ssl_set(mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, opt_ssl_capath, opt_ssl_cipher); - mysql_options(&mysql_connection,MYSQL_OPT_SSL_VERIFY_SERVER_CERT, + mysql_options(mysql,MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (char*)&opt_ssl_verify_server_cert); #endif if (opt_protocol) - mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); + mysql_options(mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); #ifdef HAVE_SMEM if (shared_memory_base_name) - mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); + mysql_options(mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); #endif - if (!(sock= mysql_real_connect(&mysql_connection,host,user,passwd, - database,opt_mysql_port,opt_mysql_unix_port, - 0))) + if (!(mysql_real_connect(mysql,host,user,passwd, + database,opt_mysql_port,opt_mysql_unix_port, + 0))) { ignore_errors=0; /* NO RETURN FROM db_error */ - db_error(&mysql_connection); + db_error(mysql); } - mysql_connection.reconnect= 0; + mysql->reconnect= 0; if (verbose) fprintf(stdout, "Selecting database %s\n", database); - if (mysql_select_db(sock, database)) + if (mysql_select_db(mysql, database)) { ignore_errors=0; - db_error(&mysql_connection); + db_error(mysql); } - return sock; + return mysql; } -static void db_disconnect(char *host, MYSQL *sock) +static void db_disconnect(char *host, MYSQL *mysql) { if (verbose) fprintf(stdout, "Disconnecting from %s\n", host ? host : "localhost"); - mysql_close(sock); + mysql_close(mysql); } -static void safe_exit(int error, MYSQL *sock) +static void safe_exit(int error, MYSQL *mysql) { if (ignore_errors) return; - if (sock) - mysql_close(sock); + if (mysql) + mysql_close(mysql); exit(error); } @@ -434,8 +454,8 @@ static void safe_exit(int error, MYSQL *sock) static void db_error_with_table(MYSQL *mysql, char *table) { - my_printf_error(0,"Error: %s, when using table: %s", - MYF(0), mysql_error(mysql), table); + my_printf_error(0,"Error: %d, %s, when using table: %s", + MYF(0), mysql_errno(mysql), mysql_error(mysql), table); safe_exit(1, mysql); } @@ -443,7 +463,7 @@ static void db_error_with_table(MYSQL *mysql, char *table) static void db_error(MYSQL *mysql) { - my_printf_error(0,"Error: %s", MYF(0), mysql_error(mysql)); + my_printf_error(0,"Error: %d %s", MYF(0), mysql_errno(mysql), mysql_error(mysql)); safe_exit(1, mysql); } @@ -497,13 +517,55 @@ static char *field_escape(char *to,const char *from,uint length) return to; } +int exitcode= 0; + +#ifdef HAVE_LIBPTHREAD +pthread_handler_t worker_thread(void *arg) +{ + int error; + char *raw_table_name= (char *)arg; + MYSQL *mysql= 0; + + if (mysql_thread_init()) + goto error; + + if (!(mysql= db_connect(current_host,current_db,current_user,opt_password))) + { + goto error; + } + + if (mysql_query(mysql, "/*!40101 set @@character_set_database=binary */;")) + { + db_error(mysql); /* We shall countinue here, if --force was given */ + goto error; + } + + /* + We are not currently catching the error here. + */ + if((error= write_to_table(raw_table_name, mysql))) + if (exitcode == 0) + exitcode= error; + +error: + if (mysql) + db_disconnect(current_host, mysql); + + pthread_mutex_lock(&counter_mutex); + counter--; + pthread_cond_signal(&count_threshhold); + pthread_mutex_unlock(&counter_mutex); + my_thread_end(); + + return 0; +} +#endif int main(int argc, char **argv) { - int exitcode=0, error=0; + int error=0; char **argv_to_free; - MYSQL *sock=0; MY_INIT(argv[0]); load_defaults("my",load_default_groups,&argc,&argv); @@ -514,30 +576,89 @@ int main(int argc, char **argv) free_defaults(argv_to_free); return(1); } - if (!(sock= db_connect(current_host,current_db,current_user,opt_password))) - { - free_defaults(argv_to_free); - return(1); /* purecov: deadcode */ - } - if (mysql_query(sock, "/*!40101 set @@character_set_database=binary */;")) +#ifdef HAVE_LIBPTHREAD + if (opt_use_threads && !lock_tables) { - db_error(sock); /* We shall countinue here, if --force was given */ - return(1); + pthread_t mainthread; /* Thread descriptor */ + pthread_attr_t attr; /* Thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, + PTHREAD_CREATE_DETACHED); + + VOID(pthread_mutex_init(&counter_mutex, NULL)); + VOID(pthread_cond_init(&count_threshhold, NULL)); + + for (counter= 0; *argv != NULL; argv++) /* Loop through tables */ + { + pthread_mutex_lock(&counter_mutex); + while (counter == opt_use_threads) + { + struct timespec abstime; + + set_timespec(abstime, 3); + pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime); + } + /* Before exiting the lock we set ourselves up for the next thread */ + counter++; + pthread_mutex_unlock(&counter_mutex); + /* now create the thread */ + if (pthread_create(&mainthread, &attr, worker_thread, + (void *)*argv) != 0) + { + pthread_mutex_lock(&counter_mutex); + counter--; + pthread_mutex_unlock(&counter_mutex); + fprintf(stderr,"%s: Could not create thread\n", + my_progname); + } + } + + /* + We loop until we know that all children have cleaned up. + */ + pthread_mutex_lock(&counter_mutex); + while (counter) + { + struct timespec abstime; + + set_timespec(abstime, 3); + pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime); + } + pthread_mutex_unlock(&counter_mutex); + VOID(pthread_mutex_destroy(&counter_mutex)); + VOID(pthread_cond_destroy(&count_threshhold)); + pthread_attr_destroy(&attr); } + else +#endif + { + MYSQL *mysql= 0; + if (!(mysql= db_connect(current_host,current_db,current_user,opt_password))) + { + free_defaults(argv_to_free); + return(1); /* purecov: deadcode */ + } - if (lock_tables) - lock_table(sock, argc, argv); - for (; *argv != NULL; argv++) - if ((error=write_to_table(*argv, sock))) - if (exitcode == 0) - exitcode = error; - db_disconnect(current_host, sock); + if (mysql_query(mysql, "/*!40101 set @@character_set_database=binary */;")) + { + db_error(mysql); /* We shall countinue here, if --force was given */ + return(1); + } + + if (lock_tables) + lock_table(mysql, argc, argv); + for (; *argv != NULL; argv++) + if ((error= write_to_table(*argv, mysql))) + if (exitcode == 0) + exitcode= error; + db_disconnect(current_host, mysql); + } my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); #ifdef HAVE_SMEM my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); #endif free_defaults(argv_to_free); - my_end(0); + my_end(info_flag ? MY_CHECK_ERROR : 0); return(exitcode); } diff --git a/client/mysqlmanager-pwgen.c b/client/mysqlmanager-pwgen.c deleted file mode 100644 index 716a1e4bf4e..00000000000 --- a/client/mysqlmanager-pwgen.c +++ /dev/null @@ -1,160 +0,0 @@ -/* Copyright (C) 2000 MySQL 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 - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#define MANAGER_PWGEN_VERSION "1.4" - -#include <my_global.h> -#include <m_ctype.h> -#include <my_sys.h> -#include <m_string.h> -#include <mysql_version.h> -#include <errno.h> -#include <my_getopt.h> -#include <md5.h> - -const char* outfile=0,*user="root"; - -static struct my_option my_long_options[] = -{ - {"output-file", 'o', "Write the output to the file with the given name.", - (gptr*) &outfile, (gptr*) &outfile, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, - 0, 0}, - {"user", 'u', "Put given user in the password file.", (gptr*) &user, - (gptr*) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"help", '?', "Display this message and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, - 0, 0, 0, 0, 0, 0}, - {"version", 'V', "Display version info.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, - 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} -}; - -static void die(const char* fmt, ...) -{ - va_list args; - DBUG_ENTER("die"); - va_start(args, fmt); - if (fmt) - { - fprintf(stderr, "%s: ", my_progname); - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); - fflush(stderr); - } - va_end(args); - exit(1); -} - -static void print_version(void) -{ - printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname, - MANAGER_PWGEN_VERSION, - MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); -} - -void usage() -{ - print_version(); - printf("MySQL AB, by Sasha\n"); - printf("This software comes with ABSOLUTELY NO WARRANTY\n\n"); - printf("Generates a password file to be used by mysqltest.\n\n"); - printf("Usage: %s [OPTIONS]\n", my_progname); - my_print_help(my_long_options); - my_print_variables(my_long_options); -} - -static my_bool -get_one_option(int optid, const struct my_option *opt __attribute__((unused)), - char *argument __attribute__((unused))) -{ - switch (optid) { - case '?': - usage(); - exit(0); - case 'V': - print_version(); - exit(0); - } - return 0; -} - - -int parse_args(int argc, char** argv) -{ - int ho_error; - - if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) - exit(ho_error); - - return 0; -} - -void get_pass(char* pw, int len) -{ - FILE* fp; - char* pw_end=pw+len; - /* - /dev/random is more secure than rand() because the seed is easy to - predict, so we resort to rand() only if /dev/random is not available - */ - if ((fp=fopen("/dev/random","r"))) - { - fread(pw,len,1,fp); - fclose(fp); - while (pw<pw_end) - { - char tmp= 'a'+((uint)*pw % 26); - *pw++= tmp; - } - } - else - { - srand(time(NULL)); - while (pw<pw_end) - { - char tmp= 'a'+((uint)*pw % 26); - *pw++= tmp; - } - } - *pw_end=0; -} - - -int main(int argc, char** argv) -{ - FILE* fp; - my_MD5_CTX context; - uchar digest[16]; - char pw[17]; - uint i; - - MY_INIT(argv[0]); - parse_args(argc,argv); - if (!outfile) - die("Missing --output-file"); - - if (!(fp=fopen(outfile,"w"))) - die("Could not open '%s'(errno=%d)",outfile,errno); - get_pass(pw,sizeof(pw)-1); - my_MD5Init(&context); - my_MD5Update(&context,(uchar*) pw,sizeof(pw)-1); - my_MD5Final(digest,&context); - fprintf(fp,"%s:",user); - for (i=0;i<sizeof(digest);i++) - fprintf(fp,"%02x",digest[i]); - fprintf(fp,"\n"); - fclose(fp); - printf("%s\n",pw); - return 0; -} diff --git a/client/mysqlmanagerc.c b/client/mysqlmanagerc.c deleted file mode 100644 index 1fdedab97fb..00000000000 --- a/client/mysqlmanagerc.c +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright (C) 2000 MySQL 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 - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#define MANAGER_CLIENT_VERSION "1.4" - -#include <my_global.h> -#include <mysql.h> -#include <mysql_version.h> -#include <mysqld_error.h> -#include <my_sys.h> -#include <m_string.h> -#include <my_getopt.h> -#include <stdarg.h> -#include <sys/stat.h> -#include <unistd.h> - -#ifndef MYSQL_MANAGER_PORT -#define MYSQL_MANAGER_PORT 9305 -#endif - -static void die(const char* fmt, ...); - -const char* user="root",*host="localhost"; -char* pass=0; -my_bool quiet=0; -uint port=MYSQL_MANAGER_PORT; -static const char *load_default_groups[]= { "mysqlmanagerc",0 }; -char** default_argv; -MYSQL_MANAGER *manager; -FILE* fp, *fp_out; - -static struct my_option my_long_options[] = -{ - {"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"user", 'u', "User for login.", (gptr*) &user, (gptr*) &user, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"password", 'p', "Password to use when connecting to server.", - 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"port", 'P', "Port number to use for connection.", (gptr*) &port, - (gptr*) &port, 0, GET_UINT, REQUIRED_ARG, MYSQL_MANAGER_PORT, 0, 0, 0, 0, - 0}, - {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, - 0, 0, 0, 0, 0, 0}, - {"version", 'V', "Output version information and exit.", 0, 0, 0, - GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"quiet", 'q', "Suppress all normal output.", (gptr*) &quiet, (gptr*) &quiet, - 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} -}; - -static void die(const char* fmt, ...) -{ - va_list args; - DBUG_ENTER("die"); - va_start(args, fmt); - if (fmt) - { - fprintf(stderr, "%s: ", my_progname); - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); - fflush(stderr); - } - va_end(args); - exit(1); -} - -static void print_version(void) -{ - printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname, - MANAGER_CLIENT_VERSION, - MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); -} - -void usage() -{ - print_version(); - printf("MySQL AB, by Sasha\n"); - printf("This software comes with ABSOLUTELY NO WARRANTY\n\n"); - printf("Command-line client for MySQL manager daemon.\n\n"); - printf("Usage: %s [OPTIONS] < command_file\n", my_progname); - my_print_help(my_long_options); - printf(" --no-defaults Don't read default options from any options file.\n"); - my_print_variables(my_long_options); -} - - -static my_bool -get_one_option(int optid, const struct my_option *opt __attribute__((unused)), - char *argument) -{ - my_bool tty_password=0; - - switch (optid) { - case 'p': - if (argument) - { - my_free(pass, MYF(MY_ALLOW_ZERO_PTR)); - pass= my_strdup(argument, MYF(MY_FAE)); - while (*argument) *argument++= 'x'; /* Destroy argument */ - } - else - tty_password=1; - break; - case 'V': - print_version(); - exit(0); - case '?': - usage(); - exit(0); - } - return 0; -} - - -int parse_args(int argc, char **argv) -{ - int ho_error; - - load_defaults("my",load_default_groups,&argc,&argv); - default_argv= argv; - - if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) - exit(ho_error); - - return 0; -} - - -int main(int argc, char** argv) -{ - MY_INIT(argv[0]); - fp=stdin; - fp_out=stdout; - parse_args(argc,argv); - if (!(manager=mysql_manager_init(0))) - die("Failed in mysql_manager_init()"); - if (!mysql_manager_connect(manager,host,user,pass,port)) - die("Could not connect to MySQL manager: %s (%d)",manager->last_error, - manager->last_errno); - for (;!feof(fp);) - { - char buf[4096]; - if (!fgets(buf,sizeof(buf),fp)) - break; - if (!quiet) - fprintf(fp_out,"<<%s",buf); - if (mysql_manager_command(manager,buf,strlen(buf))) - die("Error in command: %s (%d)",manager->last_error,manager->last_errno); - while (!manager->eof) - { - if (mysql_manager_fetch_line(manager,buf,sizeof(buf))) - die("Error fetching result line: %s (%d)", manager->last_error, - manager->last_errno); - if (!quiet) - fprintf(fp_out,">>%s\n",buf); - } - } - mysql_manager_close(manager); - return 0; -} diff --git a/client/mysqlshow.c b/client/mysqlshow.c index 5be01cc5a52..0c6a6229964 100644 --- a/client/mysqlshow.c +++ b/client/mysqlshow.c @@ -15,7 +15,7 @@ /* Show databases, tables or columns */ -#define SHOW_VERSION "9.5" +#define SHOW_VERSION "9.6" #include "client_priv.h" #include <my_sys.h> @@ -27,8 +27,8 @@ #include <sslopt-vars.h> static my_string host=0,opt_password=0,user=0; -static my_bool opt_show_keys= 0, opt_compress= 0, opt_count=0, opt_status= 0, - tty_password= 0, opt_table_type= 0; +static my_bool opt_show_keys= 0, opt_compress= 0, opt_count=0, opt_status= 0; +static my_bool tty_password= 0, opt_table_type= 0, info_flag= 0; static uint opt_verbose=0; static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME; @@ -128,8 +128,7 @@ int main(int argc, char **argv) } mysql.reconnect= 1; - switch (argc) - { + switch (argc) { case 0: error=list_dbs(&mysql,wild); break; case 1: if (opt_status) @@ -150,7 +149,7 @@ int main(int argc, char **argv) #ifdef HAVE_SMEM my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); #endif - my_end(0); + my_end(info_flag ? MY_CHECK_ERROR : 0); exit(error ? 1 : 0); return 0; /* No compiler warnings */ } @@ -176,6 +175,8 @@ static struct my_option my_long_options[] = 0, 0, 0}, {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", (gptr*) &info_flag, + (gptr*) &info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0, GET_STR, @@ -286,14 +287,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), #endif break; case OPT_MYSQL_PROTOCOL: - { - if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0) - { - fprintf(stderr, "Unknown option to protocol: %s\n", argument); - exit(1); - } + opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib, + opt->name); break; - } case '#': DBUG_PUSH(argument ? argument : "d:t:o"); break; diff --git a/client/mysqlslap.c b/client/mysqlslap.c new file mode 100644 index 00000000000..0335922881a --- /dev/null +++ b/client/mysqlslap.c @@ -0,0 +1,2104 @@ +/* Copyright (C) 2005 MySQL 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + original idea: Brian Aker via playing with ab for too many years + coded by: Patrick Galbraith +*/ + + +/* + MySQL Slap + + A simple program designed to work as if multiple clients querying the database, + then reporting the timing of each stage. + + MySQL slap runs three stages: + 1) Create schema,table, and optionally any SP or data you want to beign + the test with. (single client) + 2) Load test (many clients) + 3) Cleanup (disconnection, drop table if specified, single client) + + Examples: + + Supply your own create and query SQL statements, with 50 clients + querying (200 selects for each): + + mysqlslap --create="CREATE TABLE A (a int);INSERT INTO A (23)" \ + --query="SELECT * FROM A" --concurrency=50 --iterations=200 + + Let the program build the query SQL statement with a table of two int + columns, three varchar columns, five clients querying (20 times each), + don't create the table or insert the data (using the previous test's + schema and data): + + mysqlslap --concurrency=5 --iterations=20 \ + --number-int-cols=2 --number-char-cols=3 \ + --auto-generate-sql + + Tell the program to load the create, insert and query SQL statements from + the specified files, where the create.sql file has multiple table creation + statements delimited by ';' and multiple insert statements delimited by ';'. + The --query file will have multiple queries delimited by ';', run all the + load statements, and then run all the queries in the query file + with five clients (five times each): + + mysqlslap --concurrency=5 \ + --iterations=5 --query=query.sql --create=create.sql \ + --delimiter=";" + +TODO: + Add language for better tests + String length for files and those put on the command line are not + setup to handle binary data. + More stats + Break up tests and run them on multiple hosts at once. + Allow output to be fed into a database directly. + +*/ + +#define SHOW_VERSION "0.9" + +#define HUGE_STRING_LENGTH 8196 +#define RAND_STRING_SIZE 126 + +/* Types */ +#define SELECT_TYPE 0 +#define UPDATE_TYPE 1 +#define INSERT_TYPE 2 +#define UPDATE_TYPE_REQUIRES_PREFIX 3 +#define CREATE_TABLE_TYPE 4 +#define SELECT_TYPE_REQUIRES_PREFIX 5 + +#include "client_priv.h" +#include <mysqld_error.h> +#include <my_dir.h> +#include <signal.h> +#include <stdarg.h> +#include <sslopt-vars.h> +#include <sys/types.h> +#ifndef __WIN__ +#include <sys/wait.h> +#endif +#include <ctype.h> + +#ifdef __WIN__ +#define srandom srand +#define random rand +#define snprintf _snprintf +#endif + +#ifdef HAVE_SMEM +static char *shared_memory_base_name=0; +#endif + +/* Global Thread counter */ +uint thread_counter; +pthread_mutex_t counter_mutex; +pthread_cond_t count_threshhold; +uint master_wakeup; +pthread_mutex_t sleeper_mutex; +pthread_cond_t sleep_threshhold; + +static char **defaults_argv; + +char **primary_keys; +unsigned long long primary_keys_number_of; + +static char *host= NULL, *opt_password= NULL, *user= NULL, + *user_supplied_query= NULL, + *user_supplied_pre_statements= NULL, + *user_supplied_post_statements= NULL, + *default_engine= NULL, + *opt_mysql_unix_port= NULL; + +const char *delimiter= "\n"; + +const char *create_schema_string= "mysqlslap"; + +static my_bool opt_preserve; + +static my_bool opt_only_print= FALSE; + +static my_bool opt_compress= FALSE, tty_password= FALSE, + opt_silent= FALSE, + auto_generate_sql_autoincrement= FALSE, + auto_generate_sql_guid_primary= FALSE, + auto_generate_sql= FALSE; +const char *auto_generate_sql_type= "mixed"; + +static unsigned long connect_flags= CLIENT_MULTI_RESULTS; + +static int verbose, delimiter_length; +const char *num_int_cols_opt; +const char *num_char_cols_opt; +/* Yes, we do set defaults here */ +static unsigned int num_int_cols= 1; +static unsigned int num_char_cols= 1; +static unsigned int num_int_cols_index= 0; +static unsigned int num_char_cols_index= 0; + +static unsigned int iterations; +static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME; +static ulonglong actual_queries= 0; +static ulonglong auto_actual_queries; +static ulonglong auto_generate_sql_unique_write_number; +static ulonglong auto_generate_sql_unique_query_number; +static unsigned int auto_generate_sql_secondary_indexes; +static ulonglong num_of_query; +static ulonglong auto_generate_sql_number; +const char *concurrency_str= NULL; +static char *create_string; +uint *concurrency; + +const char *default_dbug_option="d:t:o,/tmp/mysqlslap.trace"; +const char *opt_csv_str; +File csv_file; + +static uint opt_protocol= 0; + +static int get_options(int *argc,char ***argv); +static uint opt_mysql_port= 0; + +static const char *load_default_groups[]= { "mysqlslap","client",0 }; + +typedef struct statement statement; + +struct statement { + char *string; + size_t length; + unsigned char type; + char *option; + size_t option_length; + statement *next; +}; + +typedef struct option_string option_string; + +struct option_string { + char *string; + size_t length; + char *option; + size_t option_length; + option_string *next; +}; + +typedef struct stats stats; + +struct stats { + long int timing; + uint users; + unsigned long long rows; +}; + +typedef struct thread_context thread_context; + +struct thread_context { + statement *stmt; + ulonglong limit; +}; + +typedef struct conclusions conclusions; + +struct conclusions { + char *engine; + long int avg_timing; + long int max_timing; + long int min_timing; + uint users; + unsigned long long avg_rows; + /* The following are not used yet */ + unsigned long long max_rows; + unsigned long long min_rows; +}; + +static option_string *engine_options= NULL; +static statement *pre_statements= NULL; +static statement *post_statements= NULL; +static statement *create_statements= NULL, + *query_statements= NULL; + +/* Prototypes */ +void print_conclusions(conclusions *con); +void print_conclusions_csv(conclusions *con); +void generate_stats(conclusions *con, option_string *eng, stats *sptr); +uint parse_comma(const char *string, uint **range); +uint parse_delimiter(const char *script, statement **stmt, char delm); +uint parse_option(const char *origin, option_string **stmt, char delm); +static int drop_schema(MYSQL *mysql, const char *db); +uint get_random_string(char *buf); +static statement *build_table_string(void); +static statement *build_insert_string(void); +static statement *build_update_string(void); +static statement * build_select_string(my_bool key); +static int generate_primary_key_list(MYSQL *mysql, option_string *engine_stmt); +static int drop_primary_key_list(void); +static int create_schema(MYSQL *mysql, const char *db, statement *stmt, + option_string *engine_stmt); +static int run_scheduler(stats *sptr, statement *stmts, uint concur, + ulonglong limit); +pthread_handler_t run_task(void *p); +void statement_cleanup(statement *stmt); +void option_cleanup(option_string *stmt); +void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr); +static int run_statements(MYSQL *mysql, statement *stmt); + +static const char ALPHANUMERICS[]= + "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz"; + +#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1) + + +static long int timedif(struct timeval a, struct timeval b) +{ + register int us, s; + + us = a.tv_usec - b.tv_usec; + us /= 1000; + s = a.tv_sec - b.tv_sec; + s *= 1000; + return s + us; +} + +#ifdef __WIN__ +static int gettimeofday(struct timeval *tp, void *tzp) +{ + unsigned int ticks; + ticks= GetTickCount(); + tp->tv_usec= ticks*1000; + tp->tv_sec= ticks/1000; + + return 0; +} +#endif + +int main(int argc, char **argv) +{ + MYSQL mysql; + option_string *eptr; + + MY_INIT(argv[0]); + + load_defaults("my",load_default_groups,&argc,&argv); + defaults_argv=argv; + if (get_options(&argc,&argv)) + { + free_defaults(defaults_argv); + my_end(0); + exit(1); + } + + /* Seed the random number generator if we will be using it. */ + if (auto_generate_sql) + srandom((uint)time(NULL)); + + /* globals? Yes, so we only have to run strlen once */ + delimiter_length= strlen(delimiter); + + if (argc > 2) + { + fprintf(stderr,"%s: Too many arguments\n",my_progname); + free_defaults(defaults_argv); + my_end(0); + 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); + + if (!opt_only_print) + { + if (!(mysql_real_connect(&mysql, host, user, opt_password, + NULL, opt_mysql_port, + opt_mysql_unix_port, connect_flags))) + { + fprintf(stderr,"%s: Error when connecting to server: %s\n", + my_progname,mysql_error(&mysql)); + free_defaults(defaults_argv); + my_end(0); + exit(1); + } + } + + VOID(pthread_mutex_init(&counter_mutex, NULL)); + VOID(pthread_cond_init(&count_threshhold, NULL)); + VOID(pthread_mutex_init(&sleeper_mutex, NULL)); + VOID(pthread_cond_init(&sleep_threshhold, NULL)); + + /* Main iterations loop */ + eptr= engine_options; + do + { + /* For the final stage we run whatever queries we were asked to run */ + uint *current; + + if (verbose >= 2) + printf("Starting Concurrency Test\n"); + + if (*concurrency) + { + for (current= concurrency; current && *current; current++) + concurrency_loop(&mysql, *current, eptr); + } + else + { + uint infinite= 1; + do { + concurrency_loop(&mysql, infinite, eptr); + } + while (infinite++); + } + + if (!opt_preserve) + drop_schema(&mysql, create_schema_string); + + } while (eptr ? (eptr= eptr->next) : 0); + + VOID(pthread_mutex_destroy(&counter_mutex)); + VOID(pthread_cond_destroy(&count_threshhold)); + VOID(pthread_mutex_destroy(&sleeper_mutex)); + VOID(pthread_cond_destroy(&sleep_threshhold)); + + if (!opt_only_print) + mysql_close(&mysql); /* Close & free connection */ + + /* now free all the strings we created */ + if (opt_password) + my_free((gptr)opt_password, MYF(0)); + + my_free((gptr)concurrency, MYF(0)); + + statement_cleanup(create_statements); + statement_cleanup(query_statements); + statement_cleanup(pre_statements); + statement_cleanup(post_statements); + option_cleanup(engine_options); + +#ifdef HAVE_SMEM + if (shared_memory_base_name) + my_free((gptr)shared_memory_base_name, MYF(MY_ALLOW_ZERO_PTR)); +#endif + free_defaults(defaults_argv); + my_end(0); + + return 0; +} + +void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr) +{ + unsigned int x; + stats *head_sptr; + stats *sptr; + conclusions conclusion; + unsigned long long client_limit; + + head_sptr= (stats *)my_malloc(sizeof(stats) * iterations, + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + + bzero(&conclusion, sizeof(conclusions)); + + if (auto_actual_queries) + client_limit= auto_actual_queries; + else if (num_of_query) + client_limit= num_of_query / current; + else + client_limit= actual_queries; + + for (x= 0, sptr= head_sptr; x < iterations; x++, sptr++) + { + /* + We might not want to load any data, such as when we are calling + a stored_procedure that doesn't use data, or we know we already have + data in the table. + */ + if (!opt_preserve) + drop_schema(mysql, create_schema_string); + + /* First we create */ + if (create_statements) + create_schema(mysql, create_schema_string, create_statements, eptr); + + /* + If we generated GUID we need to build a list of them from creation that + we can later use. + */ + if (verbose >= 2) + printf("Generating primary key list\n"); + if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary) + generate_primary_key_list(mysql, eptr); + + if (pre_statements) + run_statements(mysql, pre_statements); + + run_scheduler(sptr, query_statements, current, client_limit); + + if (post_statements) + run_statements(mysql, post_statements); + + /* We are finished with this run */ + if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary) + drop_primary_key_list(); + } + + if (verbose >= 2) + printf("Generating stats\n"); + + generate_stats(&conclusion, eptr, head_sptr); + + if (!opt_silent) + print_conclusions(&conclusion); + if (opt_csv_str) + print_conclusions_csv(&conclusion); + + my_free((gptr)head_sptr, MYF(0)); + +} + + +static struct my_option my_long_options[] = +{ + {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, + 0, 0, 0, 0, 0, 0}, + {"auto-generate-sql", 'a', + "Generate SQL where not supplied by file or command line.", + (gptr*) &auto_generate_sql, (gptr*) &auto_generate_sql, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"auto-generate-sql-add-autoincrement", OPT_SLAP_AUTO_GENERATE_ADD_AUTO, + "Add autoincrement to auto-generated tables.", + (gptr*) &auto_generate_sql_autoincrement, + (gptr*) &auto_generate_sql_autoincrement, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"auto-generate-sql-execute-number", OPT_SLAP_AUTO_GENERATE_EXECUTE_QUERIES, + "Set this number to generate a set number of queries to run.\n", + (gptr*) &auto_actual_queries, (gptr*) &auto_actual_queries, + 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"auto-generate-sql-guid-primary", OPT_SLAP_AUTO_GENERATE_GUID_PRIMARY, + "Add GUID based primary keys to auto-generated tables.", + (gptr*) &auto_generate_sql_guid_primary, + (gptr*) &auto_generate_sql_guid_primary, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"auto-generate-sql-load-type", OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE, + "Load types are mixed, update, write, key, or read. Default is mixed\n", + (gptr*) &auto_generate_sql_type, (gptr*) &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, + "Number of secondary indexes to add auto-generated tables.", + (gptr*) &auto_generate_sql_secondary_indexes, + (gptr*) &auto_generate_sql_secondary_indexes, 0, + GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"auto-generate-sql-unique-query-number", + OPT_SLAP_AUTO_GENERATE_UNIQUE_QUERY_NUM, + "Number of unique queries auto tests", + (gptr*) &auto_generate_sql_unique_query_number, + (gptr*) &auto_generate_sql_unique_query_number, + 0, GET_ULL, REQUIRED_ARG, 10, 0, 0, 0, 0, 0}, + {"auto-generate-sql-unique-write-number", + OPT_SLAP_AUTO_GENERATE_UNIQUE_WRITE_NUM, + "Number of unique queries for auto-generate-sql-write-number", + (gptr*) &auto_generate_sql_unique_write_number, + (gptr*) &auto_generate_sql_unique_write_number, + 0, GET_ULL, REQUIRED_ARG, 10, 0, 0, 0, 0, 0}, + {"auto-generate-sql-write-number", OPT_SLAP_AUTO_GENERATE_WRITE_NUM, + "Number of rows to insert to used in read and write loads (default is 100).\n", + (gptr*) &auto_generate_sql_number, (gptr*) &auto_generate_sql_number, + 0, GET_ULL, REQUIRED_ARG, 100, 0, 0, 0, 0, 0}, + {"compress", 'C', "Use compression in server/client protocol.", + (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, + 0, 0, 0}, + {"concurrency", 'c', "Number of clients to simulate for query to run.", + (gptr*) &concurrency_str, (gptr*) &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.", + (gptr*) &create_string, (gptr*) &create_string, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"create-schema", OPT_CREATE_SLAP_SCHEMA, "Schema to run tests in.", + (gptr*) &create_schema_string, (gptr*) &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.", + (gptr*) &opt_csv_str, (gptr*) &opt_csv_str, 0, GET_STR, + OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", + (gptr*) &default_dbug_option, (gptr*) &default_dbug_option, 0, GET_STR, + OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"delimiter", 'F', + "Delimiter to use in SQL statements supplied in file or command line.", + (gptr*) &delimiter, (gptr*) &delimiter, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"engine", 'e', "Storage engine to use for creating the table.", + (gptr*) &default_engine, (gptr*) &default_engine, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"iterations", 'i', "Number of times too run the tests.", (gptr*) &iterations, + (gptr*) &iterations, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, + {"number-char-cols", 'x', + "Number of VARCHAR columns to create table with if specifying --auto-generate-sql ", + (gptr*) &num_char_cols_opt, (gptr*) &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 table with if specifying --auto-generate-sql.", + (gptr*) &num_int_cols_opt, (gptr*) &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).", + (gptr*) &num_of_query, (gptr*) &num_of_query, 0, + GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"only-print", OPT_MYSQL_ONLY_PRINT, + "This causes mysqlslap to not connect to the databases, but instead print " + "out what it would have done instead.", + (gptr*) &opt_only_print, (gptr*) &opt_only_print, 0, GET_BOOL, NO_ARG, + 0, 0, 0, 0, 0, 0}, + {"password", 'p', + "Password to use when connecting to server. If password is not given it's " + "asked from the tty.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef __WIN__ + {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, + NO_ARG, 0, 0, 0, 0, 0, 0}, +#endif + {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port, + (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, + 0}, + {"post-query", OPT_SLAP_POST_QUERY, + "Query to run or file containing query to run after executing.", + (gptr*) &user_supplied_post_statements, + (gptr*) &user_supplied_post_statements, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"pre-query", OPT_SLAP_PRE_QUERY, + "Query to run or file containing query to run before executing.", + (gptr*) &user_supplied_pre_statements, + (gptr*) &user_supplied_pre_statements, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"preserve-schema", OPT_MYSQL_PRESERVE_SCHEMA, + "Preserve the schema from the mysqlslap run, this happens unless " + "--auto-generate-sql or --create are used.", + (gptr*) &opt_preserve, (gptr*) &opt_preserve, 0, GET_BOOL, + NO_ARG, TRUE, 0, 0, 0, 0, 0}, + {"protocol", OPT_MYSQL_PROTOCOL, + "The protocol of connection (tcp,socket,pipe,memory).", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"query", 'q', "Query to run or file containing query to run.", + (gptr*) &user_supplied_query, (gptr*) &user_supplied_query, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef HAVE_SMEM + {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME, + "Base name of shared memory.", (gptr*) &shared_memory_base_name, + (gptr*) &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, +#endif + {"silent", 's', "Run program in silent mode - no output.", + (gptr*) &opt_silent, (gptr*) &opt_silent, 0, GET_BOOL, NO_ARG, + 0, 0, 0, 0, 0, 0}, + {"socket", 'S', "Socket file to use for connection.", + (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#include <sslopt-longopts.h> +#ifndef DONT_ALLOW_USER_CHANGE + {"user", 'u', "User for login if not current user.", (gptr*) &user, + (gptr*) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif + {"verbose", 'v', + "More verbose output; You can use this multiple times to get even more " + "verbose output.", (gptr*) &verbose, (gptr*) &verbose, 0, + GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, + NO_ARG, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} +}; + + +#include <help_start.h> + +static void print_version(void) +{ + printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,SHOW_VERSION, + MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); +} + + +static void usage(void) +{ + print_version(); + puts("Copyright (C) 2005 MySQL 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("Run a query multiple times against the server\n"); + printf("Usage: %s [OPTIONS]\n",my_progname); + print_defaults("my",load_default_groups); + my_print_help(my_long_options); +} + +#include <help_end.h> + +static my_bool +get_one_option(int optid, const struct my_option *opt __attribute__((unused)), + char *argument) +{ + DBUG_ENTER("get_one_option"); + switch(optid) { +#ifdef __NETWARE__ + case OPT_AUTO_CLOSE: + setscreenmode(SCR_AUTOCLOSE_ON_EXIT); + break; +#endif + case 'v': + verbose++; + break; + case 'p': + if (argument) + { + char *start= argument; + my_free((gptr)opt_password, MYF(MY_ALLOW_ZERO_PTR)); + opt_password= my_strdup(argument,MYF(MY_FAE)); + while (*argument) *argument++= 'x'; /* Destroy argument */ + if (*start) + start[1]= 0; /* Cut length of argument */ + tty_password= 0; + } + else + tty_password= 1; + break; + case 'W': +#ifdef __WIN__ + opt_protocol= MYSQL_PROTOCOL_PIPE; +#endif + break; + case OPT_MYSQL_PROTOCOL: + opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib, + opt->name); + break; + case '#': + DBUG_PUSH(argument ? argument : default_dbug_option); + break; +#include <sslopt-case.h> + case 'V': + print_version(); + exit(0); + break; + case '?': + case 'I': /* Info */ + usage(); + exit(0); + } + DBUG_RETURN(0); +} + + +uint +get_random_string(char *buf) +{ + char *buf_ptr= buf; + int x; + DBUG_ENTER("get_random_string"); + for (x= RAND_STRING_SIZE; x > 0; x--) + *buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE]; + DBUG_RETURN(buf_ptr - buf); +} + + +/* + build_table_string + + This function builds a create table query if the user opts to not supply + a file or string containing a create table statement +*/ +static statement * +build_table_string(void) +{ + char buf[HUGE_STRING_LENGTH]; + unsigned int col_count; + statement *ptr; + DYNAMIC_STRING table_string; + DBUG_ENTER("build_table_string"); + + DBUG_PRINT("info", ("num int cols %u num char cols %u", + num_int_cols, num_char_cols)); + + init_dynamic_string(&table_string, "", 1024, 1024); + + dynstr_append(&table_string, "CREATE TABLE `t1` ("); + + if (auto_generate_sql_autoincrement) + { + dynstr_append(&table_string, "id serial"); + + if (num_int_cols || num_char_cols) + dynstr_append(&table_string, ","); + } + + if (auto_generate_sql_guid_primary) + { + dynstr_append(&table_string, "id varchar(32) primary key"); + + if (num_int_cols || num_char_cols || auto_generate_sql_guid_primary) + dynstr_append(&table_string, ","); + } + + if (auto_generate_sql_secondary_indexes) + { + unsigned int count; + + for (count= 0; count < auto_generate_sql_secondary_indexes; count++) + { + if (count) /* Except for the first pass we add a comma */ + dynstr_append(&table_string, ","); + + if (snprintf(buf, HUGE_STRING_LENGTH, "id%d varchar(32) unique key", count) + > HUGE_STRING_LENGTH) + { + fprintf(stderr, "Memory Allocation error in create table\n"); + exit(1); + } + dynstr_append(&table_string, buf); + } + + if (num_int_cols || num_char_cols) + dynstr_append(&table_string, ","); + } + + if (num_int_cols) + for (col_count= 1; col_count <= num_int_cols; col_count++) + { + if (num_int_cols_index) + { + if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32), INDEX(intcol%d)", + col_count, col_count) > HUGE_STRING_LENGTH) + { + fprintf(stderr, "Memory Allocation error in create table\n"); + exit(1); + } + } + else + { + if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32) ", col_count) + > HUGE_STRING_LENGTH) + { + fprintf(stderr, "Memory Allocation error in create table\n"); + exit(1); + } + } + dynstr_append(&table_string, buf); + + if (col_count < num_int_cols || num_char_cols > 0) + dynstr_append(&table_string, ","); + } + + if (num_char_cols) + for (col_count= 1; col_count <= num_char_cols; col_count++) + { + if (num_char_cols_index) + { + if (snprintf(buf, HUGE_STRING_LENGTH, + "charcol%d VARCHAR(128), INDEX(charcol%d) ", + col_count, col_count) > HUGE_STRING_LENGTH) + { + fprintf(stderr, "Memory Allocation error in creating table\n"); + exit(1); + } + } + else + { + if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d VARCHAR(128)", + col_count) > HUGE_STRING_LENGTH) + { + fprintf(stderr, "Memory Allocation error in creating table\n"); + exit(1); + } + } + dynstr_append(&table_string, buf); + + if (col_count < num_char_cols) + dynstr_append(&table_string, ","); + } + + dynstr_append(&table_string, ")"); + ptr= (statement *)my_malloc(sizeof(statement), + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + ptr->string = (char *)my_malloc(table_string.length+1, + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + ptr->length= table_string.length+1; + ptr->type= CREATE_TABLE_TYPE; + strmov(ptr->string, table_string.str); + dynstr_free(&table_string); + DBUG_RETURN(ptr); +} + +/* + build_update_string() + + This function builds insert statements when the user opts to not supply + an insert file or string containing insert data +*/ +static statement * +build_update_string(void) +{ + char buf[HUGE_STRING_LENGTH]; + unsigned int col_count; + statement *ptr; + DYNAMIC_STRING update_string; + DBUG_ENTER("build_update_string"); + + init_dynamic_string(&update_string, "", 1024, 1024); + + dynstr_append(&update_string, "UPDATE t1 SET "); + + if (num_int_cols) + for (col_count= 1; col_count <= num_int_cols; col_count++) + { + if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d = %ld", col_count, + random()) > HUGE_STRING_LENGTH) + { + fprintf(stderr, "Memory Allocation error in creating update\n"); + exit(1); + } + dynstr_append(&update_string, buf); + + if (col_count < num_int_cols || num_char_cols > 0) + dynstr_append_mem(&update_string, ",", 1); + } + + if (num_char_cols) + for (col_count= 1; col_count <= num_char_cols; col_count++) + { + char rand_buffer[RAND_STRING_SIZE]; + int buf_len= get_random_string(rand_buffer); + + if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d = '%.*s'", col_count, + buf_len, rand_buffer) + > HUGE_STRING_LENGTH) + { + fprintf(stderr, "Memory Allocation error in creating update\n"); + exit(1); + } + dynstr_append(&update_string, buf); + + if (col_count < num_char_cols) + dynstr_append_mem(&update_string, ",", 1); + } + + if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary) + dynstr_append(&update_string, " WHERE id = "); + + + ptr= (statement *)my_malloc(sizeof(statement), + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + + ptr->string= (char *)my_malloc(update_string.length + 1, + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + ptr->length= update_string.length+1; + if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary) + ptr->type= UPDATE_TYPE_REQUIRES_PREFIX ; + else + ptr->type= UPDATE_TYPE; + strmov(ptr->string, update_string.str); + dynstr_free(&update_string); + DBUG_RETURN(ptr); +} + + +/* + build_insert_string() + + This function builds insert statements when the user opts to not supply + an insert file or string containing insert data +*/ +static statement * +build_insert_string(void) +{ + char buf[HUGE_STRING_LENGTH]; + unsigned int col_count; + statement *ptr; + DYNAMIC_STRING insert_string; + DBUG_ENTER("build_insert_string"); + + init_dynamic_string(&insert_string, "", 1024, 1024); + + dynstr_append(&insert_string, "INSERT INTO t1 VALUES ("); + + if (auto_generate_sql_autoincrement) + { + dynstr_append(&insert_string, "NULL"); + + if (num_int_cols || num_char_cols) + dynstr_append(&insert_string, ","); + } + + if (auto_generate_sql_guid_primary) + { + dynstr_append(&insert_string, "uuid()"); + + if (num_int_cols || num_char_cols) + dynstr_append(&insert_string, ","); + } + + if (auto_generate_sql_secondary_indexes) + { + unsigned int count; + + for (count= 0; count < auto_generate_sql_secondary_indexes; count++) + { + if (count) /* Except for the first pass we add a comma */ + dynstr_append(&insert_string, ","); + + dynstr_append(&insert_string, "uuid()"); + } + + if (num_int_cols || num_char_cols) + dynstr_append(&insert_string, ","); + } + + if (num_int_cols) + for (col_count= 1; col_count <= num_int_cols; col_count++) + { + if (snprintf(buf, HUGE_STRING_LENGTH, "%ld", random()) > HUGE_STRING_LENGTH) + { + fprintf(stderr, "Memory Allocation error in creating insert\n"); + exit(1); + } + dynstr_append(&insert_string, buf); + + if (col_count < num_int_cols || num_char_cols > 0) + dynstr_append_mem(&insert_string, ",", 1); + } + + if (num_char_cols) + for (col_count= 1; col_count <= num_char_cols; col_count++) + { + int buf_len= get_random_string(buf); + dynstr_append_mem(&insert_string, "'", 1); + dynstr_append_mem(&insert_string, buf, buf_len); + dynstr_append_mem(&insert_string, "'", 1); + + if (col_count < num_char_cols) + dynstr_append_mem(&insert_string, ",", 1); + } + + dynstr_append_mem(&insert_string, ")", 1); + + ptr= (statement *)my_malloc(sizeof(statement), + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + ptr->string= (char *)my_malloc(insert_string.length + 1, + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + ptr->length= insert_string.length+1; + ptr->type= INSERT_TYPE; + strmov(ptr->string, insert_string.str); + dynstr_free(&insert_string); + DBUG_RETURN(ptr); +} + + +/* + build_select_string() + + This function builds a query if the user opts to not supply a query + statement or file containing a query statement +*/ +static statement * +build_select_string(my_bool key) +{ + char buf[HUGE_STRING_LENGTH]; + unsigned int col_count; + statement *ptr; + static DYNAMIC_STRING query_string; + DBUG_ENTER("build_select_string"); + + init_dynamic_string(&query_string, "", 1024, 1024); + + dynstr_append_mem(&query_string, "SELECT ", 7); + for (col_count= 1; col_count <= num_int_cols; col_count++) + { + if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d", col_count) + > HUGE_STRING_LENGTH) + { + fprintf(stderr, "Memory Allocation error in creating select\n"); + exit(1); + } + dynstr_append(&query_string, buf); + + if (col_count < num_int_cols || num_char_cols > 0) + dynstr_append_mem(&query_string, ",", 1); + + } + for (col_count= 1; col_count <= num_char_cols; col_count++) + { + if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d", col_count) + > HUGE_STRING_LENGTH) + { + fprintf(stderr, "Memory Allocation error in creating select\n"); + exit(1); + } + dynstr_append(&query_string, buf); + + if (col_count < num_char_cols) + dynstr_append_mem(&query_string, ",", 1); + + } + dynstr_append(&query_string, " FROM t1"); + + if ((key) && + (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)) + dynstr_append(&query_string, " WHERE id = "); + + ptr= (statement *)my_malloc(sizeof(statement), + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + ptr->string= (char *)my_malloc(query_string.length + 1, + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + ptr->length= query_string.length+1; + if ((key) && + (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)) + ptr->type= SELECT_TYPE_REQUIRES_PREFIX; + else + ptr->type= SELECT_TYPE; + strmov(ptr->string, query_string.str); + dynstr_free(&query_string); + DBUG_RETURN(ptr); +} + +static int +get_options(int *argc,char ***argv) +{ + int ho_error; + char *tmp_string; + MY_STAT sbuf; /* Stat information for the data file */ + + DBUG_ENTER("get_options"); + if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option))) + exit(ho_error); + + if (!user) + user= (char *)"root"; + + if (create_string || auto_generate_sql) + { + if (verbose >= 1) + fprintf(stderr, "Turning off preserve-schema!\n"); + opt_preserve= FALSE; + } + + if (auto_generate_sql && (create_string || user_supplied_query)) + { + fprintf(stderr, + "%s: Can't use --auto-generate-sql when create and query strings are specified!\n", + my_progname); + exit(1); + } + + if (auto_generate_sql && auto_generate_sql_guid_primary && + auto_generate_sql_autoincrement) + { + fprintf(stderr, + "%s: Either auto-generate-sql-guid-primary or auto-generate-sql-add-autoincrement can be used!\n", + my_progname); + exit(1); + } + + /* + We are testing to make sure that if someone specified a key search + that we actually added a key! + */ + if (auto_generate_sql && auto_generate_sql_type[0] == 'k') + if ( auto_generate_sql_autoincrement == FALSE && + auto_generate_sql_guid_primary == FALSE) + { + fprintf(stderr, + "%s: Can't perform key test without a primary key!\n", + my_progname); + exit(1); + } + + + + if (auto_generate_sql && num_of_query && auto_actual_queries) + { + fprintf(stderr, + "%s: Either auto-generate-sql-execute-number or number-of-queries can be used!\n", + my_progname); + exit(1); + } + + parse_comma(concurrency_str ? concurrency_str : "1", &concurrency); + + if (opt_csv_str) + { + opt_silent= TRUE; + + if (opt_csv_str[0] == '-') + { + csv_file= fileno(stdout); + } + else + { + if ((csv_file= my_open(opt_csv_str, O_CREAT|O_WRONLY|O_APPEND, MYF(0))) + == -1) + { + fprintf(stderr,"%s: Could not open csv file: %sn\n", + my_progname, opt_csv_str); + exit(1); + } + } + } + + if (opt_only_print) + opt_silent= TRUE; + + if (num_int_cols_opt) + { + option_string *str; + parse_option(num_int_cols_opt, &str, ','); + num_int_cols= atoi(str->string); + if (str->option) + num_int_cols_index= atoi(str->option); + option_cleanup(str); + } + + if (num_char_cols_opt) + { + option_string *str; + parse_option(num_char_cols_opt, &str, ','); + num_char_cols= atoi(str->string); + if (str->option) + num_char_cols_index= atoi(str->option); + else + num_char_cols_index= 0; + option_cleanup(str); + } + + + if (auto_generate_sql) + { + unsigned long long x= 0; + statement *ptr_statement; + + if (verbose >= 2) + printf("Building Create Statements for Auto\n"); + + create_statements= build_table_string(); + /* + Pre-populate table + */ + for (ptr_statement= create_statements, x= 0; + x < auto_generate_sql_unique_write_number; + x++, ptr_statement= ptr_statement->next) + { + ptr_statement->next= build_insert_string(); + } + + if (verbose >= 2) + printf("Building Query Statements for Auto\n"); + + if (auto_generate_sql_type[0] == 'r') + { + if (verbose >= 2) + printf("Generating SELECT Statements for Auto\n"); + + query_statements= build_select_string(FALSE); + for (ptr_statement= query_statements, x= 0; + x < auto_generate_sql_unique_query_number; + x++, ptr_statement= ptr_statement->next) + { + ptr_statement->next= build_select_string(FALSE); + } + } + else if (auto_generate_sql_type[0] == 'k') + { + if (verbose >= 2) + printf("Generating SELECT for keys Statements for Auto\n"); + + query_statements= build_select_string(TRUE); + for (ptr_statement= query_statements, x= 0; + x < auto_generate_sql_unique_query_number; + x++, ptr_statement= ptr_statement->next) + { + ptr_statement->next= build_select_string(TRUE); + } + } + else if (auto_generate_sql_type[0] == 'w') + { + /* + We generate a number of strings in case the engine is + Archive (since strings which were identical one after another + would be too easily optimized). + */ + if (verbose >= 2) + printf("Generating INSERT Statements for Auto\n"); + query_statements= build_insert_string(); + for (ptr_statement= query_statements, x= 0; + x < auto_generate_sql_unique_query_number; + x++, ptr_statement= ptr_statement->next) + { + ptr_statement->next= build_insert_string(); + } + } + else if (auto_generate_sql_type[0] == 'u') + { + query_statements= build_update_string(); + for (ptr_statement= query_statements, x= 0; + x < auto_generate_sql_unique_query_number; + x++, ptr_statement= ptr_statement->next) + { + ptr_statement->next= build_update_string(); + } + } + else /* Mixed mode is default */ + { + int coin= 0; + + query_statements= build_insert_string(); + /* + This logic should be extended to do a more mixed load, + at the moment it results in "every other". + */ + for (ptr_statement= query_statements, x= 0; + x < auto_generate_sql_unique_query_number; + x++, ptr_statement= ptr_statement->next) + { + if (coin) + { + ptr_statement->next= build_insert_string(); + coin= 0; + } + else + { + ptr_statement->next= build_select_string(TRUE); + coin= 1; + } + } + } + } + else + { + if (create_string && my_stat(create_string, &sbuf, MYF(0))) + { + File data_file; + if (!MY_S_ISREG(sbuf.st_mode)) + { + fprintf(stderr,"%s: Create file was not a regular file\n", + my_progname); + exit(1); + } + if ((data_file= my_open(create_string, O_RDWR, MYF(0))) == -1) + { + fprintf(stderr,"%s: Could not open create file\n", my_progname); + exit(1); + } + tmp_string= (char *)my_malloc(sbuf.st_size + 1, + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + my_read(data_file, tmp_string, sbuf.st_size, MYF(0)); + tmp_string[sbuf.st_size]= '\0'; + my_close(data_file,MYF(0)); + parse_delimiter(tmp_string, &create_statements, delimiter[0]); + my_free((gptr)tmp_string, MYF(0)); + } + else if (create_string) + { + parse_delimiter(create_string, &create_statements, delimiter[0]); + } + + if (user_supplied_query && my_stat(user_supplied_query, &sbuf, MYF(0))) + { + File data_file; + if (!MY_S_ISREG(sbuf.st_mode)) + { + fprintf(stderr,"%s: User query supplied file was not a regular file\n", + my_progname); + exit(1); + } + if ((data_file= my_open(user_supplied_query, O_RDWR, MYF(0))) == -1) + { + fprintf(stderr,"%s: Could not open query supplied file\n", my_progname); + exit(1); + } + tmp_string= (char *)my_malloc(sbuf.st_size + 1, + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + my_read(data_file, tmp_string, sbuf.st_size, MYF(0)); + tmp_string[sbuf.st_size]= '\0'; + my_close(data_file,MYF(0)); + if (user_supplied_query) + actual_queries= parse_delimiter(tmp_string, &query_statements, + delimiter[0]); + my_free((gptr)tmp_string, MYF(0)); + } + else if (user_supplied_query) + { + actual_queries= parse_delimiter(user_supplied_query, &query_statements, + delimiter[0]); + } + } + + if (user_supplied_pre_statements && my_stat(user_supplied_pre_statements, &sbuf, MYF(0))) + { + File data_file; + if (!MY_S_ISREG(sbuf.st_mode)) + { + fprintf(stderr,"%s: User query supplied file was not a regular file\n", + my_progname); + exit(1); + } + if ((data_file= my_open(user_supplied_pre_statements, O_RDWR, MYF(0))) == -1) + { + fprintf(stderr,"%s: Could not open query supplied file\n", my_progname); + exit(1); + } + tmp_string= (char *)my_malloc(sbuf.st_size + 1, + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + my_read(data_file, tmp_string, sbuf.st_size, MYF(0)); + tmp_string[sbuf.st_size]= '\0'; + my_close(data_file,MYF(0)); + if (user_supplied_pre_statements) + actual_queries= parse_delimiter(tmp_string, &pre_statements, + delimiter[0]); + my_free((gptr)tmp_string, MYF(0)); + } + else if (user_supplied_pre_statements) + { + actual_queries= parse_delimiter(user_supplied_pre_statements, &pre_statements, + delimiter[0]); + } + + if (user_supplied_post_statements && my_stat(user_supplied_post_statements, &sbuf, MYF(0))) + { + File data_file; + if (!MY_S_ISREG(sbuf.st_mode)) + { + fprintf(stderr,"%s: User query supplied file was not a regular file\n", + my_progname); + exit(1); + } + if ((data_file= my_open(user_supplied_post_statements, O_RDWR, MYF(0))) == -1) + { + fprintf(stderr,"%s: Could not open query supplied file\n", my_progname); + exit(1); + } + tmp_string= (char *)my_malloc(sbuf.st_size + 1, + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + my_read(data_file, tmp_string, sbuf.st_size, MYF(0)); + tmp_string[sbuf.st_size]= '\0'; + my_close(data_file,MYF(0)); + if (user_supplied_post_statements) + parse_delimiter(tmp_string, &post_statements, + delimiter[0]); + my_free((gptr)tmp_string, MYF(0)); + } + else if (user_supplied_post_statements) + { + parse_delimiter(user_supplied_post_statements, &post_statements, + delimiter[0]); + } + + if (verbose >= 2) + printf("Parsing engines to use.\n"); + + if (default_engine) + parse_option(default_engine, &engine_options, ','); + + if (tty_password) + opt_password= get_tty_password(NullS); + DBUG_RETURN(0); +} + + +static int run_query(MYSQL *mysql, const char *query, int len) +{ + if (opt_only_print) + { + printf("%.*s;\n", len, query); + return 0; + } + + if (verbose >= 3) + printf("%.*s;\n", len, query); + return mysql_real_query(mysql, query, len); +} + + +static int +generate_primary_key_list(MYSQL *mysql, option_string *engine_stmt) +{ + MYSQL_RES *result; + MYSQL_ROW row; + unsigned long long counter; + DBUG_ENTER("generate_primary_key_list"); + + /* + Blackhole is a special case, this allows us to test the upper end + of the server during load runs. + */ + if (opt_only_print || (engine_stmt && + strstr(engine_stmt->string, "blackhole"))) + { + primary_keys_number_of= 1; + primary_keys= (char **)my_malloc((uint)(sizeof(char *) * + primary_keys_number_of), + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + /* Yes, we strdup a const string to simplify the interface */ + primary_keys[0]= my_strdup("796c4422-1d94-102a-9d6d-00e0812d", MYF(0)); + } + else + { + if (run_query(mysql, "SELECT id from t1", strlen("SELECT id from t1"))) + { + fprintf(stderr,"%s: Cannot select GUID primary keys. (%s)\n", my_progname, + mysql_error(mysql)); + exit(1); + } + + result= mysql_store_result(mysql); + primary_keys_number_of= mysql_num_rows(result); + + /* So why check this? Blackhole :) */ + if (primary_keys_number_of) + { + /* + We create the structure and loop and create the items. + */ + primary_keys= (char **)my_malloc((uint)(sizeof(char *) * + primary_keys_number_of), + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + row= mysql_fetch_row(result); + for (counter= 0; counter < primary_keys_number_of; + counter++, row= mysql_fetch_row(result)) + primary_keys[counter]= my_strdup(row[0], MYF(0)); + } + + mysql_free_result(result); + } + + DBUG_RETURN(0); +} + +static int +drop_primary_key_list(void) +{ + unsigned long long counter; + + if (primary_keys_number_of) + { + for (counter= 0; counter < primary_keys_number_of; counter++) + my_free((gptr)primary_keys[counter], MYF(0)); + + my_free((gptr)primary_keys, MYF(0)); + } + + return 0; +} + +static int +create_schema(MYSQL *mysql, const char *db, statement *stmt, + option_string *engine_stmt) +{ + char query[HUGE_STRING_LENGTH]; + statement *ptr; + statement *after_create; + int len; + ulonglong count; + DBUG_ENTER("create_schema"); + + len= snprintf(query, HUGE_STRING_LENGTH, "CREATE SCHEMA `%s`", db); + + if (verbose >= 2) + printf("Loading Pre-data\n"); + + if (run_query(mysql, query, len)) + { + fprintf(stderr,"%s: Cannot create schema %s : %s\n", my_progname, db, + mysql_error(mysql)); + exit(1); + } + + if (opt_only_print) + { + printf("use %s;\n", db); + } + else + { + if (verbose >= 3) + printf("%s;\n", query); + + if (mysql_select_db(mysql, db)) + { + fprintf(stderr,"%s: Cannot select schema '%s': %s\n",my_progname, db, + mysql_error(mysql)); + exit(1); + } + } + + 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; + +limit_not_met: + for (ptr= after_create; ptr && ptr->length; ptr= ptr->next, count++) + { + if (auto_generate_sql && ( auto_generate_sql_number == count)) + break; + + if (engine_stmt && engine_stmt->option && ptr->type == CREATE_TABLE_TYPE) + { + char buffer[HUGE_STRING_LENGTH]; + + snprintf(buffer, HUGE_STRING_LENGTH, "%s %s", ptr->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 (run_query(mysql, ptr->string, ptr->length)) + { + fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n", + my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql)); + exit(1); + } + } + } + + if (auto_generate_sql && (auto_generate_sql_number > count )) + { + /* Special case for auto create, we don't want to create tables twice */ + after_create= stmt->next; + goto limit_not_met; + } + + DBUG_RETURN(0); +} + +static int +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); + + if (run_query(mysql, query, len)) + { + fprintf(stderr,"%s: Cannot drop database '%s' ERROR : %s\n", + my_progname, db, mysql_error(mysql)); + exit(1); + } + + + + DBUG_RETURN(0); +} + +static int +run_statements(MYSQL *mysql, statement *stmt) +{ + statement *ptr; + DBUG_ENTER("run_statements"); + + for (ptr= stmt; ptr && ptr->length; ptr= ptr->next) + { + if (run_query(mysql, ptr->string, ptr->length)) + { + fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n", + my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql)); + exit(1); + } + } + + DBUG_RETURN(0); +} + +static int +run_scheduler(stats *sptr, statement *stmts, uint concur, ulonglong limit) +{ + uint x; + struct timeval start_time, end_time; + thread_context con; + pthread_t mainthread; /* Thread descriptor */ + pthread_attr_t attr; /* Thread attributes */ + DBUG_ENTER("run_scheduler"); + + con.stmt= stmts; + con.limit= limit; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, + PTHREAD_CREATE_DETACHED); + + pthread_mutex_lock(&counter_mutex); + thread_counter= 0; + + pthread_mutex_lock(&sleeper_mutex); + master_wakeup= 1; + pthread_mutex_unlock(&sleeper_mutex); + for (x= 0; x < concur; x++) + { + /* now you create the thread */ + if (pthread_create(&mainthread, &attr, run_task, + (void *)&con) != 0) + { + fprintf(stderr,"%s: Could not create thread\n", + my_progname); + exit(0); + } + thread_counter++; + } + pthread_mutex_unlock(&counter_mutex); + pthread_attr_destroy(&attr); + + pthread_mutex_lock(&sleeper_mutex); + master_wakeup= 0; + pthread_mutex_unlock(&sleeper_mutex); + pthread_cond_broadcast(&sleep_threshhold); + + gettimeofday(&start_time, NULL); + + /* + We loop until we know that all children have cleaned up. + */ + pthread_mutex_lock(&counter_mutex); + while (thread_counter) + { + struct timespec abstime; + + set_timespec(abstime, 3); + pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime); + } + pthread_mutex_unlock(&counter_mutex); + + gettimeofday(&end_time, NULL); + + + sptr->timing= timedif(end_time, start_time); + sptr->users= concur; + sptr->rows= limit; + + DBUG_RETURN(0); +} + + +pthread_handler_t run_task(void *p) +{ + ulonglong counter= 0, queries; + MYSQL *mysql; + MYSQL_RES *result; + MYSQL_ROW row; + statement *ptr; + thread_context *con= (thread_context *)p; + + DBUG_ENTER("run_task"); + DBUG_PRINT("info", ("task script \"%s\"", con->stmt ? con->stmt->string : "")); + + pthread_mutex_lock(&sleeper_mutex); + while (master_wakeup) + { + pthread_cond_wait(&sleep_threshhold, &sleeper_mutex); + } + pthread_mutex_unlock(&sleeper_mutex); + + if (!(mysql= mysql_init(NULL))) + { + fprintf(stderr,"%s: mysql_init() failed ERROR : %s\n", + my_progname, mysql_error(mysql)); + exit(0); + } + + if (mysql_thread_init()) + { + fprintf(stderr,"%s: mysql_thread_init() failed ERROR : %s\n", + my_progname, mysql_error(mysql)); + exit(0); + } + + DBUG_PRINT("info", ("trying to connect to host %s as user %s", host, user)); + + if (!opt_only_print) + { + /* Connect to server */ + static ulong connection_retry_sleep= 100000; /* Microseconds */ + int i, connect_error= 1; + for (i= 0; i < 10; i++) + { + if (mysql_real_connect(mysql, host, user, opt_password, + create_schema_string, + opt_mysql_port, + opt_mysql_unix_port, + connect_flags)) + { + /* Connect suceeded */ + connect_error= 0; + break; + } + my_sleep(connection_retry_sleep); + } + if (connect_error) + { + fprintf(stderr,"%s: Error when connecting to server: %d %s\n", + my_progname, mysql_errno(mysql), mysql_error(mysql)); + goto end; + } + } + DBUG_PRINT("info", ("connected.")); + if (verbose >= 3) + printf("connected!\n"); + queries= 0; + +limit_not_met: + for (ptr= con->stmt; ptr && ptr->length; ptr= ptr->next) + { + /* + We have to execute differently based on query type. This should become a function. + */ + if ((ptr->type == UPDATE_TYPE_REQUIRES_PREFIX) || + (ptr->type == SELECT_TYPE_REQUIRES_PREFIX)) + { + int length; + unsigned int key_val; + char *key; + char buffer[HUGE_STRING_LENGTH]; + + /* + This should only happen if some sort of new engine was + implemented that didn't properly handle UPDATEs. + + Just in case someone runs this under an experimental engine we don't + want a crash so the if() is placed here. + */ + DBUG_ASSERT(primary_keys_number_of); + if (primary_keys_number_of) + { + key_val= (unsigned int)(random() % primary_keys_number_of); + key= primary_keys[key_val]; + + DBUG_ASSERT(key); + + length= snprintf(buffer, HUGE_STRING_LENGTH, "%.*s '%s'", + (int)ptr->length, ptr->string, key); + + if (run_query(mysql, buffer, length)) + { + fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n", + my_progname, (uint)length, buffer, mysql_error(mysql)); + exit(0); + } + } + } + else + { + if (run_query(mysql, ptr->string, ptr->length)) + { + fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n", + my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql)); + exit(0); + } + } + + if (mysql_field_count(mysql)) + { + result= mysql_store_result(mysql); + while ((row = mysql_fetch_row(result))) + counter++; + mysql_free_result(result); + } + queries++; + + if (con->limit && queries == con->limit) + goto end; + } + + if (con->limit && queries < con->limit) + goto limit_not_met; + +end: + + if (!opt_only_print) + mysql_close(mysql); + + my_thread_end(); + + pthread_mutex_lock(&counter_mutex); + thread_counter--; + pthread_cond_signal(&count_threshhold); + pthread_mutex_unlock(&counter_mutex); + + DBUG_RETURN(0); +} + +uint +parse_option(const char *origin, option_string **stmt, char delm) +{ + char *retstr; + char *ptr= (char *)origin; + option_string **sptr= stmt; + option_string *tmp; + uint length= strlen(origin); + 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)); + (retstr= strchr(ptr, delm)); + tmp->next= (option_string *)my_malloc(sizeof(option_string), + MYF(MY_ZEROFILL|MY_FAE|MY_WME)), + tmp= tmp->next) + { + char buffer[HUGE_STRING_LENGTH]; + char *buffer_ptr; + + count++; + strncpy(buffer, ptr, (size_t)(retstr - ptr)); + if ((buffer_ptr= strchr(buffer, ':'))) + { + char *option_ptr; + + tmp->length= (size_t)(buffer_ptr - buffer); + tmp->string= my_strndup(ptr, (uint)tmp->length, MYF(MY_FAE)); + + option_ptr= ptr + 1 + tmp->length; + + /* Move past the : and the first string */ + tmp->option_length= (size_t)(retstr - option_ptr); + tmp->option= my_strndup(option_ptr, (uint)tmp->option_length, + MYF(MY_FAE)); + } + else + { + tmp->string= my_strndup(ptr, (size_t)(retstr - ptr), MYF(MY_FAE)); + tmp->length= (size_t)(retstr - ptr); + } + + ptr+= retstr - ptr + 1; + if (isspace(*ptr)) + ptr++; + count++; + } + + if (ptr != origin+length) + { + char *origin_ptr; + + if ((origin_ptr= strchr(ptr, ':'))) + { + char *option_ptr; + + tmp->length= (size_t)(origin_ptr - ptr); + tmp->string= my_strndup(origin, tmp->length, MYF(MY_FAE)); + + option_ptr= (char *)ptr + 1 + tmp->length; + + /* Move past the : and the first string */ + tmp->option_length= (size_t)((ptr + length) - option_ptr); + tmp->option= my_strndup(option_ptr, tmp->option_length, + MYF(MY_FAE)); + } + else + { + tmp->length= (size_t)((ptr + length) - ptr); + tmp->string= my_strndup(ptr, tmp->length, MYF(MY_FAE)); + } + + count++; + } + + return count; +} + + +uint +parse_delimiter(const char *script, statement **stmt, char delm) +{ + char *retstr; + char *ptr= (char *)script; + statement **sptr= stmt; + statement *tmp; + uint length= strlen(script); + uint count= 0; /* We know that there is always one */ + + for (tmp= *sptr= (statement *)my_malloc(sizeof(statement), + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + (retstr= strchr(ptr, delm)); + tmp->next= (statement *)my_malloc(sizeof(statement), + MYF(MY_ZEROFILL|MY_FAE|MY_WME)), + tmp= tmp->next) + { + count++; + tmp->string= my_strndup(ptr, (uint)(retstr - ptr), MYF(MY_FAE)); + tmp->length= (size_t)(retstr - ptr); + ptr+= retstr - ptr + 1; + if (isspace(*ptr)) + ptr++; + count++; + } + + if (ptr != script+length) + { + tmp->string= my_strndup(ptr, (uint)((script + length) - ptr), + MYF(MY_FAE)); + tmp->length= (size_t)((script + length) - ptr); + count++; + } + + return count; +} + + +uint +parse_comma(const char *string, uint **range) +{ + uint count= 1,x; /* We know that there is always one */ + char *retstr; + char *ptr= (char *)string; + uint *nptr; + + for (;*ptr; ptr++) + if (*ptr == ',') count++; + + /* One extra spot for the NULL */ + nptr= *range= (uint *)my_malloc(sizeof(uint) * (count + 1), + MYF(MY_ZEROFILL|MY_FAE|MY_WME)); + + ptr= (char *)string; + x= 0; + while ((retstr= strchr(ptr,','))) + { + nptr[x++]= atoi(ptr); + ptr+= retstr - ptr + 1; + } + nptr[x++]= atoi(ptr); + + return count; +} + +void +print_conclusions(conclusions *con) +{ + printf("Benchmark\n"); + if (con->engine) + printf("\tRunning for engine %s\n", con->engine); + printf("\tAverage number of seconds to run all queries: %ld.%03ld seconds\n", + con->avg_timing / 1000, con->avg_timing % 1000); + printf("\tMinimum number of seconds to run all queries: %ld.%03ld seconds\n", + con->min_timing / 1000, con->min_timing % 1000); + printf("\tMaximum number of seconds to run all queries: %ld.%03ld seconds\n", + con->max_timing / 1000, con->max_timing % 1000); + printf("\tNumber of clients running queries: %d\n", con->users); + printf("\tAverage number of queries per client: %llu\n", con->avg_rows); + printf("\n"); +} + +void +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 */ + ptr, /* Load type */ + con->avg_timing / 1000, con->avg_timing % 1000, /* Time to load */ + con->min_timing / 1000, con->min_timing % 1000, /* Min time */ + con->max_timing / 1000, con->max_timing % 1000, /* Max time */ + con->users, /* Children used */ + con->avg_rows /* Queries run */ + ); + my_write(csv_file, buffer, (uint)strlen(buffer), MYF(0)); +} + +void +generate_stats(conclusions *con, option_string *eng, stats *sptr) +{ + stats *ptr; + unsigned int x; + + con->min_timing= sptr->timing; + con->max_timing= sptr->timing; + con->min_rows= sptr->rows; + con->max_rows= sptr->rows; + + /* At the moment we assume uniform */ + con->users= sptr->users; + con->avg_rows= sptr->rows; + + /* With no next, we know it is the last element that was malloced */ + for (ptr= sptr, x= 0; x < iterations; ptr++, x++) + { + con->avg_timing+= ptr->timing; + + if (ptr->timing > con->max_timing) + con->max_timing= ptr->timing; + if (ptr->timing < con->min_timing) + con->min_timing= ptr->timing; + } + con->avg_timing= con->avg_timing/iterations; + + if (eng && eng->string) + con->engine= eng->string; + else + con->engine= NULL; +} + +void +option_cleanup(option_string *stmt) +{ + option_string *ptr, *nptr; + if (!stmt) + return; + + for (ptr= stmt; ptr; ptr= nptr) + { + nptr= ptr->next; + if (ptr->string) + my_free((gptr)ptr->string, MYF(0)); + if (ptr->option) + my_free((gptr)ptr->option, MYF(0)); + my_free((gptr)(byte *)ptr, MYF(0)); + } +} + +void +statement_cleanup(statement *stmt) +{ + statement *ptr, *nptr; + if (!stmt) + return; + + for (ptr= stmt; ptr; ptr= nptr) + { + nptr= ptr->next; + if (ptr->string) + my_free((gptr)ptr->string, MYF(0)); + my_free((gptr)(byte *)ptr, MYF(0)); + } +} diff --git a/client/mysqltest.c b/client/mysqltest.c index 5640d0c24ba..1ba20c8929f 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -33,18 +33,12 @@ #define MTEST_VERSION "3.2" -#include <my_global.h> -#include <mysql_embed.h> -#include <my_sys.h> -#include <m_string.h> -#include <mysql.h> +#include "client_priv.h" #include <mysql_version.h> #include <mysqld_error.h> -#include <errmsg.h> #include <m_ctype.h> #include <my_dir.h> #include <hash.h> -#include <my_getopt.h> #include <stdarg.h> #include <violite.h> #include "my_regex.h" /* Our own version of regex */ @@ -52,14 +46,6 @@ #include <sys/wait.h> #endif -#ifndef WEXITSTATUS -# ifdef __WIN__ -# define WEXITSTATUS(stat_val) (stat_val) -# else -# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) -# endif -#endif - /* Use cygwin for --exec and --system before 5.0 */ #if MYSQL_VERSION_ID < 50000 #define USE_CYGWIN @@ -81,11 +67,9 @@ }; enum { - OPT_SKIP_SAFEMALLOC=256, OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, - OPT_SSL_CA, OPT_SSL_CAPATH, OPT_SSL_CIPHER, OPT_PS_PROTOCOL, - OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL, - OPT_SSL_VERIFY_SERVER_CERT, OPT_MAX_CONNECT_RETRIES, - OPT_MARK_PROGRESS, OPT_CHARSETS_DIR, OPT_LOG_DIR + OPT_SKIP_SAFEMALLOC=OPT_MAX_CLIENT_OPTION, + OPT_PS_PROTOCOL, OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL, + OPT_MAX_CONNECT_RETRIES, OPT_MARK_PROGRESS, OPT_LOG_DIR }; static int record= 0, opt_sleep= -1; @@ -1562,7 +1546,7 @@ void do_source(struct st_command *command) { static DYNAMIC_STRING ds_filename; const struct command_arg source_args[] = { - "filename", ARG_STRING, TRUE, &ds_filename, "File to source" + { "filename", ARG_STRING, TRUE, &ds_filename, "File to source" } }; DBUG_ENTER("do_source"); @@ -1948,7 +1932,7 @@ void do_remove_file(struct st_command *command) int error; static DYNAMIC_STRING ds_filename; const struct command_arg rm_args[] = { - "filename", ARG_STRING, TRUE, &ds_filename, "File to delete" + { "filename", ARG_STRING, TRUE, &ds_filename, "File to delete" } }; DBUG_ENTER("do_remove_file"); @@ -1982,8 +1966,8 @@ void do_copy_file(struct st_command *command) static DYNAMIC_STRING ds_from_file; static DYNAMIC_STRING ds_to_file; const struct command_arg copy_file_args[] = { - "from_file", ARG_STRING, TRUE, &ds_from_file, "Filename to copy from", - "to_file", ARG_STRING, TRUE, &ds_to_file, "Filename to copy to" + { "from_file", ARG_STRING, TRUE, &ds_from_file, "Filename to copy from" }, + { "to_file", ARG_STRING, TRUE, &ds_to_file, "Filename to copy to" } }; DBUG_ENTER("do_copy_file"); @@ -2019,8 +2003,8 @@ void do_chmod_file(struct st_command *command) static DYNAMIC_STRING ds_mode; static DYNAMIC_STRING ds_file; const struct command_arg chmod_file_args[] = { - "mode", ARG_STRING, TRUE, &ds_mode, "Mode of file", - "file", ARG_STRING, TRUE, &ds_file, "Filename of file to modify" + { "mode", ARG_STRING, TRUE, &ds_mode, "Mode of file" }, + { "file", ARG_STRING, TRUE, &ds_file, "Filename of file to modify" } }; DBUG_ENTER("do_chmod_file"); @@ -2057,7 +2041,7 @@ void do_file_exist(struct st_command *command) int error; static DYNAMIC_STRING ds_filename; const struct command_arg file_exist_args[] = { - "filename", ARG_STRING, TRUE, &ds_filename, "File to check if it exist" + { "filename", ARG_STRING, TRUE, &ds_filename, "File to check if it exist" } }; DBUG_ENTER("do_file_exist"); @@ -2139,8 +2123,8 @@ void do_write_file_command(struct st_command *command, my_bool append) static DYNAMIC_STRING ds_filename; static DYNAMIC_STRING ds_delimiter; const struct command_arg write_file_args[] = { - "filename", ARG_STRING, TRUE, &ds_filename, "File to write to", - "delimiter", ARG_STRING, FALSE, &ds_delimiter, "Delimiter to read until" + { "filename", ARG_STRING, TRUE, &ds_filename, "File to write to" }, + { "delimiter", ARG_STRING, FALSE, &ds_delimiter, "Delimiter to read until" } }; DBUG_ENTER("do_write_file"); @@ -2248,7 +2232,7 @@ void do_cat_file(struct st_command *command) char buff[512]; static DYNAMIC_STRING ds_filename; const struct command_arg cat_file_args[] = { - "filename", ARG_STRING, TRUE, &ds_filename, "File to read from" + { "filename", ARG_STRING, TRUE, &ds_filename, "File to read from" } }; DBUG_ENTER("do_cat_file"); @@ -2312,8 +2296,8 @@ void do_diff_files(struct st_command *command) static DYNAMIC_STRING ds_filename; static DYNAMIC_STRING ds_filename2; const struct command_arg diff_file_args[] = { - "file1", ARG_STRING, TRUE, &ds_filename, "First file to diff", - "file2", ARG_STRING, TRUE, &ds_filename2, "Second file to diff" + { "file1", ARG_STRING, TRUE, &ds_filename, "First file to diff" }, + { "file2", ARG_STRING, TRUE, &ds_filename2, "Second file to diff" } }; DBUG_ENTER("do_diff_files"); @@ -2389,7 +2373,7 @@ void do_perl(struct st_command *command) static DYNAMIC_STRING ds_script; static DYNAMIC_STRING ds_delimiter; const struct command_arg perl_args[] = { - "delimiter", ARG_STRING, FALSE, &ds_delimiter, "Delimiter to read until" + { "delimiter", ARG_STRING, FALSE, &ds_delimiter, "Delimiter to read until" } }; DBUG_ENTER("do_perl"); @@ -2535,17 +2519,20 @@ wait_for_position: if (!(res= mysql_store_result(mysql))) die("mysql_store_result() returned NULL for '%s'", query_buf); if (!(row= mysql_fetch_row(res))) + { + mysql_free_result(res); die("empty result in %s", query_buf); + } if (!row[0]) { /* It may be that the slave SQL thread has not started yet, though START SLAVE has been issued ? */ + mysql_free_result(res); if (tries++ == 30) die("could not sync with master ('%s' returned NULL)", query_buf); sleep(1); /* So at most we will wait 30 seconds and make 31 tries */ - mysql_free_result(res); goto wait_for_position; } mysql_free_result(res); @@ -2586,6 +2573,7 @@ int do_save_master_pos() MYSQL *mysql = &cur_con->mysql; const char *query; int rpl_parse; + DBUG_ENTER("do_save_master_pos"); rpl_parse = mysql_rpl_parse_enabled(mysql); mysql_disable_rpl_parse(mysql); @@ -2610,7 +2598,7 @@ int do_save_master_pos() if (have_ndbcluster) { - ulonglong start_epoch= 0, applied_epoch= 0, + ulonglong start_epoch= 0, handled_epoch= 0, latest_epoch=0, latest_trans_epoch=0, latest_handled_binlog_epoch= 0, latest_received_binlog_epoch= 0, latest_applied_binlog_epoch= 0; @@ -2713,9 +2701,9 @@ int do_save_master_pos() if (!row) die("result does not contain '%s' in '%s'", binlog, query); - if (latest_applied_binlog_epoch > applied_epoch) + if (latest_handled_binlog_epoch > handled_epoch) count= 0; - applied_epoch= latest_applied_binlog_epoch; + handled_epoch= latest_handled_binlog_epoch; count++; if (latest_handled_binlog_epoch >= start_epoch) do_continue= 0; @@ -2743,7 +2731,7 @@ int do_save_master_pos() if (rpl_parse) mysql_enable_rpl_parse(mysql); - return 0; + DBUG_RETURN(0); } @@ -3198,7 +3186,7 @@ struct st_connection * find_connection_by_name(const char *name) int select_connection_name(const char *name) { - DBUG_ENTER("select_connection2"); + DBUG_ENTER("select_connection_name"); DBUG_PRINT("enter",("name: '%s'", name)); if (!(cur_con= find_connection_by_name(name))) @@ -3221,7 +3209,7 @@ int select_connection(struct st_command *command) if (*p) *p++= 0; command->last_argument= p; - return select_connection_name(name); + DBUG_RETURN(select_connection_name(name)); } @@ -3464,18 +3452,14 @@ void do_connect(struct st_command *command) static DYNAMIC_STRING ds_sock; static DYNAMIC_STRING ds_options; const struct command_arg connect_args[] = { - "connection name", ARG_STRING, TRUE, &ds_connection_name, - "Name of the connection", - "host", ARG_STRING, TRUE, &ds_host, "Host to connect to", - "user", ARG_STRING, FALSE, &ds_user, "User to connect as", - "passsword", ARG_STRING, FALSE, &ds_password, - "Password used when connecting", - "database", ARG_STRING, FALSE, &ds_database, - "Dtabase to select after connect", - "port", ARG_STRING, FALSE, &ds_port, "Port to connect to", - "socket", ARG_STRING, FALSE, &ds_sock, "Socket to connect with", - "options", ARG_STRING, FALSE, &ds_options, - "Options to use while connecting" + { "connection name", ARG_STRING, TRUE, &ds_connection_name, "Name of the connection" }, + { "host", ARG_STRING, TRUE, &ds_host, "Host to connect to" }, + { "user", ARG_STRING, FALSE, &ds_user, "User to connect as" }, + { "passsword", ARG_STRING, FALSE, &ds_password, "Password used when connecting" }, + { "database", ARG_STRING, FALSE, &ds_database, "Database to select after connect" }, + { "port", ARG_STRING, FALSE, &ds_port, "Port to connect to" }, + { "socket", ARG_STRING, FALSE, &ds_sock, "Socket to connect with" }, + { "options", ARG_STRING, FALSE, &ds_options, "Options to use while connecting" } }; DBUG_ENTER("do_connect"); diff --git a/client/sql_string.h b/client/sql_string.h index a74fbf58082..da19c1ccfe5 100644 --- a/client/sql_string.h +++ b/client/sql_string.h @@ -23,8 +23,6 @@ #define NOT_FIXED_DEC 31 #endif -#define STRING_WITH_LEN(X) ((const char*) X), ((uint) (sizeof(X) - 1)) - class String; int sortcmp(const String *a,const String *b, CHARSET_INFO *cs); String *copy_if_not_alloced(String *a,String *b,uint32 arg_length); |