summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rwxr-xr-xclient/CMakeLists.txt20
-rw-r--r--client/Makefile.am109
-rw-r--r--client/client_priv.h37
-rw-r--r--client/completion_hash.cc2
-rw-r--r--client/get_password.c6
-rw-r--r--client/my_readline.h2
-rw-r--r--client/mysql.cc569
-rw-r--r--client/mysql_upgrade.c72
-rw-r--r--client/mysqladmin.cc209
-rw-r--r--client/mysqlbinlog.cc1337
-rw-r--r--client/mysqlcheck.c213
-rw-r--r--client/mysqldump.c1653
-rw-r--r--client/mysqlimport.c338
-rw-r--r--client/mysqlmanager-pwgen.c157
-rw-r--r--client/mysqlmanagerc.c178
-rw-r--r--client/mysqlshow.c84
-rw-r--r--client/mysqlslap.c2201
-rw-r--r--client/mysqltest.cc (renamed from client/mysqltest.c)1943
-rw-r--r--client/readline.cc32
-rw-r--r--client/sql_string.cc14
-rw-r--r--client/sql_string.h2
21 files changed, 6759 insertions, 2419 deletions
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt
index a419da5eabf..e96437d40d0 100755
--- a/client/CMakeLists.txt
+++ b/client/CMakeLists.txt
@@ -15,7 +15,7 @@
INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake")
# We use the "mysqlclient_notls" library here just as safety, in case
-# any of the clients here would go beond the client API and access the
+# any of the clients here would go beyond the client API and access the
# Thread Local Storage directly.
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
@@ -32,9 +32,9 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
ADD_EXECUTABLE(mysql completion_hash.cc mysql.cc readline.cc sql_string.cc ../mysys/my_conio.c)
TARGET_LINK_LIBRARIES(mysql mysqlclient_notls wsock32)
-ADD_EXECUTABLE(mysqltest mysqltest.c ../mysys/my_getsystime.c
- ../mysys/my_copy.c ../mysys/my_mkdir.c)
-TARGET_LINK_LIBRARIES(mysqltest mysqlclient_notls regex wsock32)
+ADD_EXECUTABLE(mysqltest mysqltest.cc)
+SET_SOURCE_FILES_PROPERTIES(mysqltest.cc PROPERTIES COMPILE_FLAGS "-DTHREADS")
+TARGET_LINK_LIBRARIES(mysqltest mysqlclient mysys regex wsock32 dbug)
ADD_EXECUTABLE(mysqlcheck mysqlcheck.c)
TARGET_LINK_LIBRARIES(mysqlcheck mysqlclient_notls wsock32)
@@ -52,12 +52,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 672bb2e0c47..94db565ba37 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -1,65 +1,114 @@
# 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 \
- $(top_srcdir)/mysys/my_mkdir.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.cc
+mysqltest_CXXFLAGS= -DTHREAD -UUNDEF_THREADS_HACK
+mysqltest_LDADD = $(CXXLDFLAGS) $(CLIENT_THREAD_LIBS) \
+ @CLIENT_EXTRA_LDFLAGS@ \
+ $(LIBMYSQLCLIENT_LA) \
+ $(top_builddir)/mysys/libmysys.a \
+ $(top_builddir)/regex/libregex.a \
+ $(CLIENT_THREAD_LIBS)
+
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 \
+ rpl_utility.h rpl_tblmap.h rpl_tblmap.cc \
+ 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 \
@@ -72,7 +121,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..06145232995 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_MODE, 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..ea024f76fb6 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;
@@ -107,7 +107,7 @@ char *get_tty_password(char *opt_message)
* to will not include the eol characters.
*/
-static void get_password(char *to,uint length,int fd,bool echo)
+static void get_password(char *to,uint length,int fd, my_bool echo)
{
char *pos=to,*end=to+length;
@@ -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 32d6da4c626..62ad19bece9 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, bool *truncated);
extern void batch_readline_end(LINE_BUFFER *buffer);
diff --git a/client/mysql.cc b/client/mysql.cc
index b7d66071ca5..5f360b83dc1 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -43,15 +43,18 @@
#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
/* Buffer to hold 'version' and 'version_comment' */
-#define MAX_SERVER_VERSION_LENGTH 128
+static char *server_version= NULL;
-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
@@ -131,7 +134,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,
@@ -140,12 +143,15 @@ 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, ignore_spaces= 0;
-static volatile int executing_query= 0, interrupted_query= 0;
+ show_warnings= 0, executing_query= 0, interrupted_query= 0,
+ ignore_spaces= 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,
@@ -194,6 +200,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*),
@@ -1010,7 +1018,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
@@ -1049,22 +1060,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");
@@ -1125,7 +1126,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);
@@ -1149,7 +1151,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.",
@@ -1182,7 +1184,12 @@ int main(int argc,char *argv[])
histfile= 0;
}
}
- if (histfile)
+
+ /* We used to suggest setting MYSQL_HISTFILE=/dev/null. */
+ if (histfile && strncmp(histfile, "/dev/null", 10) == 0)
+ histfile= NULL;
+
+ if (histfile && histfile[0])
{
if (verbose)
tee_fprintf(stdout, "Reading history-file %s\n",histfile);
@@ -1213,47 +1220,12 @@ int main(int argc,char *argv[])
#endif
}
-sig_handler mysql_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++)
- goto err;
-
- 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))
- goto err;
- /* 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, (uint) strlen(kill_buffer));
- mysql_close(kill_mysql);
- tee_fprintf(stdout, "Query aborted by Ctrl+C\n");
-
- return;
-
-err:
-#ifdef _WIN32
- /*
- When SIGINT is raised on Windows, the OS creates a new thread to handle the
- interrupt. Once that thread completes, the main thread continues running
- only to find that it's resources have already been free'd when the sigint
- handler called mysql_end().
- */
- mysql_thread_end();
- return;
-#else
- mysql_end(sig);
-#endif
-}
-
sig_handler mysql_end(int sig)
{
mysql_close(&mysql);
#ifdef HAVE_READLINE
- if (!status.batch && !quick && !opt_html && !opt_xml && histfile)
+ if (!status.batch && !quick && !opt_html && !opt_xml &&
+ histfile && histfile[0])
{
/* write-history */
if (verbose)
@@ -1271,6 +1243,7 @@ sig_handler mysql_end(int sig)
glob_buffer.free();
old_buffer.free();
processed_prompt.free();
+ my_free(server_version,MYF(MY_ALLOW_ZERO_PTR));
my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
my_free(opt_mysql_unix_port,MYF(MY_ALLOW_ZERO_PTR));
my_free(histfile,MYF(MY_ALLOW_ZERO_PTR));
@@ -1285,13 +1258,60 @@ 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 : MY_CHECK_ERROR);
+ 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)
+ goto err;
+
+ 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))
+ goto err;
+
+ /* 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;
+
+ return;
+
+err:
+#ifdef _WIN32
+ /*
+ When SIGINT is raised on Windows, the OS creates a new thread to handle the
+ interrupt. Once that thread completes, the main thread continues running
+ only to find that it's resources have already been free'd when the sigint
+ handler called mysql_end().
+ */
+ mysql_thread_end();
+ return;
+#else
+ mysql_end(sig);
+#endif
+}
+
+
static struct my_option my_long_options[] =
{
{"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
@@ -1304,7 +1324,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.",
@@ -1312,67 +1332,76 @@ 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*) &current_db,
- (gptr*) &current_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**) &current_db,
+ (uchar**) &current_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.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"ignore-spaces", 'i', "Ignore space after function names.",
- (gptr*) &ignore_spaces, (gptr*) &ignore_spaces, 0, GET_BOOL, NO_ARG, 0, 0,
+ (uchar**) &ignore_spaces, (uchar**) &ignore_spaces, 0, GET_BOOL, 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*) &current_host,
- (gptr*) &current_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**) &current_host,
+ (uchar**) &current_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.",
@@ -1381,7 +1410,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.",
@@ -1407,50 +1436,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*) &current_prompt, (gptr*) &current_prompt, 0, GET_STR_ALLOC,
+ (uchar**) &current_prompt, (uchar**) &current_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*) &current_user,
- (gptr*) &current_user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"user", 'u', "User for login if not current user.", (uchar**) &current_user,
+ (uchar**) &current_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},
@@ -1460,33 +1487,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}
};
@@ -1517,7 +1546,7 @@ static void usage(int version)
if (version)
return;
printf("\
-Copyright (C) 2000-2008 MySQL AB\n\
+Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.\n\
This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
and you are welcome to modify and redistribute it under the GPL license\n");
printf("Usage: %s [OPTIONS] [database]\n", my_progname);
@@ -1531,7 +1560,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)
{
@@ -1609,15 +1638,34 @@ 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)
+#ifndef EMBEDDED_LIBRARY
+ opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
+ opt->name);
+#endif
+ 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;
@@ -1656,7 +1704,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)
@@ -1750,6 +1798,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;
if (ignore_spaces)
connect_flag|= CLIENT_IGNORE_SPACE;
@@ -1759,7 +1811,7 @@ static int get_options(int argc, char **argv)
static int read_and_execute(bool interactive)
{
-#if defined(OS2) || defined(__NETWARE__)
+#if defined(__NETWARE__)
char linebuffer[254];
String buffer;
#endif
@@ -1808,9 +1860,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);
@@ -1821,12 +1871,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);
@@ -1842,32 +1892,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
@@ -1915,7 +1945,7 @@ static int read_and_execute(bool interactive)
}
}
-#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__)
+#if defined( __WIN__) || defined(__NETWARE__)
buffer.free();
#endif
#if defined( __WIN__)
@@ -2030,7 +2060,8 @@ static bool add_line(String &buffer,char *line,char *in_string,
}
#endif
if (!*ml_comment && inchar == '\\' &&
- !(mysql.server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES))
+ !(*in_string &&
+ (mysql.server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES)))
{
// Found possbile one character command like \c
@@ -2262,7 +2293,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
@@ -2271,11 +2302,11 @@ static char **new_mysql_completion (const char *text, int start, int end);
*/
#if defined(USE_NEW_READLINE_INTERFACE)
-char *no_completion(const char*,int)
+extern "C" char *no_completion(const char*,int)
#elif defined(USE_LIBEDIT_INTERFACE)
-int no_completion(const char*,int)
+extern "C" int no_completion(const char*,int)
#else
-char *no_completion()
+extern "C" char *no_completion()
#endif
{
return 0; /* No filename completion */
@@ -2377,9 +2408,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)
@@ -2885,10 +2916,11 @@ com_go(String *buffer,char *line __attribute__((unused)))
char buff[200]; /* about 110 chars used so far */
char time_buff[52+3+1]; /* time max + space&parens + NUL */
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
@@ -2924,9 +2956,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
@@ -2938,15 +2968,11 @@ 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
{
char *pos;
@@ -2955,18 +2981,15 @@ com_go(String *buffer,char *line __attribute__((unused)))
{
if (!(result=mysql_use_result(&mysql)) && mysql_field_count(&mysql))
{
- executing_query= 0;
- return put_error(&mysql);
+ 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)
@@ -2977,7 +3000,7 @@ com_go(String *buffer,char *line __attribute__((unused)))
/* Every branch must truncate buff . */
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)
@@ -3042,23 +3065,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 */
}
@@ -3130,32 +3150,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-?";
}
}
@@ -3184,6 +3204,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);
@@ -3229,7 +3250,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))
@@ -3274,6 +3295,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);
@@ -3285,7 +3308,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";
@@ -3325,7 +3347,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);
}
@@ -3371,20 +3393,25 @@ print_table_data_html(MYSQL_RES *result)
{
while((field = mysql_fetch_field(result)))
{
- tee_fprintf(PAGER, "<TH>%s</TH>", (field->name ?
- (field->name[0] ? field->name :
- " &nbsp; ") : "NULL"));
+ tee_fputs("<TH>", PAGER);
+ if (field->name && field->name[0])
+ xmlencode_print(field->name, field->name_length);
+ else
+ tee_fputs(field->name ? " &nbsp; " : "NULL", PAGER);
+ tee_fputs("</TH>", PAGER);
}
(void) tee_fputs("</TR>", PAGER);
}
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++)
{
(void) tee_fputs("<TD>", PAGER);
- safe_put_field(cur[i],lengths[i]);
+ xmlencode_print(cur[i], lengths[i]);
(void) tee_fputs("</TD>", PAGER);
}
(void) tee_fputs("</TR>", PAGER);
@@ -3409,6 +3436,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++)
@@ -3448,6 +3477,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);
@@ -3469,24 +3500,39 @@ 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";
- mysql_real_query_for_lazy(query, (uint) strlen(query));
+ mysql_real_query_for_lazy(query, strlen(query));
mysql_store_result_for_lazy(&result);
/* 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);
}
@@ -3718,10 +3764,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")) &&
@@ -4162,7 +4208,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
@@ -4335,16 +4381,11 @@ select_limit, max_join_size);
static const char *
server_version_string(MYSQL *con)
{
- static char buf[MAX_SERVER_VERSION_LENGTH] = "";
-
/* Only one thread calls this, so no synchronization is needed */
- if (buf[0] == '\0')
+ if (server_version == NULL)
{
- char *bufp = buf;
MYSQL_RES *result;
- bufp= strnmov(buf, mysql_get_server_info(con), sizeof buf);
-
/* "limit 1" is protection against SQL_SELECT_LIMIT=0 */
if (!mysql_query(con, "select @@version_comment limit 1") &&
(result = mysql_use_result(con)))
@@ -4352,18 +4393,32 @@ server_version_string(MYSQL *con)
MYSQL_ROW cur = mysql_fetch_row(result);
if (cur && cur[0])
{
- bufp = strxnmov(bufp, (uint) (sizeof buf - (bufp - buf)), " ", cur[0],
- NullS);
+ /* version, space, comment, \0 */
+ size_t len= strlen(mysql_get_server_info(con)) + strlen(cur[0]) + 2;
+
+ if ((server_version= (char *) my_malloc(len, MYF(MY_WME))))
+ {
+ char *bufp;
+ bufp = strmov(server_version, mysql_get_server_info(con));
+ bufp = strmov(bufp, " ");
+ (void) strmov(bufp, cur[0]);
+ }
}
mysql_free_result(result);
}
- /* str*nmov doesn't guarantee NUL-termination */
- if (bufp == buf + sizeof buf)
- buf[sizeof buf - 1] = '\0';
+ /*
+ If for some reason we didn't get a version_comment, we'll
+ keep things simple.
+ */
+
+ if (server_version == NULL)
+ {
+ server_version= strdup(mysql_get_server_info(con));
+ }
}
- return buf;
+ return server_version ? server_version : "";
}
static int
@@ -4462,9 +4517,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)
@@ -4480,9 +4532,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);
}
@@ -4493,9 +4542,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);
@@ -4506,14 +4552,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>
@@ -4525,7 +4568,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;
@@ -4790,13 +4833,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 e3500c81fb9..cbc60d8acad 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;
@@ -58,6 +61,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**)&not_used, (uchar**)&not_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},
@@ -65,26 +73,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*)&not_used, (gptr*)&not_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,
@@ -107,13 +115,13 @@ 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},
+#include <sslopt-longopts.h>
{"tmpdir", 't', "Directory for temporary files",
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},
-#include <sslopt-longopts.h>
+ {"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},
{"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}
};
@@ -147,7 +155,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);
}
@@ -209,8 +217,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;
@@ -218,9 +227,12 @@ 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':
+ if (argument == disabled_my_option)
+ argument= (char*) ""; // Don't require password
tty_password= 1;
add_option= FALSE;
if (argument)
@@ -344,7 +356,6 @@ static void find_tool(char *tool_executable_name, const char *tool_name,
const char *self_name)
{
char *last_fn_libchar;
-
DYNAMIC_STRING ds_tmp;
DBUG_ENTER("find_tool");
DBUG_PRINT("enter", ("progname: %s", my_progname));
@@ -429,7 +440,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, (uint) strlen(query),
+ if (my_write(fd, (uchar*) query, strlen(query),
MYF(MY_FNABP | MY_WME)))
{
my_close(fd, MYF(0));
@@ -611,6 +622,20 @@ static int run_mysqlcheck_upgrade(void)
}
+static int run_mysqlcheck_fixnames(void)
+{
+ verbose("Running 'mysqlcheck'...");
+ return run_tool(mysqlcheck_path,
+ NULL, /* Send output from mysqlcheck directly to screen */
+ "--no-defaults",
+ ds_args.str,
+ "--all-databases",
+ "--fix-db-names",
+ "--fix-table-names",
+ NULL);
+}
+
+
static const char *expected_errors[]=
{
"ERROR 1060", /* Duplicate column name */
@@ -736,6 +761,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)
{
@@ -769,7 +798,8 @@ int main(int argc, char **argv)
/*
Run "mysqlcheck" and "mysql_fix_privilege_tables.sql"
*/
- if (run_mysqlcheck_upgrade() ||
+ if (run_mysqlcheck_fixnames() ||
+ run_mysqlcheck_upgrade() ||
run_sql_fix_privilege_tables())
{
/*
@@ -784,7 +814,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 24b95be8626..9865b67bb3b 100644
--- a/client/mysqladmin.cc
+++ b/client/mysqladmin.cc
@@ -23,11 +23,7 @@
#include <sys/stat.h>
#include <mysql.h>
-#ifdef LATER_HAVE_NDBCLUSTER_DB
-#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,20 +36,18 @@ 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;
-#ifdef LATER_HAVE_NDBCLUSTER_DB
-static my_bool opt_ndbcluster=0;
-static char *opt_ndb_connectstring=0;
-#endif
+static char * unix_port=0;
#ifdef HAVE_SMEM
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 +63,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);
@@ -101,9 +97,6 @@ enum commands {
ADMIN_PING, ADMIN_EXTENDED_STATUS, ADMIN_FLUSH_STATUS,
ADMIN_FLUSH_PRIVILEGES, ADMIN_START_SLAVE, ADMIN_STOP_SLAVE,
ADMIN_FLUSH_THREADS, ADMIN_OLD_PASSWORD
-#ifdef LATER_HAVE_NDBCLUSTER_DB
- ,ADMIN_NDB_MGM
-#endif
};
static const char *command_names[]= {
"create", "drop", "shutdown",
@@ -114,9 +107,6 @@ static const char *command_names[]= {
"ping", "extended-status", "flush-status",
"flush-privileges", "start-slave", "stop-slave",
"flush-threads","old-password",
-#ifdef LATER_HAVE_NDBCLUSTER_DB
- "ndb-mgm",
-#endif
NullS
};
@@ -131,27 +121,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,66 +165,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},
- {"ndb-connectstring", OPT_NDB_CONNECTSTRING, ""
- "", (gptr*) &opt_ndb_connectstring,
- (gptr*) &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}
};
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)
{
@@ -240,6 +232,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
opt_count_iterations= 1;
break;
case 'p':
+ if (argument == disabled_my_option)
+ argument= (char*) ""; // Don't require password
if (argument)
{
char *start=argument;
@@ -288,15 +282,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 +310,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 +349,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 +412,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 +449,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 +524,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 +541,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 +566,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 +587,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 +598,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 +606,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;
}
@@ -619,7 +614,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
case ADMIN_VER:
new_line=1;
print_version();
- puts("Copyright (C) 2000-2006 MySQL AB");
+ puts("Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.");
puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
printf("Server version\t\t%s\n", mysql_get_server_info(mysql));
printf("Protocol version\t%d\n", mysql_get_proto_info(mysql));
@@ -655,7 +650,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,16 +673,22 @@ 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];
for (;;)
{
- if (mysql_kill(mysql,(ulong) atol(pos)))
+ /* We don't use mysql_kill(), since it only handles 32-bit IDs. */
+ char buff[26], *out; /* "KILL " + max 20 digs + NUL */
+ out= strxmov(buff, "KILL ", NullS);
+ ullstr(strtoull(pos, NULL, 0), out);
+
+ if (mysql_query(mysql, buff))
{
- my_printf_error(0,"kill failed on %ld; error: '%s'",MYF(ME_BELL),
- atol(pos), mysql_error(mysql));
+ /* out still points to just the number */
+ my_printf_error(0, "kill failed on %s; error: '%s'", error_flags,
+ out, mysql_error(mysql));
error=1;
}
if (!(pos=strchr(pos,',')))
@@ -702,7 +703,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 +717,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 +739,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 +789,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 +799,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 +809,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 +819,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 +836,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 +859,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 +870,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 +895,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 +903,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 +917,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 +928,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 +938,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,32 +964,14 @@ 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;
}
}
mysql->reconnect=1; /* Automatic reconnect is default */
break;
-#ifdef LATER_HAVE_NDBCLUSTER_DB
- case ADMIN_NDB_MGM:
- {
- if (argc < 2)
- {
- my_printf_error(0,"Too few arguments to ndb-mgm",MYF(ME_BELL));
- return 1;
- }
- {
- Ndb_mgmclient_handle cmd=
- ndb_mgmclient_handle_create(opt_ndb_connectstring);
- ndb_mgmclient_execute(cmd, --argc, ++argv);
- ndb_mgmclient_handle_destroy(cmd);
- }
- argc= 0;
- }
- 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;
}
}
@@ -1008,7 +991,7 @@ static void print_version(void)
static void usage(void)
{
print_version();
- puts("Copyright (C) 2000-2006 MySQL AB");
+ puts("Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.");
puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
puts("Administration program for the mysqld daemon.");
printf("Usage: %s [OPTIONS] command command....\n", my_progname);
@@ -1066,7 +1049,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 +1274,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 36b86ae7a96..2cf91ec7da5 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -59,20 +59,33 @@ static const char* default_dbug_option = "d:t:o,/tmp/mysqlbinlog.trace";
#endif
static const char *load_default_groups[]= { "mysqlbinlog","client",0 };
-void sql_print_error(const char *format, ...);
+static void error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
+static void warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
static bool one_database=0, to_last_remote_log= 0, disable_log_bin= 0;
static bool opt_hexdump= 0;
+const char *base64_output_mode_names[]=
+{"NEVER", "AUTO", "ALWAYS", "UNSPEC", "DECODE-ROWS", NullS};
+TYPELIB base64_output_mode_typelib=
+ { array_elements(base64_output_mode_names) - 1, "",
+ base64_output_mode_names, NULL };
+static enum_base64_output_mode opt_base64_output_mode= BASE64_OUTPUT_UNSPEC;
+static const char *opt_base64_output_mode_str= NullS;
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;
static char *charset= 0;
+static uint verbose= 0;
+
static ulonglong start_position, stop_position;
#define start_position_mot ((my_off_t)start_position)
#define stop_position_mot ((my_off_t)stop_position)
@@ -83,23 +96,33 @@ static ulonglong rec_count= 0;
static short binlog_flags = 0;
static MYSQL* mysql = NULL;
static const char* dirname_for_local_load= 0;
-static bool stop_passed= 0;
-/*
- check_header() will set the pointer below.
- Why do we need here a pointer on an event instead of an event ?
- This is because the event will be created (alloced) in read_log_event()
- (which returns a pointer) in check_header().
+/**
+ Pointer to the Format_description_log_event of the currently active binlog.
+
+ This will be changed each time a new Format_description_log_event is
+ found in the binlog. It is finally destroyed at program termination.
*/
-Format_description_log_event* glob_description_event;
+static Format_description_log_event* glob_description_event= NULL;
-static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
- const char* logname);
-static int dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
- const char* logname);
-static int dump_log_entries(const char* logname);
-static void die(const char* fmt, ...) __attribute__ ((__noreturn__));
-static MYSQL* safe_connect();
+/**
+ Exit status for functions in this file.
+*/
+enum Exit_status {
+ /** No error occurred and execution should continue. */
+ OK_CONTINUE= 0,
+ /** An error occurred and execution should stop. */
+ ERROR_STOP,
+ /** No error occurred but execution should stop. */
+ OK_STOP
+};
+
+static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
+ const char* logname);
+static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
+ const char* logname);
+static Exit_status dump_log_entries(const char* logname);
+static Exit_status safe_connect();
class Load_log_processor
@@ -122,22 +145,29 @@ class Load_log_processor
char *fname;
Create_file_log_event *event;
};
+ /*
+ @todo Should be a map (e.g., a hash map), not an array. With the
+ present implementation, the number of elements in this array is
+ about the number of files loaded since the server started, which
+ may be big after a few years. We should be able to use existing
+ library data structures for this. /Sven
+ */
DYNAMIC_ARRAY file_names;
- /*
- Looking for new uniquie filename that doesn't exist yet by
- adding postfix -%x
-
- SYNOPSIS
- create_unique_file()
-
- filename buffer for filename
- file_name_end tail of buffer that should be changed
- should point to a memory enough to printf("-%x",..)
-
- RETURN VALUES
- values less than 0 - can't find new filename
- values great or equal 0 - created file with found filename
+ /**
+ Looks for a non-existing filename by adding a numerical suffix to
+ the given base name, creates the generated file, and returns the
+ filename by modifying the filename argument.
+
+ @param[in,out] filename Base filename
+
+ @param[in,out] file_name_end Pointer to last character of
+ filename. The numerical suffix will be written to this position.
+ Note that there must be a least five bytes of allocated memory
+ after file_name_end.
+
+ @retval -1 Error (can't find new filename).
+ @retval >=0 Found file.
*/
File create_unique_file(char *filename, char *file_name_end)
{
@@ -191,22 +221,20 @@ public:
delete_dynamic(&file_names);
}
- /*
- Obtain Create_file event for LOAD DATA statement by its file_id.
+ /**
+ Obtain Create_file event for LOAD DATA statement by its file_id
+ and remove it from this Load_log_processor's list of events.
- SYNOPSIS
- grab_event()
- file_id - file_id identifiying LOAD DATA statement
+ Checks whether we have already seen a Create_file_log_event with
+ the given file_id. If yes, returns a pointer to the event and
+ removes the event from array describing active temporary files.
+ From this moment, the caller is responsible for freeing the memory
+ occupied by the event.
- DESCRIPTION
- Checks whenever we have already seen Create_file event for this file_id.
- If yes then returns pointer to it and removes it from array describing
- active temporary files. Since this moment caller is responsible for
- freeing memory occupied by this event and associated file name.
+ @param[in] file_id File id identifying LOAD DATA statement.
- RETURN VALUES
- Pointer to Create_file event or 0 if there was no such event
- with this file_id.
+ @return Pointer to Create_file_log_event, or NULL if we have not
+ seen any Create_file_log_event with this file_id.
*/
Create_file_log_event *grab_event(uint file_id)
{
@@ -221,23 +249,20 @@ public:
return res;
}
- /*
- Obtain file name of temporary file for LOAD DATA statement by its file_id.
-
- SYNOPSIS
- grab_fname()
- file_id - file_id identifiying LOAD DATA statement
-
- DESCRIPTION
- Checks whenever we have already seen Begin_load_query event for this
- file_id. If yes then returns file name of corresponding temporary file.
- Removes record about this file from the array of active temporary files.
- Since this moment caller is responsible for freeing memory occupied by
- this name.
-
- RETURN VALUES
- String with name of temporary file or 0 if we have not seen Begin_load_query
- event with this file_id.
+ /**
+ Obtain file name of temporary file for LOAD DATA statement by its
+ file_id and remove it from this Load_log_processor's list of events.
+
+ @param[in] file_id Identifier for the LOAD DATA statement.
+
+ Checks whether we have already seen Begin_load_query event for
+ this file_id. If yes, returns the file name of the corresponding
+ temporary file and removes the filename from the array of active
+ temporary files. From this moment, the caller is responsible for
+ freeing the memory occupied by this name.
+
+ @return String with the name of the temporary file, or NULL if we
+ have not seen any Begin_load_query_event with this file_id.
*/
char *grab_fname(uint file_id)
{
@@ -254,33 +279,43 @@ public:
}
return res;
}
- int process(Create_file_log_event *ce);
- int process(Begin_load_query_log_event *ce);
- int process(Append_block_log_event *ae);
+ Exit_status process(Create_file_log_event *ce);
+ Exit_status process(Begin_load_query_log_event *ce);
+ Exit_status process(Append_block_log_event *ae);
File prepare_new_file_for_old_format(Load_log_event *le, char *filename);
- int load_old_format_file(NET* net, const char *server_fname,
- uint server_fname_len, File file);
- int process_first_event(const char *bname, uint blen, const char *block,
- uint block_len, uint file_id,
- Create_file_log_event *ce);
+ Exit_status load_old_format_file(NET* net, const char *server_fname,
+ uint server_fname_len, File file);
+ Exit_status process_first_event(const char *bname, size_t blen,
+ const uchar *block,
+ size_t block_len, uint file_id,
+ Create_file_log_event *ce);
};
+/**
+ Creates and opens a new temporary file in the directory specified by previous call to init_by_dir_name() or init_by_cur_dir().
+
+ @param[in] le The basename of the created file will start with the
+ basename of the file pointed to by this Load_log_event.
+ @param[out] filename Buffer to save the filename in.
+
+ @return File handle >= 0 on success, -1 on error.
+*/
File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le,
char *filename)
{
- uint len;
+ size_t len;
char *tail;
File file;
- fn_format(filename, le->fname, target_dir_name, "", 1);
- len= (uint) strlen(filename);
+ fn_format(filename, le->fname, target_dir_name, "", MY_REPLACE_DIR);
+ len= strlen(filename);
tail= filename + len;
if ((file= create_unique_file(filename,tail)) < 0)
{
- sql_print_error("Could not construct local filename %s",filename);
+ error("Could not construct local filename %s.",filename);
return -1;
}
@@ -290,16 +325,33 @@ 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)
+/**
+ Reads a file from a server and saves it locally.
+
+ @param[in,out] net The server to read from.
+
+ @param[in] server_fname The name of the file that the server should
+ read.
+
+ @param[in] server_fname_len The length of server_fname.
+
+ @param[in,out] file The file to write to.
+
+ @retval ERROR_STOP An error occurred - the program should terminate.
+ @retval OK_CONTINUE No error, the program should continue.
+*/
+Exit_status 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))
{
- sql_print_error("Failed requesting the remote dump of %s", server_fname);
- return -1;
+ error("Failed requesting the remote dump of %s.", server_fname);
+ return ERROR_STOP;
}
for (;;)
@@ -307,10 +359,10 @@ 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;
+ error("Failed sending the ack packet.");
+ return ERROR_STOP;
}
/*
we just need to send something, as the server will read but
@@ -321,63 +373,63 @@ int Load_log_processor::load_old_format_file(NET* net, const char*server_fname,
}
else if (packet_len == packet_error)
{
- sql_print_error("Failed reading a packet during the dump of %s ",
- server_fname);
- return -1;
+ error("Failed reading a packet during the dump of %s.", server_fname);
+ return ERROR_STOP;
}
if (packet_len > UINT_MAX)
{
- sql_print_error("Illegal length of packet read from net");
- return -1;
+ error("Illegal length of packet read from net.");
+ return ERROR_STOP;
}
- 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;
+ return ERROR_STOP;
}
- return 0;
+ return OK_CONTINUE;
}
-/*
- Process first event in the sequence of events representing LOAD DATA
- statement.
-
- SYNOPSIS
- process_first_event()
- bname - base name for temporary file to be created
- blen - base name length
- block - first block of data to be loaded
- block_len - first block length
- file_id - identifies LOAD DATA statement
- ce - pointer to Create_file event object if we are processing
- this type of event.
-
- DESCRIPTION
- Creates temporary file to be used in LOAD DATA and writes first block of
- data to it. Registers its file name (and optional Create_file event)
- in the array of active temporary files.
-
- RETURN VALUES
- 0 - success
- non-0 - error
+/**
+ Process the first event in the sequence of events representing a
+ LOAD DATA statement.
+
+ Creates a temporary file to be used in LOAD DATA and writes first
+ block of data to it. Registers its file name (and optional
+ Create_file event) in the array of active temporary files.
+
+ @param bname Base name for temporary file to be created.
+ @param blen Base name length.
+ @param block First block of data to be loaded.
+ @param block_len First block length.
+ @param file_id Identifies the LOAD DATA statement.
+ @param ce Pointer to Create_file event object if we are processing
+ this type of event.
+
+ @retval ERROR_STOP An error occurred - the program should terminate.
+ @retval OK_CONTINUE No error, the program should continue.
*/
-
-int Load_log_processor::process_first_event(const char *bname, uint blen,
- const char *block, uint block_len,
- uint file_id,
- Create_file_log_event *ce)
+Exit_status Load_log_processor::process_first_event(const char *bname,
+ size_t blen,
+ const uchar *block,
+ size_t block_len,
+ uint file_id,
+ Create_file_log_event *ce)
{
- size_t full_len= target_dir_name_len + blen + 9 + 9 + 1;
- int error= 0;
+ uint full_len= target_dir_name_len + blen + 9 + 9 + 1;
+ Exit_status retval= OK_CONTINUE;
char *fname, *ptr;
File file;
File_name_record rec;
DBUG_ENTER("Load_log_processor::process_first_event");
- if (!(fname= my_malloc(full_len,MYF(MY_WME))))
- DBUG_RETURN(-1);
+ if (!(fname= (char*) my_malloc(full_len,MYF(MY_WME))))
+ {
+ error("Out of memory.");
+ delete ce;
+ DBUG_RETURN(ERROR_STOP);
+ }
memcpy(fname, target_dir_name, target_dir_name_len);
ptr= fname + target_dir_name_len;
@@ -387,50 +439,99 @@ int Load_log_processor::process_first_event(const char *bname, uint blen,
if ((file= create_unique_file(fname,ptr)) < 0)
{
- sql_print_error("Could not construct local filename %s%s",
- target_dir_name,bname);
- DBUG_RETURN(-1);
+ error("Could not construct local filename %s%s.",
+ target_dir_name,bname);
+ delete ce;
+ DBUG_RETURN(ERROR_STOP);
}
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);
- DBUG_RETURN(-1);
+ error("Out of memory.");
+ delete ce;
+ DBUG_RETURN(ERROR_STOP);
}
if (ce)
ce->set_fname_outside_temp_buf(fname, (uint) strlen(fname));
- if (my_write(file, (byte*)block, block_len, MYF(MY_WME|MY_NABP)))
- error= -1;
+ if (my_write(file, (uchar*)block, block_len, MYF(MY_WME|MY_NABP)))
+ {
+ error("Failed writing to file.");
+ retval= ERROR_STOP;
+ }
if (my_close(file, MYF(MY_WME)))
- error= -1;
- DBUG_RETURN(error);
+ {
+ error("Failed closing file.");
+ retval= ERROR_STOP;
+ }
+ DBUG_RETURN(retval);
}
-int Load_log_processor::process(Create_file_log_event *ce)
+/**
+ Process the given Create_file_log_event.
+
+ @see Load_log_processor::process_first_event(const char*,uint,const char*,uint,uint,Create_file_log_event*)
+
+ @param ce Create_file_log_event to process.
+
+ @retval ERROR_STOP An error occurred - the program should terminate.
+ @retval OK_CONTINUE No error, the program should continue.
+*/
+Exit_status Load_log_processor::process(Create_file_log_event *ce)
{
const char *bname= ce->fname + dirname_length(ce->fname);
- uint blen= (uint) (ce->fname_len - (bname-ce->fname));
+ uint blen= ce->fname_len - (bname-ce->fname);
return process_first_event(bname, blen, ce->block, ce->block_len,
ce->file_id, ce);
}
-int Load_log_processor::process(Begin_load_query_log_event *blqe)
+/**
+ Process the given Begin_load_query_log_event.
+
+ @see Load_log_processor::process_first_event(const char*,uint,const char*,uint,uint,Create_file_log_event*)
+
+ @param ce Begin_load_query_log_event to process.
+
+ @retval ERROR_STOP An error occurred - the program should terminate.
+ @retval OK_CONTINUE No error, the program should continue.
+*/
+Exit_status Load_log_processor::process(Begin_load_query_log_event *blqe)
{
return process_first_event("SQL_LOAD_MB", 11, blqe->block, blqe->block_len,
blqe->file_id, 0);
}
-int Load_log_processor::process(Append_block_log_event *ae)
+/**
+ Process the given Append_block_log_event.
+
+ Appends the chunk of the file contents specified by the event to the
+ file created by a previous Begin_load_query_log_event or
+ Create_file_log_event.
+
+ If the file_id for the event does not correspond to any file
+ previously registered through a Begin_load_query_log_event or
+ Create_file_log_event, this member function will print a warning and
+ return OK_CONTINUE. It is safe to return OK_CONTINUE, because no
+ query will be written for this event. We should not print an error
+ and fail, since the missing file_id could be because a (valid)
+ --start-position has been specified after the Begin/Create event but
+ before this Append event.
+
+ @param ae Append_block_log_event to process.
+
+ @retval ERROR_STOP An error occurred - the program should terminate.
+
+ @retval OK_CONTINUE No error, the program should continue.
+*/
+Exit_status Load_log_processor::process(Append_block_log_event *ae)
{
DBUG_ENTER("Load_log_processor::process");
const char* fname= ((ae->file_id < file_names.elements) ?
@@ -440,15 +541,24 @@ int Load_log_processor::process(Append_block_log_event *ae)
if (fname)
{
File file;
- int error= 0;
+ Exit_status retval= OK_CONTINUE;
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)))
- error= -1;
+ {
+ error("Failed opening file %s", fname);
+ DBUG_RETURN(ERROR_STOP);
+ }
+ if (my_write(file,(uchar*)ae->block,ae->block_len,MYF(MY_WME|MY_NABP)))
+ {
+ error("Failed writing to file %s", fname);
+ retval= ERROR_STOP;
+ }
if (my_close(file,MYF(MY_WME)))
- error= -1;
- DBUG_RETURN(error);
+ {
+ error("Failed closing file %s", fname);
+ retval= ERROR_STOP;
+ }
+ DBUG_RETURN(retval);
}
/*
@@ -456,13 +566,13 @@ int Load_log_processor::process(Append_block_log_event *ae)
--start-position). Assuming it's a big --start-position, we just do
nothing and print a warning.
*/
- fprintf(stderr,"Warning: ignoring Append_block as there is no \
-Create_file event for file_id: %u\n",ae->file_id);
- DBUG_RETURN(-1);
+ warning("Ignoring Append_block as there is no "
+ "Create_file event for file_id: %u", ae->file_id);
+ DBUG_RETURN(OK_CONTINUE);
}
-Load_log_processor load_processor;
+static Load_log_processor load_processor;
/**
@@ -490,7 +600,16 @@ static void convert_path_to_forward_slashes(char *fname)
}
-static bool check_database(const char *log_dbname)
+/**
+ Indicates whether the given database should be filtered out,
+ according to the --database=X option.
+
+ @param log_dbname Name of database.
+
+ @return nonzero if the database with the given name should be
+ filtered out, 0 otherwise.
+*/
+static bool shall_skip_database(const char *log_dbname)
{
return one_database &&
(log_dbname != NULL) &&
@@ -498,30 +617,73 @@ static bool check_database(const char *log_dbname)
}
-/*
- Process an event
-
- SYNOPSIS
- process_event()
-
- RETURN
- 0 ok and continue
- 1 error and terminate
- -1 ok and terminate
-
- TODO
- This function returns 0 even in some error cases. This should be changed.
+/**
+ Prints the given event in base64 format.
+
+ The header is printed to the head cache and the body is printed to
+ the body cache of the print_event_info structure. This allows all
+ base64 events corresponding to the same statement to be joined into
+ one BINLOG statement.
+
+ @param[in] ev Log_event to print.
+ @param[in,out] result_file FILE to which the output will be written.
+ @param[in,out] print_event_info Parameters and context state
+ determining how to print.
+
+ @retval ERROR_STOP An error occurred - the program should terminate.
+ @retval OK_CONTINUE No error, the program should continue.
*/
+static Exit_status
+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 */
+ if (copy_event_cache_to_file_and_reinit(head, result_file) ||
+ copy_event_cache_to_file_and_reinit(body, result_file))
+ {
+ error("Error writing event to file.");
+ DBUG_RETURN(ERROR_STOP);
+ }
+ DBUG_RETURN(OK_CONTINUE);
+}
-int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
- my_off_t pos)
+/**
+ Print the given event, and either delete it or delegate the deletion
+ to someone else.
+
+ The deletion may be delegated in two cases: (1) the event is a
+ Format_description_log_event, and is saved in
+ glob_description_event; (2) the event is a Create_file_log_event,
+ and is saved in load_processor.
+
+ @param[in,out] print_event_info Parameters and context state
+ determining how to print.
+ @param[in] ev Log_event to process.
+ @param[in] pos Offset from beginning of binlog file.
+ @param[in] logname Name of input binlog.
+
+ @retval ERROR_STOP An error occurred - the program should terminate.
+ @retval OK_CONTINUE No error, the program should continue.
+ @retval OK_STOP No error, but the end of the specified range of
+ events to process has been reached and the program should terminate.
+*/
+Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
+ my_off_t pos, const char *logname)
{
char ll_buff[21];
Log_event_type ev_type= ev->get_type_code();
DBUG_ENTER("process_event");
print_event_info->short_form= short_form;
+ Exit_status retval= OK_CONTINUE;
/*
Format events are not concerned by --offset and such, we always need to
@@ -541,11 +703,15 @@ 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))
+ /* skip just this event, continue processing the log. */
+ goto end;
if (((my_time_t)(ev->when) >= stop_datetime)
|| (pos >= stop_position_mot))
{
- stop_passed= 1; // skip all next binlogs
- DBUG_RETURN(-1);
+ /* end the program */
+ retval= OK_STOP;
+ goto end;
}
if (!short_form)
fprintf(result_file, "# at %s\n",llstr(pos,ll_buff));
@@ -555,12 +721,25 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
else
print_event_info->hexdump_from= pos;
+ print_event_info->base64_output_mode= opt_base64_output_mode;
+
+ DBUG_PRINT("debug", ("event_type: %s", ev->get_type_str()));
+
switch (ev_type) {
case QUERY_EVENT:
- if (check_database(((Query_log_event*)ev)->db))
+ if (shall_skip_database(((Query_log_event*)ev)->db))
goto end;
- ev->print(result_file, print_event_info);
+ if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS)
+ {
+ if ((retval= write_event_header_and_base64(ev, result_file,
+ print_event_info)) !=
+ OK_CONTINUE)
+ goto end;
+ }
+ else
+ ev->print(result_file, print_event_info);
break;
+
case CREATE_FILE_EVENT:
{
Create_file_log_event* ce= (Create_file_log_event*)ev;
@@ -570,7 +749,7 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
related Append_block and Exec_load.
Note that Load event from 3.23 is not tested.
*/
- if (check_database(ce->db))
+ if (shall_skip_database(ce->db))
goto end; // Next event
/*
We print the event, but with a leading '#': this is just to inform
@@ -579,22 +758,42 @@ 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_mode == BASE64_OUTPUT_ALWAYS)
+ {
+ if ((retval= write_event_header_and_base64(ce, result_file,
+ print_event_info)) !=
+ OK_CONTINUE)
+ goto end;
+ }
+ 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)
{
- if (load_processor.process(ce))
- break; // Error
- ev= 0;
+ /*
+ transfer the responsibility for destroying the event to
+ load_processor
+ */
+ ev= NULL;
+ if ((retval= load_processor.process(ce)) != OK_CONTINUE)
+ goto end;
}
break;
}
+
case APPEND_BLOCK_EVENT:
+ /*
+ Append_block_log_events can safely print themselves even if
+ the subsequent call load_processor.process fails, because the
+ output of Append_block_log_event::print is only a comment.
+ */
ev->print(result_file, print_event_info);
- if (load_processor.process((Append_block_log_event*) ev))
- break; // Error
+ if ((retval= load_processor.process((Append_block_log_event*) ev)) !=
+ OK_CONTINUE)
+ goto end;
break;
+
case EXEC_LOAD_EVENT:
{
ev->print(result_file, print_event_info);
@@ -617,16 +816,17 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
delete ce;
}
else
- fprintf(stderr,"Warning: ignoring Exec_load as there is no \
-Create_file event for file_id: %u\n",exv->file_id);
+ warning("Ignoring Execute_load_log_event as there is no "
+ "Create_file event for file_id: %u", exv->file_id);
break;
}
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;
+ 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
@@ -634,39 +834,81 @@ 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))
+ {
+ error("Attempting to dump binlog '%s', which was not closed properly. "
+ "Most probably, mysqld is still writing it, or it crashed. "
+ "Rerun with --force-if-open to ignore this problem.", logname);
+ DBUG_RETURN(ERROR_STOP);
+ }
break;
case BEGIN_LOAD_QUERY_EVENT:
ev->print(result_file, print_event_info);
- load_processor.process((Begin_load_query_log_event*) ev);
+ if ((retval= load_processor.process((Begin_load_query_log_event*) ev)) !=
+ OK_CONTINUE)
+ goto end;
break;
case EXECUTE_LOAD_QUERY_EVENT:
{
Execute_load_query_log_event *exlq= (Execute_load_query_log_event*)ev;
char *fname= load_processor.grab_fname(exlq->file_id);
- if (check_database(exlq->db))
+ if (!shall_skip_database(exlq->db))
{
if (fname)
- my_free(fname, MYF(MY_WME));
- goto end;
+ {
+ convert_path_to_forward_slashes(fname);
+ exlq->print(result_file, print_event_info, fname);
+ }
+ else
+ warning("Ignoring Execute_load_query since there is no "
+ "Begin_load_query event for file_id: %u", exlq->file_id);
}
if (fname)
- {
- convert_path_to_forward_slashes(fname);
- exlq->print(result_file, print_event_info, fname);
my_free(fname, MYF(MY_WME));
- }
- else
- fprintf(stderr,"Warning: ignoring Execute_load_query as there is no \
-Begin_load_query event for file_id: %u\n", exlq->file_id);
break;
}
+ case TABLE_MAP_EVENT:
+ case WRITE_ROWS_EVENT:
+ case DELETE_ROWS_EVENT:
+ case UPDATE_ROWS_EVENT:
+ case PRE_GA_WRITE_ROWS_EVENT:
+ case PRE_GA_DELETE_ROWS_EVENT:
+ case PRE_GA_UPDATE_ROWS_EVENT:
+ /*
+ These events must be printed in base64 format, if printed.
+ base64 format requires a FD event to be safe, so if no FD
+ event has been printed, we give an error. Except if user
+ passed --short-form, because --short-form disables printing
+ row events.
+ */
+ if (!print_event_info->printed_fd_event && !short_form)
+ {
+ const char* type_str= ev->get_type_str();
+ if (opt_base64_output_mode == BASE64_OUTPUT_NEVER)
+ error("--base64-output=never specified, but binlog contains a "
+ "%s event which must be printed in base64.",
+ type_str);
+ else
+ error("malformed binlog: it does not contain any "
+ "Format_description_log_event. I now found a %s event, which "
+ "is not safe to process without a "
+ "Format_description_log_event.",
+ type_str);
+ goto err;
+ }
+ /* FALL THROUGH */
default:
ev->print(result_file, print_event_info);
}
}
+ goto end;
+
+err:
+ retval= ERROR_STOP;
end:
rec_count++;
/*
@@ -679,17 +921,29 @@ end:
ev->temp_buf= 0;
delete ev;
}
- DBUG_RETURN(0);
+ DBUG_RETURN(retval);
}
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_MODE,
+ "Determine when the output statements should be base64-encoded BINLOG "
+ "statements: 'never' disables it and works only for binlogs without "
+ "row-based events; 'auto' is the default and prints base64 only when "
+ "necessary (i.e., for row-based events and format description events); "
+ "'always' prints base64 whenever possible. 'always' is for debugging "
+ "only and should not be used in a production system. The default is "
+ "'auto'. --base64-output is a short form for --base64-output=always."
+ ,(uchar**) &opt_base64_output_mode_str,
+ (uchar**) &opt_base64_output_mode_str,
+ 0, GET_STR, OPT_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
@@ -697,33 +951,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},
@@ -733,33 +997,36 @@ 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},
- {"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,
+ "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 regular queries: no extra info and no "
+ "row-based events. This is for testing only, and should not be used in "
+ "production systems. If you want to suppress base64-output, consider "
+ "using --base64-output=never instead.",
+ (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 "
@@ -767,57 +1034,116 @@ 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},
+ {"verbose", 'v', "Reconstruct SQL statements out of row events. "
+ "-v -v adds comments on column data types",
+ 0, 0, 0, GET_NO_ARG, NO_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}
};
-void sql_print_error(const char *format,...)
+/**
+ Auxiliary function used by error() and warning().
+
+ Prints the given text (normally "WARNING: " or "ERROR: "), followed
+ by the given vprintf-style string, followed by a newline.
+
+ @param format Printf-style format string.
+ @param args List of arguments for the format string.
+ @param msg Text to print before the string.
+*/
+static void error_or_warning(const char *format, va_list args, const char *msg)
{
- va_list args;
- va_start(args, format);
- fprintf(stderr, "ERROR: ");
+ fprintf(stderr, "%s: ", msg);
vfprintf(stderr, format, args);
fprintf(stderr, "\n");
+}
+
+/**
+ Prints a message to stderr, prefixed with the text "ERROR: " and
+ suffixed with a newline.
+
+ @param format Printf-style format string, followed by printf
+ varargs.
+*/
+static void error(const char *format,...)
+{
+ va_list args;
+ va_start(args, format);
+ error_or_warning(format, args, "ERROR");
+ va_end(args);
+}
+
+
+/**
+ This function is used in log_event.cc to report errors.
+
+ @param format Printf-style format string, followed by printf
+ varargs.
+*/
+static void sql_print_error(const char *format,...)
+{
+ va_list args;
+ va_start(args, format);
+ error_or_warning(format, args, "ERROR");
va_end(args);
}
+/**
+ Prints a message to stderr, prefixed with the text "WARNING: " and
+ suffixed with a newline.
+
+ @param format Printf-style format string, followed by printf
+ varargs.
+*/
+static void warning(const char *format,...)
+{
+ va_list args;
+ va_start(args, format);
+ error_or_warning(format, args, "WARNING");
+ va_end(args);
+}
+
+/**
+ Frees memory for global variables in this file.
+*/
static void cleanup()
{
my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
@@ -825,27 +1151,17 @@ static void cleanup()
my_free((char*) host, MYF(MY_ALLOW_ZERO_PTR));
my_free((char*) user, MYF(MY_ALLOW_ZERO_PTR));
my_free((char*) dirname_for_local_load, MYF(MY_ALLOW_ZERO_PTR));
-}
-static void die(const char* fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- fprintf(stderr, "ERROR: ");
- vfprintf(stderr, fmt, args);
- fprintf(stderr, "\n");
- va_end(args);
- cleanup();
- /* We cannot free DBUG, it is used in global destructors after exit(). */
- my_end(MY_DONT_FREE_DBUG);
- exit(1);
+ delete glob_description_event;
+ if (mysql)
+ mysql_close(mysql);
}
#include <help_start.h>
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);
}
@@ -876,7 +1192,7 @@ static my_time_t convert_str_to_timestamp(const char* str)
if (str_to_datetime(str, (uint) strlen(str), &l_time, 0, &was_cut) !=
MYSQL_TIMESTAMP_DATETIME || was_cut)
{
- fprintf(stderr, "Incorrect date and time argument: %s\n", str);
+ error("Incorrect date and time argument: %s", str);
exit(1);
}
/*
@@ -910,6 +1226,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
one_database = 1;
break;
case 'p':
+ if (argument == disabled_my_option)
+ argument= (char*) ""; // Don't require password
if (argument)
{
my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
@@ -930,20 +1248,30 @@ 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;
case OPT_STOP_DATETIME:
stop_datetime= convert_str_to_timestamp(stop_datetime_str);
break;
+ case OPT_BASE64_OUTPUT_MODE:
+ if (argument == NULL)
+ opt_base64_output_mode= BASE64_OUTPUT_ALWAYS;
+ else
+ {
+ opt_base64_output_mode= (enum_base64_output_mode)
+ (find_type_or_exit(argument, &base64_output_mode_typelib, opt->name)-1);
+ }
+ break;
+ case 'v':
+ if (argument == disabled_my_option)
+ verbose= 0;
+ else
+ verbose++;
+ break;
case 'V':
print_version();
exit(0);
@@ -966,97 +1294,127 @@ 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;
}
-static MYSQL* safe_connect()
+
+/**
+ Create and initialize the global mysql object, and connect to the
+ server.
+
+ @retval ERROR_STOP An error occurred - the program should terminate.
+ @retval OK_CONTINUE No error, the program should continue.
+*/
+static Exit_status safe_connect()
{
- MYSQL *local_mysql= mysql_init(NULL);
+ mysql= mysql_init(NULL);
- if (!local_mysql)
- die("Failed on mysql_init");
+ if (!mysql)
+ {
+ error("Failed on mysql_init.");
+ return ERROR_STOP;
+ }
if (opt_protocol)
- mysql_options(local_mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol);
- if (!mysql_real_connect(local_mysql, host, user, pass, 0, port, sock, 0))
+ mysql_options(mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol);
+ if (!mysql_real_connect(mysql, host, user, pass, 0, port, sock, 0))
{
- char errmsg[256];
- strmake(errmsg, mysql_error(local_mysql), sizeof(errmsg)-1);
- mysql_close(local_mysql);
- die("failed on connect: %s", errmsg);
+ error("Failed on connect: %s", mysql_error(mysql));
+ return ERROR_STOP;
}
- local_mysql->reconnect= 1;
- return local_mysql;
+ mysql->reconnect= 1;
+ return OK_CONTINUE;
}
-static int dump_log_entries(const char* logname)
+/**
+ High-level function for dumping a named binlog.
+
+ This function calls dump_remote_log_entries() or
+ dump_local_log_entries() to do the job.
+
+ @param[in] logname Name of input binlog.
+
+ @retval ERROR_STOP An error occurred - the program should terminate.
+ @retval OK_CONTINUE No error, the program should continue.
+ @retval OK_STOP No error, but the end of the specified range of
+ events to process has been reached and the program should terminate.
+*/
+static Exit_status dump_log_entries(const char* logname)
{
- int rc;
+ Exit_status rc;
PRINT_EVENT_INFO print_event_info;
+
+ if (!print_event_info.init_ok())
+ return ERROR_STOP;
/*
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, "/*!*/;");
+
+ print_event_info.verbose= short_form ? 0 : verbose;
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;
}
-/*
- This is not as smart as check_header() (used for local log); it will not work
- for a binlog which mixes format. TODO: fix this.
+/**
+ When reading a remote binlog, this function is used to grab the
+ Format_description_log_event in the beginning of the stream.
+
+ This is not as smart as check_header() (used for local log); it will
+ not work for a binlog which mixes format. TODO: fix this.
+
+ @retval ERROR_STOP An error occurred - the program should terminate.
+ @retval OK_CONTINUE No error, the program should continue.
*/
-static int check_master_version(MYSQL *mysql_arg,
- Format_description_log_event
- **description_event)
+static Exit_status check_master_version()
{
MYSQL_RES* res = 0;
MYSQL_ROW row;
const char* version;
- if (mysql_query(mysql_arg, "SELECT VERSION()") ||
- !(res = mysql_store_result(mysql_arg)))
+ if (mysql_query(mysql, "SELECT VERSION()") ||
+ !(res = mysql_store_result(mysql)))
{
- /* purecov: begin inspected */
- char errmsg[256];
- strmake(errmsg, mysql_error(mysql_arg), sizeof(errmsg)-1);
- mysql_close(mysql_arg);
- die("Error checking master version: %s", errmsg);
- /* purecov: end */
+ error("Could not find server version: "
+ "Query failed when checking master version: %s", mysql_error(mysql));
+ return ERROR_STOP;
}
if (!(row = mysql_fetch_row(res)))
{
- /* purecov: begin inspected */
- mysql_free_result(res);
- mysql_close(mysql);
- die("Master returned no rows for SELECT VERSION()");
- /* purecov: end */
+ error("Could not find server version: "
+ "Master returned no rows for SELECT VERSION().");
+ goto err;
}
+
if (!(version = row[0]))
{
- /* purecov: begin inspected */
- mysql_free_result(res);
- mysql_close(mysql_arg);
- die("Master reported NULL for the version");
- /* purecov: end */
+ error("Could not find server version: "
+ "Master reported NULL for the version.");
+ goto err;
}
+ delete glob_description_event;
switch (*version) {
case '3':
- *description_event= new Format_description_log_event(1);
+ glob_description_event= new Format_description_log_event(1);
break;
case '4':
- *description_event= new Format_description_log_event(3);
+ glob_description_event= new Format_description_log_event(3);
+ break;
case '5':
/*
The server is soon going to send us its Format_description log
@@ -1064,31 +1422,53 @@ static int check_master_version(MYSQL *mysql_arg,
So we first assume that this is 4.0 (which is enough to read the
Format_desc event if one comes).
*/
- *description_event= new Format_description_log_event(3);
+ glob_description_event= new Format_description_log_event(3);
break;
default:
- /* purecov: begin inspected */
- mysql_free_result(res);
- mysql_close(mysql_arg);
- die("Master reported unrecognized MySQL version '%s'", version);
- /* purecov: end */
+ glob_description_event= NULL;
+ error("Could not find server version: "
+ "Master reported unrecognized MySQL version '%s'.", version);
+ goto err;
+ }
+ if (!glob_description_event || !glob_description_event->is_valid())
+ {
+ error("Failed creating Format_description_log_event; out of memory?");
+ goto err;
}
+
mysql_free_result(res);
- return 0;
+ return OK_CONTINUE;
+
+err:
+ mysql_free_result(res);
+ return ERROR_STOP;
}
-static int dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
- const char* logname)
+/**
+ Requests binlog dump from a remote server and prints the events it
+ receives.
+
+ @param[in,out] print_event_info Parameters and context state
+ determining how to print.
+ @param[in] logname Name of input binlog.
+
+ @retval ERROR_STOP An error occurred - the program should terminate.
+ @retval OK_CONTINUE No error, the program should continue.
+ @retval OK_STOP No error, but the end of the specified range of
+ events to process has been reached and the program should terminate.
+*/
+static Exit_status 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;
- int error= 0;
my_off_t old_off= start_position_mot;
char fname[FN_REFLEN+1];
+ Exit_status retval= OK_CONTINUE;
DBUG_ENTER("dump_remote_log_entries");
/*
@@ -1096,20 +1476,12 @@ static int dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
we cannot re-use the same connection as before, because it is now dead
(COM_BINLOG_DUMP kills the thread when it finishes).
*/
- mysql= safe_connect();
+ if ((retval= safe_connect()) != OK_CONTINUE)
+ DBUG_RETURN(retval);
net= &mysql->net;
- if (check_master_version(mysql, &glob_description_event))
- {
- fprintf(stderr, "Could not find server version");
- DBUG_RETURN(1);
- }
- if (!glob_description_event || !glob_description_event->is_valid())
- {
- fprintf(stderr, "Invalid Format_description log event; \
-could be out of memory");
- DBUG_RETURN(1);
- }
+ if ((retval= check_master_version()) != OK_CONTINUE)
+ DBUG_RETURN(retval);
/*
COM_BINLOG_DUMP accepts only 4 bytes for the position, so we are forced to
@@ -1118,21 +1490,19 @@ could be out of memory");
int4store(buf, (uint32)start_position);
int2store(buf + BIN_LOG_HEADER_SIZE, binlog_flags);
- size_t tlen= strlen(logname);
+ size_t tlen = strlen(logname);
if (tlen > UINT_MAX)
{
- fprintf(stderr,"Log name too long\n");
- error= 1;
- goto err;
+ error("Log name too long.");
+ DBUG_RETURN(ERROR_STOP);
}
logname_len = (uint) tlen;
int4store(buf + 6, 0);
memcpy(buf + 10, logname, logname_len);
if (simple_command(mysql, COM_BINLOG_DUMP, buf, logname_len + 10, 1))
{
- fprintf(stderr,"Got fatal error sending the log dump command\n");
- error= 1;
- goto err;
+ error("Got fatal error sending the log dump command.");
+ DBUG_RETURN(ERROR_STOP);
}
for (;;)
@@ -1143,10 +1513,8 @@ could be out of memory");
len= cli_safe_read(mysql);
if (len == packet_error)
{
- fprintf(stderr, "Got error reading packet from server: %s\n",
- mysql_error(mysql));
- error= 1;
- goto err;
+ error("Got error reading packet from server: %s", mysql_error(mysql));
+ DBUG_RETURN(ERROR_STOP);
}
if (len < 8 && net->read_pos[0] == 254)
break; // end of data
@@ -1156,9 +1524,8 @@ could be out of memory");
len - 1, &error_msg,
glob_description_event)))
{
- fprintf(stderr, "Could not construct log event object\n");
- error= 1;
- goto err;
+ error("Could not construct log event object: %s", error_msg);
+ DBUG_RETURN(ERROR_STOP);
}
/*
If reading from a remote host, ensure the temp_buf for the
@@ -1196,8 +1563,7 @@ could be out of memory");
if ((rev->ident_len != logname_len) ||
memcmp(rev->new_log_ident, logname, logname_len))
{
- error= 0;
- goto err;
+ DBUG_RETURN(OK_CONTINUE);
}
/*
Otherwise, this is a fake Rotate for our log, at the very
@@ -1222,11 +1588,9 @@ could be out of memory");
if (old_off != BIN_LOG_HEADER_SIZE)
len= 1; // fake event, don't increment old_off
}
- if ((error= process_event(print_event_info, ev, old_off)))
- {
- error= ((error < 0) ? 0 : 1);
- goto err;
- }
+ Exit_status retval= process_event(print_event_info, ev, old_off, logname);
+ if (retval != OK_CONTINUE)
+ DBUG_RETURN(retval);
}
else
{
@@ -1234,26 +1598,21 @@ could be out of memory");
const char *old_fname= le->fname;
uint old_len= le->fname_len;
File file;
+ Exit_status retval;
if ((file= load_processor.prepare_new_file_for_old_format(le,fname)) < 0)
- {
- error= 1;
- goto err;
- }
+ DBUG_RETURN(ERROR_STOP);
- if ((error= process_event(print_event_info, ev, old_off)))
+ retval= process_event(print_event_info, ev, old_off, logname);
+ if (retval != OK_CONTINUE)
{
my_close(file,MYF(MY_WME));
- error= ((error < 0) ? 0 : 1);
- goto err;
+ DBUG_RETURN(retval);
}
- error= load_processor.load_old_format_file(net,old_fname,old_len,file);
+ retval= load_processor.load_old_format_file(net,old_fname,old_len,file);
my_close(file,MYF(MY_WME));
- if (error)
- {
- error= 1;
- goto err;
- }
+ if (retval != OK_CONTINUE)
+ DBUG_RETURN(retval);
}
/*
Let's adjust offset for remote log as for local log to produce
@@ -1262,26 +1621,63 @@ could be out of memory");
old_off+= len-1;
}
-err:
- mysql_close(mysql);
- DBUG_RETURN(error);
+ DBUG_RETURN(OK_CONTINUE);
}
-static void check_header(IO_CACHE* file,
- Format_description_log_event **description_event)
+/**
+ Reads the @c Format_description_log_event from the beginning of a
+ local input file.
+
+ The @c Format_description_log_event is only read if it is outside
+ the range specified with @c --start-position; otherwise, it will be
+ seen later. If this is an old binlog, a fake @c
+ Format_description_event is created. This also prints a @c
+ Format_description_log_event to the output, unless we reach the
+ --start-position range. In this case, it is assumed that a @c
+ Format_description_log_event will be found when reading events the
+ usual way.
+
+ @param file The file to which a @c Format_description_log_event will
+ be printed.
+
+ @param[in,out] print_event_info Parameters and context state
+ determining how to print.
+
+ @param[in] logname Name of input binlog.
+
+ @retval ERROR_STOP An error occurred - the program should terminate.
+ @retval OK_CONTINUE No error, the program should continue.
+ @retval OK_STOP No error, but the end of the specified range of
+ events to process has been reached and the program should terminate.
+*/
+static Exit_status check_header(IO_CACHE* file,
+ PRINT_EVENT_INFO *print_event_info,
+ const char* logname)
{
- 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);
+ delete glob_description_event;
+ if (!(glob_description_event= new Format_description_log_event(3)))
+ {
+ error("Failed creating Format_description_log_event; out of memory?");
+ return ERROR_STOP;
+ }
+
pos= my_b_tell(file);
my_b_seek(file, (my_off_t)0);
if (my_b_read(file, header, sizeof(header)))
- die("Failed reading header; Probably an empty file");
+ {
+ error("Failed reading header; probably an empty file.");
+ return ERROR_STOP;
+ }
if (memcmp(header, BINLOG_MAGIC, sizeof(header)))
- die("File is not a binary log file");
+ {
+ error("File is not a binary log file.");
+ return ERROR_STOP;
+ }
/*
Imagine we are running with --start-position=1000. We still need
@@ -1302,9 +1698,11 @@ static void check_header(IO_CACHE* file,
if (my_b_read(file, buf, sizeof(buf)))
{
if (file->error)
- die("\
-Could not read entry at offset %lu : Error in log format or read error",
- tmp_pos);
+ {
+ error("Could not read entry at offset %llu: "
+ "Error in log format or read error.", (ulonglong)tmp_pos);
+ return ERROR_STOP;
+ }
/*
Otherwise this is just EOF : this log currently contains 0-2
events. Maybe it's going to be filled in the next
@@ -1323,40 +1721,75 @@ Could not read entry at offset %lu : Error in log format or read error",
}
else
{
- DBUG_PRINT("info",("buf[4]=%d", buf[4]));
+ DBUG_PRINT("info",("buf[EVENT_TYPE_OFFSET=%d]=%d",
+ EVENT_TYPE_OFFSET, buf[EVENT_TYPE_OFFSET]));
/* always test for a Start_v3, even if no --start-position */
- if (buf[4] == START_EVENT_V3) /* This is 3.23 or 4.x */
+ if (buf[EVENT_TYPE_OFFSET] == START_EVENT_V3)
{
+ /* This is 3.23 or 4.x */
if (uint4korr(buf + EVENT_LEN_OFFSET) <
(LOG_EVENT_MINIMAL_HEADER_LEN + START_V3_HEADER_LEN))
{
/* This is 3.23 (format 1) */
- delete *description_event;
- *description_event= new Format_description_log_event(1);
+ delete glob_description_event;
+ if (!(glob_description_event= new Format_description_log_event(1)))
+ {
+ error("Failed creating Format_description_log_event; "
+ "out of memory?");
+ return ERROR_STOP;
+ }
}
break;
}
else if (tmp_pos >= start_position)
break;
- else if (buf[4] == FORMAT_DESCRIPTION_EVENT) /* This is 5.0 */
+ else if (buf[EVENT_TYPE_OFFSET] == 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*)
- Log_event::read_log_event(file, *description_event)))
+ if (!(new_description_event= (Format_description_log_event*)
+ Log_event::read_log_event(file, glob_description_event)))
/* EOF can't be hit here normally, so it's a real error */
- 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);
+ {
+ error("Could not read a Format_description_log_event event at "
+ "offset %llu; this could be a log format error or read error.",
+ (ulonglong)tmp_pos);
+ return ERROR_STOP;
+ }
+ if (opt_base64_output_mode == BASE64_OUTPUT_AUTO
+ || opt_base64_output_mode == BASE64_OUTPUT_ALWAYS)
+ {
+ /*
+ process_event will delete *description_event and set it to
+ the new one, so we should not do it ourselves in this
+ case.
+ */
+ Exit_status retval= process_event(print_event_info,
+ new_description_event, tmp_pos,
+ logname);
+ if (retval != OK_CONTINUE)
+ return retval;
+ }
+ else
+ {
+ delete glob_description_event;
+ glob_description_event= new_description_event;
+ }
DBUG_PRINT("info",("Setting description_event"));
}
- else if (buf[4] == ROTATE_EVENT)
+ else if (buf[EVENT_TYPE_OFFSET] == ROTATE_EVENT)
{
Log_event *ev;
my_b_seek(file, tmp_pos); /* seek back to event's start */
- if (!(ev= Log_event::read_log_event(file, *description_event)))
+ if (!(ev= Log_event::read_log_event(file, glob_description_event)))
+ {
/* EOF can't be hit here normally, so it's a real error */
- die("Could not read a Rotate_log_event event at offset %lu ;"
- " this could be a log format error or read error", tmp_pos);
+ error("Could not read a Rotate_log_event event at offset %llu;"
+ " this could be a log format error or read error.",
+ (ulonglong)tmp_pos);
+ return ERROR_STOP;
+ }
delete ev;
}
else
@@ -1364,78 +1797,98 @@ at offset %lu ; this could be a log format error or read error",
}
}
my_b_seek(file, pos);
+ return OK_CONTINUE;
}
-static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
- const char* logname)
+/**
+ Reads a local binlog and prints the events it sees.
+
+ @param[in] logname Name of input binlog.
+
+ @param[in,out] print_event_info Parameters and context state
+ determining how to print.
+
+ @retval ERROR_STOP An error occurred - the program should terminate.
+ @retval OK_CONTINUE No error, the program should continue.
+ @retval OK_STOP No error, but the end of the specified range of
+ events to process has been reached and the program should terminate.
+*/
+static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
+ const char* logname)
{
File fd = -1;
IO_CACHE cache,*file= &cache;
- byte tmp_buff[BIN_LOG_HEADER_SIZE];
- int error= 0;
+ uchar tmp_buff[BIN_LOG_HEADER_SIZE];
+ Exit_status retval= OK_CONTINUE;
- if (logname && logname[0] != '-')
+ if (logname && strcmp(logname, "-") != 0)
{
+ /* read from normal file */
if ((fd = my_open(logname, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0)
- return 1;
+ return ERROR_STOP;
if (init_io_cache(file, fd, 0, READ_CACHE, start_position_mot, 0,
MYF(MY_WME | MY_NABP)))
{
my_close(fd, MYF(MY_WME));
- return 1;
+ return ERROR_STOP;
}
- check_header(file, &glob_description_event);
+ if ((retval= check_header(file, print_event_info, logname)) != OK_CONTINUE)
+ goto end;
}
- else // reading from stdin;
+ else
{
+ /* read 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)
{
- fprintf(stderr, "Could not set binary mode on stdin.\n");
- return 1;
+ error("Could not set binary mode on stdin.");
+ return ERROR_STOP;
}
-#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;
- check_header(file, &glob_description_event);
+ {
+ error("Failed to init IO cache.");
+ return ERROR_STOP;
+ }
+ if ((retval= check_header(file, print_event_info, logname)) != OK_CONTINUE)
+ goto end;
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)
{
tmp=min(length,sizeof(buff));
if (my_b_read(file, buff, (uint) tmp))
{
- error= 1;
- goto end;
+ error("Failed reading from file.");
+ goto err;
}
}
}
}
if (!glob_description_event || !glob_description_event->is_valid())
- die("Invalid Format_description log event; could be out of memory");
+ {
+ error("Invalid Format_description log event; could be out of memory.");
+ goto err;
+ }
if (!start_position && my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE))
{
- error= 1;
- goto end;
+ error("Failed reading from file.");
+ goto err;
}
for (;;)
{
@@ -1453,36 +1906,36 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
file->error= 0;
else if (file->error)
{
- fprintf(stderr,
- "Could not read entry at offset %s:"
- "Error in log format or read error\n",
- llstr(old_off,llbuff));
- error= 1;
+ error("Could not read entry at offset %s: "
+ "Error in log format or read error.",
+ llstr(old_off,llbuff));
+ goto err;
}
// file->error == 0 means EOF, that's OK, we break in this case
- break;
- }
- if ((error= process_event(print_event_info, ev, old_off)))
- {
- if (error < 0)
- error= 0;
- break;
+ goto end;
}
+ if ((retval= process_event(print_event_info, ev, old_off, logname)) !=
+ OK_CONTINUE)
+ goto end;
}
+ /* NOTREACHED */
+
+err:
+ retval= ERROR_STOP;
+
end:
if (fd >= 0)
my_close(fd, MYF(MY_WME));
end_io_cache(file);
- delete glob_description_event;
- return error;
+ return retval;
}
int main(int argc, char** argv)
{
- static char **defaults_argv;
- int exit_value= 0;
+ char **defaults_argv;
+ Exit_status retval= OK_CONTINUE;
ulonglong save_stop_position;
MY_INIT(argv[0]);
DBUG_ENTER("main");
@@ -1500,6 +1953,9 @@ int main(int argc, char** argv)
exit(1);
}
+ if (opt_base64_output_mode == BASE64_OUTPUT_UNSPEC)
+ opt_base64_output_mode= BASE64_OUTPUT_AUTO;
+
my_set_max_open_files(open_files_limit);
MY_TMPDIR tmpdir;
@@ -1541,15 +1997,13 @@ int main(int argc, char** argv)
"\n/*!40101 SET NAMES %s */;\n", charset);
for (save_stop_position= stop_position, stop_position= ~(my_off_t)0 ;
- (--argc >= 0) && !stop_passed ; )
+ (--argc >= 0) ; )
{
if (argc == 0) // last log, --stop-position applies
stop_position= save_stop_position;
- if (dump_log_entries(*(argv++)))
- {
- exit_value=1;
+ if ((retval= dump_log_entries(*argv++)) != OK_CONTINUE)
break;
- }
+
// For next log, --start-position does not apply
start_position= BIN_LOG_HEADER_SIZE;
}
@@ -1579,9 +2033,11 @@ 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);
- exit(exit_value);
- DBUG_RETURN(exit_value); // Keep compilers happy
+ my_end(my_end_arg | MY_DONT_FREE_DBUG);
+
+ exit(retval == ERROR_STOP ? 1 : 0);
+ /* Keep compilers happy. */
+ DBUG_RETURN(retval == ERROR_STOP ? 1 : 0);
}
/*
@@ -1591,12 +2047,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 15922e672a6..1bdb28f5a11 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,33 +33,34 @@ 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;
+ *default_charset= 0, *current_host= 0;
static int first_error = 0;
DYNAMIC_ARRAY tables4repair;
#ifdef HAVE_SMEM
static char *shared_memory_base_name=0;
#endif
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 +68,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 +82,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 +95,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*) &current_host,
- (gptr*) &current_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"host",'h', "Connect to host.", (uchar**) &current_host,
+ (uchar**) &current_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 +146,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*) &current_user,
- (gptr*) &current_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"user", 'u', "User for login if not current user.", (uchar**) &current_user,
+ (uchar**) &current_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 +196,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,7 +278,16 @@ 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;
+ opt_databases= 1;
+ break;
+ case OPT_FIX_TABLE_NAMES:
+ what_to_do= DO_UPGRADE;
+ break;
case 'p':
+ if (argument == disabled_my_option)
+ argument= (char*) ""; // Don't require password
if (argument)
{
char *start = argument;
@@ -288,6 +315,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 +326,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;
}
@@ -342,11 +365,20 @@ static int get_options(int *argc, char ***argv)
what_to_do = DO_CHECK;
}
- /* TODO: This variable is not yet used */
- if (strcmp(default_charset, charset_info->csname) &&
- !(charset_info= get_charset_by_csname(default_charset,
- MY_CS_PRIMARY, MYF(MY_WME))))
- exit(1);
+ /*
+ If there's no --default-character-set option given with
+ --fix-table-name or --fix-db-name set the default character set to "utf8".
+ */
+ if (!default_charset && (opt_fix_db_names || opt_fix_table_names))
+ {
+ default_charset= (char*) "utf8";
+ }
+ if (default_charset && !get_charset_by_csname(default_charset, MY_CS_PRIMARY,
+ MYF(MY_WME)))
+ {
+ printf("Unsupported character set: %s\n", default_charset);
+ return 1;
+ }
if (*argc > 0 && opt_alldbs)
{
printf("You should give only options, no arguments at all, with option\n");
@@ -363,6 +395,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 +418,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 +431,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;
@@ -536,20 +572,73 @@ 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])
- {
- if ((num_columns == 2) && (strcmp(row[1], "VIEW") == 0))
- continue;
-
- handle_request_for_tables(row[0], fixed_name_length(row[0]));
- }
+ {
+ /* Skip views if we don't perform renaming. */
+ if ((what_to_do != DO_UPGRADE) && (num_columns == 2) && (strcmp(row[1], "VIEW") == 0))
+ continue;
+
+ handle_request_for_tables(row[0], fixed_name_length(row[0]));
+ }
}
mysql_free_result(res);
return 0;
} /* 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 &&
@@ -583,17 +672,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))))
@@ -650,7 +741,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;
@@ -670,7 +761,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);
}
@@ -696,6 +787,8 @@ static int dbConnect(char *host, char *user, char *passwd)
if (shared_memory_base_name)
mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
#endif
+ if (default_charset)
+ mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset);
if (!(sock = mysql_real_connect(&mysql_connection, host, user, passwd,
NULL, opt_mysql_port, opt_mysql_unix_port, 0)))
{
@@ -745,7 +838,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))
@@ -787,6 +880,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 a9d2788de05..323376dd8bf 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2009 Sun Microsystems, Inc.
+/* Copyright 2000-2008 MySQL AB, 2008, 2009 Sun Microsystems, Inc.
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
@@ -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,
@@ -114,8 +118,9 @@ static my_bool server_supports_switching_charsets= TRUE;
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>
@@ -151,7 +156,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",
@@ -176,95 +180,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,
+ "Give less verbose output (useful for debugging). Disables structure comments and header/footer constructs. Enables options --skip-add-drop-table --skip-add-locks --skip-comments --skip-disable-keys --skip-set-charset",
+ (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 "
@@ -275,44 +294,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*) &current_host,
- (gptr*) &current_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**) &current_host,
+ (uchar**) &current_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 "
@@ -324,29 +343,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},
@@ -355,7 +374,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},
@@ -363,38 +382,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
/*
@@ -412,40 +428,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*) &current_user, (gptr*) &current_user, 0, GET_STR, REQUIRED_ARG,
+ (uchar**) &current_user, (uchar**) &current_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}
@@ -472,6 +488,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>
@@ -558,8 +578,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);
@@ -570,7 +592,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 :
"");
@@ -652,18 +676,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= (uint) strlen(entry);
- return (byte*) entry;
+ *length= strlen(entry);
+ return (uchar*) entry;
}
@@ -678,6 +702,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
break;
#endif
case 'p':
+ if (argument == disabled_my_option)
+ argument= (char*) ""; // Don't require password
if (argument)
{
char *start=argument;
@@ -721,7 +747,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);
@@ -762,7 +788,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;
}
@@ -791,7 +817,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
uint size_for_sql_mode= 0;
const char **ptr;
for (ptr= compatible_mode_names; *ptr; ptr++)
- size_for_sql_mode+= (uint) strlen(*ptr);
+ size_for_sql_mode+= strlen(*ptr);
size_for_sql_mode+= sizeof(compatible_mode_names)-1;
DBUG_ASSERT(sizeof(compatible_mode_normal_str)>=size_for_sql_mode);
}
@@ -816,14 +842,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;
}
@@ -844,11 +865,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)))
@@ -856,6 +881,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 */
@@ -1013,6 +1042,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)
+{
+ my_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);
+}
+
+
/**
Switch charset for results to some specified charset. If the server does not
support character_set_results variable, nothing can be done here. As for
@@ -1039,9 +1269,127 @@ static int switch_character_set_results(MYSQL *mysql, const char *cs_name)
"SET SESSION character_set_results = '%s'",
(const char *) cs_name);
- return mysql_real_query(mysql, query_buffer, (uint) query_length);
+ 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
@@ -1078,7 +1426,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);
}
@@ -1372,8 +1720,7 @@ static void print_xml_tag(FILE * xml_file, const char* sbeg,
fputs(attribute_name, xml_file);
fputc('\"', xml_file);
- print_quoted_xml(xml_file, attribute_value,
- (uint) strlen(attribute_value));
+ print_quoted_xml(xml_file, attribute_value, strlen(attribute_value));
fputc('\"', xml_file);
attribute_name= va_arg(arg_list, char *);
@@ -1413,7 +1760,7 @@ static void print_xml_null_tag(FILE * xml_file, const char* sbeg,
fputs("<", xml_file);
fputs(stag_atr, xml_file);
fputs("\"", xml_file);
- print_quoted_xml(xml_file, sval, (uint) strlen(sval));
+ print_quoted_xml(xml_file, sval, strlen(sval));
fputs("\" xsi:nil=\"true\" />", xml_file);
fputs(line_end, xml_file);
check_io(xml_file);
@@ -1463,6 +1810,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.
@@ -1500,7 +2044,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;
@@ -1508,10 +2052,14 @@ 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));
- mysql_real_escape_string(mysql, db_name_buff, db, (uint) strlen(db));
+ mysql_real_escape_string(mysql, db_name_buff, db, strlen(db));
/* nice comments */
if (opt_comments)
@@ -1524,10 +2072,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++)
@@ -1544,9 +2095,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);
@@ -1570,63 +2121,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((uint) strlen(row[2]) + 23);
-
- query_str_tail= strnmov(query_str, row[2],
- (uint) (definer_begin - row[2]));
- query_str_tail= strmov(query_str_tail, "*/ /*!50020");
- query_str_tail= strnmov(query_str_tail, definer_begin,
- (uint) (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 */
@@ -1636,8 +2191,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"));
@@ -1666,13 +2222,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));
@@ -1787,7 +2342,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),
@@ -1805,49 +2362,57 @@ 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]);
- }
- /*
- Stand-in tables are always MyISAM tables as the default
- engine might have a column-limit that's lower than the
- number of columns in the view, and MyISAM support is
- guaranteed to be in the server anyway.
- */
- fprintf(sql_file, "\n) ENGINE=MyISAM */;\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]);
}
+
+ /*
+ Stand-in tables are always MyISAM tables as the default
+ engine might have a column-limit that's lower than the
+ number of columns in the view, and MyISAM support is
+ guaranteed to be in the server anyway.
+ */
+ fprintf(sql_file,
+ "\n) ENGINE=MyISAM */;\n"
+ "SET character_set_client = @saved_cs_client;\n");
+
+ check_io(sql_file);
}
+
mysql_free_result(result);
if (path)
@@ -1886,7 +2451,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);
@@ -1952,7 +2520,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);
@@ -2083,6 +2654,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)
@@ -2153,102 +2725,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);
-/*
+ char name_buff[NAME_LEN * 4 + 3];
+
+ 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);
- dump_triggers_for_table
+ switch_cs_variables(sql_file, ";",
+ row[3], /* character_set_client */
+ row[3], /* character_set_results */
+ row[4]); /* collation_connection */
- 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
+ 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], (uint) 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,
@@ -2365,7 +3054,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 */
@@ -2397,6 +3086,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);
@@ -2455,6 +3156,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;
}
}
@@ -2641,7 +3343,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, "'");
@@ -2710,7 +3412,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);
@@ -2809,8 +3511,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:
@@ -2844,6 +3546,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;
@@ -2928,8 +3887,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];
@@ -2962,10 +3924,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 */
@@ -3010,9 +3972,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);
}
@@ -3037,10 +3999,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");
@@ -3056,16 +4023,29 @@ static int dump_all_tables_in_db(char *database)
while ((table= getTableName(0)))
{
char *end= strmov(afterdot, table);
- if (include_table(hash_key, (uint) (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)
{
@@ -3208,7 +4188,7 @@ 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;
@@ -3237,8 +4217,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;
@@ -3247,14 +4232,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)
@@ -3267,7 +4263,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 */
@@ -3276,6 +4279,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)
@@ -3348,7 +4357,10 @@ static int do_flush_tables_read_lock(MYSQL *mysql_con)
update starts between the two FLUSHes, we have that bad stall.
*/
return
- ( mysql_query_with_error_report(mysql_con, 0, "FLUSH TABLES") ||
+ ( mysql_query_with_error_report(mysql_con, 0,
+ ((opt_master_data != 0) ?
+ "FLUSH /*!40101 LOCAL */ TABLES" :
+ "FLUSH TABLES")) ||
mysql_query_with_error_report(mysql_con, 0,
"FLUSH TABLES WITH READ LOCK") );
}
@@ -3577,7 +4589,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") ||
!strcmp(table_type,"FEDERATED")))
result= IGNORE_DATA;
}
@@ -3639,7 +4652,7 @@ static char *primary_key_fields(const char *table_name)
do
{
quoted_field= quote_name(row[4], buff, 0);
- result_length+= (uint) strlen(quoted_field) + 1; /* + 1 for ',' or \0 */
+ result_length+= strlen(quoted_field) + 1; /* + 1 for ',' or \0 */
} while ((row= mysql_fetch_row(res)) && atoi(row[3]) > 1);
}
@@ -3699,8 +4712,7 @@ static int replace(DYNAMIC_STRING *ds_str,
return 1;
init_dynamic_string_checked(&ds_tmp, "",
ds_str->length + replace_len, 256);
- dynstr_append_mem_checked(&ds_tmp, ds_str->str,
- (uint) (start - ds_str->str));
+ dynstr_append_mem_checked(&ds_tmp, ds_str->str, start - ds_str->str);
dynstr_append_mem_checked(&ds_tmp, replace_str, replace_len);
dynstr_append_checked(&ds_tmp, start + search_len);
dynstr_set_checked(ds_str, ds_tmp.str);
@@ -3747,14 +4759,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);
}
@@ -3784,9 +4804,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))
{
/*
@@ -3816,6 +4838,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);
}
@@ -3843,10 +4868,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];
@@ -3872,12 +4897,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)
{
@@ -3985,16 +5029,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..ec418244f3d 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*) &current_host,
- (gptr*) &current_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"host", 'h', "Connect to host.", (uchar**) &current_host,
+ (uchar**) &current_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*) &current_user,
- (gptr*) &current_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"user", 'u', "User for login if not current user.", (uchar**) &current_user,
+ (uchar**) &current_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}
@@ -170,7 +193,7 @@ static void print_version(void)
static void usage(void)
{
print_version();
- puts("Copyright (C) 2000-2006 MySQL AB");
+ puts("Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.");
puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
printf("\
Loads tables from text files in various formats. The base name of the\n\
@@ -198,6 +221,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
break;
#endif
case 'p':
+ if (argument == disabled_my_option)
+ argument= (char*) ""; // Don't require password
if (argument)
{
char *start=argument;
@@ -218,16 +243,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 +267,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 +300,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 +308,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 +317,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 +363,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 +381,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 +396,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 +471,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 +480,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 +534,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 +593,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 568358b1cda..00000000000
--- a/client/mysqlmanager-pwgen.c
+++ /dev/null
@@ -1,157 +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;
- 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_MD5_HASH(digest,(uchar*) pw,sizeof(pw)-1);
- 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..e401d6cad8f 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.",
@@ -241,7 +249,7 @@ static void print_version(void)
static void usage(void)
{
print_version();
- puts("Copyright (C) 2000-2006 MySQL AB");
+ puts("Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.");
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("Shows the structure of a mysql database (databases,tables and columns)\n");
printf("Usage: %s [OPTIONS] [database [table [column]]]\n",my_progname);
@@ -273,6 +281,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
opt_verbose++;
break;
case 'p':
+ if (argument == disabled_my_option)
+ argument= (char*) ""; // Don't require password
if (argument)
{
char *start=argument;
@@ -292,16 +302,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 +341,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 +753,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 +777,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 +792,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 +818,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..4cf8c7204ed
--- /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 == disabled_my_option)
+ argument= (char*) ""; // Don't require password
+ 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;
+ size_t 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.cc
index 2f19fad9ea9..f29fd36aa27 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.cc
@@ -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 */
@@ -54,14 +48,14 @@
#ifdef __WIN__
#include <direct.h>
#endif
+#include <signal.h>
+#include <my_stacktrace.h>
-
-#ifndef WEXITSTATUS
-# ifdef __WIN__
-# define WEXITSTATUS(stat_val) (stat_val)
-# else
-# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
-# endif
+#ifdef __WIN__
+#include <crtdbg.h>
+#define SIGNAL_FMT "exception 0x%x"
+#else
+#define SIGNAL_FMT "signal %d"
#endif
/* Use cygwin for --exec and --system before 5.0 */
@@ -79,11 +73,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;
@@ -94,6 +86,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;
@@ -114,6 +107,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;
@@ -175,7 +169,8 @@ static ulonglong timer_start;
static void timer_output(void);
static ulonglong timer_now(void);
-static ulonglong progress_start= 0;
+
+static ulong connection_retry_sleep= 100000; /* Microseconds */
/* Precompiled re's */
static my_regex_t ps_re; /* the query can be run using PS protocol */
@@ -190,12 +185,12 @@ DYNAMIC_ARRAY q_lines;
#include "sslopt-vars.h"
-struct
+struct Parser
{
int read_lines,current_line;
} parser;
-struct
+struct MasterPos
{
char file[FN_REFLEN];
ulong pos;
@@ -204,7 +199,7 @@ struct
/* if set, all results are concated and compared against this file */
const char *result_file_name= 0;
-typedef struct st_var
+typedef struct
{
char *name;
int name_len;
@@ -228,6 +223,7 @@ struct st_connection
/* Used when creating views and sp, to avoid implicit commit */
MYSQL* util_mysql;
char *name;
+ size_t name_len;
MYSQL_STMT* stmt;
#ifdef EMBEDDED_LIBRARY
@@ -282,6 +278,8 @@ enum enum_commands {
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_CHANGE_USER, Q_MKDIR, Q_RMDIR,
+ Q_LIST_FILES, Q_LIST_FILES_WRITE_FILE, Q_LIST_FILES_APPEND_FILE,
+ Q_SEND_SHUTDOWN, Q_SHUTDOWN_SERVER,
Q_UNKNOWN, /* Unknown command. */
Q_COMMENT, /* Comments, ignored. */
@@ -373,6 +371,11 @@ const char *command_names[]=
"change_user",
"mkdir",
"rmdir",
+ "list_files",
+ "list_files_write_file",
+ "list_files_append_file",
+ "send_shutdown",
+ "shutdown_server",
0
};
@@ -422,7 +425,7 @@ struct st_command
TYPELIB command_typelib= {array_elements(command_names),"",
command_names, 0};
-DYNAMIC_STRING ds_res, ds_progress, ds_warning_messages;
+DYNAMIC_STRING ds_res;
char builtin_echo[FN_REFLEN];
@@ -432,8 +435,6 @@ void abort_not_supported_test(const char *fmt, ...)
ATTRIBUTE_FORMAT(printf, 1, 2);
void verbose_msg(const char *fmt, ...)
ATTRIBUTE_FORMAT(printf, 1, 2);
-void warning_msg(const char *fmt, ...)
- ATTRIBUTE_FORMAT(printf, 1, 2);
void log_msg(const char *fmt, ...)
ATTRIBUTE_FORMAT(printf, 1, 2);
@@ -446,15 +447,15 @@ VAR* var_get(const char *var_name, const char** var_name_end,
void eval_expr(VAR* v, const char *p, const char** p_end);
my_bool match_delimiter(int c, const char *delim, uint length);
void dump_result_to_reject_file(char *buf, int size);
-void dump_result_to_log_file(char *buf, int size);
void dump_warning_messages();
-void dump_progress();
void do_eval(DYNAMIC_STRING *query_eval, const char *query,
const char *query_end, my_bool pass_through_escape_chars);
void str_to_file(const char *fname, char *str, int size);
void str_to_file2(const char *fname, char *str, int size, my_bool append);
+void fix_win_paths(const char *val, int len);
+
#ifdef __WIN__
void free_tmp_sh_file();
void free_win_path_patterns();
@@ -483,6 +484,177 @@ void free_all_replace(){
}
+class LogFile {
+ FILE* m_file;
+ char m_file_name[FN_REFLEN];
+ size_t m_bytes_written;
+public:
+ LogFile() : m_file(NULL), m_bytes_written(0) {
+ bzero(m_file_name, sizeof(m_file_name));
+ }
+
+ ~LogFile() {
+ close();
+ }
+
+ const char* file_name() const { return m_file_name; }
+ size_t bytes_written() const { return m_bytes_written; }
+
+ void open(const char* dir, const char* name, const char* ext)
+ {
+ DBUG_ENTER("LogFile::open");
+ DBUG_PRINT("enter", ("dir: '%s', name: '%s'",
+ dir, name));
+ if (!name)
+ {
+ m_file= stdout;
+ DBUG_VOID_RETURN;
+ }
+
+ fn_format(m_file_name, name, dir, ext,
+ *dir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
+ MY_REPLACE_EXT);
+
+ DBUG_PRINT("info", ("file_name: %s", m_file_name));
+
+ if ((m_file= fopen(m_file_name, "wb+")) == NULL)
+ die("Failed to open log file %s, errno: %d", m_file_name, errno);
+
+ DBUG_VOID_RETURN;
+ }
+
+ void close()
+ {
+ if (m_file) {
+ if (m_file != stdout)
+ fclose(m_file);
+ else
+ fflush(m_file);
+ }
+ m_file= NULL;
+ }
+
+ void flush()
+ {
+ if (m_file && m_file != stdout)
+ {
+ if (fflush(m_file))
+ die("Failed to flush '%s', errno: %d", m_file_name, errno);
+ }
+ }
+
+ void write(DYNAMIC_STRING* ds)
+ {
+ DBUG_ENTER("LogFile::write");
+ DBUG_ASSERT(m_file);
+
+ if (ds->length == 0)
+ DBUG_VOID_RETURN;
+ DBUG_ASSERT(ds->str);
+
+ if (fwrite(ds->str, 1, ds->length, m_file) != ds->length)
+ die("Failed to write %lu bytes to '%s', errno: %d",
+ (unsigned long)ds->length, m_file_name, errno);
+ m_bytes_written+= ds->length;
+ DBUG_VOID_RETURN;
+ }
+
+ void show_tail(uint lines) {
+ DBUG_ENTER("LogFile::show_tail");
+
+ if (!m_file || m_file == stdout)
+ DBUG_VOID_RETURN;
+
+ if (lines == 0)
+ DBUG_VOID_RETURN;
+ lines++;
+
+ int show_offset= 0;
+ char buf[256];
+ size_t bytes;
+ bool found_bof= false;
+
+ /* Search backward in file until "lines" newline has been found */
+ while (lines && !found_bof)
+ {
+ show_offset-= sizeof(buf);
+ while(fseek(m_file, show_offset, SEEK_END) != 0 && show_offset < 0)
+ {
+ found_bof= true;
+ // Seeking before start of file
+ show_offset++;
+ }
+
+ if ((bytes= fread(buf, 1, sizeof(buf), m_file)) <= 0)
+ {
+ fprintf(stderr, "Failed to read from '%s', errno: %d\n",
+ m_file_name, errno);
+ DBUG_VOID_RETURN;
+ }
+
+ DBUG_PRINT("info", ("Read %lu bytes from file, buf: %s",
+ (unsigned long)bytes, buf));
+
+ char* show_from= buf + bytes;
+ while(show_from > buf && lines > 0 )
+ {
+ show_from--;
+ if (*show_from == '\n')
+ lines--;
+ }
+ if (show_from != buf)
+ {
+ // The last new line was found in this buf, adjust offset
+ show_offset+= (show_from - buf) + 1;
+ DBUG_PRINT("info", ("adjusted offset to %d", show_offset));
+ }
+ DBUG_PRINT("info", ("show_offset: %d", show_offset));
+ }
+
+ fprintf(stderr, "\nThe result from queries just before the failure was:\n");
+
+ DBUG_PRINT("info", ("show_offset: %d", show_offset));
+ if (!lines)
+ {
+ fprintf(stderr, "< snip >\n");
+
+ if (fseek(m_file, show_offset, SEEK_END) != 0)
+ {
+ fprintf(stderr, "Failed to seek to position %d in '%s', errno: %d",
+ show_offset, m_file_name, errno);
+ DBUG_VOID_RETURN;
+ }
+
+ }
+ else {
+ DBUG_PRINT("info", ("Showing the whole file"));
+ if (fseek(m_file, 0L, SEEK_SET) != 0)
+ {
+ fprintf(stderr, "Failed to seek to pos 0 in '%s', errno: %d",
+ m_file_name, errno);
+ DBUG_VOID_RETURN;
+ }
+ }
+
+ while ((bytes= fread(buf, 1, sizeof(buf), m_file)) > 0)
+ fwrite(buf, 1, bytes, stderr);
+
+ if (!lines)
+ {
+ fprintf(stderr,
+ "\nMore results from queries before failure can be found in %s\n",
+ m_file_name);
+ }
+ fflush(stderr);
+
+ DBUG_VOID_RETURN;
+ }
+};
+
+LogFile log_file;
+LogFile progress_file;
+
+
/* Disable functions that only exist in MySQL 4.0 */
#if MYSQL_VERSION_ID < 40000
void mysql_enable_rpl_parse(MYSQL* mysql __attribute__((unused))) {}
@@ -496,6 +668,9 @@ void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val);
void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val);
void dynstr_append_sorted(DYNAMIC_STRING* ds, DYNAMIC_STRING* ds_input);
+static int match_expected_error(struct st_command *command,
+ unsigned int err_errno,
+ const char *err_sqlstate);
void handle_error(struct st_command*,
unsigned int err_errno, const char *err_error,
const char *err_sqlstate, DYNAMIC_STRING *ds);
@@ -619,12 +794,15 @@ void do_eval(DYNAMIC_STRING *query_eval, const char *query,
break;
}
}
+#ifdef __WIN__
+ fix_win_paths(query_eval->str, query_eval->length);
+#endif
DBUG_VOID_RETURN;
}
/*
- Run query and dump the result to stdout in vertical format
+ Run query and dump the result to stderr in vertical format
NOTE! This function should be safe to call when an error
has occured and thus any further errors will be ignored(although logged)
@@ -801,7 +979,7 @@ void check_command_args(struct st_command *command,
ptr++;
if (ptr > start)
{
- init_dynamic_string(arg->ds, 0, (uint) (ptr - start), 32);
+ init_dynamic_string(arg->ds, 0, ptr-start, 32);
do_eval(arg->ds, start, ptr, FALSE);
}
else
@@ -849,29 +1027,25 @@ void check_command_args(struct st_command *command,
DBUG_VOID_RETURN;
}
-
void handle_command_error(struct st_command *command, uint error)
{
DBUG_ENTER("handle_command_error");
DBUG_PRINT("enter", ("error: %d", error));
if (error != 0)
{
- uint i;
+ int i;
if (command->abort_on_error)
die("command \"%.*s\" failed with error %d",
command->first_word_len, command->query, error);
- for (i= 0; i < command->expected_errors.count; i++)
+
+ i= match_expected_error(command, error, NULL);
+
+ if (i >= 0)
{
- DBUG_PRINT("info", ("expected error: %d",
- command->expected_errors.err[i].code.errnum));
- if ((command->expected_errors.err[i].type == ERR_ERRNO) &&
- (command->expected_errors.err[i].code.errnum == error))
- {
- DBUG_PRINT("info", ("command \"%.*s\" failed with expected error: %d",
- command->first_word_len, command->query, error));
- DBUG_VOID_RETURN;
- }
+ DBUG_PRINT("info", ("command \"%.*s\" failed with expected error: %d",
+ command->first_word_len, command->query, error));
+ DBUG_VOID_RETURN;
}
die("command \"%.*s\" failed with wrong error: %d",
command->first_word_len, command->query, error);
@@ -929,7 +1103,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;
@@ -948,8 +1122,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++)
{
@@ -960,8 +1134,6 @@ void free_used_memory()
my_free(embedded_server_args[--embedded_server_arg_count],MYF(0));
delete_dynamic(&q_lines);
dynstr_free(&ds_res);
- dynstr_free(&ds_progress);
- dynstr_free(&ds_warning_messages);
free_all_replace();
my_free(opt_pass,MYF(MY_ALLOW_ZERO_PTR));
free_defaults(default_argv);
@@ -983,12 +1155,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;
@@ -1041,31 +1211,7 @@ void die(const char *fmt, ...)
fprintf(stderr, "\n");
fflush(stderr);
- /* Show results from queries just before failure */
- if (ds_res.length && opt_tail_lines)
- {
- int tail_lines= opt_tail_lines;
- char* show_from= ds_res.str + ds_res.length - 1;
- while(show_from > ds_res.str && tail_lines > 0 )
- {
- show_from--;
- if (*show_from == '\n')
- tail_lines--;
- }
- fprintf(stderr, "\nThe result from queries just before the failure was:\n");
- if (show_from > ds_res.str)
- fprintf(stderr, "< snip >");
- fprintf(stderr, "%s", show_from);
- fflush(stderr);
- }
-
- /* Dump the result that has been accumulated so far to .log file */
- if (result_file_name && ds_res.length)
- dump_result_to_log_file(ds_res.str, ds_res.length);
-
- /* Dump warning messages */
- if (result_file_name && ds_warning_messages.length)
- dump_warning_messages();
+ log_file.show_tail(opt_tail_lines);
/*
Help debugging by displaying any warnings that might have
@@ -1139,41 +1285,6 @@ void verbose_msg(const char *fmt, ...)
}
-void warning_msg(const char *fmt, ...)
-{
- va_list args;
- char buff[512];
- size_t len;
- DBUG_ENTER("warning_msg");
-
- va_start(args, fmt);
- dynstr_append(&ds_warning_messages, "mysqltest: ");
- if (start_lineno != 0)
- {
- dynstr_append(&ds_warning_messages, "Warning detected ");
- if (cur_file && cur_file != file_stack)
- {
- len= my_snprintf(buff, sizeof(buff), "in included file %s ",
- cur_file->file_name);
- dynstr_append_mem(&ds_warning_messages,
- buff, (uint) len);
- }
- len= my_snprintf(buff, sizeof(buff), "at line %d: ",
- start_lineno);
- dynstr_append_mem(&ds_warning_messages,
- buff, (uint) len);
- }
-
- len= my_vsnprintf(buff, sizeof(buff), fmt, args);
- dynstr_append_mem(&ds_warning_messages, buff, (uint) len);
-
- dynstr_append(&ds_warning_messages, "\n");
- va_end(args);
-
- DBUG_VOID_RETURN;
-}
-
-
void log_msg(const char *fmt, ...)
{
va_list args;
@@ -1185,7 +1296,7 @@ void log_msg(const char *fmt, ...)
len= my_vsnprintf(buff, sizeof(buff)-1, fmt, args);
va_end(args);
- dynstr_append_mem(&ds_res, buff, (uint) len);
+ dynstr_append_mem(&ds_res, buff, len);
dynstr_append(&ds_res, "\n");
DBUG_VOID_RETURN;
@@ -1205,12 +1316,12 @@ void log_msg(const char *fmt, ...)
void cat_file(DYNAMIC_STRING* ds, const char* filename)
{
int fd;
- uint len;
+ size_t len;
char buff[512];
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;
@@ -1222,7 +1333,7 @@ void cat_file(DYNAMIC_STRING* ds, const char* filename)
/* Add fake newline instead of cr and output the line */
*p= '\n';
p++; /* Step past the "fake" newline */
- dynstr_append_mem(ds, start, (uint) (p - start));
+ dynstr_append_mem(ds, start, p-start);
p++; /* Step past the "fake" newline */
start= p;
}
@@ -1230,7 +1341,7 @@ void cat_file(DYNAMIC_STRING* ds, const char* filename)
p++;
}
/* Output any chars that migh be left */
- dynstr_append_mem(ds, start, (uint) (p - start));
+ dynstr_append_mem(ds, start, p-start);
}
my_close(fd, MYF(0));
}
@@ -1329,10 +1440,12 @@ static int run_tool(const char *tool_path, DYNAMIC_STRING *ds_res, ...)
DBUG_RETURN(ret);
}
+
/*
Test if diff is present. This is needed on Windows systems
as the OS returns 1 whether diff is successful or if it is
not present.
+ Takes name of diff program as argument
We run diff -v and look for output in stdout.
We don't redirect stderr to stdout to make for a simplified check
@@ -1340,23 +1453,24 @@ static int run_tool(const char *tool_path, DYNAMIC_STRING *ds_res, ...)
not present.
*/
-int diff_check()
+int diff_check (const char *diff_name)
{
- char buf[512]= {0};
- FILE *res_file;
- const char *cmd = "diff -v";
- int have_diff = 0;
+ char buf[512]= {0};
+ FILE *res_file;
+ char cmd[128];
+ my_snprintf (cmd, sizeof(cmd), "%s -v", diff_name);
+ int have_diff = 0;
- if (!(res_file= popen(cmd, "r")))
- die("popen(\"%s\", \"r\") failed", cmd);
+ if (!(res_file= popen(cmd, "r")))
+ die("popen(\"%s\", \"r\") failed", cmd);
-/* if diff is not present, nothing will be in stdout to increment have_diff */
- if (fgets(buf, sizeof(buf), res_file))
- {
- have_diff += 1;
- }
- pclose(res_file);
- return have_diff;
+ /* if diff is not present, nothing will be in stdout to increment have_diff */
+ if (fgets(buf, sizeof(buf), res_file))
+ {
+ have_diff += 1;
+ }
+ pclose(res_file);
+ return have_diff;
}
/*
@@ -1375,13 +1489,12 @@ int diff_check()
void show_diff(DYNAMIC_STRING* ds,
const char* filename1, const char* filename2)
{
-
DYNAMIC_STRING ds_tmp;
- int have_diff = 0;
+ const char *diff_name = 0;
if (init_dynamic_string(&ds_tmp, "", 256, 256))
die("Out of memory");
-
+
/* determine if we have diff on Windows
needs special processing due to return values
on that OS
@@ -1390,15 +1503,20 @@ void show_diff(DYNAMIC_STRING* ds,
the way it's implemented does not work with default 'diff' on Solaris.
*/
#ifdef __WIN__
- have_diff = diff_check();
+ if (diff_check("diff"))
+ diff_name = "diff";
+ else if (diff_check("mtrdiff"))
+ diff_name = "mtrdiff";
+ else
+ diff_name = 0;
#else
- have_diff = 1;
+ diff_name = "diff"; // Otherwise always assume it's called diff
#endif
- if (have_diff)
+ if (diff_name)
{
/* First try with unified diff */
- if (run_tool("diff",
+ if (run_tool(diff_name,
&ds_tmp, /* Get output from diff in ds_tmp */
"-u",
filename1,
@@ -1409,7 +1527,7 @@ void show_diff(DYNAMIC_STRING* ds,
dynstr_set(&ds_tmp, "");
/* Fallback to context diff with "diff -c" */
- if (run_tool("diff",
+ if (run_tool(diff_name,
&ds_tmp, /* Get output from diff in ds_tmp */
"-c",
filename1,
@@ -1417,25 +1535,34 @@ void show_diff(DYNAMIC_STRING* ds,
"2>&1",
NULL) > 1) /* Most "diff" tools return >1 if error */
{
- have_diff= 0;
- }
+ dynstr_set(&ds_tmp, "");
+
+ /* Fallback to simple diff with "diff" */
+ if (run_tool(diff_name,
+ &ds_tmp, /* Get output from diff in ds_tmp */
+ filename1,
+ filename2,
+ "2>&1",
+ NULL) > 1) /* Most "diff" tools return >1 if error */
+ {
+ diff_name= 0;
+ }
+ }
}
- }
+ }
-if (!(have_diff))
+ if (! diff_name)
{
/*
Fallback to dump both files to result file and inform
about installing "diff"
*/
-
- dynstr_set(&ds_tmp, "");
-
- dynstr_append(&ds_tmp,
+ dynstr_append(&ds_tmp, "\n");
+ dynstr_append(&ds_tmp,
"\n"
"The two files differ but it was not possible to execute 'diff' in\n"
-"order to show only the difference, tried both 'diff -u' or 'diff -c'.\n"
-"Instead the whole content of the two files was shown for you to diff manually. ;)\n\n"
+"order to show only the difference. Instead the whole content of the\n"
+"two files was shown for you to diff manually.\n\n"
"To get a better report you should install 'diff' on your system, which you\n"
"for example can get from http://www.gnu.org/software/diffutils/diffutils.html\n"
#ifdef __WIN__
@@ -1443,16 +1570,16 @@ if (!(have_diff))
#endif
"\n");
- dynstr_append(&ds_tmp, " --- ");
- dynstr_append(&ds_tmp, filename1);
- dynstr_append(&ds_tmp, " >>>\n");
- cat_file(&ds_tmp, filename1);
- dynstr_append(&ds_tmp, "<<<\n --- ");
- dynstr_append(&ds_tmp, filename1);
- dynstr_append(&ds_tmp, " >>>\n");
- cat_file(&ds_tmp, filename2);
- dynstr_append(&ds_tmp, "<<<<\n");
- }
+ dynstr_append(&ds_tmp, " --- ");
+ dynstr_append(&ds_tmp, filename1);
+ dynstr_append(&ds_tmp, " >>>\n");
+ cat_file(&ds_tmp, filename1);
+ dynstr_append(&ds_tmp, "<<<\n --- ");
+ dynstr_append(&ds_tmp, filename1);
+ dynstr_append(&ds_tmp, " >>>\n");
+ cat_file(&ds_tmp, filename2);
+ dynstr_append(&ds_tmp, "<<<<\n");
+ }
if (ds)
{
@@ -1494,7 +1621,7 @@ int compare_files2(File fd, const char* filename2)
{
int error= RESULT_OK;
File fd2;
- uint len, len2;
+ size_t len, len2;
char buff[512], buff2[512];
if ((fd2= my_open(filename2, O_RDONLY, MYF(0))) < 0)
@@ -1502,10 +1629,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 */
@@ -1525,7 +1652,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 */
@@ -1594,7 +1721,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)
{
@@ -1615,18 +1742,17 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
/*
- Check the content of ds against result file
+ Check the content of log against result file
SYNOPSIS
check_result
- ds - content to be checked
RETURN VALUES
error - the function will not return
*/
-void check_result(DYNAMIC_STRING* ds)
+void check_result()
{
const char* mess= "Result content mismatch\n";
@@ -1634,11 +1760,7 @@ void check_result(DYNAMIC_STRING* ds)
DBUG_ASSERT(result_file_name);
DBUG_PRINT("enter", ("result_file_name: %s", result_file_name));
- 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 (compare_files(log_file.file_name(), result_file_name)) {
case RESULT_OK:
break; /* ok */
case RESULT_LENGTH_MISMATCH:
@@ -1651,7 +1773,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)
{
@@ -1665,9 +1788,10 @@ void check_result(DYNAMIC_STRING* ds)
fn_format(reject_file, result_file_name, opt_logdir,
".reject", MY_REPLACE_DIR | MY_REPLACE_EXT);
}
- str_to_file(reject_file, ds->str, ds->length);
- dynstr_set(ds, NULL); /* Don't create a .log file */
+ if (my_copy(log_file.file_name(), reject_file, MYF(0)) != 0)
+ die("Failed to copy '%s' to '%s', errno: %d",
+ log_file.file_name(), reject_file, errno);
show_diff(NULL, result_file_name, reject_file);
die(mess);
@@ -1754,13 +1878,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;
}
@@ -1770,9 +1894,9 @@ VAR *var_init(VAR *v, const char *name, int name_len, const char *val,
int val_alloc_len;
VAR *tmp_var;
if (!name_len && name)
- name_len = (uint) strlen(name);
+ name_len = strlen(name);
if (!val_len && val)
- val_len = (uint) strlen(val) ;
+ val_len = strlen(val) ;
val_alloc_len = val_len + 16; /* room to grow */
if (!(tmp_var=v) && !(tmp_var = (VAR*)my_malloc(sizeof(*tmp_var)
+ name_len+1, MYF(MY_WME))))
@@ -1781,7 +1905,7 @@ VAR *var_init(VAR *v, const char *name, int name_len, const char *val,
tmp_var->name = (name) ? (char*) tmp_var + sizeof(*tmp_var) : 0;
tmp_var->alloced = (v == 0);
- if (!(tmp_var->str_val = my_malloc(val_alloc_len+1, MYF(MY_WME))))
+ if (!(tmp_var->str_val = (char*)my_malloc(val_alloc_len+1, MYF(MY_WME))))
die("Out of memory");
memcpy(tmp_var->name, name, name_len);
@@ -1804,7 +1928,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));
}
@@ -1815,8 +1939,8 @@ VAR* var_from_env(const char *name, const char *def_val)
if (!(tmp = getenv(name)))
tmp = def_val;
- v = var_init(0, name, (uint) strlen(name), tmp, (uint) strlen(tmp));
- my_hash_insert(&var_hash, (byte*)v);
+ v = var_init(0, name, strlen(name), tmp, strlen(tmp));
+ my_hash_insert(&var_hash, (uchar*)v);
return v;
}
@@ -1849,7 +1973,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);
@@ -1864,7 +1989,7 @@ VAR* var_get(const char *var_name, const char **var_name_end, my_bool raw,
{
sprintf(v->str_val, "%d", v->int_val);
v->int_dirty = 0;
- v->str_val_len = (uint) strlen(v->str_val);
+ v->str_val_len = strlen(v->str_val);
}
if (var_name_end)
*var_name_end = var_name ;
@@ -1880,10 +2005,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;
}
@@ -1927,7 +2052,7 @@ void var_set(const char *var_name, const char *var_name_end,
{
sprintf(v->str_val, "%d", v->int_val);
v->int_dirty= 0;
- v->str_val_len= (uint) strlen(v->str_val);
+ v->str_val_len= strlen(v->str_val);
}
my_snprintf(buf, sizeof(buf), "%.*s=%.*s",
v->name_len, v->name,
@@ -1935,7 +2060,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;
}
@@ -1965,6 +2090,7 @@ void var_set_errno(int sql_errno)
var_set_int("$mysql_errno", sql_errno);
}
+
/*
Set variable from the result of a query
@@ -2006,7 +2132,7 @@ void var_query_set(VAR *var, const char *query, const char** query_end)
++query;
/* Eval the query, thus replacing all environment variables */
- init_dynamic_string(&ds_query, 0, (uint) ((end - query) + 32), 256);
+ init_dynamic_string(&ds_query, 0, (end - query) + 32, 256);
do_eval(&ds_query, query, end, FALSE);
if (mysql_real_query(mysql, ds_query.str, ds_query.length))
@@ -2082,9 +2208,9 @@ void var_set_query_get_value(struct st_command *command, VAR *var)
static DYNAMIC_STRING ds_col;
static DYNAMIC_STRING ds_row;
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",
+ {"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"}
};
DBUG_ENTER("var_set_query_get_value");
@@ -2181,8 +2307,8 @@ void var_copy(VAR *dest, VAR *src)
/* Alloc/realloc data for str_val in dest */
if (dest->alloced_len < src->alloced_len &&
!(dest->str_val= dest->str_val
- ? my_realloc(dest->str_val, src->alloced_len, MYF(MY_WME))
- : my_malloc(src->alloced_len, MYF(MY_WME))))
+ ? (char*)my_realloc(dest->str_val, src->alloced_len, MYF(MY_WME))
+ : (char*)my_malloc(src->alloced_len, MYF(MY_WME))))
die("Out of memory");
else
dest->alloced_len= src->alloced_len;
@@ -2203,8 +2329,16 @@ void eval_expr(VAR *v, const char *p, const char **p_end)
if (*p == '$')
{
VAR *vp;
+ const char* expected_end= *p_end; // Remember var end
if ((vp= var_get(p, p_end, 0, 0)))
var_copy(v, vp);
+
+ /* Make sure there was just a $variable and nothing else */
+ const char* end= *p_end + 1;
+ if (end < expected_end)
+ die("Found junk '%.*s' after $variable in expression",
+ (int)(expected_end - end - 1), end);
+
DBUG_VOID_RETURN;
}
@@ -2223,7 +2357,7 @@ void eval_expr(VAR *v, const char *p, const char **p_end)
struct st_command command;
memset(&command, 0, sizeof(command));
command.query= (char*)p;
- command.first_word_len= (uint) len;
+ command.first_word_len= len;
command.first_argument= command.query + len;
command.end= (char*)*p_end;
var_set_query_get_value(&command, v);
@@ -2240,9 +2374,9 @@ void eval_expr(VAR *v, const char *p, const char **p_end)
v->alloced_len = (new_val_len < MIN_VAR_ALLOC - 1) ?
MIN_VAR_ALLOC : new_val_len + 1;
if (!(v->str_val =
- v->str_val ? my_realloc(v->str_val, v->alloced_len+1,
- MYF(MY_WME)) :
- my_malloc(v->alloced_len+1, MYF(MY_WME))))
+ v->str_val ?
+ (char*)my_realloc(v->str_val, v->alloced_len+1, MYF(MY_WME)) :
+ (char*)my_malloc(v->alloced_len+1, MYF(MY_WME))))
die("Out of memory");
}
v->str_val_len = new_val_len;
@@ -2259,8 +2393,19 @@ void eval_expr(VAR *v, const char *p, const char **p_end)
int open_file(const char *name)
{
char buff[FN_REFLEN];
+ size_t length;
DBUG_ENTER("open_file");
DBUG_PRINT("enter", ("name: %s", name));
+
+ /* Extract path from current file and try it as base first */
+ if (dirname_part(buff, cur_file->file_name, &length))
+ {
+ strxmov(buff, buff, name, NullS);
+ if (access(buff, F_OK) == 0){
+ DBUG_PRINT("info", ("The file exists"));
+ name= buff;
+ }
+ }
if (!test_if_hard_path(name))
{
strxmov(buff, opt_basedir, name, NullS);
@@ -2274,7 +2419,7 @@ int open_file(const char *name)
if (!(cur_file->file = my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0))))
{
cur_file--;
- die("Could not open file '%s'", buff);
+ die("Could not open '%s' for reading, errno: %d", buff, errno);
}
cur_file->file_name= my_strdup(buff, MYF(MY_FAE));
cur_file->lineno=1;
@@ -2300,7 +2445,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");
@@ -2367,9 +2512,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));
@@ -2413,7 +2559,7 @@ static int replace(DYNAMIC_STRING *ds_str,
return 1;
init_dynamic_string(&ds_tmp, "",
ds_str->length + replace_len, 256);
- dynstr_append_mem(&ds_tmp, ds_str->str, (uint) (start - ds_str->str));
+ dynstr_append_mem(&ds_tmp, ds_str->str, start - ds_str->str);
dynstr_append_mem(&ds_tmp, replace_str, replace_len);
dynstr_append(&ds_tmp, start + search_len);
dynstr_set(ds_str, ds_tmp.str);
@@ -2468,7 +2614,7 @@ void do_exec(struct st_command *command)
if (builtin_echo[0] && strncmp(cmd, "echo", 4) == 0)
{
/* Replace echo with our "builtin" echo */
- replace(&ds_cmd, "echo", 4, builtin_echo, (uint) strlen(builtin_echo));
+ replace(&ds_cmd, "echo", 4, builtin_echo, strlen(builtin_echo));
}
#ifdef __WIN__
@@ -2486,7 +2632,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))
{
@@ -2503,33 +2652,32 @@ void do_exec(struct st_command *command)
error= pclose(res_file);
if (error > 0)
{
- uint status= WEXITSTATUS(error), i;
- my_bool ok= 0;
+ uint status= WEXITSTATUS(error);
+ int i;
if (command->abort_on_error)
{
log_msg("exec of '%s' failed, error: %d, status: %d, errno: %d",
ds_cmd.str, error, status, errno);
- die("command \"%s\" failed", command->first_argument);
+ dynstr_free(&ds_cmd);
+ die("command \"%s\" failed\n\nOutput from before failure:\n%s\n",
+ command->first_argument, ds_res.str);
}
DBUG_PRINT("info",
("error: %d, status: %d", error, status));
- for (i= 0; i < command->expected_errors.count; i++)
+
+ i= match_expected_error(command, status, NULL);
+
+ if (i >= 0)
+ DBUG_PRINT("info", ("command \"%s\" failed with expected error: %d",
+ command->first_argument, status));
+ else
{
- DBUG_PRINT("info", ("expected error: %d",
- command->expected_errors.err[i].code.errnum));
- if ((command->expected_errors.err[i].type == ERR_ERRNO) &&
- (command->expected_errors.err[i].code.errnum == status))
- {
- ok= 1;
- DBUG_PRINT("info", ("command \"%s\" failed with expected error: %d",
- command->first_argument, status));
- }
- }
- 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)
@@ -2537,6 +2685,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);
}
@@ -2558,7 +2707,7 @@ enum enum_operator
SYNOPSIS
do_modify_var()
query called command
- operator operation to perform on the var
+ op operation to perform on the var
DESCRIPTION
dec $var_name
@@ -2567,7 +2716,7 @@ enum enum_operator
*/
int do_modify_var(struct st_command *command,
- enum enum_operator operator)
+ enum enum_operator op)
{
const char *p= command->first_argument;
VAR* v;
@@ -2577,7 +2726,7 @@ int do_modify_var(struct st_command *command,
die("The argument to %.*s must be a variable (start with $)",
command->first_word_len, command->query);
v= var_get(p, &p, 1, 0);
- switch (operator) {
+ switch (op) {
case DO_DEC:
v->int_val--;
break;
@@ -2686,7 +2835,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");
@@ -2720,8 +2869,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");
@@ -2757,8 +2906,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");
@@ -2795,7 +2944,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");
@@ -2827,7 +2976,7 @@ void do_mkdir(struct st_command *command)
int error;
static DYNAMIC_STRING ds_dirname;
const struct command_arg mkdir_args[] = {
- "dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to create"
+ {"dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to create"}
};
DBUG_ENTER("do_mkdir");
@@ -2857,7 +3006,7 @@ void do_rmdir(struct st_command *command)
int error;
static DYNAMIC_STRING ds_dirname;
const struct command_arg rmdir_args[] = {
- "dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to remove"
+ {"dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to remove"}
};
DBUG_ENTER("do_rmdir");
@@ -2874,6 +3023,126 @@ void do_rmdir(struct st_command *command)
/*
+ SYNOPSIS
+ get_list_files
+ ds output
+ ds_dirname dir to list
+ ds_wild wild-card file pattern (can be empty)
+
+ DESCRIPTION
+ list all entries in directory (matching ds_wild if given)
+*/
+
+static int get_list_files(DYNAMIC_STRING *ds, const DYNAMIC_STRING *ds_dirname,
+ const DYNAMIC_STRING *ds_wild)
+{
+ uint i;
+ MY_DIR *dir_info;
+ FILEINFO *file;
+ DBUG_ENTER("get_list_files");
+
+ DBUG_PRINT("info", ("listing directory: %s", ds_dirname->str));
+ /* Note that my_dir sorts the list if not given any flags */
+ if (!(dir_info= my_dir(ds_dirname->str, MYF(0))))
+ DBUG_RETURN(1);
+ for (i= 0; i < (uint) dir_info->number_off_files; i++)
+ {
+ file= dir_info->dir_entry + i;
+ if (file->name[0] == '.' &&
+ (file->name[1] == '\0' ||
+ (file->name[1] == '.' && file->name[2] == '\0')))
+ continue; /* . or .. */
+ if (ds_wild && ds_wild->length &&
+ wild_compare(file->name, ds_wild->str, 0))
+ continue;
+ dynstr_append(ds, file->name);
+ dynstr_append(ds, "\n");
+ }
+ my_dirend(dir_info);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ SYNOPSIS
+ do_list_files
+ command called command
+
+ DESCRIPTION
+ list_files <dir_name> [<file_name>]
+ List files and directories in directory <dir_name> (like `ls`)
+ [Matching <file_name>, where wild-cards are allowed]
+*/
+
+static void do_list_files(struct st_command *command)
+{
+ int error;
+ static DYNAMIC_STRING ds_dirname;
+ static DYNAMIC_STRING ds_wild;
+ const struct command_arg list_files_args[] = {
+ {"dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to list"},
+ {"file", ARG_STRING, FALSE, &ds_wild, "Filename (incl. wildcard)"}
+ };
+ DBUG_ENTER("do_list_files");
+
+ check_command_args(command, command->first_argument,
+ list_files_args,
+ sizeof(list_files_args)/sizeof(struct command_arg), ' ');
+
+ error= get_list_files(&ds_res, &ds_dirname, &ds_wild);
+ handle_command_error(command, error);
+ dynstr_free(&ds_dirname);
+ dynstr_free(&ds_wild);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ SYNOPSIS
+ do_list_files_write_file_command
+ command called command
+ append append file, or create new
+
+ DESCRIPTION
+ list_files_{write|append}_file <filename> <dir_name> [<match_file>]
+ List files and directories in directory <dir_name> (like `ls`)
+ [Matching <match_file>, where wild-cards are allowed]
+
+ Note: File will be truncated if exists and append is not true.
+*/
+
+static void do_list_files_write_file_command(struct st_command *command,
+ my_bool append)
+{
+ int error;
+ static DYNAMIC_STRING ds_content;
+ static DYNAMIC_STRING ds_filename;
+ static DYNAMIC_STRING ds_dirname;
+ static DYNAMIC_STRING ds_wild;
+ const struct command_arg list_files_args[] = {
+ {"filename", ARG_STRING, TRUE, &ds_filename, "Filename for write"},
+ {"dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to list"},
+ {"file", ARG_STRING, FALSE, &ds_wild, "Filename (incl. wildcard)"}
+ };
+ DBUG_ENTER("do_list_files_write_file");
+
+ check_command_args(command, command->first_argument,
+ list_files_args,
+ sizeof(list_files_args)/sizeof(struct command_arg), ' ');
+
+ init_dynamic_string(&ds_content, "", 1024, 1024);
+ error= get_list_files(&ds_content, &ds_dirname, &ds_wild);
+ handle_command_error(command, error);
+ str_to_file2(ds_filename.str, ds_content.str, ds_content.length, append);
+ dynstr_free(&ds_content);
+ dynstr_free(&ds_filename);
+ dynstr_free(&ds_dirname);
+ dynstr_free(&ds_wild);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
Read characters from line buffer or file. This is needed to allow
my_ungetc() to buffer MAX_DELIMITER_LENGTH characters for a file
@@ -2902,8 +3171,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);
@@ -2952,8 +3221,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");
@@ -3064,7 +3333,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");
@@ -3101,8 +3370,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");
@@ -3112,6 +3381,14 @@ void do_diff_files(struct st_command *command)
sizeof(diff_file_args)/sizeof(struct command_arg),
' ');
+ if (access(ds_filename.str, F_OK) != 0)
+ die("command \"diff_files\" failed, file '%s' does not exist",
+ ds_filename.str);
+
+ if (access(ds_filename2.str, F_OK) != 0)
+ die("command \"diff_files\" failed, file '%s' does not exist",
+ ds_filename2.str);
+
if ((error= compare_files(ds_filename.str, ds_filename2.str)))
{
/* Compare of the two files failed, append them to output
@@ -3172,7 +3449,7 @@ 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;
}
@@ -3270,7 +3547,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");
@@ -3397,24 +3674,19 @@ void do_wait_for_slave_to_stop(struct st_command *c __attribute__((unused)))
}
-void do_sync_with_master2(long offset)
+void do_sync_with_master2(struct st_command *command, long offset)
{
MYSQL_RES *res;
MYSQL_ROW row;
MYSQL *mysql= &cur_con->mysql;
char query_buf[FN_REFLEN+128];
- int tries= 0;
- int rpl_parse;
+ int timeout= 300; /* seconds */
if (!master_pos.file[0])
die("Calling 'sync_with_master' without calling 'save_master_pos'");
- rpl_parse= mysql_rpl_parse_enabled(mysql);
- mysql_disable_rpl_parse(mysql);
- sprintf(query_buf, "select master_pos_wait('%s', %ld)", master_pos.file,
- master_pos.pos + offset);
-
-wait_for_position:
+ sprintf(query_buf, "select master_pos_wait('%s', %ld, %d)",
+ master_pos.file, master_pos.pos + offset, timeout);
if (mysql_query(mysql, query_buf))
die("failed in '%s': %d: %s", query_buf, mysql_errno(mysql),
@@ -3423,31 +3695,52 @@ 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])
+ }
+
+ int result= -99;
+ const char* result_str= row[0];
+ if (result_str)
+ result= atoi(result_str);
+
+ mysql_free_result(res);
+
+ if (!result_str || result < 0)
{
- /*
- It may be that the slave SQL thread has not started yet, though START
- SLAVE has been issued ?
- */
- if (tries++ == 30)
+ /* master_pos_wait returned NULL or < 0 */
+ show_query(mysql, "SHOW MASTER STATUS");
+ show_query(mysql, "SHOW SLAVE STATUS");
+ show_query(mysql, "SHOW PROCESSLIST");
+ fprintf(stderr, "analyze: sync_with_master\n");
+
+ if (!result_str)
{
- show_query(mysql, "SHOW MASTER STATUS");
- show_query(mysql, "SHOW SLAVE STATUS");
- die("could not sync with master ('%s' returned NULL)", query_buf);
+ /*
+ master_pos_wait returned NULL. This indicates that
+ slave SQL thread is not started, the slave's master
+ information is not initialized, the arguments are
+ incorrect, or an error has occured
+ */
+ die("%.*s failed: '%s' returned NULL "\
+ "indicating slave SQL thread failure",
+ command->first_word_len, command->query, query_buf);
+
}
- sleep(1); /* So at most we will wait 30 seconds and make 31 tries */
- mysql_free_result(res);
- goto wait_for_position;
+
+ if (result == -1)
+ die("%.*s failed: '%s' returned -1 "\
+ "indicating timeout after %d seconds",
+ command->first_word_len, command->query, query_buf, timeout);
+ else
+ die("%.*s failed: '%s' returned unknown result :%d",
+ command->first_word_len, command->query, query_buf, result);
}
- mysql_free_result(res);
- if (rpl_parse)
- mysql_enable_rpl_parse(mysql);
return;
}
-
void do_sync_with_master(struct st_command *command)
{
long offset= 0;
@@ -3462,7 +3755,7 @@ void do_sync_with_master(struct st_command *command)
die("Invalid integer argument \"%s\"", offset_start);
command->last_argument= p;
}
- do_sync_with_master2(offset);
+ do_sync_with_master2(command, offset);
return;
}
@@ -3478,6 +3771,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);
@@ -3502,7 +3796,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;
@@ -3605,9 +3899,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;
@@ -3635,7 +3929,7 @@ int do_save_master_pos()
if (rpl_parse)
mysql_enable_rpl_parse(mysql);
- return 0;
+ DBUG_RETURN(0);
}
@@ -3811,6 +4105,145 @@ void do_set_charset(struct st_command *command)
}
+/*
+ Run query and return one field in the result set from the
+ first row and <column>
+*/
+
+int query_get_string(MYSQL* mysql, const char* query,
+ int column, DYNAMIC_STRING* ds)
+{
+ MYSQL_RES *res= NULL;
+ MYSQL_ROW row;
+
+ if (mysql_query(mysql, query))
+ die("'%s' failed: %d %s", query,
+ mysql_errno(mysql), mysql_error(mysql));
+ if ((res= mysql_store_result(mysql)) == NULL)
+ die("Failed to store result: %d %s",
+ mysql_errno(mysql), mysql_error(mysql));
+
+ if ((row= mysql_fetch_row(res)) == NULL)
+ {
+ mysql_free_result(res);
+ ds= 0;
+ return 1;
+ }
+ init_dynamic_string(ds, (row[column] ? row[column] : "NULL"), ~0, 32);
+ mysql_free_result(res);
+ return 0;
+}
+
+
+static int my_kill(int pid, int sig)
+{
+#ifdef __WIN__
+ HANDLE proc;
+ if ((proc= OpenProcess(PROCESS_TERMINATE, FALSE, pid)) == NULL)
+ return -1;
+ if (sig == 0)
+ {
+ CloseHandle(proc);
+ return 0;
+ }
+ (void)TerminateProcess(proc, 201);
+ CloseHandle(proc);
+ return 1;
+#else
+ return kill(pid, sig);
+#endif
+}
+
+
+
+/*
+ Shutdown the server of current connection and
+ make sure it goes away within <timeout> seconds
+
+ NOTE! Currently only works with local server
+
+ SYNOPSIS
+ do_shutdown_server()
+ command called command
+
+ DESCRIPTION
+ shutdown [<timeout>]
+
+*/
+
+void do_shutdown_server(struct st_command *command)
+{
+ int timeout=60, pid;
+ DYNAMIC_STRING ds_pidfile_name;
+ MYSQL* mysql = &cur_con->mysql;
+ static DYNAMIC_STRING ds_timeout;
+ const struct command_arg shutdown_args[] = {
+ {"timeout", ARG_STRING, FALSE, &ds_timeout, "Timeout before killing server"}
+ };
+ DBUG_ENTER("do_shutdown_server");
+
+ check_command_args(command, command->first_argument, shutdown_args,
+ sizeof(shutdown_args)/sizeof(struct command_arg),
+ ' ');
+
+ if (ds_timeout.length)
+ {
+ timeout= atoi(ds_timeout.str);
+ if (timeout == 0)
+ die("Illegal argument for timeout: '%s'", ds_timeout.str);
+ }
+ dynstr_free(&ds_timeout);
+
+ /* Get the servers pid_file name and use it to read pid */
+ if (query_get_string(mysql, "SHOW VARIABLES LIKE 'pid_file'", 1,
+ &ds_pidfile_name))
+ die("Failed to get pid_file from server");
+
+ /* Read the pid from the file */
+ {
+ int fd;
+ char buff[32];
+
+ if ((fd= my_open(ds_pidfile_name.str, O_RDONLY, MYF(0))) < 0)
+ die("Failed to open file '%s'", ds_pidfile_name.str);
+ dynstr_free(&ds_pidfile_name);
+
+ if (my_read(fd, (uchar*)&buff,
+ sizeof(buff), MYF(0)) <= 0){
+ my_close(fd, MYF(0));
+ die("pid file was empty");
+ }
+ my_close(fd, MYF(0));
+
+ pid= atoi(buff);
+ if (pid == 0)
+ die("Pidfile didn't contain a valid number");
+ }
+ DBUG_PRINT("info", ("Got pid %d", pid));
+
+ /* Tell server to shutdown if timeout > 0*/
+ if (timeout && mysql_shutdown(mysql, SHUTDOWN_DEFAULT))
+ die("mysql_shutdown failed");
+
+ /* Check that server dies */
+ while(timeout--){
+ if (my_kill(pid, 0) < 0){
+ DBUG_PRINT("info", ("Process %d does not exist anymore", pid));
+ DBUG_VOID_RETURN;
+ }
+ DBUG_PRINT("info", ("Sleeping, timeout: %d", timeout));
+ my_sleep(1000000L);
+ }
+
+ /* Kill the server */
+ DBUG_PRINT("info", ("Killing server, pid: %d", pid));
+ (void)my_kill(pid, 9);
+
+ DBUG_VOID_RETURN;
+
+}
+
+
#if MYSQL_VERSION_ID >= 50000
/* List of error names to error codes, available from 5.0 */
typedef struct
@@ -4074,62 +4507,73 @@ void set_reconnect(MYSQL* mysql, int val)
}
-int select_connection_name(const char *name)
+/**
+ Change the current connection to the given st_connection, and update
+ $mysql_get_server_version and $CURRENT_CONNECTION accordingly.
+*/
+void set_current_connection(struct st_connection *con)
{
- DBUG_ENTER("select_connection2");
+ cur_con= con;
+ /* Update $mysql_get_server_version to that of current connection */
+ var_set_int("$mysql_get_server_version",
+ mysql_get_server_version(&con->mysql));
+ /* Update $CURRENT_CONNECTION to the name of the current connection */
+ var_set_string("$CURRENT_CONNECTION", con->name);
+}
+
+
+void select_connection_name(const char *name)
+{
+ DBUG_ENTER("select_connection_name");
DBUG_PRINT("enter",("name: '%s'", name));
+ st_connection *con= find_connection_by_name(name);
- if (!(cur_con= find_connection_by_name(name)))
+ if (!con)
die("connection '%s' not found in connection pool", name);
- DBUG_RETURN(0);
+
+ set_current_connection(con);
+
+ DBUG_VOID_RETURN;
}
-int select_connection(struct st_command *command)
+void select_connection(struct st_command *command)
{
- int ret;
- char *p= command->first_argument;
+ DBUG_ENTER("select_connection");
static DYNAMIC_STRING ds_connection;
const struct command_arg connection_args[] = {
{ "connection_name", ARG_STRING, TRUE, &ds_connection, "Name of the connection that we switch to." }
};
- DBUG_ENTER("select_connection");
-
- if (!*p)
- die("Missing connection name in connect");
-
check_command_args(command, command->first_argument, connection_args,
sizeof(connection_args)/sizeof(struct command_arg),
',');
DBUG_PRINT("info", ("changing connection: %s", ds_connection.str));
-
- ret= select_connection_name(ds_connection.str);
+ select_connection_name(ds_connection.str);
dynstr_free(&ds_connection);
- return ret;
+ DBUG_VOID_RETURN;
}
void do_close_connection(struct st_command *command)
{
- char *p= command->first_argument, *name;
- struct st_connection *con;
-
DBUG_ENTER("close_connection");
- DBUG_PRINT("enter",("name: '%s'",p));
- if (!*p)
- die("Missing connection name in disconnect");
- name= p;
- while (*p && !my_isspace(charset_info,*p))
- p++;
+ struct st_connection *con;
+ static DYNAMIC_STRING ds_connection;
+ const struct command_arg close_connection_args[] = {
+ { "connection_name", ARG_STRING, TRUE, &ds_connection,
+ "Name of the connection to close." }
+ };
+ check_command_args(command, command->first_argument,
+ close_connection_args,
+ sizeof(close_connection_args)/sizeof(struct command_arg),
+ ' ');
- if (*p)
- *p++= 0;
- command->last_argument= p;
+ DBUG_PRINT("enter",("connection name: '%s'", ds_connection.str));
- if (!(con= find_connection_by_name(name)))
- die("connection '%s' not found in connection pool", name);
+ if (!(con= find_connection_by_name(ds_connection.str)))
+ die("connection '%s' not found in connection pool", ds_connection.str);
DBUG_PRINT("info", ("Closing connection %s", con->name));
#ifndef EMBEDDED_LIBRARY
@@ -4168,6 +4612,13 @@ void do_close_connection(struct st_command *command)
if (!(con->name = my_strdup("-closed_connection-", MYF(MY_WME))))
die("Out of memory");
+ if (con == cur_con)
+ {
+ /* Current connection was closed */
+ var_set_int("$mysql_get_server_version", 0xFFFFFFFF);
+ var_set_string("$CURRENT_CONNECTION", con->name);
+ }
+
DBUG_VOID_RETURN;
}
@@ -4202,9 +4653,12 @@ void safe_connect(MYSQL* mysql, const char *name, const char *host,
int port, const char *sock)
{
int failed_attempts= 0;
- static ulong connection_retry_sleep= 100000; /* Microseconds */
DBUG_ENTER("safe_connect");
+
+ verbose_msg("Connecting to server %s:%d (socket %s) as '%s'"
+ ", connection '%s', attempt %d ...",
+ host, port, sock, user, name, failed_attempts);
while(!mysql_real_connect(mysql, host,user, pass, db, port, sock,
CLIENT_MULTI_STATEMENTS | CLIENT_REMEMBER_OPTIONS))
{
@@ -4236,6 +4690,7 @@ void safe_connect(MYSQL* mysql, const char *name, const char *host,
}
failed_attempts++;
}
+ verbose_msg("... Connected.");
DBUG_VOID_RETURN;
}
@@ -4269,6 +4724,7 @@ int connect_n_handle_errors(struct st_command *command,
const char* db, int port, const char* sock)
{
DYNAMIC_STRING *ds;
+ int failed_attempts= 0;
ds= &ds_res;
@@ -4297,14 +4753,48 @@ int connect_n_handle_errors(struct st_command *command,
dynstr_append_mem(ds, delimiter, delimiter_length);
dynstr_append_mem(ds, "\n", 1);
}
- if (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0,
+ while (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0,
CLIENT_MULTI_STATEMENTS))
{
+ /*
+ If we have used up all our connections check whether this
+ is expected (by --error). If so, handle the error right away.
+ Otherwise, give it some extra time to rule out race-conditions.
+ If extra-time doesn't help, we have an unexpected error and
+ must abort -- just proceeding to handle_error() when second
+ and third chances are used up will handle that for us.
+
+ There are various user-limits of which only max_user_connections
+ and max_connections_per_hour apply at connect time. For the
+ the second to create a race in our logic, we'd need a limits
+ test that runs without a FLUSH for longer than an hour, so we'll
+ stay clear of trying to work out which exact user-limit was
+ exceeded.
+ */
+
+ if (((mysql_errno(con) == ER_TOO_MANY_USER_CONNECTIONS) ||
+ (mysql_errno(con) == ER_USER_LIMIT_REACHED)) &&
+ (failed_attempts++ < opt_max_connect_retries))
+ {
+ int i;
+
+ i= match_expected_error(command, mysql_errno(con), mysql_sqlstate(con));
+
+ if (i >= 0)
+ goto do_handle_error; /* expected error, handle */
+
+ my_sleep(connection_retry_sleep); /* unexpected error, wait */
+ continue; /* and give it 1 more chance */
+ }
+
+do_handle_error:
+ var_set_errno(mysql_errno(con));
handle_error(command, mysql_errno(con), mysql_error(con),
mysql_sqlstate(con), ds);
return 0; /* Not connected */
}
+ var_set_errno(0);
handle_no_error(command);
return 1; /* Connected */
}
@@ -4339,7 +4829,7 @@ void do_connect(struct st_command *command)
{
int con_port= opt_port;
char *con_options;
- bool con_ssl= 0, con_compress= 0;
+ my_bool con_ssl= 0, con_compress= 0;
struct st_connection* con_slot;
static DYNAMIC_STRING ds_connection_name;
@@ -4351,18 +4841,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");
@@ -4483,8 +4969,9 @@ void do_connect(struct st_command *command)
ds_connection_name.str));
if (!(con_slot->name= my_strdup(ds_connection_name.str, MYF(MY_WME))))
die("Out of memory");
- cur_con= con_slot;
-
+ con_slot->name_len= strlen(con_slot->name);
+ set_current_connection(con_slot);
+
if (con_slot == next_con)
next_con++; /* if we used the next_con slot, advance the pointer */
}
@@ -4634,7 +5121,7 @@ void do_delimiter(struct st_command* command)
die("Can't set empty delimiter");
strmake(delimiter, p, sizeof(delimiter) - 1);
- delimiter_length= (uint) strlen(delimiter);
+ delimiter_length= strlen(delimiter);
DBUG_PRINT("exit", ("delimiter: %s", delimiter));
command->last_argument= p + delimiter_length;
@@ -4720,7 +5207,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)
{
@@ -4760,11 +5247,9 @@ int read_line(char *buf, int size)
}
else if ((c == '{' &&
(!my_strnncoll_simple(charset_info, (const uchar*) "while", 5,
- (uchar*) buf, min(5, (uint) (p - buf)),
- 0) ||
+ (uchar*) buf, min(5, p - buf), 0) ||
!my_strnncoll_simple(charset_info, (const uchar*) "if", 2,
- (uchar*) buf, min(2, (uint) (p - buf)),
- 0))))
+ (uchar*) buf, min(2, p - buf), 0))))
{
/* Only if and while commands can be terminated by { */
*p++= c;
@@ -4941,55 +5426,6 @@ void convert_to_format_v1(char* query)
/*
- Check a command that is about to be sent (or should have been
- sent if parsing was enabled) to mysql server for
- suspicious things and generate warnings.
-*/
-
-void scan_command_for_warnings(struct st_command *command)
-{
- const char *ptr= command->query;
- DBUG_ENTER("scan_command_for_warnings");
- DBUG_PRINT("enter", ("query: %s", command->query));
-
- while(*ptr)
- {
- /*
- Look for query's that lines that start with a -- comment
- and has a mysqltest command
- */
- if (ptr[0] == '\n' &&
- ptr[1] && ptr[1] == '-' &&
- ptr[2] && ptr[2] == '-' &&
- ptr[3])
- {
- uint type;
- char save;
- char *end, *start= (char*)ptr+3;
- /* Skip leading spaces */
- while (*start && my_isspace(charset_info, *start))
- start++;
- end= start;
- /* Find end of command(next space) */
- while (*end && !my_isspace(charset_info, *end))
- end++;
- save= *end;
- *end= 0;
- DBUG_PRINT("info", ("Checking '%s'", start));
- type= find_type(start, &command_typelib, 1+2);
- if (type)
- warning_msg("Embedded mysqltest command '--%s' detected in "
- "query '%s' was this intentional? ",
- start, command->query);
- *end= save;
- }
-
- ptr++;
- }
- DBUG_VOID_RETURN;
-}
-
-/*
Check for unexpected "junk" after the end of query
This is normally caused by missing delimiters or when
switching between different delimiters
@@ -5046,6 +5482,19 @@ void check_eol_junk(const char *eol)
}
+bool is_delimiter(const char* p)
+{
+ uint match= 0;
+ char* delim= delimiter;
+ while (*p && *p == *delim++)
+ {
+ match++;
+ p++;
+ }
+
+ return (match == delimiter_length);
+}
+
/*
Create a command from a set of lines
@@ -5075,13 +5524,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;
@@ -5112,9 +5561,11 @@ int read_command(struct st_command** command_ptr)
if (!(command->query_buf= command->query= my_strdup(p, MYF(MY_WME))))
die("Out of memory");
- /* Calculate first word length(the command), terminated by space or ( */
+ /*
+ Calculate first word length(the command), terminated
+ by 'space' , '(' or 'delimiter' */
p= command->query;
- while (*p && !my_isspace(charset_info, *p) && *p != '(')
+ while (*p && !my_isspace(charset_info, *p) && *p != '(' && !is_delimiter(p))
p++;
command->first_word_len= (uint) (p - command->query);
DBUG_PRINT("info", ("first_word: %.*s",
@@ -5126,7 +5577,7 @@ int read_command(struct st_command** command_ptr)
command->first_argument= p;
command->end= strend(command->query);
- command->query_len= (uint) (command->end - command->query);
+ command->query_len= (command->end - command->query);
parser.read_lines++;
DBUG_RETURN(0);
}
@@ -5136,18 +5587,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",
@@ -5156,19 +5607,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},
@@ -5178,55 +5635,55 @@ 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},
+#include "sslopt-longopts.h"
{"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).",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"timer-file", 'm', "File where the timing in micro seconds is stored.",
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}
};
@@ -5309,6 +5766,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':
@@ -5326,7 +5784,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
DBUG_ASSERT(cur_file == file_stack && cur_file->file == 0);
if (!(cur_file->file=
my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0))))
- die("Could not open %s: errno = %d", buff, errno);
+ die("Could not open '%s' for reading, errno: %d", buff, errno);
cur_file->file_name= my_strdup(buff, MYF(MY_FAE));
cur_file->lineno= 1;
break;
@@ -5345,6 +5803,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
break;
}
case 'p':
+ if (argument == disabled_my_option)
+ argument= (char*) ""; // Don't require password
if (argument)
{
my_free(opt_pass, MYF(MY_ALLOW_ZERO_PTR));
@@ -5372,6 +5832,11 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
die("Can't use server argument");
}
break;
+ case OPT_LOG_DIR:
+ /* Check that the file exists */
+ if (access(opt_logdir, F_OK) != 0)
+ die("The specified log directory does not exist: '%s'", opt_logdir);
+ break;
case 'F':
read_embedded_server_arguments(argument);
break;
@@ -5408,6 +5873,18 @@ 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;
+
+
+ if (!record)
+ {
+ /* Check that the result file exists */
+ if (result_file_name && access(result_file_name, F_OK) != 0)
+ die("The specified result file '%s' does not exist", result_file_name);
+ }
return 0;
}
@@ -5439,11 +5916,11 @@ void str_to_file2(const char *fname, char *str, int size, my_bool append)
flags|= O_TRUNC;
if ((fd= my_open(buff, flags,
MYF(MY_WME | MY_FFNF))) < 0)
- die("Could not open %s: errno = %d", buff, errno);
+ die("Could not open '%s' for writing, 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)))
- die("write failed");
+ die("Could not find end of file '%s', errno: %d", buff, errno);
+ if (my_write(fd, (uchar*)str, size, MYF(MY_WME|MY_FNABP)))
+ die("write failed, errno: %d", errno);
my_close(fd, MYF(0));
}
@@ -5463,37 +5940,6 @@ void str_to_file(const char *fname, char *str, int size)
}
-void dump_result_to_log_file(char *buf, int size)
-{
- char log_file[FN_REFLEN];
- str_to_file(fn_format(log_file, result_file_name, opt_logdir, ".log",
- *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
- MY_REPLACE_EXT),
- buf, size);
- fprintf(stderr, "\nMore results from queries before failure can be found in %s\n",
- log_file);
-}
-
-void dump_progress(void)
-{
- char progress_file[FN_REFLEN];
- str_to_file(fn_format(progress_file, result_file_name,
- opt_logdir, ".progress",
- *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
- MY_REPLACE_EXT),
- ds_progress.str, ds_progress.length);
-}
-
-void dump_warning_messages(void)
-{
- char warn_file[FN_REFLEN];
-
- str_to_file(fn_format(warn_file, result_file_name, opt_logdir, ".warnings",
- *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
- MY_REPLACE_EXT),
- ds_warning_messages.str, ds_warning_messages.length);
-}
-
void check_regerr(my_regex_t* r, int err)
{
char err_buf[1024];
@@ -5554,7 +6000,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));
@@ -5574,7 +6020,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);
}
@@ -5605,7 +6051,7 @@ void fix_win_paths(const char *val, int len)
DBUG_PRINT("info", ("pattern: %s", *pattern));
/* Search for the path in string */
- while ((p= strstr(val, *pattern)))
+ while ((p= strstr((char*)val, *pattern)))
{
DBUG_PRINT("info", ("Found %s in val p: %s", *pattern, p));
@@ -5630,8 +6076,10 @@ void fix_win_paths(const char *val, int len)
*/
void append_field(DYNAMIC_STRING *ds, uint col_idx, MYSQL_FIELD* field,
- const char* val, ulonglong len, bool is_null)
+ char* val, ulonglong len, my_bool is_null)
{
+ char null[]= "NULL";
+
if (col_idx < max_replace_column && replace_column[col_idx])
{
val= replace_column[col_idx];
@@ -5639,7 +6087,7 @@ void append_field(DYNAMIC_STRING *ds, uint col_idx, MYSQL_FIELD* field,
}
else if (is_null)
{
- val= "NULL";
+ val= null;
len= 4;
}
#ifdef __WIN__
@@ -5653,9 +6101,18 @@ void append_field(DYNAMIC_STRING *ds, uint col_idx, MYSQL_FIELD* field,
(start[1] == '-' || start[1] == '+') && start[2] == '0')
{
start+=2; /* Now points at first '0' */
- /* Move all chars after the first '0' one step left */
- memmove(start, start + 1, strlen(start));
- len--;
+ if (field->flags & ZEROFILL_FLAG)
+ {
+ /* Move all chars before the first '0' one step right */
+ memmove(val + 1, val, start - val);
+ *val= '0';
+ }
+ else
+ {
+ /* Move all chars after the first '0' one step left */
+ memmove(start, start + 1, strlen(start));
+ len--;
+ }
}
}
#endif
@@ -5694,7 +6151,7 @@ void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res)
lengths = mysql_fetch_lengths(res);
for (i = 0; i < num_fields; i++)
append_field(ds, i, &fields[i],
- (const char*)row[i], lengths[i], !row[i]);
+ row[i], lengths[i], !row[i]);
if (!display_result_vertically)
dynstr_append_mem(ds, "\n", 1);
}
@@ -5727,7 +6184,7 @@ void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt,
{
uint max_length= fields[i].max_length + 1;
my_bind[i].buffer_type= MYSQL_TYPE_STRING;
- my_bind[i].buffer= (char *)my_malloc(max_length, MYF(MY_WME | MY_FAE));
+ my_bind[i].buffer= my_malloc(max_length, MYF(MY_WME | MY_FAE));
my_bind[i].buffer_length= max_length;
my_bind[i].is_null= &is_null[i];
my_bind[i].length= &length[i];
@@ -5743,7 +6200,7 @@ void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt,
while (mysql_stmt_fetch(stmt) == 0)
{
for (i= 0; i < num_fields; i++)
- append_field(ds, i, &fields[i], (const char *) my_bind[i].buffer,
+ append_field(ds, i, &fields[i], (char*)my_bind[i].buffer,
*my_bind[i].length, *my_bind[i].is_null);
if (!display_result_vertically)
dynstr_append_mem(ds, "\n", 1);
@@ -5756,12 +6213,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));
}
@@ -6040,6 +6497,56 @@ end:
/*
+ Check whether given error is in list of expected errors
+
+ SYNOPSIS
+ match_expected_error()
+
+ PARAMETERS
+ command the current command (and its expect-list)
+ err_errno error number of the error that actually occurred
+ err_sqlstate SQL-state that was thrown, or NULL for impossible
+ (file-ops, diff, etc.)
+
+ RETURNS
+ -1 for not in list, index in list of expected errors otherwise
+
+ NOTE
+ If caller needs to know whether the list was empty, they should
+ check command->expected_errors.count.
+*/
+
+static int match_expected_error(struct st_command *command,
+ unsigned int err_errno,
+ const char *err_sqlstate)
+{
+ uint i;
+
+ for (i= 0 ; (uint) i < command->expected_errors.count ; i++)
+ {
+ if ((command->expected_errors.err[i].type == ERR_ERRNO) &&
+ (command->expected_errors.err[i].code.errnum == err_errno))
+ return i;
+
+ if (command->expected_errors.err[i].type == ERR_SQLSTATE)
+ {
+ /*
+ NULL is quite likely, but not in conjunction with a SQL-state expect!
+ */
+ if (unlikely(err_sqlstate == NULL))
+ die("expecting a SQL-state (%s) from query '%s' which cannot produce one...",
+ command->expected_errors.err[i].code.sqlstate, command->query);
+
+ if (strncmp(command->expected_errors.err[i].code.sqlstate,
+ err_sqlstate, SQLSTATE_LENGTH) == 0)
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+/*
Handle errors which occurred during execution
SYNOPSIS
@@ -6051,18 +6558,15 @@ 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,
unsigned int err_errno, const char *err_error,
const char *err_sqlstate, DYNAMIC_STRING *ds)
{
- uint i;
+ int i;
DBUG_ENTER("handle_error");
@@ -6088,34 +6592,30 @@ void handle_error(struct st_command *command,
DBUG_PRINT("info", ("expected_errors.count: %d",
command->expected_errors.count));
- for (i= 0 ; (uint) i < command->expected_errors.count ; i++)
+
+ i= match_expected_error(command, err_errno, err_sqlstate);
+
+ if (i >= 0)
{
- if (((command->expected_errors.err[i].type == ERR_ERRNO) &&
- (command->expected_errors.err[i].code.errnum == err_errno)) ||
- ((command->expected_errors.err[i].type == ERR_SQLSTATE) &&
- (strncmp(command->expected_errors.err[i].code.sqlstate,
- err_sqlstate, SQLSTATE_LENGTH) == 0)))
+ if (!disable_result_log)
{
- if (!disable_result_log)
+ if (command->expected_errors.count == 1)
{
- if (command->expected_errors.count == 1)
- {
- /* Only log error if there is one possible error */
- dynstr_append_mem(ds, "ERROR ", 6);
- replace_dynstr_append(ds, err_sqlstate);
- dynstr_append_mem(ds, ": ", 2);
- replace_dynstr_append(ds, err_error);
- dynstr_append_mem(ds,"\n",1);
- }
- /* Don't log error if we may not get an error */
- else if (command->expected_errors.err[0].type == ERR_SQLSTATE ||
- (command->expected_errors.err[0].type == ERR_ERRNO &&
- command->expected_errors.err[0].code.errnum != 0))
- dynstr_append(ds,"Got one of the listed errors\n");
+ /* Only log error if there is one possible error */
+ dynstr_append_mem(ds, "ERROR ", 6);
+ replace_dynstr_append(ds, err_sqlstate);
+ dynstr_append_mem(ds, ": ", 2);
+ replace_dynstr_append(ds, err_error);
+ dynstr_append_mem(ds,"\n",1);
}
- /* OK */
- DBUG_VOID_RETURN;
+ /* Don't log error if we may not get an error */
+ else if (command->expected_errors.err[0].type == ERR_SQLSTATE ||
+ (command->expected_errors.err[0].type == ERR_ERRNO &&
+ command->expected_errors.err[0].code.errnum != 0))
+ dynstr_append(ds,"Got one of the listed errors\n");
}
+ /* OK */
+ DBUG_VOID_RETURN;
}
DBUG_PRINT("info",("i: %d expected_errors: %d", i,
@@ -6130,7 +6630,7 @@ void handle_error(struct st_command *command,
dynstr_append_mem(ds, "\n", 1);
}
- if (i)
+ if (command->expected_errors.count > 0)
{
if (command->expected_errors.err[0].type == ERR_ERRNO)
die("query '%s' failed with wrong errno %d: '%s', instead of %d...",
@@ -6409,6 +6909,8 @@ int util_query(MYSQL* org_mysql, const char* query){
if (!(mysql= mysql_init(mysql)))
die("Failed in mysql_init()");
+ /* enable local infile, in non-binary builds often disabled by default */
+ mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, 0);
safe_connect(mysql, "util", org_mysql->host, org_mysql->user,
org_mysql->passwd, org_mysql->db, org_mysql->port,
org_mysql->unix_socket);
@@ -6452,9 +6954,6 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
init_dynamic_string(&ds_warnings, NULL, 0, 256);
- /* Scan for warning before sending to server */
- scan_command_for_warnings(command);
-
/*
Evaluate query if this is an eval command
*/
@@ -6468,7 +6967,7 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
else
{
query = command->query;
- query_len = (uint) strlen(query);
+ query_len = strlen(query);
}
/*
@@ -6529,7 +7028,7 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
*/
view_created= 1;
query= (char*)"SELECT * FROM mysqltest_tmp_v";
- query_len = (uint) strlen(query);
+ query_len = strlen(query);
/*
Collect warnings from create of the view that should otherwise
@@ -6577,7 +7076,7 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
sp_created= 1;
query= (char*)"CALL mysqltest_tmp_sp()";
- query_len = (uint) strlen(query);
+ query_len = strlen(query);
}
dynstr_free(&query_str);
}
@@ -6670,7 +7169,7 @@ void init_re_comp(my_regex_t *re, const char* str)
if (err)
{
char erbuf[100];
- size_t len= my_regerror(err, re, erbuf, sizeof(erbuf));
+ int len= my_regerror(err, re, erbuf, sizeof(erbuf));
die("error %s, %d/%d `%s'\n",
re_eprint(err), (int)len, (int)sizeof(erbuf), erbuf);
}
@@ -6726,7 +7225,7 @@ int match_re(my_regex_t *re, char *str)
{
char erbuf[100];
- size_t len= my_regerror(err, re, erbuf, sizeof(erbuf));
+ int len= my_regerror(err, re, erbuf, sizeof(erbuf));
die("error %s, %d/%d `%s'\n",
re_eprint(err), (int)len, (int)sizeof(erbuf), erbuf);
}
@@ -6784,28 +7283,10 @@ void get_command_type(struct st_command* command)
}
else
{
- /* -- comment that didn't contain a mysqltest command */
- command->type= Q_COMMENT;
- warning_msg("Suspicious command '--%s' detected, was this intentional? "\
- "Use # instead of -- to avoid this warning",
- command->query);
-
- if (command->first_word_len &&
- strcmp(command->query + command->first_word_len - 1, delimiter) == 0)
- {
- /*
- Detect comment with command using extra delimiter
- Ex --disable_query_log;
- ^ Extra delimiter causing the command
- to be skipped
- */
- save= command->query[command->first_word_len-1];
- command->query[command->first_word_len-1]= 0;
- if (find_type(command->query, &command_typelib, 1+2) > 0)
- die("Extra delimiter \";\" found");
- command->query[command->first_word_len-1]= save;
-
- }
+ /* -- "comment" that didn't contain a mysqltest command */
+ die("Found line beginning with -- that didn't contain "\
+ "a valid mysqltest command, check your syntax or "\
+ "use # if you intended to write a comment");
}
}
@@ -6824,22 +7305,25 @@ void get_command_type(struct st_command* command)
/*
Record how many milliseconds it took to execute the test file
- up until the current line and save it in the dynamic string ds_progress.
-
- The ds_progress will be dumped to <test_name>.progress when
- test run completes
+ up until the current line and write it to .progress file
*/
void mark_progress(struct st_command* command __attribute__((unused)),
int line)
{
+ static ulonglong progress_start= 0; // < Beware
+ DYNAMIC_STRING ds_progress;
+
char buf[32], *end;
ulonglong timer= timer_now();
if (!progress_start)
progress_start= timer;
timer-= progress_start;
+ if (init_dynamic_string(&ds_progress, "", 256, 256))
+ die("Out of memory");
+
/* Milliseconds since start */
end= longlong2str(timer, buf, 10);
dynstr_append_mem(&ds_progress, buf, (int)(end-buf));
@@ -6861,8 +7345,117 @@ void mark_progress(struct st_command* command __attribute__((unused)),
dynstr_append_mem(&ds_progress, "\n", 1);
+ progress_file.write(&ds_progress);
+
+ dynstr_free(&ds_progress);
+
}
+#ifdef HAVE_STACKTRACE
+
+static void dump_backtrace(void)
+{
+ struct st_connection *conn= cur_con;
+
+ my_safe_print_str("read_command_buf", read_command_buf,
+ sizeof(read_command_buf));
+ if (conn)
+ {
+ my_safe_print_str("conn->name", conn->name, conn->name_len);
+#ifdef EMBEDDED_LIBRARY
+ my_safe_print_str("conn->cur_query", conn->cur_query, conn->cur_query_len);
+#endif
+ }
+ fputs("Attempting backtrace...\n", stderr);
+ my_print_stacktrace(NULL, my_thread_stack_size);
+}
+
+#else
+
+static void dump_backtrace(void)
+{
+ fputs("Backtrace not available.\n", stderr);
+}
+
+#endif
+
+static sig_handler signal_handler(int sig)
+{
+ fprintf(stderr, "mysqltest got " SIGNAL_FMT "\n", sig);
+ dump_backtrace();
+
+ fprintf(stderr, "Writing a core file...\n");
+ fflush(stderr);
+ my_write_core(sig);
+#ifndef __WIN__
+ exit(1); // Shouldn't get here but just in case
+#endif
+}
+
+#ifdef __WIN__
+
+LONG WINAPI exception_filter(EXCEPTION_POINTERS *exp)
+{
+ __try
+ {
+ my_set_exception_pointers(exp);
+ signal_handler(exp->ExceptionRecord->ExceptionCode);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ fputs("Got exception in exception handler!\n", stderr);
+ }
+
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+
+static void init_signal_handling(void)
+{
+ UINT mode;
+
+ /* Set output destination of messages to the standard error stream. */
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+
+ /* Do not not display the a error message box. */
+ mode= SetErrorMode(0) | SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX;
+ SetErrorMode(mode);
+
+ SetUnhandledExceptionFilter(exception_filter);
+}
+
+#else /* __WIN__ */
+
+static void init_signal_handling(void)
+{
+ struct sigaction sa;
+ DBUG_ENTER("init_signal_handling");
+
+#ifdef HAVE_STACKTRACE
+ my_init_stacktrace();
+#endif
+
+ sa.sa_flags = SA_RESETHAND | SA_NODEFER;
+ sigemptyset(&sa.sa_mask);
+ sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL);
+
+ sa.sa_handler= signal_handler;
+
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGABRT, &sa, NULL);
+#ifdef SIGBUS
+ sigaction(SIGBUS, &sa, NULL);
+#endif
+ sigaction(SIGILL, &sa, NULL);
+ sigaction(SIGFPE, &sa, NULL);
+}
+
+#endif /* !__WIN__ */
int main(int argc, char **argv)
{
@@ -6870,12 +7463,13 @@ int main(int argc, char **argv)
my_bool q_send_flag= 0, abort_flag= 0;
uint command_executed= 0, last_command_executed= 0;
char save_file[FN_REFLEN];
- MY_STAT res_info;
MY_INIT(argv[0]);
save_file[0]= 0;
TMPDIR[0]= 0;
+ init_signal_handling();
+
/* Init expected errors */
memset(&saved_expected_errors, 0, sizeof(saved_expected_errors));
@@ -6927,11 +7521,18 @@ int main(int argc, char **argv)
init_win_path_patterns();
#endif
- init_dynamic_string(&ds_res, "", 65536, 65536);
- init_dynamic_string(&ds_progress, "", 0, 2048);
- init_dynamic_string(&ds_warning_messages, "", 0, 2048);
+ init_dynamic_string(&ds_res, "", 2048, 2048);
+
parse_args(argc, argv);
+ log_file.open(opt_logdir, result_file_name, ".log");
+ verbose_msg("Logging to '%s'.", log_file.file_name());
+ if (opt_mark_progress)
+ {
+ progress_file.open(opt_logdir, result_file_name, ".progress");
+ verbose_msg("Tracing progress in '%s'.", progress_file.file_name());
+ }
+
var_set_int("$PS_PROTOCOL", ps_protocol);
var_set_int("$SP_PROTOCOL", sp_protocol);
var_set_int("$VIEW_PROTOCOL", view_protocol);
@@ -6939,6 +7540,8 @@ int main(int argc, char **argv)
DBUG_PRINT("info",("result_file: '%s'",
result_file_name ? result_file_name : ""));
+ verbose_msg("Results saved in '%s'.",
+ result_file_name ? result_file_name : "");
if (mysql_server_init(embedded_server_arg_count,
embedded_server_args,
(char**) embedded_server_groups))
@@ -6959,37 +7562,37 @@ int main(int argc, char **argv)
if (cursor_protocol_enabled)
ps_protocol_enabled= 1;
- cur_con= connections;
- if (!( mysql_init(&cur_con->mysql)))
+ st_connection *con= connections;
+ if (!( mysql_init(&con->mysql)))
die("Failed in mysql_init()");
if (opt_compress)
- mysql_options(&cur_con->mysql,MYSQL_OPT_COMPRESS,NullS);
- mysql_options(&cur_con->mysql, MYSQL_OPT_LOCAL_INFILE, 0);
- mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_NAME,
+ mysql_options(&con->mysql,MYSQL_OPT_COMPRESS,NullS);
+ mysql_options(&con->mysql, MYSQL_OPT_LOCAL_INFILE, 0);
+ mysql_options(&con->mysql, MYSQL_SET_CHARSET_NAME,
charset_info->csname);
if (opt_charsets_dir)
- mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_DIR,
+ mysql_options(&con->mysql, MYSQL_SET_CHARSET_DIR,
opt_charsets_dir);
#ifdef HAVE_OPENSSL
if (opt_use_ssl)
{
- mysql_ssl_set(&cur_con->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
+ mysql_ssl_set(&con->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
opt_ssl_capath, opt_ssl_cipher);
#if MYSQL_VERSION_ID >= 50000
/* Turn on ssl_verify_server_cert only if host is "localhost" */
opt_ssl_verify_server_cert= opt_host && !strcmp(opt_host, "localhost");
- mysql_options(&cur_con->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
+ mysql_options(&con->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
&opt_ssl_verify_server_cert);
#endif
}
#endif
- if (!(cur_con->name = my_strdup("default", MYF(MY_WME))))
+ if (!(con->name = my_strdup("default", MYF(MY_WME))))
die("Out of memory");
- safe_connect(&cur_con->mysql, cur_con->name, opt_host, opt_user, opt_pass,
+ safe_connect(&con->mysql, con->name, opt_host, opt_user, opt_pass,
opt_db, opt_port, unix_sock);
/* Use all time until exit if no explicit 'start_timer' */
@@ -7002,11 +7605,14 @@ int main(int argc, char **argv)
*/
var_set_errno(-1);
+ set_current_connection(con);
+
if (opt_include)
{
open_file(opt_include);
}
+ verbose_msg("Start processing test commands from '%s' ...", cur_file->file_name);
while (!read_command(&command) && !abort_flag)
{
int current_line_inc = 1, processed = 0;
@@ -7017,8 +7623,8 @@ int main(int argc, char **argv)
command->type != Q_ENABLE_PARSING &&
command->type != Q_DISABLE_PARSING)
{
+ /* Parsing is disabled, silently convert this line to a comment */
command->type= Q_COMMENT;
- scan_command_for_warnings(command);
}
if (cur_block->ok)
@@ -7059,6 +7665,13 @@ int main(int argc, char **argv)
case Q_REMOVE_FILE: do_remove_file(command); break;
case Q_MKDIR: do_mkdir(command); break;
case Q_RMDIR: do_rmdir(command); break;
+ case Q_LIST_FILES: do_list_files(command); break;
+ case Q_LIST_FILES_WRITE_FILE:
+ do_list_files_write_file_command(command, FALSE);
+ break;
+ case Q_LIST_FILES_APPEND_FILE:
+ do_list_files_write_file_command(command, TRUE);
+ break;
case Q_FILE_EXIST: do_file_exist(command); break;
case Q_WRITE_FILE: do_write_file(command); break;
case Q_APPEND_FILE: do_append_file(command); break;
@@ -7182,15 +7795,23 @@ int main(int argc, char **argv)
select_connection(command);
else
select_connection_name("slave");
- do_sync_with_master2(0);
+ do_sync_with_master2(command, 0);
break;
}
case Q_COMMENT: /* Ignore row */
command->last_argument= command->end;
break;
case Q_PING:
- (void) mysql_ping(&cur_con->mysql);
- break;
+ handle_command_error(command, mysql_ping(&cur_con->mysql));
+ break;
+ case Q_SEND_SHUTDOWN:
+ handle_command_error(command,
+ mysql_shutdown(&cur_con->mysql,
+ SHUTDOWN_DEFAULT));
+ break;
+ case Q_SHUTDOWN_SERVER:
+ do_shutdown_server(command);
+ break;
case Q_EXEC:
do_exec(command);
command_executed++;
@@ -7299,9 +7920,17 @@ int main(int argc, char **argv)
parser.current_line += current_line_inc;
if ( opt_mark_progress )
mark_progress(command, parser.current_line);
+
+ /* Write result from command to log file immediately */
+ log_file.write(&ds_res);
+ log_file.flush();
+ dynstr_set(&ds_res, 0);
}
+ log_file.close();
+
start_lineno= 0;
+ verbose_msg("... Done processing test commands.");
if (parsing_disabled)
die("Test ended with parsing disabled");
@@ -7309,9 +7938,9 @@ int main(int argc, char **argv)
/*
The whole test has been executed _sucessfully_.
Time to compare result or save it to record file.
- The entire output from test is now kept in ds_res.
+ The entire output from test is in the log file
*/
- if (ds_res.length)
+ if (log_file.bytes_written())
{
if (result_file_name)
{
@@ -7319,22 +7948,29 @@ int main(int argc, char **argv)
if (record)
{
- /* Recording - dump the output from test to result file */
- str_to_file(result_file_name, ds_res.str, ds_res.length);
+ /* Recording */
+
+ /* save a copy of the log to result file */
+ if (my_copy(log_file.file_name(), result_file_name, MYF(0)) != 0)
+ die("Failed to copy '%s' to '%s', errno: %d",
+ log_file.file_name(), result_file_name, errno);
+
}
else
{
- /* Check that the output from test is equal to result file
- - detect missing result file
- - detect zero size result file
- */
- check_result(&ds_res);
+ /* Check that the output from test is equal to result file */
+ check_result();
}
}
else
{
- /* No result_file_name specified to compare with, print to stdout */
- printf("%s", ds_res.str);
+ /*
+ No result_file_name specified, the result
+ has been printed to stdout, exit with error
+ unless script has called "exit" to indicate success
+ */
+ if (abort_flag == 0)
+ die("Exit with failure! Call 'exit' in script to return with sucess");
}
}
else
@@ -7342,26 +7978,10 @@ int main(int argc, char **argv)
die("The test didn't produce any output");
}
- if (!command_executed &&
- result_file_name && my_stat(result_file_name, &res_info, 0))
- {
- /*
- my_stat() successful on result file. Check if we have not run a
- single query, but we do have a result file that contains data.
- Note that we don't care, if my_stat() fails. For example, for a
- non-existing or non-readable file, we assume it's fine to have
- no query output from the test file, e.g. regarded as no error.
- */
+ if (!command_executed && result_file_name)
die("No queries executed but result file found!");
- }
-
- if ( opt_mark_progress && result_file_name )
- dump_progress();
-
- /* Dump warning messages */
- if (result_file_name && ds_warning_messages.length)
- dump_warning_messages();
+ verbose_msg("Test has succeeded!");
timer_output();
/* Yes, if we got this far the test has suceeded! Sakila smiles */
cleanup_and_exit(0);
@@ -7406,7 +8026,7 @@ void timer_output(void)
ulonglong timer_now(void)
{
- return my_getsystime() / 10000;
+ return my_micro_time() / 1000;
}
@@ -7429,12 +8049,11 @@ void do_get_replace_column(struct st_command *command)
die("Missing argument in %s", command->query);
/* Allocate a buffer for results */
- start= buff= my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE));
+ start= buff= (char*)my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE));
while (*from)
{
char *to;
uint column_number;
-
to= get_string(&buff, &from, command);
if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS)
die("Wrong column number to replace_column in '%s'", command->query);
@@ -7474,15 +8093,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);
@@ -7512,7 +8131,7 @@ void do_get_replace(struct st_command *command)
bzero((char*) &from_array,sizeof(from_array));
if (!*from)
die("Missing argument in %s", command->query);
- start= buff= my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE));
+ start= buff= (char*)my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE));
while (*from)
{
char *to= buff;
@@ -7520,6 +8139,9 @@ void do_get_replace(struct st_command *command)
if (!*from)
die("Wrong number of arguments to replace_result in '%s'",
command->query);
+#ifdef __WIN__
+ fix_win_paths(to, from - to);
+#endif
insert_pointer_name(&from_array,to);
to= get_string(&buff, &from, command);
insert_pointer_name(&to_array,to);
@@ -7546,7 +8168,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;
@@ -7554,12 +8176,12 @@ void free_replace()
typedef struct st_replace {
- bool found;
+ my_bool found;
struct st_replace *next[256];
} REPLACE;
typedef struct st_replace_found {
- bool found;
+ my_bool found;
char *replace_string;
uint to_offset;
int from_offset;
@@ -7588,7 +8210,7 @@ void replace_strings_append(REPLACE *rep, DYNAMIC_STRING* ds,
if (!(rep_str = ((REPLACE_STRING*) rep_pos))->replace_string)
{
/* No match found */
- dynstr_append_mem(ds, start, (uint) (from - start - 1));
+ dynstr_append_mem(ds, start, from - start - 1);
DBUG_PRINT("exit", ("Found no more string to replace, appended: %s", start));
DBUG_VOID_RETURN;
}
@@ -7599,11 +8221,11 @@ void replace_strings_append(REPLACE *rep, DYNAMIC_STRING* ds,
rep_str->from_offset, rep_str->replace_string));
/* Append part of original string before replace string */
- dynstr_append_mem(ds, start, (uint) ((from - rep_str->to_offset) - start));
+ dynstr_append_mem(ds, start, (from - rep_str->to_offset) - start);
/* Append replace string */
dynstr_append_mem(ds, rep_str->replace_string,
- (uint) strlen(rep_str->replace_string));
+ strlen(rep_str->replace_string));
if (!*(from-=rep_str->from_offset) && rep_pos->found != 2)
{
@@ -7698,7 +8320,7 @@ struct st_replace_regex* init_replace_regex(char* expr)
char* buf,*expr_end;
char* p;
char* buf_p;
- size_t expr_len= strlen(expr);
+ uint expr_len= strlen(expr);
char last_c = 0;
struct st_regex reg;
@@ -7757,7 +8379,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) &reg))
+ if (insert_dynamic(&res->regex_arr,(uchar*) &reg))
die("Out of memory");
}
res->odd_buf_len= res->even_buf_len= 8192;
@@ -7768,7 +8390,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;
}
@@ -7809,7 +8431,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))
@@ -7862,7 +8484,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;
}
}
@@ -7875,7 +8497,7 @@ void free_replace_regex()
*/
#define SECURE_REG_BUF if (buf_len < need_buf_len) \
{ \
- size_t off= res_p - buf; \
+ int off= res_p - buf; \
buf= (char*)my_realloc(buf,need_buf_len,MYF(MY_WME+MY_FAE)); \
res_p= buf + off; \
buf_len= need_buf_len; \
@@ -7907,7 +8529,7 @@ int reg_replace(char** buf_p, int* buf_len_p, char *pattern,
char *res_p,*str_p,*str_end;
buf_len= *buf_len_p;
- len= (uint) strlen(string);
+ len= strlen(string);
str_end= string + len;
/* start with a buffer of a reasonable size that hopefully will not
@@ -7959,7 +8581,7 @@ int reg_replace(char** buf_p, int* buf_len_p, char *pattern,
we need at least what we have so far in the buffer + the part
before this match
*/
- need_buf_len= (uint) (res_p - buf) + (int) subs[0].rm_so;
+ need_buf_len= (res_p - buf) + (int) subs[0].rm_so;
/* on this pass, calculate the memory for the result buffer */
while (expr_p < replace_end)
@@ -8049,15 +8671,15 @@ int reg_replace(char** buf_p, int* buf_len_p, char *pattern,
}
else /* no match this time, just copy the string as is */
{
- size_t left_in_str= str_end-str_p;
- need_buf_len= (uint) ((res_p-buf) + left_in_str);
+ int left_in_str= str_end-str_p;
+ need_buf_len= (res_p-buf) + left_in_str;
SECURE_REG_BUF
memcpy(res_p,str_p,left_in_str);
res_p += left_in_str;
str_p= str_end;
}
}
- my_free((gptr)subs, MYF(0));
+ my_free(subs, MYF(0));
my_regfree(&r);
*res_p= 0;
*buf_p= buf;
@@ -8117,19 +8739,17 @@ 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)
{
- if (str[0] == '\\' && str[1])
- str++;
str++;
len++;
}
@@ -8138,17 +8758,16 @@ 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;
static const int END_OF_LINE= 258;
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;
@@ -8164,7 +8783,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;
@@ -8193,7 +8811,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);
}
@@ -8229,35 +8847,7 @@ REPLACE *init_replace(my_string *from, my_string *to,uint count,
}
for (pos=from[i], len=0; *pos ; pos++)
{
- if (*pos == '\\' && *(pos+1))
- {
- pos++;
- switch (*pos) {
- case 'b':
- follow_ptr->chr = SPACE_CHAR;
- break;
- case '^':
- follow_ptr->chr = START_OF_LINE;
- break;
- case '$':
- follow_ptr->chr = END_OF_LINE;
- break;
- case 'r':
- follow_ptr->chr = '\r';
- break;
- case 't':
- follow_ptr->chr = '\t';
- break;
- case 'v':
- follow_ptr->chr = '\v';
- break;
- default:
- follow_ptr->chr = (uchar) *pos;
- break;
- }
- }
- else
- follow_ptr->chr= (uchar) *pos;
+ follow_ptr->chr= (uchar) *pos;
follow_ptr->table_offset=i;
follow_ptr->len= ++len;
follow_ptr++;
@@ -8384,12 +8974,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;
@@ -8400,7 +8990,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)+
@@ -8415,9 +9006,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);
}
@@ -8433,7 +9024,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;
@@ -8465,13 +9056,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;
@@ -8494,8 +9085,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;
}
@@ -8522,13 +9113,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);
}
@@ -8596,17 +9187,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;
}
/****************************************************************************
@@ -8616,10 +9209,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");
@@ -8627,16 +9220,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;
@@ -8646,7 +9239,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);
@@ -8665,23 +9258,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 */
@@ -8694,9 +9287,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 */
@@ -8717,7 +9310,7 @@ void replace_dynstr_append_mem(DYNAMIC_STRING *ds,
if (!multi_reg_replace(glob_replace_regex, (char*)val))
{
val= glob_replace_regex->buf;
- len= (uint) strlen(val);
+ len= strlen(val);
}
}
@@ -8734,7 +9327,7 @@ void replace_dynstr_append_mem(DYNAMIC_STRING *ds,
/* Append zero-terminated string to ds, with optional replace */
void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val)
{
- replace_dynstr_append_mem(ds, val, (uint) strlen(val));
+ replace_dynstr_append_mem(ds, val, strlen(val));
}
/* Append uint to ds, with optional replace */
@@ -8742,7 +9335,7 @@ void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val)
{
char buff[22]; /* This should be enough for any int */
char *end= longlong10_to_str(val, buff, 10);
- replace_dynstr_append_mem(ds, buff, (uint) (end - buff));
+ replace_dynstr_append_mem(ds, buff, end - buff);
}
@@ -8780,7 +9373,7 @@ void dynstr_append_sorted(DYNAMIC_STRING* ds, DYNAMIC_STRING *ds_input)
while (*start && *start != '\n')
start++;
start++; /* Skip past \n */
- dynstr_append_mem(ds, ds_input->str, (uint) (start - ds_input->str));
+ dynstr_append_mem(ds, ds_input->str, start - ds_input->str);
/* Insert line(s) in array */
while (*start)
@@ -8793,7 +9386,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 726d9cd9415..b32cb71b0de 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, bool *truncated);
@@ -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;
@@ -63,13 +63,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*)
@@ -77,7 +77,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;
@@ -107,13 +107,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)
@@ -134,9 +134,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)
@@ -175,11 +175,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));
if (!read_count)
{
@@ -202,7 +202,7 @@ static uint fill_buffer(LINE_BUFFER *buffer)
char *intern_read_line(LINE_BUFFER *buffer, ulong *out_length, bool *truncated)
{
char *pos;
- uint length;
+ size_t length;
DBUG_ENTER("intern_read_line");
buffer->start_of_line=buffer->end_of_line;
diff --git a/client/sql_string.cc b/client/sql_string.cc
index 4967538ad3b..dc6147b563f 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"
@@ -503,7 +503,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;
@@ -517,7 +517,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;
@@ -642,7 +642,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)
@@ -802,10 +802,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);