diff options
Diffstat (limited to 'client')
-rwxr-xr-x | client/CMakeLists.txt | 12 | ||||
-rw-r--r-- | client/Makefile.am | 101 | ||||
-rw-r--r-- | client/client_priv.h | 37 | ||||
-rw-r--r-- | client/completion_hash.cc | 2 | ||||
-rw-r--r-- | client/get_password.c | 4 | ||||
-rw-r--r-- | client/my_readline.h | 2 | ||||
-rw-r--r-- | client/mysql.cc | 468 | ||||
-rw-r--r-- | client/mysql_upgrade.c | 57 | ||||
-rw-r--r-- | client/mysqladmin.cc | 163 | ||||
-rw-r--r-- | client/mysqlbinlog.cc | 286 | ||||
-rw-r--r-- | client/mysqlcheck.c | 180 | ||||
-rw-r--r-- | client/mysqldump.c | 1635 | ||||
-rw-r--r-- | client/mysqlimport.c | 334 | ||||
-rw-r--r-- | client/mysqlmanager-pwgen.c | 160 | ||||
-rw-r--r-- | client/mysqlmanagerc.c | 178 | ||||
-rw-r--r-- | client/mysqlshow.c | 80 | ||||
-rw-r--r-- | client/mysqlslap.c | 2201 | ||||
-rw-r--r-- | client/mysqltest.c | 435 | ||||
-rw-r--r-- | client/readline.cc | 34 | ||||
-rw-r--r-- | client/sql_string.cc | 14 | ||||
-rw-r--r-- | client/sql_string.h | 2 |
21 files changed, 4920 insertions, 1465 deletions
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 89675138750..2ef55c23c90 100755 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -51,12 +51,22 @@ ADD_DEPENDENCIES(mysql_upgrade GenFixPrivs) ADD_EXECUTABLE(mysqlshow mysqlshow.c) TARGET_LINK_LIBRARIES(mysqlshow mysqlclient_notls wsock32) -ADD_EXECUTABLE(mysqlbinlog mysqlbinlog.cc ../mysys/mf_tempdir.c ../mysys/my_new.cc) +ADD_EXECUTABLE(mysqlbinlog mysqlbinlog.cc + ../mysys/mf_tempdir.c + ../mysys/my_new.cc + ../mysys/my_bit.c + ../mysys/my_bitmap.c + ../mysys/my_vle.c + ../mysys/base64.c) TARGET_LINK_LIBRARIES(mysqlbinlog mysqlclient_notls wsock32) ADD_EXECUTABLE(mysqladmin mysqladmin.cc) TARGET_LINK_LIBRARIES(mysqladmin mysqlclient_notls wsock32) +ADD_EXECUTABLE(mysqlslap mysqlslap.c) +SET_SOURCE_FILES_PROPERTIES(mysqlslap.c PROPERTIES COMPILE_FLAGS "-DTHREADS") +TARGET_LINK_LIBRARIES(mysqlslap mysqlclient mysys zlib wsock32 dbug) + ADD_EXECUTABLE(echo echo.c) IF(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 8f509fa0763..71d6ce8a635 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 { @@ -42,14 +48,37 @@ enum options_client OPT_PROMPT, OPT_IGN_LINES,OPT_TRANSACTION,OPT_MYSQL_PROTOCOL, OPT_SHARED_MEMORY_BASE_NAME, OPT_FRM, OPT_SKIP_OPTIMIZATION, OPT_COMPATIBLE, OPT_RECONNECT, OPT_DELIMITER, OPT_SECURE_AUTH, - OPT_OPEN_FILES_LIMIT, OPT_SET_CHARSET, OPT_CREATE_OPTIONS, + OPT_OPEN_FILES_LIMIT, OPT_SET_CHARSET, OPT_CREATE_OPTIONS, OPT_SERVER_ARG, OPT_START_POSITION, OPT_STOP_POSITION, OPT_START_DATETIME, OPT_STOP_DATETIME, OPT_SIGINT_IGNORE, OPT_HEXBLOB, OPT_ORDER_BY_PRIMARY, OPT_COUNT, #ifdef HAVE_NDBCLUSTER_DB 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_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_DUMP_DATE + 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_SLAP_PRE_SYSTEM, + OPT_SLAP_POST_SYSTEM, + OPT_SLAP_COMMIT, + OPT_SLAP_DETACH, + 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_DEBUG_CHECK, OPT_COLUMN_TYPES, OPT_ERROR_LOG_FILE, + OPT_WRITE_BINLOG, OPT_DUMP_DATE, + OPT_MAX_CLIENT_OPTION }; diff --git a/client/completion_hash.cc b/client/completion_hash.cc index 4c777f8a704..cd0ea17dfaf 100644 --- a/client/completion_hash.cc +++ b/client/completion_hash.cc @@ -213,7 +213,7 @@ void completion_hash_clean(HashTable *ht) void completion_hash_free(HashTable *ht) { completion_hash_clean(ht); - my_free((gptr) ht->arBuckets,MYF(0)); + my_free(ht->arBuckets, MYF(0)); } 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/my_readline.h b/client/my_readline.h index 47be7fa9294..3ebe24b75b8 100644 --- a/client/my_readline.h +++ b/client/my_readline.h @@ -28,6 +28,6 @@ typedef struct st_line_buffer } LINE_BUFFER; extern LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file); -extern LINE_BUFFER *batch_readline_command(LINE_BUFFER *buffer, my_string str); +extern LINE_BUFFER *batch_readline_command(LINE_BUFFER *buffer, char * str); extern char *batch_readline(LINE_BUFFER *buffer); extern void batch_readline_end(LINE_BUFFER *buffer); diff --git a/client/mysql.cc b/client/mysql.cc index af28dce2cdd..682ab077b94 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.14"; /* Don't try to make a nice table if the data is too big */ #define MAX_COLUMN_LENGTH 1024 @@ -51,7 +51,10 @@ const char *VER= "14.12"; /* Buffer to hold 'version' and 'version_comment' */ #define MAX_SERVER_VERSION_LENGTH 128 -gptr sql_alloc(unsigned size); // Don't use mysqld alloc for these +/* Array of options to pass to libemysqld */ +#define MAX_SERVER_ARGS 64 + +void* sql_alloc(unsigned size); // Don't use mysqld alloc for these void sql_element_free(void *ptr); #include "sql_string.h" @@ -83,7 +86,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 +106,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 @@ -129,7 +132,7 @@ enum enum_info_type { INFO_INFO,INFO_ERROR,INFO_RESULT}; typedef enum enum_info_type INFO_TYPE; static MYSQL mysql; /* The connection */ -static my_bool info_flag=0,ignore_errors=0,wait_flag=0,quick=0, +static my_bool ignore_errors=0,wait_flag=0,quick=0, connected=0,opt_raw_data=0,unbuffered=0,output_tables=0, opt_rehash=1,skip_updates=0,safe_updates=0,one_database=0, opt_compress=0, using_opt_local_infile=0, @@ -138,12 +141,14 @@ 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 debug_info_flag, debug_check_flag; +static my_bool column_types_flag; static my_bool preserve_comments= 0; static ulong opt_max_allowed_packet, opt_net_buffer_length; static uint verbose=0,opt_silent=0,opt_mysql_port=0, opt_local_infile=0; -static my_string opt_mysql_unix_port=0; +static uint my_end_arg; +static char * opt_mysql_unix_port=0; static int connect_flag=CLIENT_INTERACTIVE; static char *current_host,*current_db,*current_user=0,*opt_password=0, *current_prompt=0, *delimiter_str= 0, @@ -192,6 +197,8 @@ void tee_putc(int c, FILE *file); static void tee_print_sized_data(const char *, unsigned int, unsigned int, bool); /* The names of functions that actually do the manipulation. */ static int get_options(int argc,char **argv); +extern "C" my_bool get_one_option(int optid, const struct my_option *opt, + char *argument); static int com_quit(String *str,char*), com_go(String *str,char*), com_ego(String *str,char*), com_print(String *str,char*), @@ -303,7 +310,10 @@ static COMMANDS commands[] = { }; static const char *load_default_groups[]= { "mysql","client",0 }; -static const char *server_default_groups[]= + +static int embedded_server_arg_count= 0; +static char *embedded_server_args[MAX_SERVER_ARGS]; +static const char *embedded_server_groups[]= { "server", "embedded", "mysql_SERVER", 0 }; #ifdef HAVE_READLINE @@ -342,22 +352,12 @@ static ulong start_timer(void); 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); - +extern "C" sig_handler mysql_end(int sig); +extern "C" sig_handler handle_sigint(int sig); int main(int argc,char *argv[]) { char buff[80]; - char *defaults, *extra_defaults, *group_suffix; - char *emb_argv[4]; - int emb_argc; - - /* Get --defaults-xxx args for mysql_server_init() */ - emb_argc= get_defaults_options(argc, argv, &defaults, &extra_defaults, - &group_suffix)+1; - memcpy((char*) emb_argv, (char*) argv, emb_argc * sizeof(*argv)); - emb_argv[emb_argc]= 0; MY_INIT(argv[0]); DBUG_ENTER("main"); @@ -418,7 +418,8 @@ int main(int argc,char *argv[]) my_end(0); exit(1); } - if (mysql_server_init(emb_argc, emb_argv, (char**) server_default_groups)) + if (mysql_server_init(embedded_server_arg_count, embedded_server_args, + (char**) embedded_server_groups)) { put_error(NULL); free_defaults(defaults_argv); @@ -442,7 +443,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.", @@ -506,28 +507,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,13 +543,44 @@ sig_handler mysql_end(int sig) my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); #endif my_free(current_prompt,MYF(MY_ALLOW_ZERO_PTR)); + while (embedded_server_arg_count > 1) + my_free(embedded_server_args[--embedded_server_arg_count],MYF(0)); mysql_server_end(); free_defaults(defaults_argv); - my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); + my_end(my_end_arg); 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, @@ -583,7 +593,7 @@ static struct my_option my_long_options[] = #endif {"auto-rehash", OPT_AUTO_REHASH, "Enable automatic rehashing. One doesn't need to use 'rehash' to get table and field completion, but startup and reconnecting may take a longer time. Disable with --disable-auto-rehash.", - (gptr*) &opt_rehash, (gptr*) &opt_rehash, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, + (uchar**) &opt_rehash, (uchar**) &opt_rehash, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"no-auto-rehash", 'A', "No automatic rehashing. One has to use 'rehash' to get table and field completion. This gives a quicker start of mysql and disables rehashing on reconnect. WARNING: options deprecated; use --disable-auto-rehash instead.", @@ -591,40 +601,49 @@ static struct my_option my_long_options[] = {"batch", 'B', "Don't use history file. Disable interactive behavior. (Enables --silent)", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"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}, + "Directory where character sets are.", (uchar**) &charsets_dir, + (uchar**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"column-type-info", OPT_COLUMN_TYPES, "Display column type information.", + (uchar**) &column_types_flag, (uchar**) &column_types_flag, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"comments", 'c', "Preserve comments. Send comments to the server." " The default is --skip-comments (discard comments), enable with --comments", - (gptr*) &preserve_comments, (gptr*) &preserve_comments, + (uchar**) &preserve_comments, (uchar**) &preserve_comments, 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, + (uchar**) &opt_compress, (uchar**) &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}, #else - {"debug", '#', "Output debug log", (gptr*) &default_dbug_option, - (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"debug", '#', "Output debug log", (uchar**) &default_dbug_option, + (uchar**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif - {"database", 'D', "Database to use.", (gptr*) ¤t_db, - (gptr*) ¤t_db, 0, GET_STR_ALLOC, 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}, + {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .", + (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-info", 'T', "Print some debug info at exit.", (uchar**) &debug_info_flag, + (uchar**) &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"database", 'D', "Database to use.", (uchar**) ¤t_db, + (uchar**) ¤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.", (uchar**) &default_charset, + (uchar**) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"delimiter", OPT_DELIMITER, "Delimiter to be used.", (uchar**) &delimiter_str, + (uchar**) &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, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"vertical", 'E', "Print the output of a query (rows) vertically.", - (gptr*) &vertical, (gptr*) &vertical, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, + (uchar**) &vertical, (uchar**) &vertical, 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, + (uchar**) &ignore_errors, (uchar**) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"named-commands", 'G', "Enable named commands. Named commands mean this program's internal commands; see mysql> help . When enabled, the named commands can be used from any line of the query, otherwise only from the first line, before an enter. Disable with --disable-named-commands. This option is disabled by default.", - (gptr*) &named_cmds, (gptr*) &named_cmds, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + (uchar**) &named_cmds, (uchar**) &named_cmds, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"no-named-commands", 'g', "Named commands are disabled. Use \\* form only, or use named commands only in the beginning of a line ending with a semicolon (;) Since version 10.9 the client now starts with this option ENABLED by default! Disable with '-G'. Long format commands still work from the first line. WARNING: option deprecated; use --disable-named-commands instead.", @@ -632,25 +651,25 @@ static struct my_option my_long_options[] = {"ignore-spaces", 'i', "Ignore space after function names.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"local-infile", OPT_LOCAL_INFILE, "Enable/disable LOAD DATA LOCAL INFILE.", - (gptr*) &opt_local_infile, - (gptr*) &opt_local_infile, 0, GET_BOOL, OPT_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}, - {"host", 'h', "Connect to host.", (gptr*) ¤t_host, - (gptr*) ¤t_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"html", 'H', "Produce HTML output.", (gptr*) &opt_html, (gptr*) &opt_html, + (uchar**) &opt_local_infile, + (uchar**) &opt_local_infile, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"no-beep", 'b', "Turn off beep on error.", (uchar**) &opt_nobeep, + (uchar**) &opt_nobeep, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"host", 'h', "Connect to host.", (uchar**) ¤t_host, + (uchar**) ¤t_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"html", 'H', "Produce HTML output.", (uchar**) &opt_html, (uchar**) &opt_html, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"xml", 'X', "Produce XML output", (gptr*) &opt_xml, (gptr*) &opt_xml, 0, + {"xml", 'X', "Produce XML output", (uchar**) &opt_xml, (uchar**) &opt_xml, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"line-numbers", OPT_LINE_NUMBERS, "Write line numbers for errors.", - (gptr*) &line_numbers, (gptr*) &line_numbers, 0, GET_BOOL, + (uchar**) &line_numbers, (uchar**) &line_numbers, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"skip-line-numbers", 'L', "Don't write line number for errors. WARNING: -L is deprecated, use long version of this option instead.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"unbuffered", 'n', "Flush buffer after each query.", (gptr*) &unbuffered, - (gptr*) &unbuffered, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"unbuffered", 'n', "Flush buffer after each query.", (uchar**) &unbuffered, + (uchar**) &unbuffered, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"column-names", OPT_COLUMN_NAMES, "Write column names in results.", - (gptr*) &column_names, (gptr*) &column_names, 0, GET_BOOL, + (uchar**) &column_names, (uchar**) &column_names, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"skip-column-names", 'N', "Don't write column names in results. WARNING: -N is deprecated, use long version of this options instead.", @@ -659,7 +678,7 @@ static struct my_option my_long_options[] = "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"sigint-ignore", OPT_SIGINT_IGNORE, "Ignore SIGINT (CTRL-C)", - (gptr*) &opt_sigint_ignore, (gptr*) &opt_sigint_ignore, 0, GET_BOOL, + (uchar**) &opt_sigint_ignore, (uchar**) &opt_sigint_ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"one-database", 'o', "Only update the default database. This is useful for skipping updates to other database in the update log.", @@ -685,50 +704,48 @@ static struct my_option my_long_options[] = "/etc/services, " #endif "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - (gptr*) &opt_mysql_port, - (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + (uchar**) &opt_mysql_port, + (uchar**) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"prompt", OPT_PROMPT, "Set the mysql prompt to this value.", - (gptr*) ¤t_prompt, (gptr*) ¤t_prompt, 0, GET_STR_ALLOC, + (uchar**) ¤t_prompt, (uchar**) ¤t_prompt, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 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}, {"quick", 'q', "Don't cache result, print it row by row. This may slow down the server if the output is suspended. Doesn't use history file.", - (gptr*) &quick, (gptr*) &quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + (uchar**) &quick, (uchar**) &quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"raw", 'r', "Write fields without conversion. Used with --batch.", - (gptr*) &opt_raw_data, (gptr*) &opt_raw_data, 0, GET_BOOL, NO_ARG, 0, 0, 0, + (uchar**) &opt_raw_data, (uchar**) &opt_raw_data, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"reconnect", OPT_RECONNECT, "Reconnect if the connection is lost. Disable with --disable-reconnect. This option is enabled by default.", - (gptr*) &opt_reconnect, (gptr*) &opt_reconnect, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + (uchar**) &opt_reconnect, (uchar**) &opt_reconnect, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"silent", 's', "Be more silent. Print results with a tab as separator, each row on new line.", 0, 0, 0, GET_NO_ARG, NO_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, + "Base name of shared memory.", (uchar**) &shared_memory_base_name, (uchar**) &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif {"socket", 'S', "Socket file to use for connection.", - (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR_ALLOC, + (uchar**) &opt_mysql_unix_port, (uchar**) &opt_mysql_unix_port, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #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}, + {"table", 't', "Output in table format.", (uchar**) &output_tables, + (uchar**) &output_tables, 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}, {"no-tee", OPT_NOTEE, "Disable outfile. See interactive help (\\h) also. WARNING: option deprecated; use --disable-tee instead", 0, 0, 0, GET_NO_ARG, NO_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_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"user", 'u', "User for login if not current user.", (uchar**) ¤t_user, + (uchar**) ¤t_user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif {"safe-updates", 'U', "Only allow UPDATE and DELETE that uses keys.", - (gptr*) &safe_updates, (gptr*) &safe_updates, 0, GET_BOOL, NO_ARG, 0, 0, + (uchar**) &safe_updates, (uchar**) &safe_updates, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"i-am-a-dummy", 'U', "Synonym for option --safe-updates, -U.", - (gptr*) &safe_updates, (gptr*) &safe_updates, 0, GET_BOOL, NO_ARG, 0, 0, + (uchar**) &safe_updates, (uchar**) &safe_updates, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"verbose", 'v', "Write more. (-v -v -v gives the table output format).", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -738,33 +755,35 @@ static struct my_option my_long_options[] = NO_ARG, 0, 0, 0, 0, 0, 0}, {"connect_timeout", OPT_CONNECT_TIMEOUT, "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}, + (uchar**) &opt_connect_timeout, + (uchar**) &opt_connect_timeout, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 3600*12, 0, + 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, + (uchar**) &opt_max_allowed_packet, (uchar**) &opt_max_allowed_packet, 0, GET_ULONG, REQUIRED_ARG, 16 *1024L*1024L, 4096, (longlong) 2*1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0}, {"net_buffer_length", OPT_NET_BUFFER_LENGTH, "Buffer for TCP/IP and socket communication", - (gptr*) &opt_net_buffer_length, (gptr*) &opt_net_buffer_length, 0, GET_ULONG, + (uchar**) &opt_net_buffer_length, (uchar**) &opt_net_buffer_length, 0, GET_ULONG, REQUIRED_ARG, 16384, 1024, 512*1024*1024L, MALLOC_OVERHEAD, 1024, 0}, {"select_limit", OPT_SELECT_LIMIT, "Automatic limit for SELECT when using --safe-updates", - (gptr*) &select_limit, - (gptr*) &select_limit, 0, GET_ULONG, REQUIRED_ARG, 1000L, 1, ULONG_MAX, + (uchar**) &select_limit, + (uchar**) &select_limit, 0, GET_ULONG, REQUIRED_ARG, 1000L, 1, ULONG_MAX, 0, 1, 0}, {"max_join_size", OPT_MAX_JOIN_SIZE, "Automatic limit for rows in a join when using --safe-updates", - (gptr*) &max_join_size, - (gptr*) &max_join_size, 0, GET_ULONG, REQUIRED_ARG, 1000000L, 1, ULONG_MAX, + (uchar**) &max_join_size, + (uchar**) &max_join_size, 0, GET_ULONG, REQUIRED_ARG, 1000000L, 1, ULONG_MAX, 0, 1, 0}, {"secure-auth", OPT_SECURE_AUTH, "Refuse client connecting to server if it" - " uses old (pre-4.1.1) protocol", (gptr*) &opt_secure_auth, - (gptr*) &opt_secure_auth, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + " uses old (pre-4.1.1) protocol", (uchar**) &opt_secure_auth, + (uchar**) &opt_secure_auth, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"server-arg", OPT_SERVER_ARG, "Send embedded server this as a parameter.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"show-warnings", OPT_SHOW_WARNINGS, "Show warnings after every statement.", - (gptr*) &show_warnings, (gptr*) &show_warnings, 0, GET_BOOL, NO_ARG, + (uchar**) &show_warnings, (uchar**) &show_warnings, 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} }; @@ -809,7 +828,7 @@ and you are welcome to modify and redistribute it under the GPL license\n"); } -static my_bool +my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) { @@ -887,15 +906,32 @@ 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) + opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib, + opt->name); + break; + case OPT_SERVER_ARG: +#ifdef EMBEDDED_LIBRARY + /* + When the embedded server is being tested, the client needs to be + able to pass command-line arguments to the embedded server so it can + locate the language files and data directory. + */ + if (!embedded_server_arg_count) { - fprintf(stderr, "Unknown option to protocol: %s\n", argument); - exit(1); + embedded_server_arg_count= 1; + embedded_server_args[0]= (char*) ""; + } + if (embedded_server_arg_count == MAX_SERVER_ARGS-1 || + !(embedded_server_args[embedded_server_arg_count++]= + my_strdup(argument, MYF(MY_FAE)))) + { + put_info("Can't use server argument", INFO_ERROR); + return 0; } +#else /*EMBEDDED_LIBRARY */ + printf("WARNING: --server-arg option not supported in this configuration.\n"); +#endif break; - } - break; case 'A': opt_rehash= 0; break; @@ -934,7 +970,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case '#': DBUG_PUSH(argument ? argument : default_dbug_option); - info_flag= 1; + debug_info_flag= 1; break; case 's': if (argument == disabled_my_option) @@ -1028,12 +1064,16 @@ static int get_options(int argc, char **argv) } if (tty_password) opt_password= get_tty_password(NullS); + if (debug_info_flag) + my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO; + if (debug_check_flag) + my_end_arg= MY_CHECK_ERROR; return(0); } static int read_and_execute(bool interactive) { -#if defined(OS2) || defined(__NETWARE__) +#if defined(__NETWARE__) char linebuffer[254]; String buffer; #endif @@ -1081,9 +1121,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); @@ -1094,12 +1132,12 @@ 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); buffer.length(0); - unsigned long clen; + size_t clen; do { line= my_cgets((char*)tmpbuf.ptr(), tmpbuf.alloced_length()-1, &clen); @@ -1115,32 +1153,12 @@ static int read_and_execute(bool interactive) */ if (line) 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 @@ -1188,7 +1206,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__) @@ -1528,7 +1546,7 @@ static bool add_line(String &buffer,char *line,char *in_string, #ifdef HAVE_READLINE static char *new_command_generator(const char *text, int); -static char **new_mysql_completion (const char *text, int start, int end); +extern "C" char **new_mysql_completion (const char *text, int start, int end); /* Tell the GNU Readline library how to complete. We want to try to complete @@ -1537,9 +1555,9 @@ static char **new_mysql_completion (const char *text, int start, int end); */ #if defined(USE_NEW_READLINE_INTERFACE) || defined(USE_LIBEDIT_INTERFACE) -char *no_completion(const char*,int) +extern "C" char *no_completion(const char*,int) #else -char *no_completion() +extern "C" char *no_completion() #endif { return 0; /* No filename completion */ @@ -1641,9 +1659,9 @@ static void initialize_readline (char *name) array of matches, or NULL if there aren't any. */ -static char **new_mysql_completion (const char *text, - int start __attribute__((unused)), - int end __attribute__((unused))) +char **new_mysql_completion (const char *text, + int start __attribute__((unused)), + int end __attribute__((unused))) { if (!status.batch && !quick) #if defined(USE_NEW_READLINE_INTERFACE) @@ -2148,10 +2166,11 @@ com_go(String *buffer,char *line __attribute__((unused))) { char buff[200], time_buff[32], *pos; MYSQL_RES *result; - ulong timer, warnings; + ulong timer, warnings= 0; uint error= 0; int err= 0; + interrupted_query= 0; if (!status.batch) { old_buffer= *buffer; // Save for edit command @@ -2187,9 +2206,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 @@ -2201,33 +2218,26 @@ com_go(String *buffer,char *line __attribute__((unused))) } #endif - if (error) - { - buffer->length(0); // Remove query on error - executing_query= 0; - return error; - } - error=0; buffer->length(0); + if (error) + goto end; + do { if (quick) { if (!(result=mysql_use_result(&mysql)) && mysql_field_count(&mysql)) { - executing_query= 0; - return put_error(&mysql); + error= put_error(&mysql); + goto end; } } else { error= mysql_store_result_for_lazy(&result); if (error) - { - executing_query= 0; - return error; - } + goto end; } if (verbose >= 3 || !opt_silent) @@ -2236,7 +2246,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) @@ -2301,23 +2311,20 @@ 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); - if (show_warnings == 1 && warnings >= 1) /* Show warnings if any */ - { - init_pager(); +end: + + /* Show warnings if any or error occured */ + if (show_warnings == 1 && (warnings >= 1 || error)) print_warnings(); - end_pager(); - } if (!error && !status.batch && (mysql.server_status & SERVER_STATUS_DB_DROPPED)) get_current_db(); + executing_query= 0; return error; /* New command follows */ } @@ -2389,32 +2396,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-?"; } } @@ -2443,6 +2450,7 @@ static char *fieldflags2str(uint f) { ff2s_check_flag(GROUP); ff2s_check_flag(UNIQUE); ff2s_check_flag(BINCMP); + ff2s_check_flag(ON_UPDATE_NOW); #undef ff2s_check_flag if (f) sprintf(s, " unknows=0x%04x", f); @@ -2488,7 +2496,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)) @@ -2533,6 +2541,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); @@ -2544,7 +2554,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"; @@ -2584,7 +2593,7 @@ print_table_data(MYSQL_RES *result) (void) tee_fputs("\n", PAGER); } tee_puts((char*) separator.ptr(), PAGER); - my_afree((gptr) num_flag); + my_afree((uchar*) num_flag); } @@ -2638,6 +2647,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++) @@ -2668,6 +2679,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++) @@ -2707,6 +2720,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); @@ -2728,6 +2743,9 @@ static void print_warnings() MYSQL_RES *result; MYSQL_ROW cur; my_ulonglong num_rows; + + /* Save current error before calling "show warnings" */ + uint error= mysql_errno(&mysql); /* Get the warnings */ query= "show warnings"; @@ -2736,16 +2754,28 @@ static void print_warnings() /* Bail out when no warnings */ if (!(num_rows= mysql_num_rows(result))) - { - mysql_free_result(result); - return; - } + goto end; + + cur= mysql_fetch_row(result); + + /* + Don't print a duplicate of the current error. It is possible for SHOW + WARNINGS to return multiple errors with the same code, but different + messages. To be safe, skip printing the duplicate only if it is the only + warning. + */ + if (!cur || num_rows == 1 && error == (uint) strtoul(cur[1], NULL, 10)) + goto end; /* Print the warnings */ - while ((cur= mysql_fetch_row(result))) + init_pager(); + do { tee_fprintf(PAGER, "%s (Code %s): %s\n", cur[0], cur[1], cur[2]); - } + } while ((cur= mysql_fetch_row(result))); + end_pager(); + +end: mysql_free_result(result); } @@ -2977,10 +3007,10 @@ com_edit(String *buffer,char *line __attribute__((unused))) MYF(MY_WME))) < 0) goto err; if (buffer->is_empty() && !old_buffer.is_empty()) - (void) my_write(fd,(byte*) old_buffer.ptr(),old_buffer.length(), + (void) my_write(fd,(uchar*) old_buffer.ptr(),old_buffer.length(), MYF(MY_WME)); else - (void) my_write(fd,(byte*) buffer->ptr(),buffer->length(),MYF(MY_WME)); + (void) my_write(fd,(uchar*) buffer->ptr(),buffer->length(),MYF(MY_WME)); (void) my_close(fd,MYF(0)); if (!(editor = (char *)getenv("EDITOR")) && @@ -3421,7 +3451,7 @@ sql_real_connect(char *host,char *database,char *user,char *password, } connected=1; #ifndef EMBEDDED_LIBRARY - mysql.reconnect=info_flag ? 1 : 0; // We want to know if this happens + mysql.reconnect= debug_info_flag; // We want to know if this happens #else mysql.reconnect= 1; #endif @@ -3720,9 +3750,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) @@ -3738,9 +3765,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); } @@ -3751,9 +3775,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); @@ -3764,14 +3785,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> @@ -3783,7 +3801,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; @@ -4043,13 +4061,13 @@ static int com_prompt(String *buffer, char *line) #ifndef EMBEDDED_LIBRARY /* Keep sql_string library happy */ -gptr sql_alloc(unsigned int Size) +void *sql_alloc(size_t Size) { return my_malloc(Size,MYF(MY_WME)); } void sql_element_free(void *ptr) { - my_free((gptr) ptr,MYF(0)); + my_free(ptr,MYF(0)); } #endif /* EMBEDDED_LIBRARY */ diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index 02829cd2178..fe2e48fdba1 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -17,6 +17,8 @@ #include <sslopt-vars.h> #include "../scripts/mysql_fix_privilege_tables_sql.c" +#define VER "1.1" + #ifdef HAVE_SYS_WAIT_H #include <sys/wait.h> #endif @@ -32,7 +34,8 @@ static char mysql_path[FN_REFLEN]; static char mysqlcheck_path[FN_REFLEN]; -static my_bool opt_force, opt_verbose; +static my_bool opt_force, opt_verbose, debug_info_flag, debug_check_flag; +static uint my_end_arg= 0; static char *opt_user= (char*)"root"; static DYNAMIC_STRING ds_args; @@ -56,6 +59,11 @@ static struct my_option my_long_options[]= NO_ARG, 0, 0, 0, 0, 0, 0}, {"basedir", 'b', "Not used by mysql_upgrade. Only for backward compatibilty", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"character-sets-dir", OPT_CHARSETS_DIR, + "Directory where character sets are.", 0, + 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"compress", OPT_COMPRESS, "Use compression in server/client protocol.", + (uchar**)¬_used, (uchar**)¬_used, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"datadir", 'd', "Not used by mysql_upgrade. Only for backward compatibilty", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -63,26 +71,26 @@ static struct my_option my_long_options[]= {"debug", '#', "This is a non-debug version. Catch this and exit", 0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0}, #else - {"debug", '#', "Output debug log", (gptr *) & default_dbug_option, - (gptr *) & default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"debug", '#', "Output debug log", (uchar* *) & default_dbug_option, + (uchar* *) & default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif + {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .", + (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-info", 'T', "Print some debug info at exit.", (uchar**) &debug_info_flag, + (uchar**) &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"default-character-set", OPT_DEFAULT_CHARSET, "Set the default character set.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"character-sets-dir", OPT_CHARSETS_DIR, - "Directory where character sets are.", 0, - 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"compress", OPT_COMPRESS, "Use compression in server/client protocol.", - (gptr*)¬_used, (gptr*)¬_used, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"force", 'f', "Force execution of mysqlcheck even if mysql_upgrade " "has already been executed for the current version of MySQL.", - (gptr*)&opt_force, (gptr*)&opt_force, 0, + (uchar**)&opt_force, (uchar**)&opt_force, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"host",'h', "Connect to host.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"password", 'p', "Password to use when connecting to server. If password is not given" - " it's solicited on the tty.", (gptr*) &opt_password,(gptr*) &opt_password, + " it's solicited on the tty.", (uchar**) &opt_password,(uchar**) &opt_password, 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, @@ -105,11 +113,11 @@ static struct my_option my_long_options[]= #endif {"socket", 'S', "Socket file to use for connection.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"user", 'u', "User for login if not current user.", (gptr*) &opt_user, - (gptr*) &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"user", 'u', "User for login if not current user.", (uchar**) &opt_user, + (uchar**) &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #include <sslopt-longopts.h> {"verbose", 'v', "Display more output about the process", - (gptr*) &opt_verbose, (gptr*) &opt_verbose, 0, + (uchar**) &opt_verbose, (uchar**) &opt_verbose, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -143,7 +151,7 @@ static void die(const char *fmt, ...) va_end(args); free_used_memory(); - my_end(MY_CHECK_ERROR); + my_end(my_end_arg); exit(1); } @@ -205,8 +213,9 @@ get_one_option(int optid, const struct my_option *opt, switch (optid) { case '?': - printf("MySQL utility for upgrading database to MySQL version %s\n", - MYSQL_SERVER_VERSION); + printf("%s Ver %s Distrib %s, for %s (%s)\n", + my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); + puts("MySQL utility for upgrading databases to new MySQL versions\n"); my_print_help(my_long_options); exit(0); break; @@ -214,6 +223,7 @@ get_one_option(int optid, const struct my_option *opt, case '#': DBUG_PUSH(argument ? argument : default_dbug_option); add_option= FALSE; + debug_check_flag= 1; break; case 'p': @@ -351,6 +361,7 @@ static my_bool get_full_path_to_executable(char* path) static void find_tool(char *tool_path, const char *tool_name) { + size_t path_len; char path[FN_REFLEN]; DYNAMIC_STRING ds_tmp; DBUG_ENTER("find_tool"); @@ -388,7 +399,7 @@ static void find_tool(char *tool_path, const char *tool_name) DBUG_PRINT("info", ("path: '%s'", path)); /* Chop off binary name (i.e mysql-upgrade) from path */ - dirname_part(path, path); + dirname_part(path, path, &path_len); /* When running in a not yet installed build and using libtool, @@ -398,13 +409,13 @@ static void find_tool(char *tool_path, const char *tool_name) mysqlcheck). Thus if path ends in .libs/, step up one directory and execute the tools from there */ - path[max((strlen(path)-1), 0)]= 0; /* Chop off last / */ + path[max(path_len-1, 0)]= 0; /* Chop off last / */ if (strncmp(path + dirname_length(path), ".libs", 5) == 0) { DBUG_PRINT("info", ("Chopping off .libs from '%s'", path)); /* Chop off .libs */ - dirname_part(path, path); + dirname_part(path, path, &path_len); } @@ -454,7 +465,7 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res, MYF(MY_WME))) < 0) die("Failed to create temporary file for defaults"); - if (my_write(fd, query, strlen(query), + if (my_write(fd, (uchar*) query, strlen(query), MYF(MY_FNABP | MY_WME))) { my_close(fd, MYF(0)); @@ -752,6 +763,10 @@ int main(int argc, char **argv) if (handle_options(&argc, &argv, my_long_options, get_one_option)) die(NULL); + if (debug_info_flag) + my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO; + if (debug_check_flag) + my_end_arg= MY_CHECK_ERROR; if (tty_password) { @@ -800,7 +815,7 @@ int main(int argc, char **argv) create_mysql_upgrade_info_file(); free_used_memory(); - my_end(MY_CHECK_ERROR); + my_end(my_end_arg); exit(0); } diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index 54f67c5df2d..b3b699f61fd 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,11 +40,12 @@ 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; -static uint tcp_port = 0, option_wait = 0, option_silent=0, nr_iterations, - opt_count_iterations= 0; + tty_password= 0, opt_nobeep; +static my_bool debug_info_flag= 0, debug_check_flag= 0; +static uint tcp_port = 0, option_wait = 0, option_silent=0, nr_iterations; +static uint opt_count_iterations= 0, my_end_arg; static ulong opt_connect_timeout, opt_shutdown_timeout; -static my_string unix_port=0; +static char * unix_port=0; #ifdef LATER_HAVE_NDBCLUSTER_DB static my_bool opt_ndbcluster=0; static char *opt_ndb_connectstring=0; @@ -54,6 +55,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 @@ -69,10 +71,12 @@ static uint ex_var_count, max_var_length, max_val_length; static void print_version(void); static void usage(void); +extern "C" my_bool get_one_option(int optid, const struct my_option *opt, + char *argument); static my_bool sql_connect(MYSQL *mysql, uint wait); static int execute_commands(MYSQL *mysql,int argc, char **argv); static int drop_db(MYSQL *mysql,const char *db); -static sig_handler endprog(int signal_number); +extern "C" sig_handler endprog(int signal_number); static void nice_time(ulong sec,char *buff); static void print_header(MYSQL_RES *result); static void print_top(MYSQL_RES *result); @@ -131,27 +135,37 @@ static struct my_option my_long_options[] = #endif {"count", 'c', "Number of iterations to make. This works with -i (--sleep) only.", - (gptr*) &nr_iterations, (gptr*) &nr_iterations, 0, GET_UINT, + (uchar**) &nr_iterations, (uchar**) &nr_iterations, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifndef DBUG_OFF {"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-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .", + (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", + (uchar**) &debug_info_flag, (uchar**) &debug_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, + (uchar**) &option_force, (uchar**) &option_force, 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, + (uchar**) &opt_compress, (uchar**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"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}, + "Directory where character sets are.", (uchar**) &charsets_dir, + (uchar**) &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}, + "Set the default character set.", (uchar**) &default_charset, + (uchar**) &default_charset, 0, GET_STR, REQUIRED_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, + {"host", 'h', "Connect to host.", (uchar**) &host, (uchar**) &host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"no-beep", 'b', "Turn off beep on error.", (uchar**) &opt_nobeep, + (uchar**) &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}, @@ -165,58 +179,58 @@ static struct my_option my_long_options[] = "/etc/services, " #endif "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - (gptr*) &tcp_port, - (gptr*) &tcp_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + (uchar**) &tcp_port, + (uchar**) &tcp_port, 0, GET_UINT, REQUIRED_ARG, 0, 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}, {"relative", 'r', "Show difference between current and previous values when used with -i. Currently works only with extended-status.", - (gptr*) &opt_relative, (gptr*) &opt_relative, 0, GET_BOOL, NO_ARG, 0, 0, 0, + (uchar**) &opt_relative, (uchar**) &opt_relative, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"set-variable", 'O', "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.", 0, 0, 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, + "Base name of shared memory.", (uchar**) &shared_memory_base_name, (uchar**) &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif {"silent", 's', "Silently exit if one can't connect to server.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"socket", 'S', "Socket file to use for connection.", - (gptr*) &unix_port, (gptr*) &unix_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, + (uchar**) &unix_port, (uchar**) &unix_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"sleep", 'i', "Execute commands again and again with a sleep between.", - (gptr*) &interval, (gptr*) &interval, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, + (uchar**) &interval, (uchar**) &interval, 0, GET_INT, 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_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"user", 'u', "User for login if not current user.", (uchar**) &user, + (uchar**) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif - {"verbose", 'v', "Write more information.", (gptr*) &opt_verbose, - (gptr*) &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"verbose", 'v', "Write more information.", (uchar**) &opt_verbose, + (uchar**) &opt_verbose, 0, GET_BOOL, 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}, {"vertical", 'E', "Print output vertically. Is similar to --relative, but prints output vertically.", - (gptr*) &opt_vertical, (gptr*) &opt_vertical, 0, GET_BOOL, NO_ARG, 0, 0, 0, + (uchar**) &opt_vertical, (uchar**) &opt_vertical, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"wait", 'w', "Wait and retry if connection is down.", 0, 0, 0, GET_UINT, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"connect_timeout", OPT_CONNECT_TIMEOUT, "", (gptr*) &opt_connect_timeout, - (gptr*) &opt_connect_timeout, 0, GET_ULONG, REQUIRED_ARG, 3600*12, 0, + {"connect_timeout", OPT_CONNECT_TIMEOUT, "", (uchar**) &opt_connect_timeout, + (uchar**) &opt_connect_timeout, 0, GET_ULONG, REQUIRED_ARG, 3600*12, 0, 3600*12, 0, 1, 0}, - {"shutdown_timeout", OPT_SHUTDOWN_TIMEOUT, "", (gptr*) &opt_shutdown_timeout, - (gptr*) &opt_shutdown_timeout, 0, GET_ULONG, REQUIRED_ARG, + {"shutdown_timeout", OPT_SHUTDOWN_TIMEOUT, "", (uchar**) &opt_shutdown_timeout, + (uchar**) &opt_shutdown_timeout, 0, GET_ULONG, REQUIRED_ARG, SHUTDOWN_DEF_TIMEOUT, 0, 3600*12, 0, 1, 0}, #ifdef LATER_HAVE_NDBCLUSTER_DB {"ndbcluster", OPT_NDBCLUSTER, "" - "", (gptr*) &opt_ndbcluster, - (gptr*) &opt_ndbcluster, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + "", (uchar**) &opt_ndbcluster, + (uchar**) &opt_ndbcluster, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"ndb-connectstring", OPT_NDB_CONNECTSTRING, "" - "", (gptr*) &opt_ndb_connectstring, - (gptr*) &opt_ndb_connectstring, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "", (uchar**) &opt_ndb_connectstring, + (uchar**) &opt_ndb_connectstring, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -224,7 +238,7 @@ static struct my_option my_long_options[] = static const char *load_default_groups[]= { "mysqladmin","client",0 }; -static my_bool +my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) { @@ -288,15 +302,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(); @@ -321,6 +330,10 @@ int main(int argc,char *argv[]) free_defaults(save_argv); exit(ho_error); } + if (debug_info_flag) + my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO; + if (debug_check_flag) + my_end_arg= MY_CHECK_ERROR; if (argc == 0) { @@ -356,6 +369,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); @@ -417,13 +432,13 @@ 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(my_end_arg); exit(error ? 1 : 0); return 0; } -static sig_handler endprog(int signal_number __attribute__((unused))) +sig_handler endprog(int signal_number __attribute__((unused))) { interrupted=1; } @@ -454,7 +469,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, @@ -529,14 +544,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++; @@ -546,7 +561,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])) @@ -571,7 +586,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; } @@ -592,7 +607,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; } @@ -603,7 +618,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; } @@ -611,7 +626,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; } @@ -655,7 +670,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; } @@ -678,7 +693,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]; @@ -686,7 +701,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; } @@ -702,7 +717,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; } @@ -716,7 +731,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; } @@ -738,7 +753,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; } @@ -788,7 +803,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; } @@ -798,7 +813,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; } @@ -808,7 +823,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; } @@ -818,7 +833,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; } @@ -835,7 +850,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]) @@ -858,7 +873,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 @@ -869,7 +884,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)) @@ -894,7 +909,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)) @@ -902,7 +917,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 @@ -916,7 +931,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; } } @@ -927,7 +942,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; } @@ -937,7 +952,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; } @@ -963,7 +978,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; } } @@ -974,7 +989,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; } { @@ -988,7 +1003,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; } } @@ -1066,7 +1081,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; } @@ -1291,7 +1306,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 3d06a21c243..7a4135ab649 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -63,11 +63,15 @@ 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 debug_info_flag, debug_check_flag; +static my_bool force_if_open_opt= 1; static ulonglong offset = 0; static const char* host = 0; static int port= 0; +static uint my_end_arg; static const char* sock= 0; static const char* user = 0; static char* pass = 0; @@ -84,6 +88,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. @@ -293,7 +298,7 @@ File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le, int Load_log_processor::load_old_format_file(NET* net, const char*server_fname, uint server_fname_len, File file) { - char buf[FN_REFLEN+1]; + uchar buf[FN_REFLEN+1]; buf[0] = 0; memcpy(buf + 1, server_fname, server_fname_len + 1); if (my_net_write(net, buf, server_fname_len +2) || net_flush(net)) @@ -307,7 +312,7 @@ int Load_log_processor::load_old_format_file(NET* net, const char*server_fname, ulong packet_len = my_net_read(net); if (packet_len == 0) { - if (my_net_write(net, "", 0) || net_flush(net)) + if (my_net_write(net, (uchar*) "", 0) || net_flush(net)) { sql_print_error("Failed sending the ack packet"); return -1; @@ -331,7 +336,7 @@ int Load_log_processor::load_old_format_file(NET* net, const char*server_fname, sql_print_error("Illegal length of packet read from net"); return -1; } - if (my_write(file, (byte*) net->read_pos, + if (my_write(file, (uchar*) net->read_pos, (uint) packet_len, MYF(MY_WME|MY_NABP))) return -1; } @@ -376,7 +381,7 @@ int Load_log_processor::process_first_event(const char *bname, uint blen, File_name_record rec; DBUG_ENTER("Load_log_processor::process_first_event"); - if (!(fname= my_malloc(full_len,MYF(MY_WME)))) + if (!(fname= (char*) my_malloc(full_len,MYF(MY_WME)))) DBUG_RETURN(-1); memcpy(fname, target_dir_name, target_dir_name_len); @@ -395,7 +400,7 @@ int Load_log_processor::process_first_event(const char *bname, uint blen, rec.fname= fname; rec.event= ce; - if (set_dynamic(&file_names, (gptr)&rec, file_id)) + if (set_dynamic(&file_names, (uchar*)&rec, file_id)) { sql_print_error("Could not construct local filename %s%s", target_dir_name, bname); @@ -405,7 +410,7 @@ int Load_log_processor::process_first_event(const char *bname, uint blen, if (ce) ce->set_fname_outside_temp_buf(fname, strlen(fname)); - if (my_write(file, (byte*)block, block_len, MYF(MY_WME|MY_NABP))) + if (my_write(file, (uchar*)block, block_len, MYF(MY_WME|MY_NABP))) error= -1; if (my_close(file, MYF(MY_WME))) error= -1; @@ -444,7 +449,7 @@ int Load_log_processor::process(Append_block_log_event *ae) if (((file= my_open(fname, O_APPEND|O_BINARY|O_WRONLY,MYF(MY_WME))) < 0)) DBUG_RETURN(-1); - if (my_write(file,(byte*)ae->block,ae->block_len,MYF(MY_WME|MY_NABP))) + if (my_write(file,(uchar*)ae->block,ae->block_len,MYF(MY_WME|MY_NABP))) error= -1; if (my_close(file,MYF(MY_WME))) error= -1; @@ -473,6 +478,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 +540,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 +557,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 +589,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,8 +634,10 @@ 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); + ev->temp_buf= 0; // as the event ref is zeroed /* We don't want this event to be deleted now, so let's hide it (I (Guilhem) should later see if this triggers a non-serious Valgrind @@ -603,6 +645,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); @@ -637,19 +685,34 @@ Begin_load_query event for file_id: %u\n", exlq->file_id); end: rec_count++; + /* + Destroy the log_event object. If reading from a remote host, + set the temp_buf to NULL so that memory isn't freed twice. + */ if (ev) + { + if (remote_opt) + ev->temp_buf= 0; delete ev; + } DBUG_RETURN(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}, #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.", + (uchar**) &opt_base64_output, (uchar**) &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 @@ -657,33 +720,43 @@ static struct my_option my_long_options[] = SET @`a`:=_cp850 0x4DFC6C6C6572 COLLATE `cp850_general_ci`; */ {"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}, -#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 + "Directory where character sets are.", (uchar**) &charsets_dir, + (uchar**) &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, + (uchar**) &database, (uchar**) &database, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifndef DBUG_OFF + {"debug", '#', "Output debug log.", (uchar**) &default_dbug_option, + (uchar**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, +#endif + {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .", + (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", + (uchar**) &debug_info_flag, (uchar**) &debug_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 " "when restoring after a crash to avoid duplication of the statements you " "already have. NOTE: you will need a SUPER privilege to use this option.", - (gptr*) &disable_log_bin, (gptr*) &disable_log_bin, 0, GET_BOOL, + (uchar**) &disable_log_bin, (uchar**) &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.", + (uchar**) &force_if_open_opt, (uchar**) &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, + (uchar**) &force_opt, (uchar**) &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, + (uchar**) &opt_hexdump, (uchar**) &opt_hexdump, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"host", 'h', "Get the binlog from server.", (gptr*) &host, (gptr*) &host, + {"host", 'h', "Get the binlog from server.", (uchar**) &host, (uchar**) &host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"offset", 'o', "Skip the first N entries.", (gptr*) &offset, (gptr*) &offset, + {"local-load", 'l', "Prepare local temporary files for LOAD DATA INFILE in the specified directory.", + (uchar**) &dirname_for_local_load, (uchar**) &dirname_for_local_load, 0, + GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"offset", 'o', "Skip the first N entries.", (uchar**) &offset, (uchar**) &offset, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"password", 'p', "Password to connect to remote server.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, @@ -693,33 +766,33 @@ static struct my_option my_long_options[] = "/etc/services, " #endif "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - (gptr*) &port, (gptr*) &port, 0, GET_INT, REQUIRED_ARG, + (uchar**) &port, (uchar**) &port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"position", 'j', "Deprecated. Use --start-position instead.", - (gptr*) &start_position, (gptr*) &start_position, 0, GET_ULL, + (uchar**) &start_position, (uchar**) &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}, {"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, + (uchar**) &remote_opt, (uchar**) &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.", + (uchar**) &server_id, (uchar**) &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}, + "Add 'SET NAMES character_set' to the output.", (uchar**) &charset, + (uchar**) &charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"short-form", 's', "Just show the queries, no extra info.", - (gptr*) &short_form, (gptr*) &short_form, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + (uchar**) &short_form, (uchar**) &short_form, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"socket", 'S', "Socket file to use for connection.", - (gptr*) &sock, (gptr*) &sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, + (uchar**) &sock, (uchar**) &sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"start-datetime", OPT_START_DATETIME, "Start reading the binlog at first event having a datetime equal or " @@ -727,43 +800,44 @@ static struct my_option my_long_options[] = "in the local time zone, in any format accepted by the MySQL server " "for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 " "(you should probably use quotes for your shell to set it properly).", - (gptr*) &start_datetime_str, (gptr*) &start_datetime_str, + (uchar**) &start_datetime_str, (uchar**) &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.", + (uchar**) &start_position, (uchar**) &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 " "in the local time zone, in any format accepted by the MySQL server " "for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 " "(you should probably use quotes for your shell to set it properly).", - (gptr*) &stop_datetime_str, (gptr*) &stop_datetime_str, + (uchar**) &stop_datetime_str, (uchar**) &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.", - (gptr*) &stop_position, (gptr*) &stop_position, 0, GET_ULL, + (uchar**) &stop_position, (uchar**) &stop_position, 0, GET_ULL, REQUIRED_ARG, (ulonglong)(~(my_off_t)0), BIN_LOG_HEADER_SIZE, (ulonglong)(~(my_off_t)0), 0, 0, 0}, {"to-last-log", 't', "Requires -R. Will not stop at the end of the \ requested binlog but rather continue printing until the end of the last \ binlog of the MySQL server. If you send the output to the same MySQL server, \ that may lead to an endless loop.", - (gptr*) &to_last_remote_log, (gptr*) &to_last_remote_log, 0, GET_BOOL, + (uchar**) &to_last_remote_log, (uchar**) &to_last_remote_log, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"user", 'u', "Connect to the remote server as username.", - (gptr*) &user, (gptr*) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, + (uchar**) &user, (uchar**) &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", + (uchar**) &open_files_limit, (uchar**) &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} }; @@ -797,7 +871,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(my_end_arg | MY_DONT_FREE_DBUG); exit(1); } @@ -805,7 +879,7 @@ static void die(const char* fmt, ...) static void print_version() { - printf("%s Ver 3.2 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE); + printf("%s Ver 3.3 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE); NETWARE_SET_SCREEN_MODE(1); } @@ -890,14 +964,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; @@ -926,7 +995,10 @@ static int parse_args(int *argc, char*** argv) load_defaults("my",load_default_groups,argc,argv); if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); - + if (debug_info_flag) + my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO; + if (debug_check_flag) + my_end_arg= MY_CHECK_ERROR; return 0; } @@ -955,19 +1027,22 @@ 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 */ fprintf(result_file, "DELIMITER /*!*/;\n"); - strcpy(print_event_info.delimiter, "/*!*/;"); + strmov(print_event_info.delimiter, "/*!*/;"); rc= (remote_opt ? dump_remote_log_entries(&print_event_info, logname) : dump_local_log_entries(&print_event_info, logname)); /* Set delimiter back to semicolon */ fprintf(result_file, "DELIMITER ;\n"); - strcpy(print_event_info.delimiter, ";"); + strmov(print_event_info.delimiter, ";"); return rc; } @@ -1017,6 +1092,7 @@ static int check_master_version(MYSQL *mysql_arg, break; case '4': *description_event= new Format_description_log_event(3); + break; case '5': /* The server is soon going to send us its Format_description log @@ -1042,7 +1118,7 @@ static int dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info, const char* logname) { - char buf[128]; + uchar buf[128]; ulong len; uint logname_len; NET* net; @@ -1078,7 +1154,7 @@ could be out of memory"); int4store(buf, (uint32)start_position); int2store(buf + BIN_LOG_HEADER_SIZE, binlog_flags); - size_s tlen = strlen(logname); + size_t tlen = strlen(logname); if (tlen > UINT_MAX) { fprintf(stderr,"Log name too long\n"); @@ -1120,6 +1196,12 @@ could be out of memory"); error= 1; goto err; } + /* + If reading from a remote host, ensure the temp_buf for the + Log_event class is pointing to the incoming stream. + */ + if (remote_opt) + ev->register_temp_buf((char*) net->read_pos + 1); Log_event_type type= ev->get_type_code(); if (glob_description_event->binlog_version >= 3 || @@ -1226,17 +1308,23 @@ err: static void check_header(IO_CACHE* file, Format_description_log_event **description_event) { - byte header[BIN_LOG_HEADER_SIZE]; - byte buf[PROBE_HEADER_LEN]; + uchar header[BIN_LOG_HEADER_SIZE]; + uchar buf[PROBE_HEADER_LEN]; my_off_t tmp_pos, pos; *description_event= new Format_description_log_event(3); pos= my_b_tell(file); my_b_seek(file, (my_off_t)0); if (my_b_read(file, header, sizeof(header))) + { + delete *description_event; die("Failed reading header; Probably an empty file"); + } if (memcmp(header, BINLOG_MAGIC, sizeof(header))) + { + delete *description_event; die("File is not a binary log file"); + } /* Imagine we are running with --start-position=1000. We still need @@ -1257,9 +1345,12 @@ static void check_header(IO_CACHE* file, if (my_b_read(file, buf, sizeof(buf))) { if (file->error) + { + delete *description_event; die("\ Could not read entry at offset %lu : Error in log format or read error", tmp_pos); + } /* Otherwise this is just EOF : this log currently contains 0-2 events. Maybe it's going to be filled in the next @@ -1295,13 +1386,19 @@ Could not read entry at offset %lu : Error in log format or read error", break; else if (buf[4] == FORMAT_DESCRIPTION_EVENT) /* This is 5.0 */ { + Format_description_log_event *new_description_event; my_b_seek(file, tmp_pos); /* seek back to event's start */ - if (!(*description_event= (Format_description_log_event*) + if (!(new_description_event= (Format_description_log_event*) Log_event::read_log_event(file, *description_event))) /* EOF can't be hit here normally, so it's a real error */ + { + delete *description_event; die("Could not read a Format_description_log_event event \ at offset %lu ; this could be a log format error or read error", tmp_pos); + } + delete *description_event; + *description_event= new_description_event; DBUG_PRINT("info",("Setting description_event")); } else if (buf[4] == ROTATE_EVENT) @@ -1310,8 +1407,11 @@ at offset %lu ; this could be a log format error or read error", my_b_seek(file, tmp_pos); /* seek back to event's start */ if (!(ev= Log_event::read_log_event(file, *description_event))) /* EOF can't be hit here normally, so it's a real error */ + { + delete *description_event; die("Could not read a Rotate_log_event event at offset %lu ;" " this could be a log format error or read error", tmp_pos); + } delete ev; } else @@ -1327,7 +1427,7 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, { File fd = -1; IO_CACHE cache,*file= &cache; - byte tmp_buff[BIN_LOG_HEADER_SIZE]; + uchar tmp_buff[BIN_LOG_HEADER_SIZE]; int error= 0; if (logname && logname[0] != '-') @@ -1345,15 +1445,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) @@ -1361,8 +1458,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; @@ -1370,7 +1466,7 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, if (start_position) { /* skip 'start_position' characters from stdin */ - byte buff[IO_SIZE]; + uchar buff[IO_SIZE]; my_off_t length,tmp; for (length= start_position_mot ; length > 0 ; length-=tmp) { @@ -1385,7 +1481,10 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, } if (!glob_description_event || !glob_description_event->is_valid()) + { + delete glob_description_event; die("Invalid Format_description log event; could be out of memory"); + } if (!start_position && my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE)) { @@ -1436,7 +1535,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]); @@ -1534,7 +1633,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(my_end_arg | 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 } @@ -1546,12 +1655,7 @@ int main(int argc, char** argv) #include "my_decimal.h" #include "decimal.c" - -#if defined(__WIN__) && !defined(CMAKE_BUILD) -#include "my_decimal.cpp" -#include "log_event.cpp" -#else #include "my_decimal.cc" #include "log_event.cc" -#endif +#include "log_event_old.cc" diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 3b504eb50b0..3350bfa17a7 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.5.0" #include "client_priv.h" #include <m_ctype.h> @@ -33,9 +33,12 @@ 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, debug_info_flag= 0, debug_check_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 int my_end_arg; +static char * opt_mysql_unix_port = 0; static char *opt_password = 0, *current_user = 0, *default_charset = (char *)MYSQL_DEFAULT_CHARSET_NAME, *current_host = 0; @@ -47,19 +50,19 @@ 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[] = { {"all-databases", 'A', "Check 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, + (uchar**) &opt_alldbs, (uchar**) &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"analyze", 'a', "Analyze given tables.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"all-in-1", '1', "Instead of issuing one query for each table, use one query per database, naming all tables in the database in a comma-separated list.", - (gptr*) &opt_all_in_1, (gptr*) &opt_all_in_1, 0, GET_BOOL, NO_ARG, 0, 0, 0, + (uchar**) &opt_all_in_1, (uchar**) &opt_all_in_1, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef __NETWARE__ {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", @@ -67,11 +70,11 @@ static struct my_option my_long_options[] = #endif {"auto-repair", OPT_AUTO_REPAIR, "If a checked table is corrupted, automatically fix it. Repairing will be done after all tables have been checked, if corrupted ones were found.", - (gptr*) &opt_auto_repair, (gptr*) &opt_auto_repair, 0, GET_BOOL, NO_ARG, 0, + (uchar**) &opt_auto_repair, (uchar**) &opt_auto_repair, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"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}, + "Directory where character sets are.", (uchar**) &charsets_dir, + (uchar**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"check", 'c', "Check table for errors.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"check-only-changed", 'C', @@ -81,11 +84,11 @@ static struct my_option my_long_options[] = "Check tables for version-dependent changes. May be used with --auto-repair to correct tables requiring version-dependent updates.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"compress", OPT_COMPRESS, "Use compression in server/client protocol.", - (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, + (uchar**) &opt_compress, (uchar**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"databases", 'B', "To check several databases. Note the difference in usage; In this case no tables are given. All name arguments are regarded as databasenames.", - (gptr*) &opt_databases, (gptr*) &opt_databases, 0, GET_BOOL, NO_ARG, + (uchar**) &opt_databases, (uchar**) &opt_databases, 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.", @@ -94,26 +97,42 @@ 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-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .", + (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", + (uchar**) &debug_info_flag, (uchar**) &debug_info_flag, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"default-character-set", OPT_DEFAULT_CHARSET, - "Set the default character set.", (gptr*) &default_charset, - (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Set the default character set.", (uchar**) &default_charset, + (uchar**) &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, + (uchar**) &opt_fast, (uchar**) &opt_fast, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"fix-db-names", OPT_FIX_DB_NAMES, "Fix database names.", + (uchar**) &opt_fix_db_names, (uchar**) &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.", + (uchar**) &opt_fix_table_names, (uchar**) &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, + (uchar**) &ignore_errors, (uchar**) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"extended", 'e', "If you are using this option with CHECK TABLE, it will ensure that the table is 100 percent consistent, but will take a long time. If you are using this option with REPAIR TABLE, it will force using old slow repair with keycache method, instead of much faster repair by sorting.", - (gptr*) &opt_extended, (gptr*) &opt_extended, 0, GET_BOOL, NO_ARG, 0, 0, 0, + (uchar**) &opt_extended, (uchar**) &opt_extended, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"host",'h', "Connect to host.", (gptr*) ¤t_host, - (gptr*) ¤t_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"host",'h', "Connect to host.", (uchar**) ¤t_host, + (uchar**) ¤t_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"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.", + (uchar**) &opt_write_binlog, (uchar**) &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', @@ -129,38 +148,38 @@ static struct my_option my_long_options[] = "/etc/services, " #endif "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - (gptr*) &opt_mysql_port, - (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, + (uchar**) &opt_mysql_port, + (uchar**) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 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}, {"quick", 'q', "If you are using this option with CHECK TABLE, it prevents the check from scanning the rows to check for wrong links. This is the fastest check. If you are using this option with REPAIR TABLE, it will try to repair only the index tree. This is the fastest repair method for a table.", - (gptr*) &opt_quick, (gptr*) &opt_quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, + (uchar**) &opt_quick, (uchar**) &opt_quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"repair", 'r', "Can fix almost anything except unique keys that aren't unique.", 0, 0, 0, GET_NO_ARG, NO_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, + "Base name of shared memory.", (uchar**) &shared_memory_base_name, (uchar**) &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif - {"silent", 's', "Print only error messages.", (gptr*) &opt_silent, - (gptr*) &opt_silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"silent", 's', "Print only error messages.", (uchar**) &opt_silent, + (uchar**) &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, + (uchar**) &opt_mysql_unix_port, (uchar**) &opt_mysql_unix_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #include <sslopt-longopts.h> {"tables", OPT_TABLES, "Overrides option --databases (-B).", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"use-frm", OPT_FRM, "When used with REPAIR, get table structure from .frm file, so the table can be repaired even if .MYI header is corrupted.", - (gptr*) &opt_frm, (gptr*) &opt_frm, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, + (uchar**) &opt_frm, (uchar**) &opt_frm, 0, GET_BOOL, NO_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}, + {"user", 'u', "User for login if not current user.", (uchar**) ¤t_user, + (uchar**) ¤t_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif {"verbose", 'v', "Print info about the various stages.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -179,6 +198,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); @@ -260,6 +280,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) { @@ -288,6 +317,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case '#': DBUG_PUSH(argument ? argument : "d:t:o"); + debug_check_flag= 1; break; #include <sslopt-case.h> case OPT_TABLES: @@ -298,15 +328,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; } @@ -363,6 +388,10 @@ static int get_options(int *argc, char ***argv) } if (tty_password) opt_password = get_tty_password(NullS); + if (debug_info_flag) + my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO; + if (debug_check_flag) + my_end_arg= MY_CHECK_ERROR; return(0); } /* get_options */ @@ -382,7 +411,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; @@ -395,7 +424,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; @@ -528,8 +557,11 @@ static int process_all_tables_in_db(char *database) else { while ((row = mysql_fetch_row(res))) - /* Skip tables with an engine of NULL (probably a view). */ - if (row[1]) + /* + Skip tables with an engine of NULL (probably a view) + if we don't perform renaming. + */ + if (row[1] || what_to_do == DO_UPGRADE) { handle_request_for_tables(row[0], fixed_name_length(row[0])); } @@ -539,6 +571,60 @@ static int process_all_tables_in_db(char *database) } /* process_all_tables_in_db */ + +static int fix_table_storage_name(const char *name) +{ + char qbuf[100 + NAME_LEN*4]; + int rc= 0; + if (strncmp(name, "#mysql50#", 9)) + return 1; + sprintf(qbuf, "RENAME TABLE `%s` TO `%s`", name, name + 9); + if (mysql_query(sock, qbuf)) + { + fprintf(stderr, "Failed to %s\n", qbuf); + fprintf(stderr, "Error: %s\n", mysql_error(sock)); + rc= 1; + } + if (verbose) + printf("%-50s %s\n", name, rc ? "FAILED" : "OK"); + return rc; +} + +static int fix_database_storage_name(const char *name) +{ + char qbuf[100 + NAME_LEN*4]; + int rc= 0; + if (strncmp(name, "#mysql50#", 9)) + return 1; + sprintf(qbuf, "ALTER DATABASE `%s` UPGRADE DATA DIRECTORY NAME", name); + if (mysql_query(sock, qbuf)) + { + fprintf(stderr, "Failed to %s\n", qbuf); + fprintf(stderr, "Error: %s\n", mysql_error(sock)); + rc= 1; + } + 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_database_storage_name(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 && @@ -572,17 +658,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_table_storage_name(tables); } if (!(query =(char *) my_malloc((sizeof(char)*(length+110)), MYF(MY_WME)))) @@ -639,7 +727,7 @@ static void print_result() */ if (found_error && opt_auto_repair && what_to_do != DO_REPAIR && strcmp(row[3],"OK")) - insert_dynamic(&tables4repair, prev); + insert_dynamic(&tables4repair, (uchar*) prev); found_error=0; if (opt_silent) continue; @@ -659,7 +747,7 @@ static void print_result() } /* add the last table to be repaired to the list */ if (found_error && opt_auto_repair && what_to_do != DO_REPAIR) - insert_dynamic(&tables4repair, prev); + insert_dynamic(&tables4repair, (uchar*) prev); mysql_free_result(res); } @@ -734,7 +822,7 @@ int main(int argc, char **argv) */ if (get_options(&argc, &argv)) { - my_end(0); + my_end(my_end_arg); exit(EX_USAGE); } if (dbConnect(current_host, current_user, opt_password)) @@ -776,6 +864,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(my_end_arg); return(first_error!=0); } /* main */ diff --git a/client/mysqldump.c b/client/mysqldump.c index 980013d539a..f119e0b40b0 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.13" #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,10 +96,13 @@ 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 my_bool insert_pat_inited= 0, debug_info_flag= 0, debug_check_flag= 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; static DYNAMIC_STRING insert_pat; static char *opt_password=0,*current_user=0, *current_host=0,*path=0,*fields_terminated=0, @@ -112,8 +116,9 @@ static char compatible_mode_normal_str[255]; static ulong opt_compatible_mode= 0; #define MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL 1 #define MYSQL_OPT_MASTER_DATA_COMMENTED_SQL 2 -static uint opt_mysql_port= 0, opt_master_data; -static my_string opt_mysql_unix_port=0; +static uint opt_mysql_port= 0, opt_master_data; +static uint my_end_arg; +static char * opt_mysql_unix_port=0; static int first_error=0; static DYNAMIC_STRING extended_row; #include <sslopt-vars.h> @@ -149,7 +154,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", @@ -174,95 +178,110 @@ HASH ignore_table; static struct my_option my_long_options[] = { {"all", 'a', "Deprecated. Use --create-options instead.", - (gptr*) &create_options, (gptr*) &create_options, 0, GET_BOOL, NO_ARG, 1, + (uchar**) &create_options, (uchar**) &create_options, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"all-databases", 'A', "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, + (uchar**) &opt_alldbs, (uchar**) &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + 0, 0}, + {"all-tablespaces", 'Y', + "Dump all the tablespaces.", + (uchar**) &opt_alltspcs, (uchar**) &opt_alltspcs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + 0, 0}, + {"no-tablespaces", 'y', + "Do not dump any tablespace information.", + (uchar**) &opt_notspcs, (uchar**) &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, + (uchar**) &opt_drop_database, (uchar**) &opt_drop_database, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"add-drop-table", OPT_DROP, "Add a 'drop table' before each create.", - (gptr*) &opt_drop, (gptr*) &opt_drop, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, + (uchar**) &opt_drop, (uchar**) &opt_drop, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"add-locks", OPT_LOCKS, "Add locks around insert statements.", - (gptr*) &opt_lock, (gptr*) &opt_lock, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, + (uchar**) &opt_lock, (uchar**) &opt_lock, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"allow-keywords", OPT_KEYWORDS, - "Allow creation of column names that are keywords.", (gptr*) &opt_keywords, - (gptr*) &opt_keywords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + "Allow creation of column names that are keywords.", (uchar**) &opt_keywords, + (uchar**) &opt_keywords, 0, GET_BOOL, 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 {"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}, + "Directory where character sets are.", (uchar**) &charsets_dir, + (uchar**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"comments", 'i', "Write additional information.", - (gptr*) &opt_comments, (gptr*) &opt_comments, 0, GET_BOOL, NO_ARG, + (uchar**) &opt_comments, (uchar**) &opt_comments, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"compatible", OPT_COMPATIBLE, "Change the dump to be compatible with a given mode. By default tables are dumped in a format optimized for MySQL. Legal modes are: ansi, mysql323, mysql40, postgresql, oracle, mssql, db2, maxdb, no_key_options, no_table_options, no_field_options. One can use several modes separated by commas. Note: Requires MySQL server version 4.1.0 or higher. This option is ignored with earlier server versions.", - (gptr*) &opt_compatible_mode_str, (gptr*) &opt_compatible_mode_str, 0, + (uchar**) &opt_compatible_mode_str, (uchar**) &opt_compatible_mode_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"compact", OPT_COMPACT, "Give less verbose output (useful for debugging). Disables structure comments and header/footer constructs. Enables options --skip-add-drop-table --no-set-names --skip-disable-keys --skip-add-locks", - (gptr*) &opt_compact, (gptr*) &opt_compact, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + (uchar**) &opt_compact, (uchar**) &opt_compact, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"complete-insert", 'c', "Use complete insert statements.", - (gptr*) &opt_complete_insert, (gptr*) &opt_complete_insert, 0, GET_BOOL, + (uchar**) &opt_complete_insert, (uchar**) &opt_complete_insert, 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, + (uchar**) &opt_compress, (uchar**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"create-options", OPT_CREATE_OPTIONS, "Include all MySQL specific create options.", - (gptr*) &create_options, (gptr*) &create_options, 0, GET_BOOL, NO_ARG, 1, + (uchar**) &create_options, (uchar**) &create_options, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"databases", 'B', "To dump several databases. Note the difference in usage; In this case no tables are given. All name arguments are regarded as databasenames. 'USE db_name;' will be included in the output.", - (gptr*) &opt_databases, (gptr*) &opt_databases, 0, GET_BOOL, NO_ARG, 0, 0, + (uchar**) &opt_databases, (uchar**) &opt_databases, 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}, #else - {"debug", '#', "Output debug log", (gptr*) &default_dbug_option, - (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"debug", '#', "Output debug log", (uchar**) &default_dbug_option, + (uchar**) &default_dbug_option, 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}, + {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .", + (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", + (uchar**) &debug_info_flag, (uchar**) &debug_info_flag, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"default-character-set", OPT_DEFAULT_CHARSET, - "Set the default character set.", (gptr*) &default_charset, - (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Set the default character set.", (uchar**) &default_charset, + (uchar**) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"delayed-insert", OPT_DELAYED, "Insert rows with INSERT DELAYED; ", - (gptr*) &opt_delayed, (gptr*) &opt_delayed, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + (uchar**) &opt_delayed, (uchar**) &opt_delayed, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"delete-master-logs", OPT_DELETE_MASTER_LOGS, "Delete logs on master after backup. This automatically enables --master-data.", - (gptr*) &opt_delete_master_logs, (gptr*) &opt_delete_master_logs, 0, + (uchar**) &opt_delete_master_logs, (uchar**) &opt_delete_master_logs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"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}, + "'/*!40000 ALTER TABLE tb_name DISABLE KEYS */; and '/*!40000 ALTER TABLE tb_name ENABLE KEYS */; will be put in the output.", (uchar**) &opt_disable_keys, + (uchar**) &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"events", 'E', "Dump events.", + (uchar**) &opt_events, (uchar**) &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, + (uchar**) &extended_insert, (uchar**) &extended_insert, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"fields-terminated-by", OPT_FTB, - "Fields in the textfile are terminated by ...", (gptr*) &fields_terminated, - (gptr*) &fields_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Fields in the textfile are terminated by ...", (uchar**) &fields_terminated, + (uchar**) &fields_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"fields-enclosed-by", OPT_ENC, - "Fields in the importfile are enclosed by ...", (gptr*) &enclosed, - (gptr*) &enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0}, + "Fields in the importfile are enclosed by ...", (uchar**) &enclosed, + (uchar**) &enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0}, {"fields-optionally-enclosed-by", OPT_O_ENC, - "Fields in the i.file are opt. enclosed by ...", (gptr*) &opt_enclosed, - (gptr*) &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0}, + "Fields in the i.file are opt. enclosed by ...", (uchar**) &opt_enclosed, + (uchar**) &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0}, {"fields-escaped-by", OPT_ESC, "Fields in the i.file are escaped by ...", - (gptr*) &escaped, (gptr*) &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + (uchar**) &escaped, (uchar**) &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"first-slave", 'x', "Deprecated, renamed to --lock-all-tables.", - (gptr*) &opt_lock_all_tables, (gptr*) &opt_lock_all_tables, 0, GET_BOOL, NO_ARG, + (uchar**) &opt_lock_all_tables, (uchar**) &opt_lock_all_tables, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"flush-logs", 'F', "Flush logs file in server before starting dump. " "Note that if you dump many databases at once (using the option " @@ -273,44 +292,44 @@ static struct my_option my_long_options[] = "to the moment all tables are locked. So if you want your dump and " "the log flush to happen at the same exact moment you should use " "--lock-all-tables or --master-data with --flush-logs", - (gptr*) &flush_logs, (gptr*) &flush_logs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + (uchar**) &flush_logs, (uchar**) &flush_logs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"flush-privileges", OPT_ESC, "Emit a FLUSH PRIVILEGES statement " "after dumping the mysql database. This option should be used any " "time the dump contains the mysql database and any other database " "that depends on the data in the mysql database for proper restore. ", - (gptr*) &flush_privileges, (gptr*) &flush_privileges, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + (uchar**) &flush_privileges, (uchar**) &flush_privileges, 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, + (uchar**) &ignore_errors, (uchar**) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"hex-blob", OPT_HEXBLOB, "Dump binary strings (BINARY, " "VARBINARY, BLOB) in hexadecimal format.", - (gptr*) &opt_hex_blob, (gptr*) &opt_hex_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"host", 'h', "Connect to host.", (gptr*) ¤t_host, - (gptr*) ¤t_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + (uchar**) &opt_hex_blob, (uchar**) &opt_hex_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"host", 'h', "Connect to host.", (uchar**) ¤t_host, + (uchar**) ¤t_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"ignore-table", OPT_IGNORE_TABLE, "Do not dump the specified table. To specify more than one table to ignore, " "use the directive multiple times, once for each table. Each table must " "be specified with both database and table names, e.g. --ignore-table=database.table", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"insert-ignore", OPT_INSERT_IGNORE, "Insert rows with INSERT IGNORE.", - (gptr*) &opt_ignore, (gptr*) &opt_ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + (uchar**) &opt_ignore, (uchar**) &opt_ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"lines-terminated-by", OPT_LTB, "Lines in the i.file are terminated by ...", - (gptr*) &lines_terminated, (gptr*) &lines_terminated, 0, GET_STR, + (uchar**) &lines_terminated, (uchar**) &lines_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"lock-all-tables", 'x', "Locks all tables across all databases. This " "is achieved by taking a global read lock for the duration of the whole " "dump. Automatically turns --single-transaction and --lock-tables off.", - (gptr*) &opt_lock_all_tables, (gptr*) &opt_lock_all_tables, 0, GET_BOOL, NO_ARG, + (uchar**) &opt_lock_all_tables, (uchar**) &opt_lock_all_tables, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"lock-tables", 'l', "Lock all tables for read.", (gptr*) &lock_tables, - (gptr*) &lock_tables, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"lock-tables", 'l', "Lock all tables for read.", (uchar**) &lock_tables, + (uchar**) &lock_tables, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"log-error", OPT_ERROR_LOG_FILE, "Append warnings and errors to given file.", - (gptr*) &log_error_file, (gptr*) &log_error_file, 0, GET_STR, + (uchar**) &log_error_file, (uchar**) &log_error_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"master-data", OPT_MASTER_DATA, "This causes the binary log position and filename to be appended to the " @@ -322,29 +341,29 @@ static struct my_option my_long_options[] = "- don't forget to read about --single-transaction below). In all cases " "any action on logs will happen at the exact moment of the dump." "Option automatically turns --lock-tables off.", - (gptr*) &opt_master_data, (gptr*) &opt_master_data, 0, + (uchar**) &opt_master_data, (uchar**) &opt_master_data, 0, GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_MASTER_DATA_COMMENTED_SQL, 0, 0, 0}, {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET, "", - (gptr*) &opt_max_allowed_packet, (gptr*) &opt_max_allowed_packet, 0, + (uchar**) &opt_max_allowed_packet, (uchar**) &opt_max_allowed_packet, 0, GET_ULONG, REQUIRED_ARG, 24*1024*1024, 4096, (longlong) 2L*1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0}, {"net_buffer_length", OPT_NET_BUFFER_LENGTH, "", - (gptr*) &opt_net_buffer_length, (gptr*) &opt_net_buffer_length, 0, + (uchar**) &opt_net_buffer_length, (uchar**) &opt_net_buffer_length, 0, GET_ULONG, REQUIRED_ARG, 1024*1024L-1025, 4096, 16*1024L*1024L, MALLOC_OVERHEAD-1024, 1024, 0}, {"no-autocommit", OPT_AUTOCOMMIT, "Wrap tables with autocommit/commit statements.", - (gptr*) &opt_autocommit, (gptr*) &opt_autocommit, 0, GET_BOOL, NO_ARG, + (uchar**) &opt_autocommit, (uchar**) &opt_autocommit, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"no-create-db", 'n', "'CREATE DATABASE /*!32312 IF NOT EXISTS*/ db_name;' will not be put in the output. The above line will be added otherwise, if --databases or --all-databases option was given.}.", - (gptr*) &opt_create_db, (gptr*) &opt_create_db, 0, GET_BOOL, NO_ARG, 0, 0, + (uchar**) &opt_create_db, (uchar**) &opt_create_db, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"no-create-info", 't', "Don't write table creation info.", - (gptr*) &opt_no_create_info, (gptr*) &opt_no_create_info, 0, GET_BOOL, + (uchar**) &opt_no_create_info, (uchar**) &opt_no_create_info, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"no-data", 'd', "No row information.", (gptr*) &opt_no_data, - (gptr*) &opt_no_data, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"no-data", 'd', "No row information.", (uchar**) &opt_no_data, + (uchar**) &opt_no_data, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"no-set-names", 'N', "Deprecated. Use --skip-set-charset instead.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -353,7 +372,7 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"order-by-primary", OPT_ORDER_BY_PRIMARY, "Sorts each table's rows by primary key, or first unique key, if such a key exists. Useful when dumping a MyISAM table to be loaded into an InnoDB table, but will make the dump itself take considerably longer.", - (gptr*) &opt_order_by_primary, (gptr*) &opt_order_by_primary, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + (uchar**) &opt_order_by_primary, (uchar**) &opt_order_by_primary, 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 solicited on the tty.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, @@ -361,38 +380,35 @@ static struct my_option my_long_options[] = {"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 or 0 for default to, in " - "order of preference, my.cnf, $MYSQL_TCP_PORT, " -#if MYSQL_PORT_DEFAULT == 0 - "/etc/services, " -#endif - "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - (gptr*) &opt_mysql_port, - (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, + {"port", 'P', "Port number to use for connection.", (uchar**) &opt_mysql_port, + (uchar**) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 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}, {"quick", 'q', "Don't buffer query, dump directly to stdout.", - (gptr*) &quick, (gptr*) &quick, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + (uchar**) &quick, (uchar**) &quick, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"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, + (uchar**) &opt_quoted, (uchar**) &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.", + (uchar**) &opt_replace_into, (uchar**) &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}, {"routines", 'R', "Dump stored routines (functions and procedures).", - (gptr*) &opt_routines, (gptr*) &opt_routines, 0, GET_BOOL, + (uchar**) &opt_routines, (uchar**) &opt_routines, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"set-charset", OPT_SET_CHARSET, "Add 'SET NAMES default_character_set' to the output. Enabled by default; suppress with --skip-set-charset.", - (gptr*) &opt_set_charset, (gptr*) &opt_set_charset, 0, GET_BOOL, NO_ARG, 1, + (uchar**) &opt_set_charset, (uchar**) &opt_set_charset, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"set-variable", 'O', "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.", 0, 0, 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, + "Base name of shared memory.", (uchar**) &shared_memory_base_name, (uchar**) &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif /* @@ -410,40 +426,40 @@ static struct my_option my_long_options[] = "connection should use the following statements: ALTER TABLE, DROP " "TABLE, RENAME TABLE, TRUNCATE TABLE, as consistent snapshot is not " "isolated from them. Option automatically turns off --lock-tables.", - (gptr*) &opt_single_transaction, (gptr*) &opt_single_transaction, 0, + (uchar**) &opt_single_transaction, (uchar**) &opt_single_transaction, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"dump-date", OPT_DUMP_DATE, "Put a dump date to the end of the output.", - (gptr*) &opt_dump_date, (gptr*) &opt_dump_date, 0, + (uchar**) &opt_dump_date, (uchar**) &opt_dump_date, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"skip-opt", OPT_SKIP_OPTIMIZATION, "Disable --opt. Disables --add-drop-table, --add-locks, --create-options, --quick, --extended-insert, --lock-tables, --set-charset, and --disable-keys.", 0, 0, 0, GET_NO_ARG, 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, + (uchar**) &opt_mysql_unix_port, (uchar**) &opt_mysql_unix_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #include <sslopt-longopts.h> {"tab",'T', "Creates tab separated textfile for each table to given path. (creates .sql and .txt files). NOTE: This only works if mysqldump is run on the same machine as the mysqld daemon.", - (gptr*) &path, (gptr*) &path, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + (uchar**) &path, (uchar**) &path, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"tables", OPT_TABLES, "Overrides option --databases (-B).", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"triggers", OPT_TRIGGERS, "Dump triggers for each dumped table", - (gptr*) &opt_dump_triggers, (gptr*) &opt_dump_triggers, 0, GET_BOOL, + (uchar**) &opt_dump_triggers, (uchar**) &opt_dump_triggers, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"tz-utc", OPT_TZ_UTC, "SET TIME_ZONE='+00:00' at top of dump to allow dumping of TIMESTAMP data when a server has data in different time zones or data is being moved between servers with different time zones.", - (gptr*) &opt_tz_utc, (gptr*) &opt_tz_utc, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + (uchar**) &opt_tz_utc, (uchar**) &opt_tz_utc, 0, GET_BOOL, NO_ARG, 1, 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, + (uchar**) ¤t_user, (uchar**) ¤t_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif {"verbose", 'v', "Print info about the various stages.", - (gptr*) &verbose, (gptr*) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + (uchar**) &verbose, (uchar**) &verbose, 0, GET_BOOL, 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}, {"where", 'w', "Dump only selected records; QUOTES mandatory!", - (gptr*) &where, (gptr*) &where, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + (uchar**) &where, (uchar**) &where, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"xml", 'X', "Dump a database as well formed XML.", 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} @@ -470,6 +486,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> @@ -556,8 +576,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); @@ -568,7 +590,9 @@ static void write_header(FILE *sql_file, char *db_name) { if (opt_comments) { - fprintf(sql_file, "-- MySQL dump %s\n--\n", DUMP_VERSION); + fprintf(sql_file, + "-- MySQL dump %s Distrib %s, for %s (%s)\n--\n", + DUMP_VERSION, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); fprintf(sql_file, "-- Host: %s Database: %s\n", current_host ? current_host : "localhost", db_name ? db_name : ""); @@ -650,18 +674,18 @@ static void write_footer(FILE *sql_file) } } /* write_footer */ -static void free_table_ent(char *key) +static void free_table_ent(char *key) { - my_free((gptr) key, MYF(0)); + my_free(key, MYF(0)); } -byte* get_table_key(const char *entry, uint *length, - my_bool not_used __attribute__((unused))) +uchar* get_table_key(const char *entry, size_t *length, + my_bool not_used __attribute__((unused))) { *length= strlen(entry); - return (byte*) entry; + return (uchar*) entry; } @@ -719,7 +743,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case '#': DBUG_PUSH(argument ? argument : default_dbug_option); - info_flag= 1; + debug_check_flag= 1; break; #include <sslopt-case.h> case 'V': print_version(); exit(0); @@ -760,7 +784,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), fprintf(stderr, "Illegal use of option --ignore-table=<database>.<table>\n"); exit(1); } - if (my_hash_insert(&ignore_table, (byte*)my_strdup(argument, MYF(0)))) + if (my_hash_insert(&ignore_table, (uchar*)my_strdup(argument, MYF(0)))) exit(EX_EOM); break; } @@ -814,14 +838,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; } @@ -842,11 +861,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))) || + (uchar*) my_strdup("mysql.apply_status", MYF(MY_WME))) || + my_hash_insert(&ignore_table, + (uchar*) my_strdup("mysql.schema", MYF(MY_WME))) || + my_hash_insert(&ignore_table, + (uchar*) my_strdup("mysql.general_log", MYF(MY_WME))) || my_hash_insert(&ignore_table, - (byte*) my_strdup("mysql.schema", MYF(MY_WME)))) + (uchar*) my_strdup("mysql.slow_log", MYF(MY_WME)))) return(EX_EOM); if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option))) @@ -854,6 +877,10 @@ static int get_options(int *argc, char ***argv) *mysql_params->p_max_allowed_packet= opt_max_allowed_packet; *mysql_params->p_net_buffer_length= opt_net_buffer_length; + if (debug_info_flag) + my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO; + if (debug_check_flag) + my_end_arg= MY_CHECK_ERROR; if (opt_delayed) opt_lock=0; /* Can't have lock with delayed */ @@ -1011,6 +1038,207 @@ static int mysql_query_with_error_report(MYSQL *mysql_con, MYSQL_RES **res, } +static int fetch_db_collation(const char *db_name, + char *db_cl_name, + int db_cl_size) +{ + bool err_status= FALSE; + char query[QUERY_LENGTH]; + MYSQL_RES *db_cl_res; + MYSQL_ROW db_cl_row; + char quoted_database_buf[NAME_LEN*2+3]; + char *qdatabase= quote_name(db_name, quoted_database_buf, 1); + + my_snprintf(query, sizeof (query), "use %s", qdatabase); + + if (mysql_query_with_error_report(mysql, NULL, query)) + return 1; + + if (mysql_query_with_error_report(mysql, &db_cl_res, + "select @@collation_database")) + return 1; + + do + { + if (mysql_num_rows(db_cl_res) != 1) + { + err_status= TRUE; + break; + } + + if (!(db_cl_row= mysql_fetch_row(db_cl_res))) + { + err_status= TRUE; + break; + } + + strncpy(db_cl_name, db_cl_row[0], db_cl_size); + db_cl_name[db_cl_size - 1]= 0; /* just in case. */ + + } while (FALSE); + + mysql_free_result(db_cl_res); + + return err_status ? 1 : 0; +} + + +static char *my_case_str(const char *str, + uint str_len, + const char *token, + uint token_len) +{ + my_match_t match; + + uint status= my_charset_latin1.coll->instr(&my_charset_latin1, + str, str_len, + token, token_len, + &match, 1); + + return status ? (char *) str + match.end : NULL; +} + + +static int switch_db_collation(FILE *sql_file, + const char *db_name, + const char *delimiter, + const char *current_db_cl_name, + const char *required_db_cl_name, + int *db_cl_altered) +{ + if (strcmp(current_db_cl_name, required_db_cl_name) != 0) + { + CHARSET_INFO *db_cl= get_charset_by_name(required_db_cl_name, MYF(0)); + + if (!db_cl) + return 1; + + fprintf(sql_file, + "ALTER DATABASE %s CHARACTER SET %s COLLATE %s %s\n", + (const char *) db_name, + (const char *) db_cl->csname, + (const char *) db_cl->name, + (const char *) delimiter); + + *db_cl_altered= 1; + + return 0; + } + + *db_cl_altered= 0; + + return 0; +} + + +static int restore_db_collation(FILE *sql_file, + const char *db_name, + const char *delimiter, + const char *db_cl_name) +{ + CHARSET_INFO *db_cl= get_charset_by_name(db_cl_name, MYF(0)); + + if (!db_cl) + return 1; + + fprintf(sql_file, + "ALTER DATABASE %s CHARACTER SET %s COLLATE %s %s\n", + (const char *) db_name, + (const char *) db_cl->csname, + (const char *) db_cl->name, + (const char *) delimiter); + + return 0; +} + + +static void switch_cs_variables(FILE *sql_file, + const char *delimiter, + const char *character_set_client, + const char *character_set_results, + const char *collation_connection) +{ + fprintf(sql_file, + "/*!50003 SET @saved_cs_client = @@character_set_client */ %s\n" + "/*!50003 SET @saved_cs_results = @@character_set_results */ %s\n" + "/*!50003 SET @saved_col_connection = @@collation_connection */ %s\n" + "/*!50003 SET character_set_client = %s */ %s\n" + "/*!50003 SET character_set_results = %s */ %s\n" + "/*!50003 SET collation_connection = %s */ %s\n", + (const char *) delimiter, + (const char *) delimiter, + (const char *) delimiter, + + (const char *) character_set_client, + (const char *) delimiter, + + (const char *) character_set_results, + (const char *) delimiter, + + (const char *) collation_connection, + (const char *) delimiter); +} + + +static void restore_cs_variables(FILE *sql_file, + const char *delimiter) +{ + fprintf(sql_file, + "/*!50003 SET character_set_client = @saved_cs_client */ %s\n" + "/*!50003 SET character_set_results = @saved_cs_results */ %s\n" + "/*!50003 SET collation_connection = @saved_col_connection */ %s\n", + (const char *) delimiter, + (const char *) delimiter, + (const char *) delimiter); +} + + +static void switch_sql_mode(FILE *sql_file, + const char *delimiter, + const char *sql_mode) +{ + fprintf(sql_file, + "/*!50003 SET @saved_sql_mode = @@sql_mode */ %s\n" + "/*!50003 SET sql_mode = '%s' */ %s\n", + (const char *) delimiter, + + (const char *) sql_mode, + (const char *) delimiter); +} + + +static void restore_sql_mode(FILE *sql_file, + const char *delimiter) +{ + fprintf(sql_file, + "/*!50003 SET sql_mode = @saved_sql_mode */ %s\n", + (const char *) delimiter); +} + + +static void switch_time_zone(FILE *sql_file, + const char *delimiter, + const char *time_zone) +{ + fprintf(sql_file, + "/*!50003 SET @saved_time_zone = @@time_zone */ %s\n" + "/*!50003 SET time_zone = '%s' */ %s\n", + (const char *) delimiter, + + (const char *) time_zone, + (const char *) delimiter); +} + + +static void restore_time_zone(FILE *sql_file, + const char *delimiter) +{ + fprintf(sql_file, + "/*!50003 SET time_zone = @saved_time_zone */ %s\n", + (const char *) delimiter); +} + + static int switch_character_set_results(MYSQL *mysql, const char *cs_name) { char query_buffer[QUERY_LENGTH]; @@ -1024,6 +1252,124 @@ static int switch_character_set_results(MYSQL *mysql, const char *cs_name) return mysql_real_query(mysql, query_buffer, query_length); } +/** + Rewrite CREATE TRIGGER statement, enclosing DEFINER clause in + version-specific comment. + + This function parses the CREATE TRIGGER statement and encloses + DEFINER-clause in version-specific comment: + input query: CREATE DEFINER=a@b TRIGGER ... + rewritten query: CREATE * / / *!50017 DEFINER=a@b * / / *!50003 TRIGGER ... + + @note This function will go away when WL#3995 is implemented. + + @param[in] trigger_def_str CREATE TRIGGER statement string. + @param[in] trigger_def_length length of the trigger_def_str. + + @return pointer to the new allocated query string. +*/ + +static char *cover_definer_clause_in_trigger(const char *trigger_def_str, + uint trigger_def_length) +{ + char *query_str= NULL; + char *definer_begin= my_case_str(trigger_def_str, trigger_def_length, + C_STRING_WITH_LEN(" DEFINER")); + char *definer_end; + + if (!definer_begin) + return NULL; + + definer_end= my_case_str(definer_begin, strlen(definer_begin), + C_STRING_WITH_LEN(" TRIGGER")); + + if (definer_end) + { + char *query_str_tail; + + /* + Allocate memory for new query string: original string + from SHOW statement and version-specific comments. + */ + query_str= alloc_query_str(trigger_def_length + 23); + + query_str_tail= strnmov(query_str, + trigger_def_str, + definer_begin - trigger_def_str); + + query_str_tail= strmov(query_str_tail, + "*/ /*!50017"); + + query_str_tail= strnmov(query_str_tail, + definer_begin, + definer_end - definer_begin); + + query_str_tail= strxmov(query_str_tail, + "*/ /*!50003", + definer_end, + NullS); + } + + return query_str; +} + +/** + Rewrite CREATE FUNCTION or CREATE PROCEDURE statement, enclosing DEFINER + clause in version-specific comment. + + This function parses the CREATE FUNCTION | PROCEDURE statement and + encloses DEFINER-clause in version-specific comment: + input query: CREATE DEFINER=a@b FUNCTION ... + rewritten query: CREATE * / / *!50020 DEFINER=a@b * / / *!50003 FUNCTION ... + + @note This function will go away when WL#3995 is implemented. + + @param[in] def_str CREATE FUNCTION|PROCEDURE statement string. + @param[in] def_str_length length of the def_str. + + @return pointer to the new allocated query string. +*/ + +static char *cover_definer_clause_in_sp(const char *def_str, + uint def_str_length) +{ + char *query_str= NULL; + char *definer_begin= my_case_str(def_str, def_str_length, + C_STRING_WITH_LEN(" DEFINER")); + char *definer_end; + + if (!definer_begin) + return NULL; + + definer_end= my_case_str(definer_begin, strlen(definer_begin), + C_STRING_WITH_LEN(" PROCEDURE")); + + if (!definer_end) + { + definer_end= my_case_str(definer_begin, strlen(definer_begin), + C_STRING_WITH_LEN(" FUNCTION")); + } + + if (definer_end) + { + char *query_str_tail; + + /* + Allocate memory for new query string: original string + from SHOW statement and version-specific comments. + */ + query_str= alloc_query_str(def_str_length + 23); + + query_str_tail= strnmov(query_str, def_str, definer_begin - def_str); + query_str_tail= strmov(query_str_tail, "*/ /*!50020"); + query_str_tail= strnmov(query_str_tail, definer_begin, + definer_end - definer_begin); + query_str_tail= strxmov(query_str_tail, "*/ /*!50003", + definer_end, NullS); + } + + return query_str; +} /* Open a new .sql file to dump the table or view into @@ -1060,7 +1406,7 @@ static void free_resources() dynstr_free(&insert_pat); if (defaults_argv) free_defaults(defaults_argv); - my_end(info_flag ? MY_CHECK_ERROR : 0); + my_end(my_end_arg); } @@ -1440,6 +1786,203 @@ 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]; + FILE *sql_file= md_result_file; + MYSQL_RES *event_res, *event_list_res; + MYSQL_ROW row, event_list_row; + + char db_cl_name[MY_CS_NAME_SIZE]; + int db_cl_altered= FALSE; + + 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"); + + /* Get database collation. */ + + if (fetch_db_collation(db_name_buff, db_cl_name, sizeof (db_cl_name))) + DBUG_RETURN(1); + + if (switch_character_set_results(mysql, "binary")) + DBUG_RETURN(1); + + 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); + + if (create_delimiter(row[3], delimiter, sizeof(delimiter)) == NULL) + { + fprintf(stderr, "%s: Warning: Can't create delimiter for event '%s'\n", + my_progname, event_name); + DBUG_RETURN(1); + } + + fprintf(sql_file, "DELIMITER %s\n", delimiter); + + if (mysql_num_fields(event_res) >= 7) + { + if (switch_db_collation(sql_file, db_name_buff, delimiter, + db_cl_name, row[6], &db_cl_altered)) + { + DBUG_RETURN(1); + } + + switch_cs_variables(sql_file, delimiter, + row[4], /* character_set_client */ + row[4], /* character_set_results */ + row[5]); /* collation_connection */ + } + else + { + /* + mysqldump is being run against the server, that does not + provide character set information in SHOW CREATE + statements. + + NOTE: the dump may be incorrect, since character set + information is required in order to restore event properly. + */ + + fprintf(sql_file, + "--\n" + "-- WARNING: old server version. " + "The following dump may be incomplete.\n" + "--\n"); + } + + switch_sql_mode(sql_file, delimiter, row[1]); + + switch_time_zone(sql_file, delimiter, row[2]); + + fprintf(sql_file, + "/*!50106 %s */ %s\n", + (const char *) row[3], + (const char *) delimiter); + + restore_time_zone(sql_file, delimiter); + restore_sql_mode(sql_file, delimiter); + + if (mysql_num_fields(event_res) >= 7) + { + restore_cs_variables(sql_file, delimiter); + + if (db_cl_altered) + { + if (restore_db_collation(sql_file, db_name_buff, delimiter, + db_cl_name)) + DBUG_RETURN(1); + } + } + } + } /* 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"); + + if (switch_character_set_results(mysql, default_charset)) + DBUG_RETURN(1); + } + 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. @@ -1477,7 +2020,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; @@ -1485,6 +2028,10 @@ static uint dump_routines_for_db(char *db) FILE *sql_file= md_result_file; MYSQL_RES *routine_res, *routine_list_res; MYSQL_ROW row, routine_list_row; + + char db_cl_name[MY_CS_NAME_SIZE]; + int db_cl_altered= FALSE; + DBUG_ENTER("dump_routines_for_db"); DBUG_PRINT("enter", ("db: '%s'", db)); @@ -1501,10 +2048,13 @@ static uint dump_routines_for_db(char *db) if (lock_tables) mysql_query(mysql, "LOCK TABLES mysql.proc READ"); - if (opt_compact) - fprintf(sql_file, "\n/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;\n"); + /* Get database collation. */ - fprintf(sql_file, "DELIMITER ;;\n"); + if (fetch_db_collation(db_name_buff, db_cl_name, sizeof (db_cl_name))) + DBUG_RETURN(1); + + if (switch_character_set_results(mysql, "binary")) + DBUG_RETURN(1); /* 0, retrieve and dump functions, 1, procedures */ for (i= 0; i <= 1; i++) @@ -1521,9 +2071,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); @@ -1547,63 +2097,67 @@ static uint dump_routines_for_db(char *db) } else if (strlen(row[2])) { - char *query_str= NULL; - char *definer_begin; - + char *query_str; if (opt_drop) - fprintf(sql_file, "/*!50003 DROP %s IF EXISTS %s */;;\n", + fprintf(sql_file, "/*!50003 DROP %s IF EXISTS %s */;\n", routine_type[i], routine_name); - /* - Cover DEFINER-clause in version-specific comments. - - TODO: this is definitely a BAD IDEA to parse SHOW CREATE output. - We should user INFORMATION_SCHEMA instead. The only problem is - that now INFORMATION_SCHEMA does not provide information about - routine parameters. - */ + query_str= cover_definer_clause_in_sp(row[2], strlen(row[2])); - definer_begin= strstr(row[2], " DEFINER"); + if (mysql_num_fields(routine_res) >= 6) + { + if (switch_db_collation(sql_file, db_name_buff, ";", + db_cl_name, row[5], &db_cl_altered)) + { + DBUG_RETURN(1); + } - if (definer_begin) + switch_cs_variables(sql_file, ";", + row[3], /* character_set_client */ + row[3], /* character_set_results */ + row[4]); /* collation_connection */ + } + else { - char *definer_end= strstr(definer_begin, " PROCEDURE"); + /* + mysqldump is being run against the server, that does not + provide character set information in SHOW CREATE + statements. + + NOTE: the dump may be incorrect, since character set + information is required in order to restore stored + procedure/function properly. + */ + + fprintf(sql_file, + "--\n" + "-- WARNING: old server version. " + "The following dump may be incomplete.\n" + "--\n"); + } - if (!definer_end) - definer_end= strstr(definer_begin, " FUNCTION"); - if (definer_end) - { - char *query_str_tail; + switch_sql_mode(sql_file, ";", row[1]); - /* - Allocate memory for new query string: original string - from SHOW statement and version-specific comments. - */ - query_str= alloc_query_str(strlen(row[2]) + 23); - - query_str_tail= strnmov(query_str, row[2], - definer_begin - row[2]); - query_str_tail= strmov(query_str_tail, "*/ /*!50020"); - query_str_tail= strnmov(query_str_tail, definer_begin, - definer_end - definer_begin); - query_str_tail= strxmov(query_str_tail, "*/ /*!50003", - definer_end, NullS); + fprintf(sql_file, + "DELIMITER ;;\n" + "/*!50003 %s */;;\n" + "DELIMITER ;\n", + (const char *) (query_str != NULL ? query_str : row[2])); + + restore_sql_mode(sql_file, ";"); + + if (mysql_num_fields(routine_res) >= 6) + { + restore_cs_variables(sql_file, ";"); + + if (db_cl_altered) + { + if (restore_db_collation(sql_file, db_name_buff, ";", db_cl_name)) + DBUG_RETURN(1); } } - /* - we need to change sql_mode only for the CREATE - PROCEDURE/FUNCTION otherwise we may need to re-quote routine_name - */ - fprintf(sql_file, "/*!50003 SET SESSION SQL_MODE=\"%s\"*/;;\n", - row[1] /* sql_mode */); - fprintf(sql_file, "/*!50003 %s */;;\n", - (query_str != NULL ? query_str : row[2])); - fprintf(sql_file, - "/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/" - ";;\n"); - my_free(query_str, MYF(MY_ALLOW_ZERO_PTR)); } } /* end of routine printing */ @@ -1613,8 +2167,9 @@ static uint dump_routines_for_db(char *db) } mysql_free_result(routine_list_res); } /* end of for i (0 .. 1) */ - /* set the delimiter back to ';' */ - fprintf(sql_file, "DELIMITER ;\n"); + + if (switch_character_set_results(mysql, default_charset)) + DBUG_RETURN(1); if (lock_tables) VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES")); @@ -1643,13 +2198,12 @@ 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; MYSQL_ROW row; - DBUG_ENTER("get_table_structure"); DBUG_PRINT("enter", ("db: %s table: %s", db, table)); @@ -1764,7 +2318,9 @@ static uint get_table_structure(char *table, char *db, char *table_type, */ my_snprintf(query_buff, sizeof(query_buff), "SHOW FIELDS FROM %s", result_table); - if (mysql_query_with_error_report(mysql, 0, query_buff)) + if (switch_character_set_results(mysql, "binary") || + mysql_query_with_error_report(mysql, &result, query_buff) || + switch_character_set_results(mysql, default_charset)) { /* View references invalid or privileged table/col/fun (err 1356), @@ -1782,43 +2338,50 @@ static uint get_table_structure(char *table, char *db, char *table_type, else my_free(scv_buff, MYF(MY_ALLOW_ZERO_PTR)); - if ((result= mysql_store_result(mysql))) + if (mysql_num_rows(result)) { - if (mysql_num_rows(result)) + if (opt_drop) { - if (opt_drop) - { /* - We have already dropped any table of the same name - above, so here we just drop the view. - */ + We have already dropped any table of the same name above, so + here we just drop the view. + */ - fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n", - opt_quoted_table); - check_io(sql_file); - } + fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n", + opt_quoted_table); + check_io(sql_file); + } - fprintf(sql_file, "/*!50001 CREATE TABLE %s (\n", result_table); - /* - Get first row, following loop will prepend comma - keeps - from having to know if the row being printed is last to - determine if there should be a _trailing_ comma. - */ - row= mysql_fetch_row(result); + fprintf(sql_file, + "SET @saved_cs_client = @@character_set_client;\n" + "SET character_set_client = utf8;\n" + "/*!50001 CREATE TABLE %s (\n", + result_table); - fprintf(sql_file, " %s %s", quote_name(row[0], name_buff, 0), - row[1]); + /* + Get first row, following loop will prepend comma - keeps from + having to know if the row being printed is last to determine if + there should be a _trailing_ comma. + */ - while((row= mysql_fetch_row(result))) - { - /* col name, col type */ - fprintf(sql_file, ",\n %s %s", - quote_name(row[0], name_buff, 0), row[1]); - } - fprintf(sql_file, "\n) */;\n"); - check_io(sql_file); + row= mysql_fetch_row(result); + + fprintf(sql_file, " %s %s", quote_name(row[0], name_buff, 0), + row[1]); + + while((row= mysql_fetch_row(result))) + { + /* col name, col type */ + fprintf(sql_file, ",\n %s %s", + quote_name(row[0], name_buff, 0), row[1]); } + fprintf(sql_file, + "\n) */;\n" + "SET character_set_client = @saved_cs_client;\n"); + + check_io(sql_file); } + mysql_free_result(result); if (path) @@ -1857,7 +2420,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); @@ -1923,7 +2489,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); @@ -2054,6 +2623,7 @@ static uint get_table_structure(char *table, char *db, char *table_type, fprintf(sql_file, " (%s)",row[7]); /* Sub key */ check_io(sql_file); } + mysql_free_result(result); if (!opt_xml) { if (keynr) @@ -2124,102 +2694,219 @@ continue_xml: DBUG_RETURN((uint) num_fields); } /* get_table_structure */ +static void dump_trigger_old(MYSQL_RES *show_triggers_rs, + MYSQL_ROW *show_trigger_row, + const char *table_name) +{ + FILE *sql_file= md_result_file; -/* + char quoted_table_name_buf[NAME_LEN * 2 + 3]; + char *quoted_table_name= quote_name(table_name, quoted_table_name_buf, 1); - dump_triggers_for_table + char name_buff[NAME_LEN * 4 + 3]; - Dumps the triggers given a table/db name. This should be called after - the tables have been dumped in case a trigger depends on the existence - of a table + DBUG_ENTER("dump_trigger_old"); + fprintf(sql_file, + "--\n" + "-- WARNING: old server version. " + "The following dump may be incomplete.\n" + "--\n"); + + if (opt_compact) + fprintf(sql_file, "/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;\n"); + + fprintf(sql_file, + "DELIMITER ;;\n" + "/*!50003 SET SESSION SQL_MODE=\"%s\" */;;\n" + "/*!50003 CREATE */ ", + (*show_trigger_row)[6]); + + if (mysql_num_fields(show_triggers_rs) > 7) + { + /* + mysqldump can be run against the server, that does not support + definer in triggers (there is no DEFINER column in SHOW TRIGGERS + output). So, we should check if we have this column before + accessing it. + */ + + size_t user_name_len; + char user_name_str[USERNAME_LENGTH + 1]; + char quoted_user_name_str[USERNAME_LENGTH * 2 + 3]; + size_t host_name_len; + char host_name_str[HOSTNAME_LENGTH + 1]; + char quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3]; + + parse_user((*show_trigger_row)[7], + strlen((*show_trigger_row)[7]), + user_name_str, &user_name_len, + host_name_str, &host_name_len); + + fprintf(sql_file, + "/*!50017 DEFINER=%s@%s */ ", + quote_name(user_name_str, quoted_user_name_str, FALSE), + quote_name(host_name_str, quoted_host_name_str, FALSE)); + } + + fprintf(sql_file, + "/*!50003 TRIGGER %s %s %s ON %s FOR EACH ROW%s%s */;;\n" + "DELIMITER ;\n", + quote_name((*show_trigger_row)[0], name_buff, 0), /* Trigger */ + (*show_trigger_row)[4], /* Timing */ + (*show_trigger_row)[1], /* Event */ + quoted_table_name, + (strchr(" \t\n\r", *((*show_trigger_row)[3]))) ? "" : " ", + (*show_trigger_row)[3] /* Statement */); + + if (opt_compact) + fprintf(sql_file, "/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */;\n"); + + DBUG_VOID_RETURN; +} + +static int dump_trigger(MYSQL_RES *show_create_trigger_rs, + const char *db_name, + const char *db_cl_name) +{ + FILE *sql_file= md_result_file; + MYSQL_ROW row; + int db_cl_altered= FALSE; + + DBUG_ENTER("dump_trigger"); + + while ((row= mysql_fetch_row(show_create_trigger_rs))) + { + char *query_str= cover_definer_clause_in_trigger(row[2], strlen(row[2])); + + + if (switch_db_collation(sql_file, db_name, ";", + db_cl_name, row[5], &db_cl_altered)) + DBUG_RETURN(TRUE); + + switch_cs_variables(sql_file, ";", + row[3], /* character_set_client */ + row[3], /* character_set_results */ + row[4]); /* collation_connection */ + + switch_sql_mode(sql_file, ";", row[1]); + + fprintf(sql_file, + "DELIMITER ;;\n" + "/*!50003 %s */;;\n" + "DELIMITER ;\n", + (const char *) (query_str != NULL ? query_str : row[2])); + + restore_sql_mode(sql_file, ";"); + restore_cs_variables(sql_file, ";"); + + if (db_cl_altered) + { + if (restore_db_collation(sql_file, db_name, ";", db_cl_name)) + DBUG_RETURN(TRUE); + } + + my_free(query_str, MYF(MY_ALLOW_ZERO_PTR)); + } + + DBUG_RETURN(FALSE); +} + +/** + Dump the triggers for a given table. + + This should be called after the tables have been dumped in case a trigger + depends on the existence of a table. + + @param[in] table_name + @param[in] db_name + + @return Error status. + @retval TRUE error has occurred. + @retval FALSE operation succeed. */ -static void dump_triggers_for_table(char *table, - char *db __attribute__((unused))) +static int dump_triggers_for_table(char *table_name, char *db_name) { - char *result_table; - char name_buff[NAME_LEN*4+3], table_buff[NAME_LEN*2+3]; - char query_buff[512]; - uint old_opt_compatible_mode=opt_compatible_mode; - FILE *sql_file= md_result_file; - MYSQL_RES *result; + char name_buff[NAME_LEN*4+3]; + char query_buff[QUERY_LENGTH]; + uint old_opt_compatible_mode= opt_compatible_mode; + MYSQL_RES *show_triggers_rs; MYSQL_ROW row; + + char db_cl_name[MY_CS_NAME_SIZE]; + DBUG_ENTER("dump_triggers_for_table"); - DBUG_PRINT("enter", ("db: %s, table: %s", db, table)); + DBUG_PRINT("enter", ("db: %s, table_name: %s", db_name, table_name)); /* Do not use ANSI_QUOTES on triggers in dump */ opt_compatible_mode&= ~MASK_ANSI_QUOTES; - result_table= quote_name(table, table_buff, 1); + + /* Get database collation. */ + + if (switch_character_set_results(mysql, "binary")) + DBUG_RETURN(TRUE); + + if (fetch_db_collation(db_name, db_cl_name, sizeof (db_cl_name))) + DBUG_RETURN(TRUE); + + /* Get list of triggers. */ my_snprintf(query_buff, sizeof(query_buff), "SHOW TRIGGERS LIKE %s", - quote_for_like(table, name_buff)); + quote_for_like(table_name, name_buff)); - if (mysql_query_with_error_report(mysql, &result, query_buff)) - { - if (path) - my_fclose(sql_file, MYF(MY_WME)); - DBUG_VOID_RETURN; - } - if (mysql_num_rows(result)) - { - fprintf(sql_file, "\n/*!50003 SET @SAVE_SQL_MODE=@@SQL_MODE*/;\n"); - fprintf(sql_file, "\nDELIMITER ;;\n"); - } - while ((row= mysql_fetch_row(result))) + if (mysql_query_with_error_report(mysql, &show_triggers_rs, query_buff)) + DBUG_RETURN(TRUE); + + /* Dump triggers. */ + + while ((row= mysql_fetch_row(show_triggers_rs))) { - fprintf(sql_file, - "/*!50003 SET SESSION SQL_MODE=\"%s\" */;;\n" - "/*!50003 CREATE */ ", - row[6] /* sql_mode */); - if (mysql_num_fields(result) > 7) + my_snprintf(query_buff, sizeof (query_buff), + "SHOW CREATE TRIGGER %s", + quote_name(row[0], name_buff, TRUE)); + + if (mysql_query(mysql, query_buff)) { /* - mysqldump can be run against the server, that does not support definer - in triggers (there is no DEFINER column in SHOW TRIGGERS output). So, - we should check if we have this column before accessing it. + mysqldump is being run against old server, that does not support + SHOW CREATE TRIGGER statement. We should use SHOW TRIGGERS output. + + NOTE: the dump may be incorrect, as old SHOW TRIGGERS does not + provide all the necessary information to restore trigger properly. */ - uint user_name_len; - char user_name_str[USERNAME_LENGTH + 1]; - char quoted_user_name_str[USERNAME_LENGTH * 2 + 3]; - uint host_name_len; - char host_name_str[HOSTNAME_LENGTH + 1]; - char quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3]; + dump_trigger_old(show_triggers_rs, &row, table_name); + } + else + { + MYSQL_RES *show_create_trigger_rs= mysql_store_result(mysql); - parse_user(row[7], strlen(row[7]), user_name_str, &user_name_len, - host_name_str, &host_name_len); + if (!show_create_trigger_rs || + dump_trigger(show_create_trigger_rs, db_name, db_cl_name)) + { + DBUG_RETURN(TRUE); + } - fprintf(sql_file, - "/*!50017 DEFINER=%s@%s */ ", - quote_name(user_name_str, quoted_user_name_str, FALSE), - quote_name(host_name_str, quoted_host_name_str, FALSE)); + mysql_free_result(show_create_trigger_rs); } - fprintf(sql_file, - "/*!50003 TRIGGER %s %s %s ON %s FOR EACH ROW%s%s */;;\n\n", - quote_name(row[0], name_buff, 0), /* Trigger */ - row[4], /* Timing */ - row[1], /* Event */ - result_table, - (strchr(" \t\n\r", *(row[3]))) ? "" : " ", - row[3] /* Statement */); - } - if (mysql_num_rows(result)) - { - fprintf(sql_file, - "DELIMITER ;\n" - "/*!50003 SET SESSION SQL_MODE=@SAVE_SQL_MODE*/;\n"); } - mysql_free_result(result); + + mysql_free_result(show_triggers_rs); + + if (switch_character_set_results(mysql, default_charset)) + DBUG_RETURN(TRUE); + /* make sure to set back opt_compatible mode to original value */ opt_compatible_mode=old_opt_compatible_mode; - DBUG_VOID_RETURN; + + DBUG_RETURN(FALSE); } static void add_load_option(DYNAMIC_STRING *str, const char *option, @@ -2336,7 +3023,7 @@ static void dump_table(char *table, char *db) /* The "table" could be a view. If so, we don't do anything here. */ - if (strcmp (table_type, "VIEW") == 0) + if (strcmp(table_type, "VIEW") == 0) DBUG_VOID_RETURN; /* Check --no-data flag */ @@ -2368,6 +3055,18 @@ static void dump_table(char *table, char *db) DBUG_VOID_RETURN; } + /* + Check --skip-events flag: it is not enough to skip creation of events + discarding SHOW CREATE EVENT statements generation. The myslq.event + table data should be skipped too. + */ + if (!opt_events && !my_strcasecmp(&my_charset_latin1, db, "mysql") && + !my_strcasecmp(&my_charset_latin1, table, "event")) + { + verbose_msg("-- Skipping data table mysql.event, --skip-events was used\n"); + DBUG_VOID_RETURN; + } + result_table= quote_name(table,table_buff, 1); opt_quoted_table= quote_name(table, table_buff2, 0); @@ -2426,6 +3125,7 @@ static void dump_table(char *table, char *db) if (mysql_real_query(mysql, query_string.str, query_string.length)) { DB_error(mysql, "when executing 'SELECT INTO OUTFILE'"); + dynstr_free(&query_string); DBUG_VOID_RETURN; } } @@ -2612,7 +3312,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, "'"); @@ -2681,7 +3381,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); @@ -2780,8 +3480,8 @@ static void dump_table(char *table, char *db) check_io(md_result_file); } mysql_free_result(res); - dynstr_free(&query_string); } + dynstr_free(&query_string); DBUG_VOID_RETURN; err: @@ -2815,6 +3515,263 @@ 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; + DBUG_ENTER("dump_tablespaces"); + + 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))) + { + dynstr_free(&sqlbuf); + 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); + DBUG_RETURN(0); + } + + my_printf_error(0, "Error: '%s' when trying to dump tablespaces", + MYF(0), mysql_error(mysql)); + DBUG_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); + mysql_free_result(tableres); + 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)) + { + dynstr_free(&sqlbuf); + DBUG_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); + } + } + + mysql_free_result(tableres); + dynstr_free(&sqlbuf); + DBUG_RETURN(0); +} + static int dump_all_databases() { MYSQL_ROW row; @@ -2899,8 +3856,11 @@ RETURN VALUES 0 Success. 1 Failure. */ + int init_dumping_tables(char *qdatabase) { + DBUG_ENTER("init_dumping_tables"); + if (!opt_create_db) { char qbuf[256]; @@ -2933,10 +3893,10 @@ int init_dumping_tables(char *qdatabase) { fprintf(md_result_file,"\n%s;\n",row[1]); } + mysql_free_result(dbinfo); } } - - return 0; + DBUG_RETURN(0); } /* init_dumping_tables */ @@ -2981,9 +3941,9 @@ static int init_dumping(char *database, int init_func(char*)) /* Return 1 if we should copy the table */ -my_bool include_table(byte* hash_key, uint len) +my_bool include_table(const uchar *hash_key, size_t len) { - return !hash_search(&ignore_table, (byte*) hash_key, len); + return !hash_search(&ignore_table, hash_key, len); } @@ -3008,10 +3968,15 @@ static int dump_all_tables_in_db(char *database) { DYNAMIC_STRING query; init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024); - for (numrows= 0 ; (table= getTableName(1)) ; numrows++) + for (numrows= 0 ; (table= getTableName(1)) ; ) { - 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((uchar*) hash_key,end - hash_key)) + { + numrows++; + 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"); @@ -3027,16 +3992,29 @@ static int dump_all_tables_in_db(char *database) while ((table= getTableName(0))) { char *end= strmov(afterdot, table); - if (include_table(hash_key, end - hash_key)) + if (include_table((uchar*) hash_key, end - hash_key)) { dump_table(table,database); my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); order_by= 0; if (opt_dump_triggers && ! opt_xml && mysql_get_server_version(mysql) >= 50009) - dump_triggers_for_table(table, database); + { + if (dump_triggers_for_table(table, database)) + { + if (path) + my_fclose(md_result_file, MYF(MY_WME)); + maybe_exit(EX_MYSQLERR); + } + } } } + 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) { @@ -3076,6 +4054,11 @@ static my_bool dump_all_views_in_db(char *database) char *table; uint numrows; char table_buff[NAME_LEN*2+3]; + char hash_key[2*NAME_LEN+2]; /* "db.tablename" */ + char *afterdot; + + afterdot= strmov(hash_key, database); + *afterdot++= '.'; if (init_dumping(database, init_dumping_views)) return 1; @@ -3085,10 +4068,15 @@ static my_bool dump_all_views_in_db(char *database) { DYNAMIC_STRING query; init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024); - for (numrows= 0 ; (table= getTableName(1)); numrows++) + for (numrows= 0 ; (table= getTableName(1)); ) { - 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((uchar*) hash_key,end - hash_key)) + { + numrows++; + 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"); @@ -3102,7 +4090,11 @@ static my_bool dump_all_views_in_db(char *database) /* We shall continue here, if --force was given */ } while ((table= getTableName(0))) - get_view_structure(table, database); + { + char *end= strmov(afterdot, table); + if (include_table((uchar*) hash_key, end - hash_key)) + get_view_structure(table, database); + } if (opt_xml) { fputs("</database>\n", md_result_file); @@ -3165,14 +4157,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 *)))) @@ -3194,8 +4186,13 @@ static int dump_selected_tables(char *db, char **table_names, int tables) } else { - maybe_die(EX_ILLEGAL_TABLE, "Couldn't find table: \"%s\"", *table_names); - /* We shall countinue here, if --force was given */ + if (!ignore_errors) + { + dynstr_free(&lock_tables_query); + free_root(&root, MYF(0)); + } + maybe_die(EX_ILLEGAL_TABLE, "Couldn't find table: \"%s\"", *table_names); + /* We shall countinue here, if --force was given */ } } end= pos; @@ -3204,14 +4201,25 @@ static int dump_selected_tables(char *db, char **table_names, int tables) { if (mysql_real_query(mysql, lock_tables_query.str, lock_tables_query.length-1)) + { + if (!ignore_errors) + { + dynstr_free(&lock_tables_query); + free_root(&root, MYF(0)); + } DB_error(mysql, "when doing LOCK TABLES"); /* We shall countinue here, if --force was given */ + } } dynstr_free(&lock_tables_query); if (flush_logs) { if (mysql_refresh(mysql, REFRESH_LOG)) + { + if (!ignore_errors) + free_root(&root, MYF(0)); DB_error(mysql, "when doing refresh"); + } /* We shall countinue here, if --force was given */ } if (opt_xml) @@ -3224,7 +4232,14 @@ static int dump_selected_tables(char *db, char **table_names, int tables) dump_table(*pos, db); if (opt_dump_triggers && mysql_get_server_version(mysql) >= 50009) - dump_triggers_for_table(*pos, db); + { + if (dump_triggers_for_table(*pos, db)) + { + if (path) + my_fclose(md_result_file, MYF(MY_WME)); + maybe_exit(EX_MYSQLERR); + } + } } /* Dump each selected view */ @@ -3233,6 +4248,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) @@ -3533,7 +4554,8 @@ char check_if_ignore_table(const char *table_name, char *table_type) If these two types, we do want to skip dumping the table */ if (!opt_no_data && - (!strcmp(table_type,"MRG_MyISAM") || !strcmp(table_type,"MRG_ISAM"))) + (!my_strcasecmp(&my_charset_latin1, table_type, "MRG_MyISAM") || + !strcmp(table_type,"MRG_ISAM"))) result= IGNORE_DATA; } mysql_free_result(res); @@ -3701,14 +4723,22 @@ static my_bool get_view_structure(char *table, char* db) result_table= quote_name(table, table_buff, 1); opt_quoted_table= quote_name(table, table_buff2, 0); + if (switch_character_set_results(mysql, "binary")) + DBUG_RETURN(1); + my_snprintf(query, sizeof(query), "SHOW CREATE TABLE %s", result_table); + if (mysql_query_with_error_report(mysql, &table_res, query)) + { + switch_character_set_results(mysql, default_charset); DBUG_RETURN(0); + } /* Check if this is a view */ field= mysql_fetch_field_direct(table_res, 0); if (strcmp(field->name, "View") != 0) { + switch_character_set_results(mysql, default_charset); verbose_msg("-- It's base table, skipped\n"); DBUG_RETURN(0); } @@ -3738,9 +4768,11 @@ static my_bool get_view_structure(char *table, char* db) my_snprintf(query, sizeof(query), - "SELECT CHECK_OPTION, DEFINER, SECURITY_TYPE " \ - "FROM information_schema.views " \ + "SELECT CHECK_OPTION, DEFINER, SECURITY_TYPE, " + " CHARACTER_SET_CLIENT, COLLATION_CONNECTION " + "FROM information_schema.views " "WHERE table_name=\"%s\" AND table_schema=\"%s\"", table, db); + if (mysql_query(mysql, query)) { /* @@ -3770,6 +4802,9 @@ static my_bool get_view_structure(char *table, char* db) if (!(table_res= mysql_store_result(mysql)) || !(row= mysql_fetch_row(table_res))) { + if (table_res) + mysql_free_result(table_res); + dynstr_free(&ds_view); DB_error(mysql, "when trying to save the result of SHOW CREATE TABLE in ds_view."); DBUG_RETURN(1); } @@ -3797,10 +4832,10 @@ static my_bool get_view_structure(char *table, char* db) Surround it with !50013 comments */ { - uint user_name_len; + size_t user_name_len; char user_name_str[USERNAME_LENGTH + 1]; char quoted_user_name_str[USERNAME_LENGTH * 2 + 3]; - uint host_name_len; + size_t host_name_len; char host_name_str[HOSTNAME_LENGTH + 1]; char quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3]; @@ -3826,12 +4861,31 @@ static my_bool get_view_structure(char *table, char* db) } /* Dump view structure to file */ - fprintf(sql_file, "/*!50001 %s */;\n", ds_view.str); + + fprintf(sql_file, + "/*!50001 SET @saved_cs_client = @@character_set_client */;\n" + "/*!50001 SET @saved_cs_results = @@character_set_results */;\n" + "/*!50001 SET @saved_col_connection = @@collation_connection */;\n" + "/*!50001 SET character_set_client = %s */;\n" + "/*!50001 SET character_set_results = %s */;\n" + "/*!50001 SET collation_connection = %s */;\n" + "/*!50001 %s */;\n" + "/*!50001 SET character_set_client = @saved_cs_client */;\n" + "/*!50001 SET character_set_results = @saved_cs_results */;\n" + "/*!50001 SET collation_connection = @saved_col_connection */;\n", + (const char *) row[3], + (const char *) row[3], + (const char *) row[4], + (const char *) ds_view.str); + check_io(sql_file); mysql_free_result(table_res); dynstr_free(&ds_view); } + if (switch_character_set_results(mysql, default_charset)) + DBUG_RETURN(1); + /* If a separate .sql file was opened, close it now */ if (sql_file != md_result_file) { @@ -3939,16 +4993,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 066e892f78a..954af0cff97 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -24,10 +24,21 @@ ** * * ** ************************* */ -#define IMPORT_VERSION "3.5" +#define IMPORT_VERSION "3.7" #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,15 +49,15 @@ 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 debug_info_flag= 0, debug_check_flag= 0; +static uint opt_use_threads=0, opt_local_file=0, my_end_arg= 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, *escaped=0, *opt_columns=0, *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME; static uint opt_mysql_port= 0, opt_protocol= 0; -static my_string opt_mysql_unix_port=0; +static char * opt_mysql_unix_port=0; static longlong opt_ignore_lines= -1; static CHARSET_INFO *charset_info= &my_charset_latin1; #include <sslopt-vars.h> @@ -62,56 +73,63 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"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}, + "Directory where character sets are.", (uchar**) &charsets_dir, + (uchar**) &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}, + "Set the default character set.", (uchar**) &default_charset, + (uchar**) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"columns", 'c', "Use only these columns to import the data to. Give the column names in a comma separated list. This is same as giving columns to LOAD DATA INFILE.", - (gptr*) &opt_columns, (gptr*) &opt_columns, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, + (uchar**) &opt_columns, (uchar**) &opt_columns, 0, GET_STR, REQUIRED_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, + (uchar**) &opt_compress, (uchar**) &opt_compress, 0, GET_BOOL, NO_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}, - {"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}, + {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .", + (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", + (uchar**) &debug_info_flag, (uchar**) &debug_info_flag, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"delete", 'd', "First delete all rows from table.", (uchar**) &opt_delete, + (uchar**) &opt_delete, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"fields-terminated-by", OPT_FTB, - "Fields in the textfile are terminated by ...", (gptr*) &fields_terminated, - (gptr*) &fields_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Fields in the textfile are terminated by ...", (uchar**) &fields_terminated, + (uchar**) &fields_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"fields-enclosed-by", OPT_ENC, - "Fields in the importfile are enclosed by ...", (gptr*) &enclosed, - (gptr*) &enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Fields in the importfile are enclosed by ...", (uchar**) &enclosed, + (uchar**) &enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"fields-optionally-enclosed-by", OPT_O_ENC, - "Fields in the i.file are opt. enclosed by ...", (gptr*) &opt_enclosed, - (gptr*) &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Fields in the i.file are opt. enclosed by ...", (uchar**) &opt_enclosed, + (uchar**) &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"fields-escaped-by", OPT_ESC, "Fields in the i.file are escaped by ...", - (gptr*) &escaped, (gptr*) &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, + (uchar**) &escaped, (uchar**) &escaped, 0, GET_STR, REQUIRED_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, + (uchar**) &ignore_errors, (uchar**) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"help", '?', "Displays this help and exits.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"host", 'h', "Connect to host.", (gptr*) ¤t_host, - (gptr*) ¤t_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"host", 'h', "Connect to host.", (uchar**) ¤t_host, + (uchar**) ¤t_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"ignore", 'i', "If duplicate unique key was found, keep old row.", - (gptr*) &ignore, (gptr*) &ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + (uchar**) &ignore, (uchar**) &ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"ignore-lines", OPT_IGN_LINES, "Ignore first n lines of data infile.", - (gptr*) &opt_ignore_lines, (gptr*) &opt_ignore_lines, 0, GET_LL, + (uchar**) &opt_ignore_lines, (uchar**) &opt_ignore_lines, 0, GET_LL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"lines-terminated-by", OPT_LTB, "Lines in the i.file are terminated by ...", - (gptr*) &lines_terminated, (gptr*) &lines_terminated, 0, GET_STR, + (uchar**) &lines_terminated, (uchar**) &lines_terminated, 0, GET_STR, 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}, + {"local", 'L', "Read all files through the client.", (uchar**) &opt_local_file, + (uchar**) &opt_local_file, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"lock-tables", 'l', "Lock all tables for write (this disables threads).", + (uchar**) &lock_tables, (uchar**) &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}, + "Use LOW_PRIORITY when updating the table.", (uchar**) &opt_low_priority, + (uchar**) &opt_low_priority, 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}, @@ -125,30 +143,35 @@ static struct my_option my_long_options[] = "/etc/services, " #endif "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - (gptr*) &opt_mysql_port, - (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, + (uchar**) &opt_mysql_port, + (uchar**) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 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}, {"replace", 'r', "If duplicate unique key was found, replace old row.", - (gptr*) &replace, (gptr*) &replace, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + (uchar**) &replace, (uchar**) &replace, 0, GET_BOOL, NO_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, + "Base name of shared memory.", (uchar**) &shared_memory_base_name, (uchar**) &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif - {"silent", 's', "Be more silent.", (gptr*) &silent, (gptr*) &silent, 0, + {"silent", 's', "Be more silent.", (uchar**) &silent, (uchar**) &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, + (uchar**) &opt_mysql_unix_port, (uchar**) &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.", + (uchar**) &opt_use_threads, (uchar**) &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}, + {"user", 'u', "User for login if not current user.", (uchar**) ¤t_user, + (uchar**) ¤t_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif - {"verbose", 'v', "Print info about the various stages.", (gptr*) &verbose, - (gptr*) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"verbose", 'v', "Print info about the various stages.", (uchar**) &verbose, + (uchar**) &verbose, 0, GET_BOOL, 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} @@ -218,16 +241,12 @@ 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"); + debug_check_flag= 1; break; #include <sslopt-case.h> case 'V': print_version(); exit(0); @@ -246,6 +265,10 @@ static int get_options(int *argc, char ***argv) if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); + if (debug_info_flag) + my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO; + if (debug_check_flag) + my_end_arg= MY_CHECK_ERROR; if (enclosed && opt_enclosed) { @@ -275,7 +298,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; @@ -283,7 +306,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 */ @@ -292,10 +315,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); } } @@ -334,17 +361,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); @@ -352,7 +379,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; @@ -367,72 +394,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); } @@ -440,8 +469,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); } @@ -449,7 +478,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); } @@ -503,13 +532,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); @@ -520,30 +591,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(my_end_arg); return(exitcode); } diff --git a/client/mysqlmanager-pwgen.c b/client/mysqlmanager-pwgen.c deleted file mode 100644 index 7a857c59743..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 "my_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 b4cc6320047..00000000000 --- a/client/mysqlmanagerc.c +++ /dev/null @@ -1,178 +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 or 0 for default to, in " - "order of preference, my.cnf, $MYSQL_TCP_PORT, " -#if MYSQL_PORT_DEFAULT == 0 - "/etc/services, " -#endif - "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", (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 7b1835055f5..a43adb0d586 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.10" #include "client_priv.h" #include <my_sys.h> @@ -26,9 +26,11 @@ #include <stdarg.h> #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 char * host=0, *opt_password=0, *user=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; +static my_bool debug_info_flag= 0, debug_check_flag= 0; +static uint my_end_arg= 0; static uint opt_verbose=0; static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME; @@ -52,7 +54,7 @@ static void print_res_top(MYSQL_RES *result); static void print_res_row(MYSQL_RES *result,MYSQL_ROW cur); static const char *load_default_groups[]= { "mysqlshow","client",0 }; -static my_string opt_mysql_unix_port=0; +static char * opt_mysql_unix_port=0; int main(int argc, char **argv) { @@ -120,7 +122,8 @@ int main(int argc, char **argv) mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); if (!(mysql_real_connect(&mysql,host,user,opt_password, - (first_argument_uses_wildcards) ? "" : argv[0],opt_mysql_port,opt_mysql_unix_port, + (first_argument_uses_wildcards) ? "" : + argv[0],opt_mysql_port,opt_mysql_unix_port, 0))) { fprintf(stderr,"%s: %s\n",my_progname,mysql_error(&mysql)); @@ -128,8 +131,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 +152,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(my_end_arg); exit(error ? 1 : 0); return 0; /* No compiler warnings */ } @@ -162,29 +164,35 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"character-sets-dir", 'c', "Directory where character sets are.", - (gptr*) &charsets_dir, (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, + (uchar**) &charsets_dir, (uchar**) &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}, + "Set the default character set.", (uchar**) &default_charset, + (uchar**) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"count", OPT_COUNT, "Show number of rows per table (may be slow for not MyISAM tables)", - (gptr*) &opt_count, (gptr*) &opt_count, 0, GET_BOOL, NO_ARG, 0, 0, 0, + (uchar**) &opt_count, (uchar**) &opt_count, 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, + (uchar**) &opt_compress, (uchar**) &opt_compress, 0, GET_BOOL, NO_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-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .", + (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", + (uchar**) &debug_info_flag, (uchar**) &debug_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, + {"host", 'h', "Connect to host.", (uchar**) &host, (uchar**) &host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"status", 'i', "Shows a lot of extra information about each table.", - (gptr*) &opt_status, (gptr*) &opt_status, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + (uchar**) &opt_status, (uchar**) &opt_status, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"keys", 'k', "Show keys for table.", (gptr*) &opt_show_keys, - (gptr*) &opt_show_keys, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"keys", 'k', "Show keys for table.", (uchar**) &opt_show_keys, + (uchar**) &opt_show_keys, 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}, @@ -194,8 +202,8 @@ static struct my_option my_long_options[] = "/etc/services, " #endif "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - (gptr*) &opt_mysql_port, - (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, + (uchar**) &opt_mysql_port, + (uchar**) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifdef __WIN__ {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, @@ -205,19 +213,19 @@ static struct my_option my_long_options[] = 0, 0, 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, + "Base name of shared memory.", (uchar**) &shared_memory_base_name, (uchar**) &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif {"show-table-type", 't', "Show table type column.", - (gptr*) &opt_table_type, (gptr*) &opt_table_type, 0, GET_BOOL, + (uchar**) &opt_table_type, (uchar**) &opt_table_type, 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, + (uchar**) &opt_mysql_unix_port, (uchar**) &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}, + {"user", 'u', "User for login if not current user.", (uchar**) &user, + (uchar**) &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.", @@ -292,16 +300,12 @@ 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"); + debug_check_flag= 1; break; #include <sslopt-case.h> case 'V': @@ -335,6 +339,10 @@ get_options(int *argc,char ***argv) */ opt_verbose= 2; } + if (debug_info_flag) + my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO; + if (debug_check_flag) + my_end_arg= MY_CHECK_ERROR; return; } @@ -743,7 +751,7 @@ print_header(const char *header,uint head_length,...) for (i=0 ; i < length+2 ; i++) putchar('-'); putchar('+'); - if (!(field=va_arg(args,my_string))) + if (!(field=va_arg(args,char *))) break; length=va_arg(args,uint); } @@ -767,7 +775,7 @@ print_header(const char *header,uint head_length,...) for (i=0 ; i < length ; i++) putchar(' '); putchar('|'); - if (!(field=va_arg(args,my_string))) + if (!(field=va_arg(args,char *))) break; length=va_arg(args,uint); } @@ -782,7 +790,7 @@ print_header(const char *header,uint head_length,...) for (i=0 ; i < length+2 ; i++) putchar('-'); putchar('+'); - if (!(field=va_arg(args,my_string))) + if (!(field=va_arg(args,char *))) break; length=va_arg(args,uint); } @@ -808,7 +816,7 @@ print_row(const char *header,uint head_length,...) field_length=(uint) strlen(field); for (i=field_length ; i <= length ; i++) putchar(' '); - if (!(field=va_arg(args,my_string))) + if (!(field=va_arg(args,char *))) break; length=va_arg(args,uint); } diff --git a/client/mysqlslap.c b/client/mysqlslap.c new file mode 100644 index 00000000000..d9bbeba9713 --- /dev/null +++ b/client/mysqlslap.c @@ -0,0 +1,2201 @@ +/* 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 --delimiter=";" \ + --create="CREATE TABLE A (a int);INSERT INTO A VALUES (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 SLAP_VERSION "1.0" + +#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 +#define DELETE_TYPE_REQUIRES_PREFIX 6 + +#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, + *pre_system= NULL, + *post_system= NULL, + *opt_mysql_unix_port= NULL; + +const char *delimiter= "\n"; + +const char *create_schema_string= "mysqlslap"; + +static my_bool opt_preserve= TRUE; +static my_bool debug_info_flag= 0, debug_check_flag= 0; +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 | + CLIENT_MULTI_STATEMENTS; + +static int verbose, delimiter_length; +static uint commit_rate; +static uint detach_rate; +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 uint my_end_arg= 0; +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); +int slap_connect(MYSQL *mysql); +static int run_query(MYSQL *mysql, const char *query, int len); + +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(opt_password, MYF(0)); + + my_free(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(shared_memory_base_name, MYF(MY_ALLOW_ZERO_PTR)); +#endif + free_defaults(defaults_argv); + my_end(my_end_arg); + + 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 (commit_rate) + run_query(mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0")); + + if (pre_system) + system(pre_system); + + /* + Pre statements are always run after all other logic so they can + correct/adjust any item that they want. + */ + if (pre_statements) + run_statements(mysql, pre_statements); + + run_scheduler(sptr, query_statements, current, client_limit); + + if (post_statements) + run_statements(mysql, post_statements); + + if (post_system) + system(post_system); + + /* 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(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.", + (uchar**) &auto_generate_sql, (uchar**) &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 an AUTO_INCREMENT column to auto-generated tables.", + (uchar**) &auto_generate_sql_autoincrement, + (uchar**) &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.", + (uchar**) &auto_actual_queries, (uchar**) &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.", + (uchar**) &auto_generate_sql_guid_primary, + (uchar**) &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, + "Specify test load type: mixed, update, write, key, or read; default is mixed.", + (uchar**) &auto_generate_sql_type, (uchar**) &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 to auto-generated tables.", + (uchar**) &auto_generate_sql_secondary_indexes, + (uchar**) &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 to generate for automatic tests.", + (uchar**) &auto_generate_sql_unique_query_number, + (uchar**) &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 to generate for auto-generate-sql-write-number.", + (uchar**) &auto_generate_sql_unique_write_number, + (uchar**) &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 row inserts to perform for each thread (default is 100).", + (uchar**) &auto_generate_sql_number, (uchar**) &auto_generate_sql_number, + 0, GET_ULL, REQUIRED_ARG, 100, 0, 0, 0, 0, 0}, + {"commit", OPT_SLAP_COMMIT, "Commit records every X number of statements.", + (uchar**) &commit_rate, (uchar**) &commit_rate, 0, GET_UINT, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"compress", 'C', "Use compression in server/client protocol.", + (uchar**) &opt_compress, (uchar**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, + 0, 0, 0}, + {"concurrency", 'c', "Number of clients to simulate for query to run.", + (uchar**) &concurrency_str, (uchar**) &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.", + (uchar**) &create_string, (uchar**) &create_string, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"create-schema", OPT_CREATE_SLAP_SCHEMA, "Schema to run tests in.", + (uchar**) &create_schema_string, (uchar**) &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.", + (uchar**) &opt_csv_str, (uchar**) &opt_csv_str, 0, GET_STR, + OPT_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}, +#else + {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", + (uchar**) &default_dbug_option, (uchar**) &default_dbug_option, 0, GET_STR, + OPT_ARG, 0, 0, 0, 0, 0, 0}, +#endif + {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .", + (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-info", 'T', "Print some debug info at exit.", (uchar**) &debug_info_flag, + (uchar**) &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"delimiter", 'F', + "Delimiter to use in SQL statements supplied in file or command line.", + (uchar**) &delimiter, (uchar**) &delimiter, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"detach", OPT_SLAP_DETACH, + "Detach (close and reopen) connections after X number of requests.", + (uchar**) &detach_rate, (uchar**) &detach_rate, 0, GET_UINT, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"engine", 'e', "Storage engine to use for creating the table.", + (uchar**) &default_engine, (uchar**) &default_engine, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"host", 'h', "Connect to host.", (uchar**) &host, (uchar**) &host, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"iterations", 'i', "Number of times to run the tests.", (uchar**) &iterations, + (uchar**) &iterations, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, + {"number-char-cols", 'x', + "Number of VARCHAR columns to create in table if specifying --auto-generate-sql.", + (uchar**) &num_char_cols_opt, (uchar**) &num_char_cols_opt, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"number-int-cols", 'y', + "Number of INT columns to create in table if specifying --auto-generate-sql.", + (uchar**) &num_int_cols_opt, (uchar**) &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).", + (uchar**) &num_of_query, (uchar**) &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.", + (uchar**) &opt_only_print, (uchar**) &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.", (uchar**) &opt_mysql_port, + (uchar**) &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 execute after tests have completed.", + (uchar**) &user_supplied_post_statements, + (uchar**) &user_supplied_post_statements, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"post-system", OPT_SLAP_POST_SYSTEM, + "system() string to execute after tests have completed.", + (uchar**) &post_system, + (uchar**) &post_system, + 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 execute before running tests.", + (uchar**) &user_supplied_pre_statements, + (uchar**) &user_supplied_pre_statements, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"pre-system", OPT_SLAP_PRE_SYSTEM, + "system() string to execute before running tests.", + (uchar**) &pre_system, + (uchar**) &pre_system, + 0, GET_STR, REQUIRED_ARG, 0, 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.", + (uchar**) &user_supplied_query, (uchar**) &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.", (uchar**) &shared_memory_base_name, + (uchar**) &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.", + (uchar**) &opt_silent, (uchar**) &opt_silent, 0, GET_BOOL, NO_ARG, + 0, 0, 0, 0, 0, 0}, + {"socket", 'S', "Socket file to use for connection.", + (uchar**) &opt_mysql_unix_port, (uchar**) &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.", (uchar**) &user, + (uchar**) &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.", (uchar**) &verbose, (uchar**) &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, SLAP_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(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); + debug_check_flag= 1; + 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 (debug_info_flag) + my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO; + if (debug_check_flag) + my_end_arg= MY_CHECK_ERROR; + + if (!user) + user= (char *)"root"; + + /* If something is created we clean it up, otherwise we leave schemas alone */ + if (create_string || auto_generate_sql) + 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, (uchar*) 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(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, (uchar*) 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(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, (uchar*) tmp_string, sbuf.st_size, MYF(0)); + tmp_string[sbuf.st_size]= '\0'; + my_close(data_file,MYF(0)); + if (user_supplied_pre_statements) + (void)parse_delimiter(tmp_string, &pre_statements, + delimiter[0]); + my_free(tmp_string, MYF(0)); + } + else if (user_supplied_pre_statements) + { + (void)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, (uchar*) tmp_string, sbuf.st_size, MYF(0)); + tmp_string[sbuf.st_size]= '\0'; + my_close(data_file,MYF(0)); + if (user_supplied_post_statements) + (void)parse_delimiter(tmp_string, &post_statements, + delimiter[0]); + my_free(tmp_string, MYF(0)); + } + else if (user_supplied_post_statements) + { + (void)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(primary_keys[counter], MYF(0)); + + my_free(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; + MYSQL_RES *result; + 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); + } + if (mysql_field_count(mysql)) + { + result= mysql_store_result(mysql); + mysql_free_result(result); + } + } + + 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; + ulonglong detach_counter; + unsigned int commit_counter; + 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) + { + if (slap_connect(mysql)) + goto end; + } + + DBUG_PRINT("info", ("connected.")); + if (verbose >= 3) + printf("connected!\n"); + queries= 0; + + commit_counter= 0; + if (commit_rate) + run_query(mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0")); + +limit_not_met: + for (ptr= con->stmt, detach_counter= 0; + ptr && ptr->length; + ptr= ptr->next, detach_counter++) + { + if (!opt_only_print && detach_rate && !(detach_counter % detach_rate)) + { + mysql_close(mysql); + + if (!(mysql= mysql_init(NULL))) + { + fprintf(stderr,"%s: mysql_init() failed ERROR : %s\n", + my_progname, mysql_error(mysql)); + exit(0); + } + + if (slap_connect(mysql)) + goto end; + } + + /* + 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); + } + } + + do + { + if (mysql_field_count(mysql)) + { + result= mysql_store_result(mysql); + while ((row = mysql_fetch_row(result))) + counter++; + mysql_free_result(result); + } + } while(mysql_next_result(mysql) == 0); + queries++; + + if (commit_rate && (++commit_counter == commit_rate)) + { + commit_counter= 0; + run_query(mysql, "COMMIT", strlen("COMMIT")); + } + + if (con->limit && queries == con->limit) + goto end; + } + + if (con->limit && queries < con->limit) + goto limit_not_met; + +end: + if (commit_rate) + run_query(mysql, "COMMIT", strlen("COMMIT")); + + 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++; + } + + 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, (uchar*) 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(ptr->string, MYF(0)); + if (ptr->option) + my_free(ptr->option, MYF(0)); + my_free(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(ptr->string, MYF(0)); + my_free(ptr, MYF(0)); + } +} + + +int +slap_connect(MYSQL *mysql) +{ + /* Connect to server */ + static ulong connection_retry_sleep= 100000; /* Microseconds */ + int x, connect_error= 1; + for (x= 0; x < 10; x++) + { + 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)); + return 1; + } + + return 0; +} diff --git a/client/mysqltest.c b/client/mysqltest.c index 88575c26bc6..31e419244e6 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -31,20 +31,14 @@ Holyfoot */ -#define MTEST_VERSION "3.2" +#define MTEST_VERSION "3.3" -#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 @@ -75,11 +61,9 @@ #define QUERY_REAP_FLAG 2 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_TAIL_LINES + 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, OPT_TAIL_LINES }; static int record= 0, opt_sleep= -1; @@ -90,6 +74,7 @@ const char *opt_include= 0, *opt_charsets_dir; static int opt_port= 0; static int opt_max_connect_retries; static my_bool opt_compress= 0, silent= 0, verbose= 0; +static my_bool debug_info_flag= 0, debug_check_flag= 0; static my_bool tty_password= 0; static my_bool opt_mark_progress= 0; static my_bool ps_protocol= 0, ps_protocol_enabled= 0; @@ -110,6 +95,7 @@ static const char *load_default_groups[]= { "mysqltest", "client", 0 }; static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer; static uint start_lineno= 0; /* Start line of current command */ +static uint my_end_arg= 0; /* Number of lines of the result to include in failure report */ static uint opt_tail_lines= 0; @@ -277,7 +263,7 @@ enum enum_commands { Q_REPLACE_REGEX, Q_REMOVE_FILE, Q_FILE_EXIST, Q_WRITE_FILE, Q_COPY_FILE, Q_PERL, Q_DIE, Q_EXIT, Q_SKIP, Q_CHMOD_FILE, Q_APPEND_FILE, Q_CAT_FILE, Q_DIFF_FILES, - Q_SEND_QUIT, + Q_SEND_QUIT, Q_CHANGE_USER, Q_UNKNOWN, /* Unknown command. */ Q_COMMENT, /* Comments, ignored. */ @@ -366,6 +352,7 @@ const char *command_names[]= "cat_file", "diff_files", "send_quit", + "change_user", 0 }; @@ -910,7 +897,7 @@ void close_files() DBUG_PRINT("info", ("closing file: %s", cur_file->file_name)); my_fclose(cur_file->file, MYF(0)); } - my_free((gptr)cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR)); + my_free((uchar*) cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR)); cur_file->file_name= 0; } DBUG_VOID_RETURN; @@ -929,8 +916,8 @@ void free_used_memory() for (i= 0 ; i < q_lines.elements ; i++) { struct st_command **q= dynamic_element(&q_lines, i, struct st_command**); - my_free((gptr) (*q)->query_buf,MYF(MY_ALLOW_ZERO_PTR)); - my_free((gptr) (*q),MYF(0)); + my_free((*q)->query_buf,MYF(MY_ALLOW_ZERO_PTR)); + my_free((*q),MYF(0)); } for (i= 0; i < 10; i++) { @@ -964,12 +951,10 @@ void free_used_memory() static void cleanup_and_exit(int exit_code) { free_used_memory(); - my_end(MY_CHECK_ERROR); + my_end(my_end_arg); - if (!silent) - { - switch (exit_code) - { + if (!silent) { + switch (exit_code) { case 1: printf("not ok\n"); break; @@ -1191,7 +1176,7 @@ void cat_file(DYNAMIC_STRING* ds, const char* filename) if ((fd= my_open(filename, O_RDONLY, MYF(0))) < 0) die("Failed to open file '%s'", filename); - while((len= my_read(fd, (byte*)&buff, + while((len= my_read(fd, (uchar*)&buff, sizeof(buff), MYF(0))) > 0) { char *p= buff, *start= buff; @@ -1431,10 +1416,10 @@ int compare_files2(File fd, const char* filename2) my_close(fd, MYF(0)); die("Failed to open second file: '%s'", filename2); } - while((len= my_read(fd, (byte*)&buff, + while((len= my_read(fd, (uchar*)&buff, sizeof(buff), MYF(0))) > 0) { - if ((len2= my_read(fd2, (byte*)&buff2, + if ((len2= my_read(fd2, (uchar*)&buff2, sizeof(buff2), MYF(0))) < len) { /* File 2 was smaller */ @@ -1454,7 +1439,7 @@ int compare_files2(File fd, const char* filename2) break; } } - if (!error && my_read(fd2, (byte*)&buff2, + if (!error && my_read(fd2, (uchar*)&buff2, sizeof(buff2), MYF(0)) > 0) { /* File 1 was smaller */ @@ -1523,7 +1508,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) die("Failed to create temporary file for ds"); /* Write ds to temporary file and set file pos to beginning*/ - if (my_write(fd, ds->str, ds->length, + if (my_write(fd, (uchar *) ds->str, ds->length, MYF(MY_FNABP | MY_WME)) || my_seek(fd, 0, SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR) { @@ -1566,8 +1551,7 @@ void check_result(DYNAMIC_STRING* ds) if (access(result_file_name, F_OK) != 0) die("The specified result file does not exist: '%s'", result_file_name); - switch (dyn_string_cmp(ds, result_file_name)) - { + switch (dyn_string_cmp(ds, result_file_name)) { case RESULT_OK: break; /* ok */ case RESULT_LENGTH_MISMATCH: @@ -1580,7 +1564,8 @@ void check_result(DYNAMIC_STRING* ds) and then show the diff */ char reject_file[FN_REFLEN]; - dirname_part(reject_file, result_file_name); + size_t reject_length; + dirname_part(reject_file, result_file_name, &reject_length); if (access(reject_file, W_OK) == 0) { @@ -1683,13 +1668,13 @@ static void strip_parentheses(struct st_command *command) } -static byte *get_var_key(const byte* var, uint* len, - my_bool __attribute__((unused)) t) +static uchar *get_var_key(const uchar* var, size_t *len, + my_bool __attribute__((unused)) t) { register char* key; key = ((VAR*)var)->name; *len = ((VAR*)var)->name_len; - return (byte*)key; + return (uchar*)key; } @@ -1733,7 +1718,7 @@ void var_free(void *v) { my_free(((VAR*) v)->str_val, MYF(MY_WME)); if (((VAR*)v)->alloced) - my_free((char*) v, MYF(MY_WME)); + my_free(v, MYF(MY_WME)); } @@ -1745,7 +1730,7 @@ VAR* var_from_env(const char *name, const char *def_val) tmp = def_val; v = var_init(0, name, strlen(name), tmp, strlen(tmp)); - my_hash_insert(&var_hash, (byte*)v); + my_hash_insert(&var_hash, (uchar*)v); return v; } @@ -1778,7 +1763,8 @@ VAR* var_get(const char *var_name, const char **var_name_end, my_bool raw, if (length >= MAX_VAR_NAME_LENGTH) die("Too long variable name: %s", save_var_name); - if (!(v = (VAR*) hash_search(&var_hash, save_var_name, length))) + if (!(v = (VAR*) hash_search(&var_hash, (const uchar*) save_var_name, + length))) { char buff[MAX_VAR_NAME_LENGTH+1]; strmake(buff, save_var_name, length); @@ -1809,10 +1795,10 @@ err: VAR *var_obtain(const char *name, int len) { VAR* v; - if ((v = (VAR*)hash_search(&var_hash, name, len))) + if ((v = (VAR*)hash_search(&var_hash, (const uchar *) name, len))) return v; v = var_init(0, name, len, "", 0); - my_hash_insert(&var_hash, (byte*)v); + my_hash_insert(&var_hash, (uchar*)v); return v; } @@ -1864,7 +1850,7 @@ void var_set(const char *var_name, const char *var_name_end, if (!(v->env_s= my_strdup(buf, MYF(MY_WME)))) die("Out of memory"); putenv(v->env_s); - my_free((gptr)old_env_s, MYF(MY_ALLOW_ZERO_PTR)); + my_free(old_env_s, MYF(MY_ALLOW_ZERO_PTR)); } DBUG_VOID_RETURN; } @@ -2013,7 +1999,7 @@ void var_set_query_get_value(struct st_command *command, VAR *var) const struct command_arg query_get_value_args[] = { "query", ARG_STRING, TRUE, &ds_query, "Query to run", "column name", ARG_STRING, TRUE, &ds_col, "Name of column", - "row number", ARG_STRING, TRUE, &ds_row, "Number for row", + "row number", ARG_STRING, TRUE, &ds_row, "Number for row" }; DBUG_ENTER("var_set_query_get_value"); @@ -2229,7 +2215,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"); @@ -2296,9 +2282,10 @@ FILE* my_popen(DYNAMIC_STRING *ds_cmd, const char *mode) static void init_builtin_echo(void) { #ifdef __WIN__ + size_t echo_length; /* Look for "echo.exe" in same dir as mysqltest was started from */ - dirname_part(builtin_echo, my_progname); + dirname_part(builtin_echo, my_progname, &echo_length); fn_format(builtin_echo, ".\\echo.exe", builtin_echo, "", MYF(MY_REPLACE_DIR)); @@ -2415,7 +2402,10 @@ void do_exec(struct st_command *command) command->first_argument, ds_cmd.str)); if (!(res_file= my_popen(&ds_cmd, "r")) && command->abort_on_error) + { + dynstr_free(&ds_cmd); die("popen(\"%s\", \"r\") failed", command->first_argument); + } while (fgets(buf, sizeof(buf), res_file)) { @@ -2439,6 +2429,7 @@ void do_exec(struct st_command *command) { log_msg("exec of '%s' failed, error: %d, status: %d, errno: %d", ds_cmd.str, error, status, errno); + dynstr_free(&ds_cmd); die("command \"%s\" failed", command->first_argument); } @@ -2457,8 +2448,11 @@ void do_exec(struct st_command *command) } } if (!ok) + { + dynstr_free(&ds_cmd); die("command \"%s\" failed with wrong error: %d", command->first_argument, status); + } } else if (command->expected_errors.err[0].type == ERR_ERRNO && command->expected_errors.err[0].code.errnum != 0) @@ -2466,6 +2460,7 @@ void do_exec(struct st_command *command) /* Error code we wanted was != 0, i.e. not an expected success */ log_msg("exec of '%s failed, error: %d, errno: %d", ds_cmd.str, error, errno); + dynstr_free(&ds_cmd); die("command \"%s\" succeeded - should have failed with errno %d...", command->first_argument, command->expected_errors.err[0].code.errnum); } @@ -2615,7 +2610,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"); @@ -2649,8 +2644,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"); @@ -2686,8 +2681,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(octal) ex. 0660", - "filename", ARG_STRING, TRUE, &ds_file, "Filename of file to modify" + { "mode", ARG_STRING, TRUE, &ds_mode, "Mode of file(octal) ex. 0660"}, + { "filename", ARG_STRING, TRUE, &ds_file, "Filename of file to modify" } }; DBUG_ENTER("do_chmod_file"); @@ -2724,7 +2719,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"); @@ -2770,8 +2765,8 @@ void read_until_delimiter(DYNAMIC_STRING *ds, { char c; DBUG_ENTER("read_until_delimiter"); - DBUG_PRINT("enter", ("delimiter: %s, length: %d", - ds_delimiter->str, ds_delimiter->length)); + DBUG_PRINT("enter", ("delimiter: %s, length: %u", + ds_delimiter->str, (uint) ds_delimiter->length)); if (ds_delimiter->length > MAX_DELIMITER_LENGTH) die("Max delimiter length(%d) exceeded", MAX_DELIMITER_LENGTH); @@ -2820,8 +2815,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"); @@ -2932,7 +2927,7 @@ void do_cat_file(struct st_command *command) { 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"); @@ -2969,8 +2964,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"); @@ -3040,7 +3035,70 @@ void do_send_quit(struct st_command *command) if (!(con= find_connection_by_name(name))) die("connection '%s' not found in connection pool", name); - simple_command(&con->mysql,COM_QUIT,NullS,0,1); + simple_command(&con->mysql,COM_QUIT,0,0,1); + + DBUG_VOID_RETURN; +} + + +/* + SYNOPSIS + do_change_user + command called command + + DESCRIPTION + change_user [<user>], [<passwd>], [<db>] + <user> - user to change to + <passwd> - user password + <db> - default database + + Changes the user and causes the database specified by db to become + the default (current) database for the the current connection. + +*/ + +void do_change_user(struct st_command *command) +{ + MYSQL *mysql = &cur_con->mysql; + /* static keyword to make the NetWare compiler happy. */ + static DYNAMIC_STRING ds_user, ds_passwd, ds_db; + const struct command_arg change_user_args[] = { + { "user", ARG_STRING, FALSE, &ds_user, "User to connect as" }, + { "password", ARG_STRING, FALSE, &ds_passwd, "Password used when connecting" }, + { "database", ARG_STRING, FALSE, &ds_db, "Database to select after connect" }, + }; + + DBUG_ENTER("do_change_user"); + + check_command_args(command, command->first_argument, + change_user_args, + sizeof(change_user_args)/sizeof(struct command_arg), + ','); + + if (cur_con->stmt) + { + mysql_stmt_close(cur_con->stmt); + cur_con->stmt= NULL; + } + + if (!ds_user.length) + dynstr_set(&ds_user, mysql->user); + + if (!ds_passwd.length) + dynstr_set(&ds_passwd, mysql->passwd); + + if (!ds_db.length) + dynstr_set(&ds_db, mysql->db); + + DBUG_PRINT("info",("connection: '%s' user: '%s' password: '%s' database: '%s'", + cur_con->name, ds_user.str, ds_passwd.str, ds_db.str)); + + if (mysql_change_user(mysql, ds_user.str, ds_passwd.str, ds_db.str)) + die("change user failed: %s", mysql_error(mysql)); + + dynstr_free(&ds_user); + dynstr_free(&ds_passwd); + dynstr_free(&ds_db); DBUG_VOID_RETURN; } @@ -3075,7 +3133,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"); @@ -3228,13 +3286,17 @@ 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) { show_query(mysql, "SHOW MASTER STATUS"); @@ -3242,7 +3304,6 @@ wait_for_position: 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); @@ -3283,6 +3344,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); @@ -3307,7 +3369,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; @@ -3410,9 +3472,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; @@ -3440,7 +3502,7 @@ int do_save_master_pos() if (rpl_parse) mysql_enable_rpl_parse(mysql); - return 0; + DBUG_RETURN(0); } @@ -3881,7 +3943,7 @@ void set_reconnect(MYSQL* mysql, int val) 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))) @@ -3904,7 +3966,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)); } @@ -4142,18 +4204,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"); @@ -4508,7 +4566,7 @@ int read_line(char *buf, int size) my_fclose(cur_file->file, MYF(0)); cur_file->file= 0; } - my_free((gptr)cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR)); + my_free((uchar*) cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR)); cur_file->file_name= 0; if (cur_file == file_stack) { @@ -4861,13 +4919,13 @@ int read_command(struct st_command** command_ptr) if (parser.current_line < parser.read_lines) { - get_dynamic(&q_lines, (gptr) command_ptr, parser.current_line) ; + get_dynamic(&q_lines, (uchar*) command_ptr, parser.current_line) ; DBUG_RETURN(0); } if (!(*command_ptr= command= (struct st_command*) my_malloc(sizeof(*command), MYF(MY_WME|MY_ZEROFILL))) || - insert_dynamic(&q_lines, (gptr) &command)) + insert_dynamic(&q_lines, (uchar*) &command)) die(NullS); command->type= Q_UNKNOWN; @@ -4922,18 +4980,18 @@ 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}, - {"basedir", 'b', "Basedir for tests.", (gptr*) &opt_basedir, - (gptr*) &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"basedir", 'b', "Basedir for tests.", (uchar**) &opt_basedir, + (uchar**) &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"character-sets-dir", OPT_CHARSETS_DIR, - "Directory where character sets are.", (gptr*) &opt_charsets_dir, - (gptr*) &opt_charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Directory where character sets are.", (uchar**) &opt_charsets_dir, + (uchar**) &opt_charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"compress", 'C', "Use the compressed server/client protocol.", - (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, + (uchar**) &opt_compress, (uchar**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"cursor-protocol", OPT_CURSOR_PROTOCOL, "Use cursors for prepared statements.", - (gptr*) &cursor_protocol, (gptr*) &cursor_protocol, 0, + (uchar**) &cursor_protocol, (uchar**) &cursor_protocol, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"database", 'D', "Database to use.", (gptr*) &opt_db, (gptr*) &opt_db, 0, + {"database", 'D', "Database to use.", (uchar**) &opt_db, (uchar**) &opt_db, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifdef DBUG_OFF {"debug", '#', "This is a non-debug version. Catch this and exit", @@ -4942,19 +5000,25 @@ 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 - {"host", 'h', "Connect to host.", (gptr*) &opt_host, (gptr*) &opt_host, 0, + {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .", + (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", + (uchar**) &debug_info_flag, (uchar**) &debug_info_flag, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"host", 'h', "Connect to host.", (uchar**) &opt_host, (uchar**) &opt_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"include", 'i', "Include SQL before each test case.", (gptr*) &opt_include, - (gptr*) &opt_include, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"logdir", OPT_LOG_DIR, "Directory for log files", (gptr*) &opt_logdir, - (gptr*) &opt_logdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"include", 'i', "Include SQL before each test case.", (uchar**) &opt_include, + (uchar**) &opt_include, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"logdir", OPT_LOG_DIR, "Directory for log files", (uchar**) &opt_logdir, + (uchar**) &opt_logdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"mark-progress", OPT_MARK_PROGRESS, "Write linenumber and elapsed time to <testname>.progress ", - (gptr*) &opt_mark_progress, (gptr*) &opt_mark_progress, 0, + (uchar**) &opt_mark_progress, (uchar**) &opt_mark_progress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"max-connect-retries", OPT_MAX_CONNECT_RETRIES, "Max number of connection attempts when connecting to server", - (gptr*) &opt_max_connect_retries, (gptr*) &opt_max_connect_retries, 0, + (uchar**) &opt_max_connect_retries, (uchar**) &opt_max_connect_retries, 0, GET_INT, REQUIRED_ARG, 500, 1, 10000, 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}, @@ -4964,39 +5028,39 @@ static struct my_option my_long_options[] = "/etc/services, " #endif "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - (gptr*) &opt_port, - (gptr*) &opt_port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + (uchar**) &opt_port, + (uchar**) &opt_port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"ps-protocol", OPT_PS_PROTOCOL, "Use prepared statements protocol for communication", - (gptr*) &ps_protocol, (gptr*) &ps_protocol, 0, + (uchar**) &ps_protocol, (uchar**) &ps_protocol, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"quiet", 's', "Suppress all normal output.", (gptr*) &silent, - (gptr*) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"quiet", 's', "Suppress all normal output.", (uchar**) &silent, + (uchar**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"record", 'r', "Record output of test_file into result file.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"result-file", 'R', "Read/Store result from/in this file.", - (gptr*) &result_file_name, (gptr*) &result_file_name, 0, + (uchar**) &result_file_name, (uchar**) &result_file_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"server-arg", 'A', "Send option value to embedded server as a parameter.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"server-file", 'F', "Read embedded server arguments from file.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"silent", 's', "Suppress all normal output. Synonym for --quiet.", - (gptr*) &silent, (gptr*) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + (uchar**) &silent, (uchar**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"skip-safemalloc", OPT_SKIP_SAFEMALLOC, "Don't use the memory allocation checking.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"sleep", 'T', "Sleep always this many seconds on sleep commands.", - (gptr*) &opt_sleep, (gptr*) &opt_sleep, 0, GET_INT, REQUIRED_ARG, -1, -1, 0, + (uchar**) &opt_sleep, (uchar**) &opt_sleep, 0, GET_INT, REQUIRED_ARG, -1, -1, 0, 0, 0, 0}, {"socket", 'S', "Socket file to use for connection.", - (gptr*) &unix_sock, (gptr*) &unix_sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, + (uchar**) &unix_sock, (uchar**) &unix_sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"sp-protocol", OPT_SP_PROTOCOL, "Use stored procedures for select", - (gptr*) &sp_protocol, (gptr*) &sp_protocol, 0, + (uchar**) &sp_protocol, (uchar**) &sp_protocol, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"tail-lines", OPT_TAIL_LINES, "Number of lines of the resul to include in a failure report", - (gptr*) &opt_tail_lines, (gptr*) &opt_tail_lines, 0, + (uchar**) &opt_tail_lines, (uchar**) &opt_tail_lines, 0, GET_INT, REQUIRED_ARG, 0, 0, 10000, 0, 0, 0}, #include "sslopt-longopts.h" {"test-file", 'x', "Read test from/in this file (default stdin).", @@ -5005,14 +5069,14 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"tmpdir", 't', "Temporary directory where sockets are put.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"user", 'u', "User for login.", (gptr*) &opt_user, (gptr*) &opt_user, 0, + {"user", 'u', "User for login.", (uchar**) &opt_user, (uchar**) &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"verbose", 'v', "Write more.", (gptr*) &verbose, (gptr*) &verbose, 0, + {"verbose", 'v', "Write more.", (uchar**) &verbose, (uchar**) &verbose, 0, GET_BOOL, 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}, {"view-protocol", OPT_VIEW_PROTOCOL, "Use views for select", - (gptr*) &view_protocol, (gptr*) &view_protocol, 0, + (uchar**) &view_protocol, (uchar**) &view_protocol, 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} }; @@ -5095,6 +5159,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case '#': #ifndef DBUG_OFF DBUG_PUSH(argument ? argument : "d:t:S:i:O,/tmp/mysqltest.trace"); + debug_check_flag= 1; #endif break; case 'r': @@ -5194,6 +5259,10 @@ int parse_args(int argc, char **argv) opt_db= *argv; if (tty_password) opt_pass= get_tty_password(NullS); /* purify tested */ + if (debug_info_flag) + my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO; + if (debug_check_flag) + my_end_arg= MY_CHECK_ERROR; return 0; } @@ -5228,7 +5297,7 @@ void str_to_file2(const char *fname, char *str, int size, my_bool append) die("Could not open %s: errno = %d", buff, errno); if (append && my_seek(fd, 0, SEEK_END, MYF(0)) == MY_FILEPOS_ERROR) die("Could not find end of file %s: errno = %d", buff, errno); - if (my_write(fd, (byte*)str, size, MYF(MY_WME|MY_FNABP))) + if (my_write(fd, (uchar*)str, size, MYF(MY_WME|MY_FNABP))) die("write failed"); my_close(fd, MYF(0)); } @@ -5339,7 +5408,7 @@ void init_win_path_patterns() continue; } - if (insert_dynamic(&patterns, (gptr) &p)) + if (insert_dynamic(&patterns, (uchar*) &p)) die(NullS); DBUG_PRINT("info", ("p: %s", p)); @@ -5359,7 +5428,7 @@ void free_win_path_patterns() for (i=0 ; i < patterns.elements ; i++) { const char** pattern= dynamic_element(&patterns, i, const char**); - my_free((gptr) *pattern, MYF(0)); + my_free((char*) *pattern, MYF(0)); } delete_dynamic(&patterns); } @@ -5541,12 +5610,12 @@ void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt, for (i= 0; i < num_fields; i++) { /* Free data for output */ - my_free((gptr)my_bind[i].buffer, MYF(MY_WME | MY_FAE)); + my_free(my_bind[i].buffer, MYF(MY_WME | MY_FAE)); } /* Free array with bind structs, lengths and NULL flags */ - my_free((gptr)my_bind , MYF(MY_WME | MY_FAE)); - my_free((gptr)length , MYF(MY_WME | MY_FAE)); - my_free((gptr)is_null , MYF(MY_WME | MY_FAE)); + my_free(my_bind , MYF(MY_WME | MY_FAE)); + my_free(length , MYF(MY_WME | MY_FAE)); + my_free(is_null , MYF(MY_WME | MY_FAE)); } @@ -5841,11 +5910,8 @@ end: ds - dynamic string which is used for output buffer NOTE - If there is an unexpected error this function will abort mysqltest - immediately. - - RETURN VALUE - error - function will not return + If there is an unexpected error this function will abort mysqltest + immediately. */ void handle_error(struct st_command *command, @@ -6852,6 +6918,7 @@ int main(int argc, char **argv) case Q_APPEND_FILE: do_append_file(command); break; case Q_DIFF_FILES: do_diff_files(command); break; case Q_SEND_QUIT: do_send_quit(command); break; + case Q_CHANGE_USER: do_change_user(command); break; case Q_CAT_FILE: do_cat_file(command); break; case Q_COPY_FILE: do_copy_file(command); break; case Q_CHMOD_FILE: do_chmod_file(command); break; @@ -7261,15 +7328,15 @@ void free_replace_column() typedef struct st_pointer_array { /* when using array-strings */ TYPELIB typelib; /* Pointer to strings */ - byte *str; /* Strings is here */ + uchar *str; /* Strings is here */ int7 *flag; /* Flag about each var. */ uint array_allocs,max_count,length,max_length; } POINTER_ARRAY; struct st_replace; -struct st_replace *init_replace(my_string *from, my_string *to, uint count, - my_string word_end_chars); -int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name); +struct st_replace *init_replace(char * *from, char * *to, uint count, + char * word_end_chars); +int insert_pointer_name(reg1 POINTER_ARRAY *pa,char * name); void replace_strings_append(struct st_replace *rep, DYNAMIC_STRING* ds, const char *from, int len); void free_pointer_array(POINTER_ARRAY *pa); @@ -7333,7 +7400,7 @@ void free_replace() DBUG_ENTER("free_replace"); if (glob_replace) { - my_free((char*) glob_replace,MYF(0)); + my_free(glob_replace,MYF(0)); glob_replace=0; } DBUG_VOID_RETURN; @@ -7544,7 +7611,7 @@ struct st_replace_regex* init_replace_regex(char* expr) reg.icase= 1; /* done parsing the statement, now place it in regex_arr */ - if (insert_dynamic(&res->regex_arr,(gptr) ®)) + if (insert_dynamic(&res->regex_arr,(uchar*) ®)) die("Out of memory"); } res->odd_buf_len= res->even_buf_len= 8192; @@ -7555,7 +7622,7 @@ struct st_replace_regex* init_replace_regex(char* expr) return res; err: - my_free((gptr)res,0); + my_free(res,0); die("Error parsing replace_regex \"%s\"", expr); return 0; } @@ -7596,7 +7663,7 @@ int multi_reg_replace(struct st_replace_regex* r,char* val) struct st_regex re; char* save_out_buf= out_buf; - get_dynamic(&r->regex_arr,(gptr)&re,i); + get_dynamic(&r->regex_arr,(uchar*)&re,i); if (!reg_replace(&out_buf, buf_len_p, re.pattern, re.replace, in_buf, re.icase)) @@ -7649,7 +7716,7 @@ void free_replace_regex() delete_dynamic(&glob_replace_regex->regex_arr); my_free(glob_replace_regex->even_buf,MYF(MY_ALLOW_ZERO_PTR)); my_free(glob_replace_regex->odd_buf,MYF(MY_ALLOW_ZERO_PTR)); - my_free((char*) glob_replace_regex,MYF(0)); + my_free(glob_replace_regex,MYF(0)); glob_replace_regex=0; } } @@ -7844,7 +7911,7 @@ int reg_replace(char** buf_p, int* buf_len_p, char *pattern, str_p= str_end; } } - my_free((gptr)subs, MYF(0)); + my_free(subs, MYF(0)); my_regfree(&r); *res_p= 0; *buf_p= buf; @@ -7904,13 +7971,13 @@ int get_next_bit(REP_SET *set,uint lastpos); int find_set(REP_SETS *sets,REP_SET *find); int find_found(FOUND_SET *found_set,uint table_offset, int found_offset); -uint start_at_word(my_string pos); -uint end_of_word(my_string pos); +uint start_at_word(char * pos); +uint end_of_word(char * pos); static uint found_sets=0; -uint replace_len(my_string str) +uint replace_len(char * str) { uint len=0; while (*str) @@ -7925,8 +7992,8 @@ uint replace_len(my_string str) /* Init a replace structure for further calls */ -REPLACE *init_replace(my_string *from, my_string *to,uint count, - my_string word_end_chars) +REPLACE *init_replace(char * *from, char * *to,uint count, + char * word_end_chars) { static const int SPACE_CHAR= 256; static const int START_OF_LINE= 257; @@ -7935,7 +8002,7 @@ REPLACE *init_replace(my_string *from, my_string *to,uint count, uint i,j,states,set_nr,len,result_len,max_length,found_end,bits_set,bit_nr; int used_sets,chr,default_state; char used_chars[LAST_CHAR_CODE],is_word_end[256]; - my_string pos,to_pos,*to_array; + char * pos, *to_pos, **to_array; REP_SETS sets; REP_SET *set,*start_states,*word_states,*new_set; FOLLOWS *follow,*follow_ptr; @@ -7951,7 +8018,6 @@ REPLACE *init_replace(my_string *from, my_string *to,uint count, if (!len) { errno=EINVAL; - my_message(0,"No to-string for last from-string",MYF(ME_BELL)); DBUG_RETURN(0); } states+=len+1; @@ -7980,7 +8046,7 @@ REPLACE *init_replace(my_string *from, my_string *to,uint count, if (!(follow=(FOLLOWS*) my_malloc((states+2)*sizeof(FOLLOWS),MYF(MY_WME)))) { free_sets(&sets); - my_free((gptr) found_set,MYF(0)); + my_free(found_set,MYF(0)); DBUG_RETURN(0); } @@ -8171,12 +8237,12 @@ REPLACE *init_replace(my_string *from, my_string *to,uint count, if ((replace=(REPLACE*) my_malloc(sizeof(REPLACE)*(sets.count)+ sizeof(REPLACE_STRING)*(found_sets+1)+ - sizeof(my_string)*count+result_len, + sizeof(char *)*count+result_len, MYF(MY_WME | MY_ZEROFILL)))) { rep_str=(REPLACE_STRING*) (replace+sets.count); - to_array=(my_string*) (rep_str+found_sets+1); - to_pos=(my_string) (to_array+count); + to_array= (char **) (rep_str+found_sets+1); + to_pos=(char *) (to_array+count); for (i=0 ; i < count ; i++) { to_array[i]=to_pos; @@ -8187,7 +8253,8 @@ REPLACE *init_replace(my_string *from, my_string *to,uint count, for (i=1 ; i <= found_sets ; i++) { pos=from[found_set[i-1].table_offset]; - rep_str[i].found= !bcmp(pos,"\\^",3) ? 2 : 1; + rep_str[i].found= !bcmp((const uchar*) pos, + (const uchar*) "\\^", 3) ? 2 : 1; rep_str[i].replace_string=to_array[found_set[i-1].table_offset]; rep_str[i].to_offset=found_set[i-1].found_offset-start_at_word(pos); rep_str[i].from_offset=found_set[i-1].found_offset-replace_len(pos)+ @@ -8202,9 +8269,9 @@ REPLACE *init_replace(my_string *from, my_string *to,uint count, replace[i].next[j]=(REPLACE*) (rep_str+(-sets.set[i].next[j]-1)); } } - my_free((gptr) follow,MYF(0)); + my_free(follow,MYF(0)); free_sets(&sets); - my_free((gptr) found_set,MYF(0)); + my_free(found_set,MYF(0)); DBUG_PRINT("exit",("Replace table has %d states",sets.count)); DBUG_RETURN(replace); } @@ -8220,7 +8287,7 @@ int init_sets(REP_SETS *sets,uint states) if (!(sets->bit_buffer=(uint*) my_malloc(sizeof(uint)*sets->size_of_bits* SET_MALLOC_HUNC,MYF(MY_WME)))) { - my_free((gptr) sets->set,MYF(0)); + my_free(sets->set,MYF(0)); return 1; } return 0; @@ -8252,13 +8319,13 @@ REP_SET *make_new_set(REP_SETS *sets) return set; } count=sets->count+sets->invisible+SET_MALLOC_HUNC; - if (!(set=(REP_SET*) my_realloc((gptr) sets->set_buffer, + if (!(set=(REP_SET*) my_realloc((uchar*) sets->set_buffer, sizeof(REP_SET)*count, MYF(MY_WME)))) return 0; sets->set_buffer=set; sets->set=set+sets->invisible; - if (!(bit_buffer=(uint*) my_realloc((gptr) sets->bit_buffer, + if (!(bit_buffer=(uint*) my_realloc((uchar*) sets->bit_buffer, (sizeof(uint)*sets->size_of_bits)*count, MYF(MY_WME)))) return 0; @@ -8281,8 +8348,8 @@ void free_last_set(REP_SETS *sets) void free_sets(REP_SETS *sets) { - my_free((gptr)sets->set_buffer,MYF(0)); - my_free((gptr)sets->bit_buffer,MYF(0)); + my_free(sets->set_buffer,MYF(0)); + my_free(sets->bit_buffer,MYF(0)); return; } @@ -8309,13 +8376,13 @@ void or_bits(REP_SET *to,REP_SET *from) void copy_bits(REP_SET *to,REP_SET *from) { - memcpy((byte*) to->bits,(byte*) from->bits, + memcpy((uchar*) to->bits,(uchar*) from->bits, (size_t) (sizeof(uint) * to->size_of_bits)); } int cmp_bits(REP_SET *set1,REP_SET *set2) { - return bcmp((byte*) set1->bits,(byte*) set2->bits, + return bcmp((uchar*) set1->bits,(uchar*) set2->bits, sizeof(uint) * set1->size_of_bits); } @@ -8383,17 +8450,19 @@ int find_found(FOUND_SET *found_set,uint table_offset, int found_offset) /* Return 1 if regexp starts with \b or ends with \b*/ -uint start_at_word(my_string pos) +uint start_at_word(char * pos) { - return (((!bcmp(pos,"\\b",2) && pos[2]) || !bcmp(pos,"\\^",2)) ? 1 : 0); + return (((!bcmp((const uchar*) pos, (const uchar*) "\\b",2) && pos[2]) || + !bcmp((const uchar*) pos, (const uchar*) "\\^", 2)) ? 1 : 0); } -uint end_of_word(my_string pos) +uint end_of_word(char * pos) { - my_string end=strend(pos); - return ((end > pos+2 && !bcmp(end-2,"\\b",2)) || - (end >= pos+2 && !bcmp(end-2,"\\$",2))) ? - 1 : 0; + char * end=strend(pos); + return ((end > pos+2 && !bcmp((const uchar*) end-2, + (const uchar*) "\\b", 2)) || + (end >= pos+2 && !bcmp((const uchar*) end-2, + (const uchar*) "\\$",2))) ? 1 : 0; } /**************************************************************************** @@ -8403,10 +8472,10 @@ uint end_of_word(my_string pos) #define PC_MALLOC 256 /* Bytes for pointers */ #define PS_MALLOC 512 /* Bytes for data */ -int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name) +int insert_pointer_name(reg1 POINTER_ARRAY *pa,char * name) { uint i,length,old_count; - byte *new_pos; + uchar *new_pos; const char **new_array; DBUG_ENTER("insert_pointer_name"); @@ -8414,16 +8483,16 @@ int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name) { if (!(pa->typelib.type_names=(const char **) my_malloc(((PC_MALLOC-MALLOC_OVERHEAD)/ - (sizeof(my_string)+sizeof(*pa->flag))* - (sizeof(my_string)+sizeof(*pa->flag))),MYF(MY_WME)))) + (sizeof(char *)+sizeof(*pa->flag))* + (sizeof(char *)+sizeof(*pa->flag))),MYF(MY_WME)))) DBUG_RETURN(-1); - if (!(pa->str= (byte*) my_malloc((uint) (PS_MALLOC-MALLOC_OVERHEAD), + if (!(pa->str= (uchar*) my_malloc((uint) (PS_MALLOC-MALLOC_OVERHEAD), MYF(MY_WME)))) { - my_free((gptr) pa->typelib.type_names,MYF(0)); + my_free((char*) pa->typelib.type_names,MYF(0)); DBUG_RETURN (-1); } - pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(byte*)+ + pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(uchar*)+ sizeof(*pa->flag)); pa->flag= (int7*) (pa->typelib.type_names+pa->max_count); pa->length=0; @@ -8433,7 +8502,7 @@ int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name) length=(uint) strlen(name)+1; if (pa->length+length >= pa->max_length) { - if (!(new_pos= (byte*) my_realloc((gptr) pa->str, + if (!(new_pos= (uchar*) my_realloc((uchar*) pa->str, (uint) (pa->max_length+PS_MALLOC), MYF(MY_WME)))) DBUG_RETURN(1); @@ -8452,23 +8521,23 @@ int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name) int len; pa->array_allocs++; len=(PC_MALLOC*pa->array_allocs - MALLOC_OVERHEAD); - if (!(new_array=(const char **) my_realloc((gptr) pa->typelib.type_names, + if (!(new_array=(const char **) my_realloc((uchar*) pa->typelib.type_names, (uint) len/ - (sizeof(byte*)+sizeof(*pa->flag))* - (sizeof(byte*)+sizeof(*pa->flag)), + (sizeof(uchar*)+sizeof(*pa->flag))* + (sizeof(uchar*)+sizeof(*pa->flag)), MYF(MY_WME)))) DBUG_RETURN(1); pa->typelib.type_names=new_array; old_count=pa->max_count; - pa->max_count=len/(sizeof(byte*) + sizeof(*pa->flag)); + pa->max_count=len/(sizeof(uchar*) + sizeof(*pa->flag)); pa->flag= (int7*) (pa->typelib.type_names+pa->max_count); - memcpy((byte*) pa->flag,(my_string) (pa->typelib.type_names+old_count), + memcpy((uchar*) pa->flag,(char *) (pa->typelib.type_names+old_count), old_count*sizeof(*pa->flag)); } pa->flag[pa->typelib.count]=0; /* Reset flag */ - pa->typelib.type_names[pa->typelib.count++]= pa->str+pa->length; + pa->typelib.type_names[pa->typelib.count++]= (char*) pa->str+pa->length; pa->typelib.type_names[pa->typelib.count]= NullS; /* Put end-mark */ - VOID(strmov(pa->str+pa->length,name)); + VOID(strmov((char*) pa->str+pa->length,name)); pa->length+=length; DBUG_RETURN(0); } /* insert_pointer_name */ @@ -8481,9 +8550,9 @@ void free_pointer_array(POINTER_ARRAY *pa) if (pa->typelib.count) { pa->typelib.count=0; - my_free((gptr) pa->typelib.type_names,MYF(0)); + my_free((char*) pa->typelib.type_names,MYF(0)); pa->typelib.type_names=0; - my_free((gptr) pa->str,MYF(0)); + my_free(pa->str,MYF(0)); } } /* free_pointer_array */ @@ -8580,7 +8649,7 @@ void dynstr_append_sorted(DYNAMIC_STRING* ds, DYNAMIC_STRING *ds_input) *line_end= 0; /* Insert pointer to the line in array */ - if (insert_dynamic(&lines, (gptr) &start)) + if (insert_dynamic(&lines, (uchar*) &start)) die("Out of memory inserting lines to sort"); start= line_end+1; diff --git a/client/readline.cc b/client/readline.cc index ad42ed2ee10..7afdbc9531e 100644 --- a/client/readline.cc +++ b/client/readline.cc @@ -22,8 +22,8 @@ static bool init_line_buffer(LINE_BUFFER *buffer,File file,ulong size, ulong max_size); -static bool init_line_buffer_from_string(LINE_BUFFER *buffer,my_string str); -static uint fill_buffer(LINE_BUFFER *buffer); +static bool init_line_buffer_from_string(LINE_BUFFER *buffer,char * str); +static size_t fill_buffer(LINE_BUFFER *buffer); static char *intern_read_line(LINE_BUFFER *buffer,ulong *out_length); @@ -35,7 +35,7 @@ LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file) return 0; if (init_line_buffer(line_buff,fileno(file),IO_SIZE,max_size)) { - my_free((char*) line_buff,MYF(0)); + my_free(line_buff,MYF(0)); return 0; } return line_buff; @@ -62,13 +62,13 @@ void batch_readline_end(LINE_BUFFER *line_buff) { if (line_buff) { - my_free((gptr) line_buff->buffer,MYF(MY_ALLOW_ZERO_PTR)); - my_free((char*) line_buff,MYF(0)); + my_free(line_buff->buffer,MYF(MY_ALLOW_ZERO_PTR)); + my_free(line_buff,MYF(0)); } } -LINE_BUFFER *batch_readline_command(LINE_BUFFER *line_buff, my_string str) +LINE_BUFFER *batch_readline_command(LINE_BUFFER *line_buff, char * str) { if (!line_buff) if (!(line_buff=(LINE_BUFFER*) @@ -76,7 +76,7 @@ LINE_BUFFER *batch_readline_command(LINE_BUFFER *line_buff, my_string str) return 0; if (init_line_buffer_from_string(line_buff,str)) { - my_free((char*) line_buff,MYF(0)); + my_free(line_buff,MYF(0)); return 0; } return line_buff; @@ -106,13 +106,13 @@ init_line_buffer(LINE_BUFFER *buffer,File file,ulong size,ulong max_buffer) several times. the resulting buffer will contain a concatenation of all strings separated by spaces */ -static bool init_line_buffer_from_string(LINE_BUFFER *buffer,my_string str) +static bool init_line_buffer_from_string(LINE_BUFFER *buffer,char * str) { uint old_length=(uint)(buffer->end - buffer->buffer); uint length= (uint) strlen(str); if (!(buffer->buffer= buffer->start_of_line= buffer->end_of_line= - (char*)my_realloc(buffer->buffer, old_length+length+2, - MYF(MY_FAE|MY_ALLOW_ZERO_PTR)))) + (char*) my_realloc((uchar*) buffer->buffer, old_length+length+2, + MYF(MY_FAE|MY_ALLOW_ZERO_PTR)))) return 1; buffer->end= buffer->buffer + old_length; if (old_length) @@ -133,9 +133,9 @@ static bool init_line_buffer_from_string(LINE_BUFFER *buffer,my_string str) bytes read from disk. */ -static uint fill_buffer(LINE_BUFFER *buffer) +static size_t fill_buffer(LINE_BUFFER *buffer) { - uint read_count; + size_t read_count; uint bufbytes= (uint) (buffer->end - buffer->start_of_line); if (buffer->eof) @@ -166,11 +166,11 @@ static uint fill_buffer(LINE_BUFFER *buffer) } /* Read in new stuff. */ - if ((read_count= my_read(buffer->file, (byte*) buffer->end, read_count, + if ((read_count= my_read(buffer->file, (uchar*) buffer->end, read_count, MYF(MY_WME))) == MY_FILE_ERROR) - return read_count; + return (size_t) -1; - DBUG_PRINT("fill_buff", ("Got %d bytes", read_count)); + DBUG_PRINT("fill_buff", ("Got %lu bytes", (ulong) read_count)); /* Kludge to pretend every nonempty file ends with a newline. */ if (!read_count && bufbytes && buffer->end[-1] != '\n') @@ -189,7 +189,7 @@ static uint fill_buffer(LINE_BUFFER *buffer) char *intern_read_line(LINE_BUFFER *buffer,ulong *out_length) { char *pos; - uint length; + size_t length; DBUG_ENTER("intern_read_line"); buffer->start_of_line=buffer->end_of_line; @@ -202,7 +202,7 @@ char *intern_read_line(LINE_BUFFER *buffer,ulong *out_length) { if ((uint) (pos - buffer->start_of_line) < buffer->max_size) { - if (!(length=fill_buffer(buffer)) || length == (uint) -1) + if (!(length=fill_buffer(buffer)) || length == (size_t) -1) DBUG_RETURN(0); continue; } diff --git a/client/sql_string.cc b/client/sql_string.cc index 9d887ff031c..c41463999aa 100644 --- a/client/sql_string.cc +++ b/client/sql_string.cc @@ -32,7 +32,7 @@ required by the string function */ -extern gptr sql_alloc(unsigned size); +extern void sql_alloc(size_t size); extern void sql_element_free(void *ptr); #include "sql_string.h" @@ -506,7 +506,7 @@ bool String::append(FILE* file, uint32 arg_length, myf my_flags) { if (realloc(str_length+arg_length)) return TRUE; - if (my_fread(file, (byte*) Ptr + str_length, arg_length, my_flags)) + if (my_fread(file, (uchar*) Ptr + str_length, arg_length, my_flags)) { shrink(str_length); return TRUE; @@ -520,7 +520,7 @@ bool String::append(IO_CACHE* file, uint32 arg_length) { if (realloc(str_length+arg_length)) return TRUE; - if (my_b_read(file, (byte*) Ptr + str_length, arg_length)) + if (my_b_read(file, (uchar*) Ptr + str_length, arg_length)) { shrink(str_length); return TRUE; @@ -645,7 +645,7 @@ bool String::replace(uint32 offset,uint32 arg_length, { if (realloc(str_length+(uint32) diff)) return TRUE; - bmove_upp(Ptr+str_length+diff,Ptr+str_length, + bmove_upp((uchar*) Ptr+str_length+diff, (uchar*) Ptr+str_length, str_length-offset-arg_length); } if (to_length) @@ -805,10 +805,8 @@ copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, const uchar *from_end= (const uchar*) from+from_length; char *to_start= to; uchar *to_end= (uchar*) to+to_length; - int (*mb_wc)(struct charset_info_st *, my_wc_t *, const uchar *, - const uchar *) = from_cs->cset->mb_wc; - int (*wc_mb)(struct charset_info_st *, my_wc_t, uchar *s, uchar *e)= - to_cs->cset->wc_mb; + my_charset_conv_mb_wc mb_wc= from_cs->cset->mb_wc; + my_charset_conv_wc_mb wc_mb= to_cs->cset->wc_mb; uint error_count= 0; while (1) 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); |