summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rwxr-xr-xclient/CMakeLists.txt99
-rw-r--r--client/Makefile.am52
-rw-r--r--client/client_priv.h15
-rw-r--r--client/completion_hash.cc3
-rw-r--r--client/completion_hash.h6
-rw-r--r--client/get_password.c3
-rw-r--r--client/my_readline.h3
-rw-r--r--client/mysql.cc656
-rw-r--r--client/mysql_upgrade.c690
-rw-r--r--client/mysqladmin.cc20
-rw-r--r--client/mysqlbinlog.cc702
-rw-r--r--client/mysqlcheck.c43
-rw-r--r--client/mysqldump.c2576
-rw-r--r--client/mysqlimport.c14
-rw-r--r--client/mysqlmanager-pwgen.c3
-rw-r--r--client/mysqlmanagerc.c3
-rw-r--r--client/mysqlshow.c174
-rw-r--r--client/mysqltest.c72
-rw-r--r--client/readline.cc6
-rw-r--r--client/sql_string.cc652
-rw-r--r--client/sql_string.h130
21 files changed, 4492 insertions, 1430 deletions
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt
new file mode 100755
index 00000000000..785bba738bf
--- /dev/null
+++ b/client/CMakeLists.txt
@@ -0,0 +1,99 @@
+# Copyright (C) 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
+SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
+
+# The old Windows build method used renamed (.cc -> .cpp) source files, fails
+# in #include in mysqlbinlog.cc. So disable that using the USING_CMAKE define.
+ADD_DEFINITIONS(-DUSING_CMAKE)
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
+ ${CMAKE_SOURCE_DIR}/zlib
+ ${CMAKE_SOURCE_DIR}/extra/yassl/include
+ ${CMAKE_SOURCE_DIR}/libmysql
+ ${CMAKE_SOURCE_DIR}/regex
+ ${CMAKE_SOURCE_DIR}/mysys
+ ${CMAKE_SOURCE_DIR}/sql
+ ${CMAKE_SOURCE_DIR}/strings)
+
+ADD_LIBRARY(mysqlclient ../mysys/array.c ../strings/bchange.c ../strings/bmove.c
+ ../strings/bmove_upp.c ../mysys/charset-def.c ../mysys/charset.c
+ ../sql-common/client.c ../strings/ctype-big5.c ../strings/ctype-bin.c
+ ../strings/ctype-cp932.c ../strings/ctype-czech.c ../strings/ctype-euc_kr.c
+ ../strings/ctype-eucjpms.c ../strings/ctype-extra.c ../strings/ctype-gb2312.c
+ ../strings/ctype-gbk.c ../strings/ctype-latin1.c ../strings/ctype-mb.c
+ ../strings/ctype-simple.c ../strings/ctype-sjis.c ../strings/ctype-tis620.c
+ ../strings/ctype-uca.c ../strings/ctype-ucs2.c ../strings/ctype-ujis.c
+ ../strings/ctype-utf8.c ../strings/ctype-win1250ch.c ../strings/ctype.c
+ ../mysys/default.c ../libmysql/errmsg.c ../mysys/errors.c
+ ../libmysql/get_password.c ../strings/int2str.c ../strings/is_prefix.c
+ ../libmysql/libmysql.c ../mysys/list.c ../strings/llstr.c
+ ../strings/longlong2str.c ../libmysql/manager.c ../mysys/mf_cache.c
+ ../mysys/mf_dirname.c ../mysys/mf_fn_ext.c ../mysys/mf_format.c
+ ../mysys/mf_iocache.c ../mysys/mf_iocache2.c ../mysys/mf_loadpath.c
+ ../mysys/mf_pack.c ../mysys/mf_path.c ../mysys/mf_tempfile.c ../mysys/mf_unixpath.c
+ ../mysys/mf_wcomp.c ../mysys/mulalloc.c ../mysys/my_access.c ../mysys/my_alloc.c
+ ../mysys/my_chsize.c ../mysys/my_compress.c ../mysys/my_create.c
+ ../mysys/my_delete.c ../mysys/my_div.c ../mysys/my_error.c ../mysys/my_file.c
+ ../mysys/my_fopen.c ../mysys/my_fstream.c ../mysys/my_gethostbyname.c
+ ../mysys/my_getopt.c ../mysys/my_getwd.c ../mysys/my_init.c ../mysys/my_lib.c
+ ../mysys/my_malloc.c ../mysys/my_messnc.c ../mysys/my_net.c ../mysys/my_once.c
+ ../mysys/my_open.c ../mysys/my_pread.c ../mysys/my_pthread.c ../mysys/my_read.c
+ ../mysys/my_realloc.c ../mysys/my_rename.c ../mysys/my_seek.c
+ ../mysys/my_static.c ../strings/my_strtoll10.c ../mysys/my_symlink.c
+ ../mysys/my_symlink2.c ../mysys/my_thr_init.c ../sql-common/my_time.c
+ ../strings/my_vsnprintf.c ../mysys/my_wincond.c ../mysys/my_winthread.c
+ ../mysys/my_write.c ../sql/net_serv.cc ../sql-common/pack.c ../sql/password.c
+ ../mysys/safemalloc.c ../mysys/sha1.c ../strings/str2int.c
+ ../strings/str_alloc.c ../strings/strcend.c ../strings/strcont.c ../strings/strend.c
+ ../strings/strfill.c ../mysys/string.c ../strings/strinstr.c ../strings/strmake.c
+ ../strings/strmov.c ../strings/strnlen.c ../strings/strnmov.c ../strings/strtod.c
+ ../strings/strtoll.c ../strings/strtoull.c ../strings/strxmov.c ../strings/strxnmov.c
+ ../mysys/thr_mutex.c ../mysys/typelib.c ../vio/vio.c ../vio/viosocket.c
+ ../vio/viossl.c ../vio/viosslfactories.c ../strings/xml.c)
+
+ADD_DEPENDENCIES(mysqlclient GenError)
+ADD_EXECUTABLE(mysql completion_hash.cc mysql.cc readline.cc sql_string.cc)
+LINK_DIRECTORIES(${MYSQL_BINARY_DIR}/mysys ${MYSQL_BINARY_DIR}/zlib)
+TARGET_LINK_LIBRARIES(mysql mysqlclient mysys yassl taocrypt zlib dbug wsock32)
+
+ADD_EXECUTABLE(mysqltest mysqltest.c)
+TARGET_LINK_LIBRARIES(mysqltest mysqlclient mysys yassl taocrypt zlib dbug regex wsock32)
+
+ADD_EXECUTABLE(mysqlcheck mysqlcheck.c)
+TARGET_LINK_LIBRARIES(mysqlcheck mysqlclient dbug yassl taocrypt zlib wsock32)
+
+ADD_EXECUTABLE(mysqldump mysqldump.c ../sql-common/my_user.c)
+TARGET_LINK_LIBRARIES(mysqldump mysqlclient mysys dbug yassl taocrypt zlib wsock32)
+
+ADD_EXECUTABLE(mysqlimport mysqlimport.c)
+TARGET_LINK_LIBRARIES(mysqlimport mysqlclient mysys dbug yassl taocrypt zlib wsock32)
+
+ADD_EXECUTABLE(mysql_upgrade mysql_upgrade.c ../mysys/my_getpagesize.c)
+TARGET_LINK_LIBRARIES(mysql_upgrade mysqlclient mysys dbug yassl taocrypt zlib wsock32)
+
+ADD_EXECUTABLE(mysqlshow mysqlshow.c)
+TARGET_LINK_LIBRARIES(mysqlshow mysqlclient mysys dbug yassl taocrypt zlib wsock32)
+
+ADD_EXECUTABLE(mysqlbinlog mysqlbinlog.cc ../mysys/mf_tempdir.c ../mysys/my_new.cc
+ ../mysys/my_bit.c ../mysys/my_bitmap.c
+ ../mysys/base64.c)
+TARGET_LINK_LIBRARIES(mysqlbinlog mysqlclient dbug yassl taocrypt zlib wsock32)
+
+ADD_EXECUTABLE(mysqladmin mysqladmin.cc)
+TARGET_LINK_LIBRARIES(mysqladmin mysqlclient mysys dbug yassl taocrypt zlib wsock32)
+
+ADD_EXECUTABLE(echo echo.c)
+
diff --git a/client/Makefile.am b/client/Makefile.am
index fe150defe03..5f1569ba2c4 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -1,9 +1,8 @@
-# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+# 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; either version 2 of the License, or
-# (at your option) any later version.
+# 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
@@ -17,35 +16,62 @@
# This file is public domain and comes with NO WARRANTY of any kind
#AUTOMAKE_OPTIONS = nostdinc
-INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
- -I$(top_srcdir)/regex $(openssl_includes)
+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 mysqlmanagerc mysqlmanager-pwgen
+ mysqldump mysqlimport mysqltest mysqlbinlog \
+ mysql_upgrade \
+ mysqltestmanagerc mysqltestmanager-pwgen
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
mysqladmin_SOURCES = mysqladmin.cc
mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD) $(CXXLDFLAGS)
-mysqlbinlog_LDADD = $(LDADD) $(CXXLDFLAGS)
-mysqltest_SOURCES= mysqltest.c \
+mysqltest_SOURCES= mysqltest.c \
$(top_srcdir)/mysys/my_getsystime.c \
$(top_srcdir)/mysys/my_copy.c
+
mysqltest_LDADD = $(top_builddir)/regex/libregex.a $(LDADD)
-mysqlbinlog_SOURCES = mysqlbinlog.cc ../mysys/mf_tempdir.c
-mysqlmanagerc_SOURCES = mysqlmanagerc.c
-sql_src=log_event.h log_event.cc
+mysqlbinlog_SOURCES = mysqlbinlog.cc \
+ $(top_srcdir)/mysys/mf_tempdir.c \
+ $(top_srcdir)/mysys/my_new.cc
+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 \
+ $(top_srcdir)/mysys/mf_getdate.c
+mysqlimport_SOURCES= mysqlimport.c
+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
+DEFS = -DUNDEF_THREADS_HACK \
+ -DDEFAULT_MYSQL_HOME="\"$(prefix)\"" \
+ -DDATADIR="\"$(localstatedir)\""
+
+EXTRA_DIST = get_password.c CMakeLists.txt echo.c
link_sources:
for f in $(sql_src) ; do \
rm -f $$f; \
@LN_CP_F@ $(top_srcdir)/sql/$$f $$f; \
- done;
+ done; \
+ for f in $(strings_src) ; do \
+ rm -f $(srcdir)/$$f; \
+ @LN_CP_F@ $(top_srcdir)/strings/$$f $$f; \
+ done; \
+ rm -f $(srcdir)/my_user.c; \
+ @LN_CP_F@ $(top_srcdir)/sql-common/my_user.c my_user.c;
+
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/client/client_priv.h b/client/client_priv.h
index 37ed407de68..7748dc612d6 100644
--- a/client/client_priv.h
+++ b/client/client_priv.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2001-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; either version 2 of the License, or
- (at your option) any later version.
+ 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
@@ -45,10 +44,12 @@ enum options_client
OPT_COMPATIBLE, OPT_RECONNECT, OPT_DELIMITER, OPT_SECURE_AUTH,
OPT_OPEN_FILES_LIMIT, OPT_SET_CHARSET, OPT_CREATE_OPTIONS,
OPT_START_POSITION, OPT_STOP_POSITION, OPT_START_DATETIME, OPT_STOP_DATETIME,
- OPT_SIGINT_IGNORE, OPT_HEXBLOB, OPT_ORDER_BY_PRIMARY
+ OPT_SIGINT_IGNORE, OPT_HEXBLOB, OPT_ORDER_BY_PRIMARY, OPT_COUNT,
#ifdef HAVE_NDBCLUSTER_DB
- ,OPT_NDBCLUSTER,OPT_NDB_CONNECTSTRING
+ OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING,
#endif
- ,OPT_IGNORE_TABLE,OPT_INSERT_IGNORE,OPT_DROP_DATABASE,
- OPT_AUTO_CLOSE
+ OPT_TRIGGERS,
+ 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
};
diff --git a/client/completion_hash.cc b/client/completion_hash.cc
index 7a3b363c93c..4c777f8a704 100644
--- a/client/completion_hash.cc
+++ b/client/completion_hash.cc
@@ -2,8 +2,7 @@
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; either version 2 of the License, or
- (at your option) any later version.
+ 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
diff --git a/client/completion_hash.h b/client/completion_hash.h
index 2595a445c9d..b91d6e4d187 100644
--- a/client/completion_hash.h
+++ b/client/completion_hash.h
@@ -1,9 +1,9 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2002 MySQL AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
+ License as published by the Free Software Foundation; version 2
+ of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/client/get_password.c b/client/get_password.c
index 1b7b4e65a9f..e7e6c850469 100644
--- a/client/get_password.c
+++ b/client/get_password.c
@@ -2,8 +2,7 @@
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; either version 2 of the License, or
- (at your option) any later version.
+ 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
diff --git a/client/my_readline.h b/client/my_readline.h
index 6052d462ab9..47be7fa9294 100644
--- a/client/my_readline.h
+++ b/client/my_readline.h
@@ -2,8 +2,7 @@
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; either version 2 of the License, or
- (at your option) any later version.
+ 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
diff --git a/client/mysql.cc b/client/mysql.cc
index d8810ba3c28..75dae284b61 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -2,8 +2,7 @@
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; either version 2 of the License, or
- (at your option) any later version.
+ 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
@@ -44,11 +43,14 @@
#include <locale.h>
#endif
-const char *VER= "14.7";
+const char *VER= "14.12";
/* 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
+
gptr sql_alloc(unsigned size); // Don't use mysqld alloc for these
void sql_element_free(void *ptr);
#include "sql_string.h"
@@ -135,7 +137,9 @@ static my_bool info_flag=0,ignore_errors=0,wait_flag=0,quick=0,
opt_xml=0,opt_nopager=1, opt_outfile=0, named_cmds= 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;
+ default_pager_set= 0, opt_sigint_ignore= 0,
+ show_warnings= 0;
+static volatile int executing_query= 0, interrupted_query= 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;
@@ -144,6 +148,7 @@ static char *current_host,*current_db,*current_user=0,*opt_password=0,
*current_prompt=0, *delimiter_str= 0,
*default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
static char *histfile;
+static char *histfile_tmp;
static String glob_buffer,old_buffer;
static String processed_prompt;
static char *full_username=0,*part_username=0,*default_prompt=0;
@@ -154,6 +159,8 @@ static char mysql_charsets_dir[FN_REFLEN+1];
static const char *xmlmeta[] = {
"&", "&amp;",
"<", "&lt;",
+ ">", "&gt;",
+ "\"", "&quot;",
0, 0
};
static const char *day_names[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
@@ -181,6 +188,7 @@ void tee_fprintf(FILE *file, const char *fmt, ...);
void tee_fputs(const char *s, FILE *file);
void tee_puts(const char *s, FILE *file);
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);
static int com_quit(String *str,char*),
@@ -191,16 +199,18 @@ static int com_quit(String *str,char*),
com_use(String *str,char*), com_source(String *str, char*),
com_rehash(String *str, char*), com_tee(String *str, char*),
com_notee(String *str, char*), com_charset(String *str,char*),
- com_prompt(String *str, char*), com_delimiter(String *str, char*);
+ com_prompt(String *str, char*), com_delimiter(String *str, char*),
+ com_warnings(String *str, char*), com_nowarnings(String *str, char*);
#ifdef USE_POPEN
static int com_nopager(String *str, char*), com_pager(String *str, char*),
com_edit(String *str,char*), com_shell(String *str, char *);
#endif
-static int read_lines(bool execute_commands);
+static int read_and_execute(bool interactive);
static int sql_connect(char *host,char *database,char *user,char *password,
uint silent);
+static const char *server_version_string(MYSQL *mysql);
static int put_info(const char *str,INFO_TYPE info,uint error=0,
const char *sql_state=0);
static int put_error(MYSQL *mysql);
@@ -232,7 +242,7 @@ static COMMANDS commands[] = {
{ "connect",'r', com_connect,1,
"Reconnect to the server. Optional arguments are db and host." },
{ "delimiter", 'd', com_delimiter, 1,
- "Set query delimiter. " },
+ "Set statement delimiter. NOTE: Takes the rest of the line as new delimiter." },
#ifdef USE_POPEN
{ "edit", 'e', com_edit, 0, "Edit command with $EDITOR."},
#endif
@@ -263,8 +273,12 @@ static COMMANDS commands[] = {
"Set outfile [to_outfile]. Append everything into given outfile." },
{ "use", 'u', com_use, 1,
"Use another database. Takes database name as argument." },
- { "charset_name", 'C', com_charset, 1,
- "Switch to another charset. Might be needed for processing binlog." },
+ { "charset", 'C', com_charset, 1,
+ "Switch to another charset. Might be needed for processing binlog with multi-byte charsets." },
+ { "warnings", 'W', com_warnings, 0,
+ "Show warnings after every statement." },
+ { "nowarning", 'w', com_nowarnings, 0,
+ "Don't show warnings after every statement." },
/* Get bash-like expansion for some commands */
{ "create table", 0, 0, 0, ""},
{ "create database", 0, 0, 0, ""},
@@ -313,7 +327,7 @@ static void initialize_readline (char *name);
static void fix_history(String *final_command);
#endif
-static COMMANDS *find_command (char *name,char cmd_name);
+static COMMANDS *find_command(char *name,char cmd_name);
static bool add_line(String &buffer,char *line,char *in_string,
bool *ml_comment);
static void remove_cntrl(String &buffer);
@@ -322,26 +336,27 @@ static void print_table_data_html(MYSQL_RES *result);
static void print_table_data_xml(MYSQL_RES *result);
static void print_tab_data(MYSQL_RES *result);
static void print_table_data_vertically(MYSQL_RES *result);
+static void print_warnings(void);
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);
int main(int argc,char *argv[])
{
char buff[80];
- char *defaults, *extra_defaults;
- char *emb_argv[3];
- int emb_argc= 1;
+ char *defaults, *extra_defaults, *group_suffix;
+ char *emb_argv[4];
+ int emb_argc;
- emb_argv[0]= argv[0];
- get_defaults_files(argc, argv, &defaults, &extra_defaults);
- if (defaults)
- emb_argv[emb_argc++]= defaults;
- if (extra_defaults)
- emb_argv[emb_argc++]= extra_defaults;
+ /* 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");
@@ -425,7 +440,7 @@ int main(int argc,char *argv[])
if (opt_sigint_ignore)
signal(SIGINT, SIG_IGN);
else
- signal(SIGINT, mysql_end); // Catch SIGINT to clean up
+ signal(SIGINT, mysql_sigint); // Catch SIGINT to clean up
signal(SIGQUIT, mysql_end); // Catch SIGQUIT to clean up
/*
@@ -435,12 +450,12 @@ int main(int argc,char *argv[])
put_info("Welcome to the MySQL monitor. Commands end with ; or \\g.",
INFO_INFO);
sprintf((char*) glob_buffer.ptr(),
- "Your MySQL connection id is %lu to server version: %s\n",
- mysql_thread_id(&mysql),mysql_get_server_info(&mysql));
+ "Your MySQL connection id is %lu\nServer version: %s\n",
+ mysql_thread_id(&mysql), server_version_string(&mysql));
put_info((char*) glob_buffer.ptr(),INFO_INFO);
#ifdef HAVE_READLINE
- initialize_readline(my_progname);
+ initialize_readline((char*) my_progname);
if (!status.batch && !quick && !opt_html && !opt_xml)
{
/* read-history from file, default ~/.mysql_history*/
@@ -453,12 +468,27 @@ int main(int argc,char *argv[])
MYF(MY_WME));
if (histfile)
sprintf(histfile,"%s/.mysql_history",getenv("HOME"));
+ char link_name[FN_REFLEN];
+ if (my_readlink(link_name, histfile, 0) == 0 &&
+ strncmp(link_name, "/dev/null", 10) == 0)
+ {
+ /* The .mysql_history file is a symlink to /dev/null, don't use it */
+ my_free(histfile, MYF(MY_ALLOW_ZERO_PTR));
+ histfile= 0;
+ }
}
if (histfile)
{
if (verbose)
tee_fprintf(stdout, "Reading history-file %s\n",histfile);
read_history(histfile);
+ if (!(histfile_tmp= (char*) my_malloc((uint) strlen(histfile) + 5,
+ MYF(MY_WME))))
+ {
+ fprintf(stderr, "Couldn't allocate memory for temp histfile!\n");
+ exit(1);
+ }
+ sprintf(histfile_tmp, "%s.TMP", histfile);
}
}
#endif
@@ -469,7 +499,7 @@ int main(int argc,char *argv[])
"Type 'help [[%]function name[%]]' to get help on usage of function.\n");
#endif
put_info(buff,INFO_INFO);
- status.exit_status=read_lines(1); // read lines and execute them
+ status.exit_status= read_and_execute(!status.batch);
if (opt_outfile)
end_tee();
mysql_end(0);
@@ -478,16 +508,39 @@ int main(int argc,char *argv[])
#endif
}
+sig_handler mysql_sigint(int sig)
+{
+ char kill_buffer[40];
+ MYSQL *kill_mysql= NULL;
+
+ signal(SIGINT, mysql_sigint);
+
+ /* terminate if no query being executed, or we already tried interrupting */
+ if (!executing_query || interrupted_query++)
+ mysql_end(sig);
+
+ kill_mysql= mysql_init(kill_mysql);
+ if (!mysql_real_connect(kill_mysql,current_host, current_user, opt_password,
+ "", opt_mysql_port, opt_mysql_unix_port,0))
+ mysql_end(sig);
+ /* kill_buffer is always big enough because max length of %lu is 15 */
+ sprintf(kill_buffer, "KILL /*!50000 QUERY */ %lu", mysql_thread_id(&mysql));
+ mysql_real_query(kill_mysql, kill_buffer, strlen(kill_buffer));
+ mysql_close(kill_mysql);
+ tee_fprintf(stdout, "Query aborted by Ctrl+C\n");
+}
+
sig_handler mysql_end(int sig)
{
mysql_close(&mysql);
#ifdef HAVE_READLINE
- if (!status.batch && !quick && !opt_html && !opt_xml)
+ if (!status.batch && !quick && !opt_html && !opt_xml && histfile)
{
/* write-history */
if (verbose)
tee_fprintf(stdout, "Writing history-file %s\n",histfile);
- write_history(histfile);
+ if (!write_history(histfile_tmp))
+ my_rename(histfile_tmp, histfile, MYF(MY_WME));
}
batch_readline_end(status.line_buff);
completion_hash_free(&ht);
@@ -502,6 +555,7 @@ sig_handler mysql_end(int sig)
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));
+ my_free(histfile_tmp,MYF(MY_ALLOW_ZERO_PTR));
my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
my_free(current_user,MYF(MY_ALLOW_ZERO_PTR));
@@ -623,7 +677,7 @@ static struct my_option my_long_options[] =
NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
- (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
+ (gptr*) &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,
@@ -700,6 +754,9 @@ static struct my_option my_long_options[] =
{"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},
+ {"show-warnings", OPT_SHOW_WARNINGS, "Show warnings after every statement.",
+ (gptr*) &show_warnings, (gptr*) &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}
};
@@ -722,7 +779,7 @@ static void usage(int version)
my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE,
readline, rl_library_version);
#else
- printf("%s Ver %s Distrib %s, for %s (%s)", my_progname, VER,
+ printf("%s Ver %s Distrib %s, for %s (%s)\n", my_progname, VER,
MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
#endif
@@ -761,10 +818,23 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
default_charset_used= 1;
break;
case OPT_DELIMITER:
- if (argument == disabled_my_option)
+ if (argument == disabled_my_option)
+ {
strmov(delimiter, DEFAULT_DELIMITER);
- else
- strmake(delimiter, argument, sizeof(delimiter) - 1);
+ }
+ else
+ {
+ /* Check that delimiter does not contain a backslash */
+ if (!strstr(argument, "\\"))
+ {
+ strmake(delimiter, argument, sizeof(delimiter) - 1);
+ }
+ else
+ {
+ put_info("DELIMITER cannot contain a backslash character", INFO_ERROR);
+ return 0;
+ }
+ }
delimiter_length= (uint)strlen(delimiter);
delimiter_str= delimiter;
break;
@@ -806,6 +876,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case OPT_NOPAGER:
printf("WARNING: option deprecated; use --disable-pager instead.\n");
opt_nopager= 1;
+ break;
case OPT_MYSQL_PROTOCOL:
{
if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0)
@@ -951,7 +1022,7 @@ static int get_options(int argc, char **argv)
return(0);
}
-static int read_lines(bool execute_commands)
+static int read_and_execute(bool interactive)
{
#if defined(OS2) || defined(__NETWARE__)
char linebuffer[254];
@@ -971,7 +1042,7 @@ static int read_lines(bool execute_commands)
for (;;)
{
- if (status.batch || !execute_commands)
+ if (!interactive)
{
line=batch_readline(status.line_buff);
line_number++;
@@ -990,6 +1061,8 @@ static int read_lines(bool execute_commands)
if (opt_outfile && glob_buffer.is_empty())
fflush(OUTFILE);
+ interrupted_query= 0;
+
#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__)
tee_fputs(prompt, stdout);
#if defined(__NETWARE__)
@@ -1004,11 +1077,12 @@ static int read_lines(bool execute_commands)
#elif defined(__WIN__)
if (!tmpbuf.is_alloced())
tmpbuf.alloc(65535);
+ tmpbuf.length(0);
buffer.length(0);
unsigned long clen;
do
{
- line= my_cgets((char *) tmpbuf.ptr(), tmpbuf.alloced_length()-1, &clen);
+ line= my_cgets((char*)tmpbuf.ptr(), tmpbuf.alloced_length()-1, &clen);
buffer.append(line, clen);
/*
if we got buffer fully filled than there is a chance that
@@ -1064,7 +1138,7 @@ static int read_lines(bool execute_commands)
Check if line is a mysql command line
(We want to allow help, print and clear anywhere at line start
*/
- if (execute_commands && (named_cmds || glob_buffer.is_empty())
+ if ((named_cmds || glob_buffer.is_empty())
&& !ml_comment && !in_string && (com=find_command(line,0)))
{
if ((*com->func)(&glob_buffer,line) > 0)
@@ -1072,7 +1146,7 @@ static int read_lines(bool execute_commands)
if (glob_buffer.is_empty()) // If buffer was emptied
in_string=0;
#ifdef HAVE_READLINE
- if (status.add_to_history && not_in_history(line))
+ if (interactive && status.add_to_history && not_in_history(line))
add_history(line);
#endif
continue;
@@ -1082,7 +1156,7 @@ static int read_lines(bool execute_commands)
}
/* if in batch mode, send last query even if it doesn't end with \g or go */
- if ((status.batch || !execute_commands) && !status.exit_status)
+ if (!interactive && !status.exit_status)
{
remove_cntrl(glob_buffer);
if (!glob_buffer.is_empty())
@@ -1104,10 +1178,12 @@ static int read_lines(bool execute_commands)
}
-static COMMANDS *find_command (char *name,char cmd_char)
+static COMMANDS *find_command(char *name,char cmd_char)
{
uint len;
char *end;
+ DBUG_ENTER("find_command");
+ DBUG_PRINT("enter",("name: '%s' char: %d", name ? name : "NULL", cmd_char));
if (!name)
{
@@ -1118,8 +1194,18 @@ static COMMANDS *find_command (char *name,char cmd_char)
{
while (my_isspace(charset_info,*name))
name++;
- if (strstr(name, delimiter) || strstr(name, "\\g"))
- return ((COMMANDS *) 0);
+ /*
+ If there is an \\g in the row or if the row has a delimiter but
+ this is not a delimiter command, let add_line() take care of
+ parsing the row and calling find_command()
+ */
+ if (strstr(name, "\\g") || (strstr(name, delimiter) &&
+ !(strlen(name) >= 9 &&
+ !my_strnncoll(charset_info,
+ (uchar*) name, 9,
+ (const uchar*) "delimiter",
+ 9))))
+ DBUG_RETURN((COMMANDS *) 0);
if ((end=strcont(name," \t")))
{
len=(uint) (end - name);
@@ -1135,15 +1221,18 @@ static COMMANDS *find_command (char *name,char cmd_char)
for (uint i= 0; commands[i].name; i++)
{
if (commands[i].func &&
- ((name &&
+ ((name &&
!my_strnncoll(charset_info,(uchar*)name,len,
(uchar*)commands[i].name,len) &&
!commands[i].name[len] &&
(!end || (end && commands[i].takes_params))) ||
!name && commands[i].cmd_char == cmd_char))
- return (&commands[i]);
+ {
+ DBUG_PRINT("exit",("found command: %s", commands[i].name));
+ DBUG_RETURN(&commands[i]);
+ }
}
- return ((COMMANDS *) 0);
+ DBUG_RETURN((COMMANDS *) 0);
}
@@ -1153,15 +1242,17 @@ static bool add_line(String &buffer,char *line,char *in_string,
uchar inchar;
char buff[80], *pos, *out;
COMMANDS *com;
+ bool need_space= 0;
+ DBUG_ENTER("add_line");
if (!line[0] && buffer.is_empty())
- return 0;
+ DBUG_RETURN(0);
#ifdef HAVE_READLINE
if (status.add_to_history && line[0] && not_in_history(line))
add_history(line);
#endif
#ifdef USE_MB
- char *strend=line+(uint) strlen(line);
+ char *end_of_line=line+(uint) strlen(line);
#endif
for (pos=out=line ; (inchar= (uchar) *pos) ; pos++)
@@ -1170,22 +1261,23 @@ static bool add_line(String &buffer,char *line,char *in_string,
buffer.is_empty())
continue;
#ifdef USE_MB
- int l;
+ int length;
if (use_mb(charset_info) &&
- (l= my_ismbchar(charset_info, pos, strend)))
+ (length= my_ismbchar(charset_info, pos, end_of_line)))
{
if (!*ml_comment)
{
- while (l--)
+ while (length--)
*out++ = *pos++;
pos--;
}
else
- pos+= l - 1;
+ pos+= length - 1;
continue;
}
#endif
- if (!*ml_comment && inchar == '\\')
+ if (!*ml_comment && inchar == '\\' &&
+ !(mysql.server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES))
{
// Found possbile one character command like \c
@@ -1202,7 +1294,7 @@ static bool add_line(String &buffer,char *line,char *in_string,
const String tmp(line,(uint) (out-line), charset_info);
buffer.append(tmp);
if ((*com->func)(&buffer,pos-1) > 0)
- return 1; // Quit
+ DBUG_RETURN(1); // Quit
if (com->takes_params)
{
for (pos++ ;
@@ -1220,29 +1312,40 @@ static bool add_line(String &buffer,char *line,char *in_string,
{
sprintf(buff,"Unknown command '\\%c'.",inchar);
if (put_info(buff,INFO_ERROR) > 0)
- return 1;
+ DBUG_RETURN(1);
*out++='\\';
*out++=(char) inchar;
continue;
}
}
-
- else if (!*ml_comment && (*pos == *delimiter &&
- is_prefix(pos + 1, delimiter + 1)) &&
- !*in_string)
+ else if (!*ml_comment && !*in_string &&
+ (*pos == *delimiter && is_prefix(pos + 1, delimiter + 1) ||
+ buffer.length() == 0 && (out - line) >= 9 &&
+ !my_strcasecmp(charset_info, line, "delimiter")))
{
uint old_delimiter_length= delimiter_length;
if (out != line)
buffer.append(line, (uint) (out - line)); // Add this line
if ((com= find_command(buffer.c_ptr(), 0)))
{
+ if (com->func == com_delimiter)
+ {
+ /*
+ Delimiter wants the get rest of the given line as argument to
+ allow one to change ';' to ';;' and back
+ */
+ char *end= strend(pos);
+ buffer.append(pos, (uint) (end - pos));
+ /* Ensure pos will point at \0 after the pos+= below */
+ pos= end - old_delimiter_length + 1;
+ }
if ((*com->func)(&buffer, buffer.c_ptr()) > 0)
- return 1; // Quit
+ DBUG_RETURN(1); // Quit
}
else
{
if (com_go(&buffer, 0) > 0) // < 0 is not fatal
- return 1;
+ DBUG_RETURN(1);
}
buffer.length(0);
out= line;
@@ -1267,6 +1370,7 @@ static bool add_line(String &buffer,char *line,char *in_string,
{
pos++;
*ml_comment= 0;
+ need_space= 1;
}
else
{ // Add found char to buffer
@@ -1276,7 +1380,14 @@ static bool add_line(String &buffer,char *line,char *in_string,
(inchar == '\'' || inchar == '"' || inchar == '`'))
*in_string= (char) inchar;
if (!*ml_comment)
+ {
+ if (need_space && !my_isspace(charset_info, (char)inchar))
+ {
+ *out++= ' ';
+ need_space= 0;
+ }
*out++= (char) inchar;
+ }
}
}
if (out != line || !buffer.is_empty())
@@ -1286,9 +1397,9 @@ static bool add_line(String &buffer,char *line,char *in_string,
if (buffer.length() + length >= buffer.alloced_length())
buffer.realloc(buffer.length()+length+IO_SIZE);
if (!(*ml_comment) && buffer.append(line,length))
- return 1;
+ DBUG_RETURN(1);
}
- return 0;
+ DBUG_RETURN(0);
}
/*****************************************************************
@@ -1309,7 +1420,7 @@ static char **new_mysql_completion (const char *text, int start, int end);
#if defined(USE_NEW_READLINE_INTERFACE) || defined(USE_LIBEDIT_INTERFACE)
char *no_completion(const char*,int)
#else
-int no_completion()
+char *no_completion()
#endif
{
return 0; /* No filename completion */
@@ -1397,10 +1508,10 @@ static void initialize_readline (char *name)
setlocale(LC_ALL,""); /* so as libedit use isprint */
#endif
rl_attempted_completion_function= (CPPFunction*)&new_mysql_completion;
- rl_completion_entry_function= (Function*)&no_completion;
+ rl_completion_entry_function= &no_completion;
#else
rl_attempted_completion_function= (CPPFunction*)&new_mysql_completion;
- rl_completion_entry_function= (Function*)&no_completion;
+ rl_completion_entry_function= &no_completion;
#endif
}
@@ -1694,11 +1805,12 @@ int mysql_real_query_for_lazy(const char *buf, int length)
{
for (uint retry=0;; retry++)
{
+ int error;
if (!mysql_real_query(&mysql,buf,length))
return 0;
- int error= put_error(&mysql);
+ error= put_error(&mysql);
if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1 ||
- !opt_reconnect)
+ !opt_reconnect)
return error;
if (reconnect())
return error;
@@ -1893,6 +2005,9 @@ com_charset(String *buffer __attribute__((unused)), char *line)
if (new_cs)
{
charset_info= new_cs;
+ mysql_set_character_set(&mysql, charset_info->csname);
+ default_charset= (char *)charset_info->csname;
+ default_charset_used= 1;
put_info("Charset changed", INFO_INFO);
}
else put_info("Charset is not found", INFO_INFO);
@@ -1952,6 +2067,8 @@ 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
@@ -1966,6 +2083,7 @@ com_go(String *buffer,char *line __attribute__((unused)))
if (error)
{
buffer->length(0); // Remove query on error
+ executing_query= 0;
return error;
}
error=0;
@@ -1976,13 +2094,19 @@ com_go(String *buffer,char *line __attribute__((unused)))
if (quick)
{
if (!(result=mysql_use_result(&mysql)) && mysql_field_count(&mysql))
+ {
+ executing_query= 0;
return put_error(&mysql);
+ }
}
else
{
error= mysql_store_result_for_lazy(&result);
if (error)
+ {
+ executing_query= 0;
return error;
+ }
}
if (verbose >= 3 || !opt_silent)
@@ -1991,7 +2115,7 @@ com_go(String *buffer,char *line __attribute__((unused)))
time_buff[0]=0;
if (result)
{
- if (!mysql_num_rows(result) && ! quick)
+ if (!mysql_num_rows(result) && ! quick && !info_flag)
{
strmov(buff, "Empty set");
}
@@ -2045,9 +2169,19 @@ 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();
+ print_warnings();
+ end_pager();
+ }
+
if (!error && !status.batch &&
(mysql.server_status & SERVER_STATUS_DB_DROPPED))
get_current_db();
@@ -2107,6 +2241,7 @@ static void end_tee()
return;
}
+
static int
com_ego(String *buffer,char *line)
{
@@ -2118,18 +2253,95 @@ com_ego(String *buffer,char *line)
return result;
}
+
+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";
+ default: return "?-unknown-?";
+ }
+}
+
+static char *fieldflags2str(uint f) {
+ static char buf[1024];
+ char *s=buf;
+ *s=0;
+#define ff2s_check_flag(X) \
+ if (f & X ## _FLAG) { s=strmov(s, # X " "); f &= ~ X ## _FLAG; }
+ ff2s_check_flag(NOT_NULL);
+ ff2s_check_flag(PRI_KEY);
+ ff2s_check_flag(UNIQUE_KEY);
+ ff2s_check_flag(MULTIPLE_KEY);
+ ff2s_check_flag(BLOB);
+ ff2s_check_flag(UNSIGNED);
+ ff2s_check_flag(ZEROFILL);
+ ff2s_check_flag(BINARY);
+ ff2s_check_flag(ENUM);
+ ff2s_check_flag(AUTO_INCREMENT);
+ ff2s_check_flag(TIMESTAMP);
+ ff2s_check_flag(SET);
+ ff2s_check_flag(NO_DEFAULT_VALUE);
+ ff2s_check_flag(NUM);
+ ff2s_check_flag(PART_KEY);
+ ff2s_check_flag(GROUP);
+ ff2s_check_flag(UNIQUE);
+ ff2s_check_flag(BINCMP);
+#undef ff2s_check_flag
+ if (f)
+ sprintf(s, " unknows=0x%04x", f);
+ return buf;
+}
+
static void
print_field_types(MYSQL_RES *result)
{
- MYSQL_FIELD *field;
+ MYSQL_FIELD *field;
+ uint i=0;
+
while ((field = mysql_fetch_field(result)))
{
- tee_fprintf(PAGER,"Catalog: '%s'\nDatabase: '%s'\nTable: '%s'\nName: '%s'\nType: %d\nLength: %ld\nMax length: %ld\nIs_null: %d\nFlags: %u\nDecimals: %u\n\n",
- field->catalog, field->db, field->table, field->name,
- (int) field->type,
- field->length, field->max_length,
- !IS_NOT_NULL(field->flags),
- field->flags, field->decimals);
+ tee_fprintf(PAGER, "Field %3u: `%s`\n"
+ "Catalog: `%s`\n"
+ "Database: `%s`\n"
+ "Table: `%s`\n"
+ "Org_table: `%s`\n"
+ "Type: %s\n"
+ "Collation: %s (%u)\n"
+ "Length: %lu\n"
+ "Max_length: %lu\n"
+ "Decimals: %u\n"
+ "Flags: %s\n\n",
+ ++i,
+ field->name, field->catalog, field->db, field->table,
+ field->org_table, fieldtype2str(field->type),
+ get_charset_name(field->charsetnr), field->charsetnr,
+ field->length, field->max_length, field->decimals,
+ fieldflags2str(field->flags));
}
tee_puts("", PAGER);
}
@@ -2147,6 +2359,8 @@ print_table_data(MYSQL_RES *result)
if (info_flag)
{
print_field_types(result);
+ if (!mysql_num_rows(result))
+ return;
mysql_field_seek(result,0);
}
separator.copy("+",1,charset_info);
@@ -2159,7 +2373,7 @@ print_table_data(MYSQL_RES *result)
length=max(length,field->max_length);
if (length < 4 && !IS_NOT_NULL(field->flags))
length=4; // Room for "NULL"
- field->max_length=length+1;
+ field->max_length=length;
separator.fill(separator.length()+length+2,'-');
separator.append('+');
}
@@ -2176,7 +2390,7 @@ print_table_data(MYSQL_RES *result)
field->name,
field->name + name_length);
uint display_length= field->max_length + name_length - numcells;
- tee_fprintf(PAGER, " %-*s|",(int) min(display_length,
+ tee_fprintf(PAGER, " %-*s |",(int) min(display_length,
MAX_COLUMN_LENGTH),
field->name);
num_flag[off]= IS_NUM(field->type);
@@ -2188,26 +2402,52 @@ print_table_data(MYSQL_RES *result)
while ((cur= mysql_fetch_row(result)))
{
ulong *lengths= mysql_fetch_lengths(result);
- (void) tee_fputs("|", PAGER);
+ (void) tee_fputs("| ", PAGER);
mysql_field_seek(result, 0);
for (uint off= 0; off < mysql_num_fields(result); off++)
{
- const char *str= cur[off] ? cur[off] : "NULL";
- field= mysql_fetch_field(result);
- uint maxlength= field->max_length;
- if (maxlength > MAX_COLUMN_LENGTH)
+ const char *buffer;
+ uint data_length;
+ uint field_max_length;
+ uint visible_length;
+ uint extra_padding;
+
+ /* If this column may have a null value, use "NULL" for empty. */
+ if (cur[off] == NULL)
+ {
+ buffer= "NULL";
+ data_length= 4;
+ }
+ else
{
- tee_fputs(str, PAGER);
- tee_fputs(" |", PAGER);
+ buffer= cur[off];
+ data_length= (uint) lengths[off];
}
+
+ field= mysql_fetch_field(result);
+ field_max_length= field->max_length;
+
+ /*
+ How many text cells on the screen will this string span? If it contains
+ multibyte characters, then the number of characters we occupy on screen
+ will be fewer than the number of bytes we occupy in memory.
+
+ We need to find how much screen real-estate we will occupy to know how
+ many extra padding-characters we should send with the printing function.
+ */
+ visible_length= charset_info->cset->numcells(charset_info, buffer, buffer + data_length);
+ extra_padding= data_length - visible_length;
+
+ if (field_max_length > MAX_COLUMN_LENGTH)
+ tee_print_sized_data(buffer, data_length, MAX_COLUMN_LENGTH+extra_padding, FALSE);
else
{
- uint currlength= (uint) lengths[off];
- uint numcells= charset_info->cset->numcells(charset_info,
- str, str + currlength);
- tee_fprintf(PAGER, num_flag[off] ? "%*s |" : " %-*s|",
- maxlength + currlength - numcells, str);
+ if (num_flag[off] != 0) /* if it is numeric, we right-justify it */
+ tee_print_sized_data(buffer, data_length, field_max_length+extra_padding, TRUE);
+ else
+ tee_print_sized_data(buffer, data_length, field_max_length+extra_padding, FALSE);
}
+ tee_fputs(" | ", PAGER);
}
(void) tee_fputs("\n", PAGER);
}
@@ -2217,6 +2457,36 @@ print_table_data(MYSQL_RES *result)
static void
+tee_print_sized_data(const char *data, unsigned int data_length, unsigned int total_bytes_to_send, bool right_justified)
+{
+ /*
+ For '\0's print ASCII spaces instead, as '\0' is eaten by (at
+ least my) console driver, and that messes up the pretty table
+ grid. (The \0 is also the reason we can't use fprintf() .)
+ */
+ unsigned int i;
+ const char *p;
+
+ if (right_justified)
+ for (i= data_length; i < total_bytes_to_send; i++)
+ tee_putc((int)' ', PAGER);
+
+ for (i= 0, p= data; i < data_length; i+= 1, p+= 1)
+ {
+ if (*p == '\0')
+ tee_putc((int)' ', PAGER);
+ else
+ tee_putc((int)*p, PAGER);
+ }
+
+ if (! right_justified)
+ for (i= data_length; i < total_bytes_to_send; i++)
+ tee_putc((int)' ', PAGER);
+}
+
+
+
+static void
print_table_data_html(MYSQL_RES *result)
{
MYSQL_ROW cur;
@@ -2269,13 +2539,16 @@ print_table_data_xml(MYSQL_RES *result)
(void) tee_fputs("\n <row>\n", PAGER);
for (uint i=0; i < mysql_num_fields(result); i++)
{
- tee_fprintf(PAGER, "\t<%s>", (fields[i].name ?
- (fields[i].name[0] ? fields[i].name :
- " &nbsp; ") : "NULL"));
- xmlencode_print(cur[i], lengths[i]);
- tee_fprintf(PAGER, "</%s>\n", (fields[i].name ?
- (fields[i].name[0] ? fields[i].name :
- " &nbsp; ") : "NULL"));
+ tee_fprintf(PAGER, "\t<field name=\"");
+ xmlencode_print(fields[i].name, (uint) strlen(fields[i].name));
+ if (cur[i])
+ {
+ tee_fprintf(PAGER, "\">");
+ xmlencode_print(cur[i], lengths[i]);
+ tee_fprintf(PAGER, "</field>\n");
+ }
+ else
+ tee_fprintf(PAGER, "\" xsi:nil=\"true\" />\n");
}
(void) tee_fputs(" </row>\n", PAGER);
}
@@ -2314,13 +2587,41 @@ print_table_data_vertically(MYSQL_RES *result)
}
-static const char
-*array_value(const char **array, char key)
+/* print_warnings should be called right after executing a statement */
+
+static void print_warnings()
+{
+ const char *query;
+ MYSQL_RES *result;
+ MYSQL_ROW cur;
+ my_ulonglong num_rows;
+
+ /* Get the warnings */
+ query= "show warnings";
+ 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;
+ }
+
+ /* Print the warnings */
+ while ((cur= mysql_fetch_row(result)))
+ {
+ tee_fprintf(PAGER, "%s (Code %s): %s\n", cur[0], cur[1], cur[2]);
+ }
+ mysql_free_result(result);
+}
+
+
+static const char *array_value(const char **array, char key)
{
- int x;
- for (x= 0; array[x]; x+= 2)
- if (*array[x] == key)
- return array[x + 1];
+ for (; *array; array+= 2)
+ if (**array == key)
+ return array[1];
return 0;
}
@@ -2646,7 +2947,11 @@ com_connect(String *buffer, char *line)
bzero(buff, sizeof(buff));
if (buffer)
{
- strmake(buff, line, sizeof(buff) - 1);
+ /*
+ Two null bytes are needed in the end of buff to allow
+ get_arg to find end of string the second time it's called.
+ */
+ strmake(buff, line, sizeof(buff)-2);
tmp= get_arg(buff, 0);
if (tmp && *tmp)
{
@@ -2724,7 +3029,7 @@ static int com_source(String *buffer, char *line)
status.line_buff=line_buff;
status.file_name=source_name;
glob_buffer.length(0); // Empty command buffer
- error=read_lines(0); // Read lines from file
+ error= read_and_execute(false);
status=old_status; // Continue as before
my_fclose(sql_file,MYF(0));
batch_readline_end(line_buff);
@@ -2747,6 +3052,14 @@ com_delimiter(String *buffer __attribute__((unused)), char *line)
INFO_ERROR);
return 0;
}
+ else
+ {
+ if (strstr(tmp, "\\"))
+ {
+ put_info("DELIMITER cannot contain a backslash character", INFO_ERROR);
+ return 0;
+ }
+ }
strmake(delimiter, tmp, sizeof(delimiter) - 1);
delimiter_length= (int)strlen(delimiter);
delimiter_str= delimiter;
@@ -2758,6 +3071,7 @@ static int
com_use(String *buffer __attribute__((unused)), char *line)
{
char *tmp, buff[FN_REFLEN + 1];
+ int select_db;
bzero(buff, sizeof(buff));
strmake(buff, line, sizeof(buff) - 1);
@@ -2777,38 +3091,73 @@ com_use(String *buffer __attribute__((unused)), char *line)
if (!current_db || cmp_database(charset_info, current_db,tmp))
{
if (one_database)
+ {
skip_updates= 1;
+ select_db= 0; // don't do mysql_select_db()
+ }
else
- {
- /*
- reconnect once if connection is down or if connection was found to
- be down during query
- */
- if (!connected && reconnect())
+ select_db= 2; // do mysql_select_db() and build_completion_hash()
+ }
+ else
+ {
+ /*
+ USE to the current db specified.
+ We do need to send mysql_select_db() to make server
+ update database level privileges, which might
+ change since last USE (see bug#10979).
+ For performance purposes, we'll skip rebuilding of completion hash.
+ */
+ skip_updates= 0;
+ select_db= 1; // do only mysql_select_db(), without completion
+ }
+
+ if (select_db)
+ {
+ /*
+ reconnect once if connection is down or if connection was found to
+ be down during query
+ */
+ if (!connected && reconnect())
return opt_reconnect ? -1 : 1; // Fatal error
- if (mysql_select_db(&mysql,tmp))
- {
- if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR)
- return put_error(&mysql);
+ if (mysql_select_db(&mysql,tmp))
+ {
+ if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR)
+ return put_error(&mysql);
- if (reconnect())
+ if (reconnect())
return opt_reconnect ? -1 : 1; // Fatal error
- if (mysql_select_db(&mysql,tmp))
- return put_error(&mysql);
- }
- my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
- current_db=my_strdup(tmp,MYF(MY_WME));
+ if (mysql_select_db(&mysql,tmp))
+ return put_error(&mysql);
+ }
+ my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
+ current_db=my_strdup(tmp,MYF(MY_WME));
#ifdef HAVE_READLINE
+ if (select_db > 1)
build_completion_hash(rehash, 1);
#endif
- }
}
- else
- skip_updates= 0;
+
put_info("Database changed",INFO_INFO);
return 0;
}
+static int
+com_warnings(String *buffer __attribute__((unused)),
+ char *line __attribute__((unused)))
+{
+ show_warnings = 1;
+ put_info("Show warnings enabled.",INFO_INFO);
+ return 0;
+}
+
+static int
+com_nowarnings(String *buffer __attribute__((unused)),
+ char *line __attribute__((unused)))
+{
+ show_warnings = 0;
+ put_info("Show warnings disabled.",INFO_INFO);
+ return 0;
+}
/*
Gets argument from a command on the command line. If get_next_arg is
@@ -2898,6 +3247,8 @@ sql_real_connect(char *host,char *database,char *user,char *password,
if (opt_use_ssl)
mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
opt_ssl_capath, opt_ssl_cipher);
+ mysql_options(&mysql,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
+ (char*)&opt_ssl_verify_server_cert);
#endif
if (opt_protocol)
mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
@@ -2932,6 +3283,8 @@ 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
+#else
+ mysql.reconnect= 1;
#endif
#ifdef HAVE_READLINE
build_completion_hash(rehash, 1);
@@ -3006,10 +3359,9 @@ com_status(String *buffer __attribute__((unused)),
mysql_free_result(result);
}
#ifdef HAVE_OPENSSL
- if (mysql.net.vio && mysql.net.vio->ssl_arg &&
- SSL_get_cipher((SSL*) mysql.net.vio->ssl_arg))
+ if ((status= mysql_get_ssl_cipher(&mysql)))
tee_fprintf(stdout, "SSL:\t\t\tCipher in use is %s\n",
- SSL_get_cipher((SSL*) mysql.net.vio->ssl_arg));
+ status);
else
#endif /* HAVE_OPENSSL */
tee_puts("SSL:\t\t\tNot in use", stdout);
@@ -3032,16 +3384,13 @@ com_status(String *buffer __attribute__((unused)),
tee_fprintf(stdout, "Using outfile:\t\t'%s'\n", opt_outfile ? outfile : "");
#endif
tee_fprintf(stdout, "Using delimiter:\t%s\n", delimiter);
- tee_fprintf(stdout, "Server version:\t\t%s\n", mysql_get_server_info(&mysql));
+ tee_fprintf(stdout, "Server version:\t\t%s\n", server_version_string(&mysql));
tee_fprintf(stdout, "Protocol version:\t%d\n", mysql_get_proto_info(&mysql));
tee_fprintf(stdout, "Connection:\t\t%s\n", mysql_get_host_info(&mysql));
if ((id= mysql_insert_id(&mysql)))
tee_fprintf(stdout, "Insert id:\t\t%s\n", llstr(id, buff));
- /*
- Don't remove "limit 1",
- it is protection againts SQL_SELECT_LIMIT=0
- */
+ /* "limit 1" is protection against SQL_SELECT_LIMIT=0 */
if (!mysql_query(&mysql,"select @@character_set_client, @@character_set_connection, @@character_set_server, @@character_set_database limit 1") &&
(result=mysql_use_result(&mysql)))
{
@@ -3106,6 +3455,38 @@ select_limit, max_join_size);
return 0;
}
+static const char *
+server_version_string(MYSQL *mysql)
+{
+ static char buf[MAX_SERVER_VERSION_LENGTH] = "";
+
+ /* Only one thread calls this, so no synchronization is needed */
+ if (buf[0] == '\0')
+ {
+ char *bufp = buf;
+ MYSQL_RES *result;
+
+ bufp = strnmov(buf, mysql_get_server_info(mysql), sizeof buf);
+
+ /* "limit 1" is protection against SQL_SELECT_LIMIT=0 */
+ if (!mysql_query(mysql, "select @@version_comment limit 1") &&
+ (result = mysql_use_result(mysql)))
+ {
+ MYSQL_ROW cur = mysql_fetch_row(result);
+ if (cur && cur[0])
+ {
+ bufp = strxnmov(bufp, sizeof buf - (bufp - buf), " ", cur[0], NullS);
+ }
+ mysql_free_result(result);
+ }
+
+ /* str*nmov doesn't guarantee NUL-termination */
+ if (bufp == buf + sizeof buf)
+ buf[sizeof buf - 1] = '\0';
+ }
+
+ return buf;
+}
static int
put_info(const char *str,INFO_TYPE info_type, uint error, const char *sqlstate)
@@ -3155,7 +3536,7 @@ put_info(const char *str,INFO_TYPE info_type, uint error, const char *sqlstate)
if (info_type == INFO_ERROR)
{
if (!opt_nobeep)
- putchar('\007'); /* This should make a bell */
+ putchar('\a'); /* This should make a bell */
vidattr(A_STANDOUT);
if (error)
{
@@ -3233,14 +3614,14 @@ void tee_puts(const char *s, FILE *file)
{
NETWARE_YIELD;
fputs(s, file);
- fputs("\n", file);
+ fputc('\n', file);
#ifdef OS2
- fflush( file);
+ fflush(file);
#endif
if (opt_outfile)
{
fputs(s, OUTFILE);
- fputs("\n", OUTFILE);
+ fputc('\n', OUTFILE);
}
}
@@ -3391,12 +3772,14 @@ static const char* construct_prompt()
case 'U':
if (!full_username)
init_username();
- processed_prompt.append(full_username);
+ processed_prompt.append(full_username ? full_username :
+ (current_user ? current_user : "(unknown)"));
break;
case 'u':
if (!full_username)
init_username();
- processed_prompt.append(part_username);
+ processed_prompt.append(part_username ? part_username :
+ (current_user ? current_user : "(unknown)"));
break;
case PROMPT_CHAR:
processed_prompt.append(PROMPT_CHAR);
@@ -3473,6 +3856,9 @@ static const char* construct_prompt()
case 't':
processed_prompt.append('\t');
break;
+ case 'l':
+ processed_prompt.append(delimiter_str);
+ break;
default:
processed_prompt.append(c);
}
diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c
new file mode 100644
index 00000000000..8eb72af6b9d
--- /dev/null
+++ b/client/mysql_upgrade.c
@@ -0,0 +1,690 @@
+/* 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 */
+
+#include "client_priv.h"
+#include <my_dir.h>
+#include <my_list.h>
+#include <sslopt-vars.h>
+
+#define UPGRADE_DEFAULTS_NAME "mysql_upgrade_defaults"
+#define MYSQL_UPGRADE_INFO_NAME "mysql_upgrade_info"
+#define MYSQL_FIX_PRIV_TABLES_NAME "mysql_fix_privilege_tables.sql"
+
+#define MY_PARENT (1 << 0)
+#define MY_ISDIR (1 << 1)
+#define MY_SEARCH_SELF (1 << 2)
+
+#ifdef __WIN__
+const char *mysqlcheck_name= "mysqlcheck.exe";
+const char *mysql_name= "mysql.exe";
+const char *mysqld_name= "mysqld.exe";
+#define EXTRA_CLIENT_PATHS "client/release", "client/debug"
+#else
+const char *mysqlcheck_name= "mysqlcheck";
+const char *mysql_name= "mysql";
+const char *mysqld_name= "mysqld";
+#define EXTRA_CLIENT_PATHS "client"
+#endif /*__WIN__*/
+
+extern TYPELIB sql_protocol_typelib;
+
+static my_bool opt_force= 0, opt_verbose= 0, opt_compress= 0;
+static char *user= (char*) "root", *basedir= 0, *datadir= 0, *opt_password= 0;
+static char *current_host= 0;
+static char *opt_default_charset= 0, *opt_charsets_dir= 0;
+#ifdef HAVE_SMEM
+static char *shared_memory_base_name= 0;
+#endif
+static char *opt_protocol= 0;
+static my_string opt_mysql_port= 0, opt_mysql_unix_port= 0;
+#ifndef DBUG_OFF
+static char *default_dbug_option= (char*) "d:t:O,/tmp/mysql_upgrade.trace";
+#endif
+static my_bool info_flag= 0, tty_password= 0;
+
+static struct my_option my_long_options[]=
+{
+ {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
+ NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"basedir", 'b', "Specifies the directory where MySQL is installed",
+ (gptr*) &basedir,
+ (gptr*) &basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"datadir", 'd', "Specifies the data directory", (gptr*) &datadir,
+ (gptr*) &datadir, 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",
+ 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},
+#endif
+ {"debug-info", 'T', "Print some debug info at exit.", (gptr *) & info_flag,
+ (gptr *) & info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"default-character-set", OPT_DEFAULT_CHARSET,
+ "Set the default character set.", (gptr*) &opt_default_charset,
+ (gptr*) &opt_default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"force", 'f', "Force execution of mysqlcheck even if mysql_upgrade "
+ "has already been executed for the current version of MySQL.",
+ (gptr*) &opt_force, (gptr*) &opt_force, 0, GET_BOOL, NO_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},
+ {"compress", OPT_COMPRESS, "Use compression in server/client protocol.",
+ (gptr*) &opt_compress, (gptr*) &opt_compress, 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, 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.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#ifdef __WIN__
+ {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0,
+ GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+ {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
+ (gptr*) &opt_mysql_port, 0, GET_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},
+#ifdef HAVE_SMEM
+ {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
+ "Base name of shared memory.", (gptr*) &shared_memory_base_name,
+ (gptr*) &shared_memory_base_name, 0,
+ GET_STR, 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, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"user", 'u', "User for login if not current user.", (gptr*) &user,
+ (gptr*) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#include <sslopt-longopts.h>
+ {"verbose", 'v', "Display more output about the process",
+ (gptr*) &opt_verbose, (gptr*) &opt_verbose, 0,
+ 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 const char *load_default_groups[]=
+{
+ "mysql_upgrade", 0
+};
+
+#include <help_end.h>
+
+static LIST *extra_defaults= NULL;
+
+typedef struct _extra_default
+{
+ int id;
+ const char *name;
+ int n_len;
+ const char *value;
+ int v_len;
+} extra_default_t;
+
+static inline
+void set_extra_default(int id, const struct my_option *opt)
+{
+ switch (id) {
+ case 'b': case 'd': /* these are ours */
+ case 'f': /* --force is ours */
+ case 'u': /* --user passed on cmdline */
+ case 'T': /* --debug-info is not accepted by mysqlcheck */
+ case 'p': /* --password may change yet */
+ /* so, do nothing */
+ break;
+ default:
+ {
+ LIST *l;
+ extra_default_t *d;
+
+ /*
+ Remove any earlier duplicates: they can
+ refer to invalid memory addresses (stale pointers)
+ */
+ l= extra_defaults;
+ while (l)
+ {
+ LIST *n= l->next;
+
+ d= l->data;
+ if (d->id == id)
+ {
+ extra_defaults= list_delete(extra_defaults, l);
+ my_free((gptr)l, MYF(0));
+ my_free((gptr)d, MYF(0));
+ }
+ l= n;
+ }
+
+ d= (extra_default_t *)my_malloc(sizeof(extra_default_t),
+ MYF(MY_FAE|MY_ZEROFILL));
+ d->id= id;
+ d->name= opt->name;
+ d->n_len= strlen(opt->name);
+ if (opt->arg_type != NO_ARG && opt->value)
+ switch (opt->var_type & GET_TYPE_MASK) {
+ case GET_BOOL:
+ if (*((int *)opt->value))
+ {
+ d->value= "true";
+ d->v_len= 4;
+ }
+ break;
+ case GET_STR:
+ case GET_STR_ALLOC:
+ d->value= *opt->value;
+ d->v_len= strlen(d->value);
+ break;
+ default:
+ my_printf_error(0, "Error: internal error at %s:%d", MYF(0),
+ __FILE__, __LINE__);
+ exit(1);
+ }
+ list_push(extra_defaults, d);
+ }
+ }
+}
+
+
+static my_bool
+get_one_option(int optid, const struct my_option *opt __attribute__ ((unused)),
+ char *argument)
+{
+ switch (optid) {
+ case '?':
+ puts
+ ("MySQL utility to upgrade database to the current server version");
+ puts("");
+ my_print_help(my_long_options);
+ exit(0);
+ case '#':
+ DBUG_PUSH(argument ? argument : default_dbug_option);
+ break;
+ case 'p':
+ tty_password= 1;
+ 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;
+ }
+ break;
+#ifdef __WIN__
+ case 'W':
+ my_free(opt_protocol, MYF(MY_ALLOW_ZERO_PTR));
+ opt_protocol= my_strdup("pipe", MYF(MY_FAE));
+ break;
+#endif
+ case OPT_MYSQL_PROTOCOL:
+ if (find_type(argument, &sql_protocol_typelib, 0) > 0)
+ {
+ my_free(opt_protocol, MYF(MY_ALLOW_ZERO_PTR));
+ opt_protocol= my_strdup(argument, MYF(MY_FAE));
+ }
+ else
+ {
+ fprintf(stderr, "Unknown option to protocol: %s\n", argument);
+ exit(1);
+ }
+ break;
+#include <sslopt-case.h>
+ default:;
+ }
+ set_extra_default(opt->id, opt);
+ return 0;
+}
+
+
+static int create_check_file(const char *path)
+{
+ int ret;
+ File fd;
+
+ fd= my_open(path, O_CREAT | O_WRONLY, MYF(MY_FAE | MY_WME));
+ if (fd < 0) {
+ ret= 1;
+ goto error;
+ }
+ ret= my_write(fd, MYSQL_SERVER_VERSION,
+ sizeof(MYSQL_SERVER_VERSION) - 1,
+ MYF(MY_WME | MY_FNABP));
+ ret|= my_close(fd, MYF(MY_FAE | MY_WME));
+error:
+ return ret;
+}
+
+
+static int create_defaults_file(const char *path, const char *forced_path)
+{
+ int ret;
+ uint cnt;
+ File forced_file, defaults_file;
+
+ DYNAMIC_STRING buf;
+ extra_default_t *d;
+
+ my_delete(path, MYF(0));
+
+ defaults_file= my_open(path, O_BINARY | O_CREAT | O_WRONLY | O_EXCL,
+ MYF(MY_FAE | MY_WME));
+ if (defaults_file < 0)
+ {
+ ret= 1;
+ goto out;
+ }
+
+ if (init_dynamic_string(&buf, NULL, my_getpagesize(), FN_REFLEN))
+ {
+ ret= 1;
+ goto error;
+ }
+
+ if (forced_path)
+ {
+ forced_file= my_open(forced_path, O_RDONLY, MYF(MY_FAE | MY_WME));
+ if (forced_file < 0)
+ {
+ ret= 1;
+ goto error;
+ }
+ do
+ {
+ cnt= my_read(forced_file, buf.str, buf.max_length, MYF(MY_WME));
+ if ((cnt == MY_FILE_ERROR)
+ || my_write(defaults_file, buf.str, cnt, MYF(MY_FNABP | MY_WME)))
+ {
+ ret= 1;
+ my_close(forced_file, MYF(0));
+ goto error;
+ }
+ } while (cnt == buf.max_length);
+ my_close(forced_file, MYF(0));
+ }
+
+ dynstr_set(&buf, "\n[client]");
+ if (opt_password)
+ {
+ if (dynstr_append(&buf, "\npassword=")
+ || dynstr_append(&buf, opt_password))
+ {
+ ret = 1;
+ goto error;
+ }
+ }
+ while (extra_defaults)
+ {
+ int len;
+
+ d= extra_defaults->data;
+ len= d->n_len + d->v_len + 1;
+ if (buf.length + len >= buf.max_length) /* to avoid realloc() */
+ {
+ if (my_write(defaults_file, buf.str, buf.length, MYF(MY_FNABP | MY_WME)))
+ {
+ ret= 1;
+ goto error;
+ }
+ dynstr_set(&buf, NULL);
+ }
+ if (dynstr_append_mem(&buf, "\n", 1)
+ || dynstr_append_mem(&buf, d->name, d->n_len)
+ || (d->v_len && (dynstr_append_mem(&buf, "=", 1)
+ || dynstr_append_mem(&buf, d->value, d->v_len))))
+ {
+ ret= 1;
+ goto error;
+ }
+ my_delete((gptr)d, MYF(0));
+ list_pop(extra_defaults); /* pop off the head */
+ }
+ if (my_write(defaults_file, buf.str, buf.length, MYF(MY_FNABP | MY_WME)))
+ {
+ ret= 1;
+ goto error;
+ }
+ /* everything's all right */
+ ret= 0;
+error:
+ dynstr_free(&buf);
+
+ if (defaults_file >= 0)
+ ret|= my_close(defaults_file, MYF(MY_WME));
+
+ if (ret)
+ my_delete(path, MYF(0));
+
+out:
+ return ret;
+}
+
+
+/* Compare filenames */
+static int comp_names(struct fileinfo *a, struct fileinfo *b)
+{
+ return (strcmp(a->name,b->name));
+}
+
+
+static int find_file(const char *name, const char *root,
+ uint flags, char *result, size_t len, ...)
+{
+ int ret= 1;
+ va_list va;
+ const char *subdir;
+ char *cp;
+ FILEINFO key;
+
+ /* Init key with name of the file to look for */
+ key.name= (char*)name;
+
+ DBUG_ASSERT(root != NULL);
+
+ cp= strmake(result, root, len);
+ if (cp[-1] != FN_LIBCHAR)
+ *cp++= FN_LIBCHAR;
+
+ va_start(va, len);
+ subdir= (!(flags & MY_SEARCH_SELF)) ? va_arg(va, char *) : "";
+ while (subdir)
+ {
+ MY_DIR *dir;
+ FILEINFO *match;
+ char *cp1;
+
+ cp1= strnmov(cp, subdir, len - (cp - result) - 1);
+
+ dir= my_dir(result, (flags & MY_ISDIR) ? MY_WANT_STAT : MYF(0));
+ if (dir)
+ {
+ match= bsearch(&key, dir->dir_entry, dir->number_off_files,
+ sizeof(FILEINFO), (qsort_cmp)comp_names);
+ if (match)
+ {
+ ret= (flags & MY_ISDIR) ? !MY_S_ISDIR(match->mystat->st_mode) : 0;
+ if (!ret)
+ {
+ if (cp1[-1] != FN_LIBCHAR)
+ *cp1++= FN_LIBCHAR;
+
+ if (!(flags & MY_PARENT))
+ strnmov(cp1, name, len - (cp1 - result));
+ else
+ *cp1= '\0';
+
+ my_dirend(dir);
+ break;
+ }
+ }
+ my_dirend(dir);
+ }
+ subdir= va_arg(va, char *);
+ }
+ va_end(va);
+ return ret;
+}
+
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ char *forced_defaults_file;
+ char *forced_extra_defaults;
+ char *defaults_group_suffix;
+ const char *script_line;
+ char *upgrade_defaults_path;
+ char *defaults_to_use= NULL;
+ int upgrade_defaults_created= 0;
+
+ char path[FN_REFLEN];
+ DYNAMIC_STRING cmdline;
+
+ MY_INIT(argv[0]);
+#ifdef __NETWARE__
+ setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
+#endif
+
+ /* Check if we are forced to use specific defaults */
+ get_defaults_options(argc, argv,
+ &forced_defaults_file, &forced_extra_defaults,
+ &defaults_group_suffix);
+
+ load_defaults("my", load_default_groups, &argc, &argv);
+
+ /*
+ Must init_dynamic_string before handle_options because string is freed
+ at error label.
+ */
+ if (init_dynamic_string(&cmdline, NULL, 2 * FN_REFLEN + 128, FN_REFLEN) ||
+ handle_options(&argc, &argv, my_long_options, get_one_option))
+ {
+ ret= 1;
+ goto error;
+ }
+ if (tty_password)
+ opt_password= get_tty_password(NullS);
+
+ if (!basedir)
+ {
+ my_getwd(path, sizeof(path), MYF(0));
+ basedir= my_strdup(path, MYF(0));
+ if (find_file("errmsg.sys", basedir, MYF(0), path, sizeof(path),
+ "share/mysql/english", NullS)
+ || find_file(mysqld_name, basedir, MYF(0), path, sizeof(path),
+ "bin", "libexec", NullS))
+ {
+ my_free((gptr)basedir, MYF(0));
+ basedir= (char *)DEFAULT_MYSQL_HOME;
+ }
+ }
+
+ if (!datadir)
+ {
+ if (!find_file("mysql", basedir, MYF(MY_ISDIR|MY_PARENT),
+ path, sizeof(path),
+ "data", "var", NullS))
+ datadir= my_strdup(path, MYF(0));
+ else
+ datadir= (char *)DATADIR;
+ }
+ if (find_file("user.frm", datadir, MYF(0), path, sizeof(path),
+ "mysql", NullS))
+ {
+ ret= 1;
+ fprintf(stderr,
+ "Can't find data directory. Please restart with"
+ " --datadir=path-to-writable-data-dir");
+ goto error;
+ }
+
+ /*
+ Create the modified defaults file to be used by mysqlcheck
+ and mysql tools
+ */
+ fn_format(path, UPGRADE_DEFAULTS_NAME, datadir, "", MYF(0));
+ upgrade_defaults_path= my_strdup(path, MYF(0));
+
+ if (extra_defaults)
+ {
+ ret= create_defaults_file(upgrade_defaults_path, forced_extra_defaults);
+ if (ret)
+ goto error;
+
+ defaults_to_use= upgrade_defaults_path;
+ upgrade_defaults_created= 1;
+ }
+ else
+ defaults_to_use= forced_extra_defaults;
+
+ if (!find_file(MYSQL_UPGRADE_INFO_NAME, datadir, MY_SEARCH_SELF,
+ path, sizeof(path), NULL, NullS)
+ && !opt_force)
+ {
+ char buf[sizeof(MYSQL_SERVER_VERSION)];
+ int fd, cnt;
+
+ fd= my_open(path, O_RDONLY, MYF(0));
+ cnt= my_read(fd, buf, sizeof(buf) - 1, MYF(0));
+ my_close(fd, MYF(0));
+ buf[cnt]= 0;
+ if (!strcmp(buf, MYSQL_SERVER_VERSION))
+ {
+ if (opt_verbose)
+ puts("mysql_upgrade has already been done for this version");
+ goto fix_priv_tables;
+ }
+ }
+
+ if (find_file(mysqlcheck_name, basedir, MYF(0), path, sizeof(path),
+ "bin", EXTRA_CLIENT_PATHS, NullS))
+ {
+ ret= 1;
+ fprintf(stderr,
+ "Can't find program '%s'\n"
+ "Please restart with --basedir=mysql-install-directory",
+ mysqlcheck_name);
+ goto error;
+ }
+ else
+ {
+#ifdef __WIN__
+ /* Windows requires an extra pair of quotes around the entire string. */
+ dynstr_set(&cmdline, "\"");
+#else
+ dynstr_set(&cmdline, "");
+#endif /* __WIN__ */
+ dynstr_append_os_quoted(&cmdline, path, NullS);
+ }
+
+ if (defaults_to_use)
+ {
+ dynstr_append(&cmdline, " ");
+ dynstr_append_os_quoted(&cmdline, "--defaults-extra-file=",
+ defaults_to_use, NullS);
+ }
+
+ dynstr_append(&cmdline, " ");
+ dynstr_append_os_quoted(&cmdline, "--check-upgrade", NullS);
+ dynstr_append(&cmdline, " ");
+ dynstr_append_os_quoted(&cmdline, "--all-databases", NullS);
+ dynstr_append(&cmdline, " ");
+ dynstr_append_os_quoted(&cmdline, "--auto-repair", NullS);
+ dynstr_append(&cmdline, " ");
+ dynstr_append_os_quoted(&cmdline, "--user=", user, NullS);
+#ifdef __WIN__
+ dynstr_append(&cmdline, "\"");
+#endif /* __WIN__ */
+
+ if (opt_verbose)
+ printf("Running %s\n", cmdline.str);
+
+ ret= system(cmdline.str);
+ if (ret)
+ {
+ fprintf(stderr, "Error executing '%s'\n", cmdline.str);
+ goto error;
+ }
+
+ fn_format(path, MYSQL_UPGRADE_INFO_NAME, datadir, "", MYF(0));
+ ret= create_check_file(path);
+ if (ret)
+ goto error;
+
+fix_priv_tables:
+ if (find_file(mysql_name, basedir, MYF(0), path, sizeof(path),
+ "bin", EXTRA_CLIENT_PATHS, NullS))
+ {
+ ret= 1;
+ fprintf(stderr,
+ "Could not find MySQL command-line client (mysql).\n"
+ "Please use --basedir to specify the directory"
+ " where MySQL is installed.");
+ goto error;
+ }
+ else
+ {
+#ifdef __WIN__
+ /* Windows requires an extra pair of quotes around the entire string. */
+ dynstr_set(&cmdline, "\"");
+#else
+ dynstr_set(&cmdline, "");
+#endif /* __WIN__ */
+ dynstr_append_os_quoted(&cmdline, path, NullS);
+ }
+
+ if (find_file(MYSQL_FIX_PRIV_TABLES_NAME, basedir, MYF(0),
+ path, sizeof(path),
+ "support_files", "share", "share/mysql", "scripts",
+ NullS)
+ && find_file(MYSQL_FIX_PRIV_TABLES_NAME, "/usr/local/mysql", MYF(0),
+ path, sizeof(path),
+ "share/mysql", NullS))
+ {
+ ret= 1;
+ fprintf(stderr,
+ "Could not find file " MYSQL_FIX_PRIV_TABLES_NAME "\n"
+ "Please use --basedir to specify the directory"
+ " where MySQL is installed");
+ goto error;
+ }
+ else
+ script_line= my_strdup(path, MYF(0));
+
+ if (defaults_to_use)
+ {
+ dynstr_append(&cmdline, " ");
+ dynstr_append_os_quoted(&cmdline, "--defaults-extra-file=",
+ defaults_to_use, NullS);
+ }
+ dynstr_append(&cmdline, " ");
+ dynstr_append_os_quoted(&cmdline, "--force", NullS);
+ dynstr_append(&cmdline, " ");
+ dynstr_append_os_quoted(&cmdline, "--no-auto-rehash", NullS);
+ dynstr_append(&cmdline, " ");
+ dynstr_append_os_quoted(&cmdline, "--batch", NullS);
+ dynstr_append(&cmdline, " ");
+ dynstr_append_os_quoted(&cmdline, "--user=", user, NullS);
+ dynstr_append(&cmdline, " ");
+ dynstr_append_os_quoted(&cmdline, "--database=mysql", NullS);
+ dynstr_append(&cmdline, " < ");
+ dynstr_append_os_quoted(&cmdline, script_line, NullS);
+#ifdef __WIN__
+ dynstr_append(&cmdline, "\"");
+#endif /* __WIN__ */
+
+ if (opt_verbose)
+ printf("Running %s\n", cmdline.str);
+
+ ret= system(cmdline.str);
+ if (ret)
+ fprintf(stderr, "Error executing '%s'\n", cmdline.str);
+
+error:
+ dynstr_free(&cmdline);
+
+ if (upgrade_defaults_created)
+ my_delete(upgrade_defaults_path, MYF(0));
+
+ my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
+ return ret;
+}
+
diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc
index 7bb3061f412..c7033f6914f 100644
--- a/client/mysqladmin.cc
+++ b/client/mysqladmin.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000-2004 MySQL AB
+/* 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; either version 2 of the License, or
- (at your option) any later version.
+ 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
@@ -161,7 +160,7 @@ static struct my_option my_long_options[] =
NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"port", 'P', "Port number to use for connection.", (gptr*) &tcp_port,
- (gptr*) &tcp_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0},
+ (gptr*) &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',
@@ -340,6 +339,8 @@ int main(int argc,char *argv[])
if (opt_use_ssl)
mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
opt_ssl_capath, opt_ssl_cipher);
+ mysql_options(&mysql,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
+ (char*)&opt_ssl_verify_server_cert);
#endif
if (opt_protocol)
mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
@@ -431,6 +432,7 @@ static my_bool sql_connect(MYSQL *mysql, uint wait)
if (mysql_real_connect(mysql,host,user,opt_password,NullS,tcp_port,
unix_port, 0))
{
+ mysql->reconnect= 1;
if (info)
{
fputs("\n",stderr);
@@ -568,6 +570,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
return -1;
}
mysql_close(mysql); /* Close connection to avoid error messages */
+ argc=1; /* force SHUTDOWN to be the last command */
if (got_pidfile)
{
if (opt_verbose)
@@ -610,7 +613,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
case ADMIN_VER:
new_line=1;
print_version();
- puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB");
+ puts("Copyright (C) 2000-2006 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");
printf("Server version\t\t%s\n", mysql_get_server_info(mysql));
printf("Protocol version\t%d\n", mysql_get_proto_info(mysql));
@@ -726,7 +729,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
void (*func) (MYSQL_RES*, MYSQL_ROW, uint);
new_line = 1;
- if (mysql_query(mysql, "show status") ||
+ 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),
@@ -999,7 +1002,7 @@ static void print_version(void)
static void usage(void)
{
print_version();
- puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB");
+ puts("Copyright (C) 2000-2006 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("Administration program for the mysqld daemon.");
printf("Usage: %s [OPTIONS] command command....\n", my_progname);
@@ -1345,6 +1348,3 @@ static my_bool wait_pidfile(char *pidfile, time_t last_modified,
}
DBUG_RETURN(error);
}
-#ifdef __GNUC__
-FIX_GCC_LINKING_PROBLEM
-#endif
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index 77240a2c750..7489cdb334c 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -2,8 +2,7 @@
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; either version 2 of the License, or
- (at your option) any later version.
+ 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
@@ -14,11 +13,29 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/*
+
+ TODO: print the catalog (some USE catalog.db ????).
+
+ Standalone program to read a MySQL binary log (or relay log);
+ can read files produced by 3.23, 4.x, 5.0 servers.
+
+ Can read binlogs from 3.23/4.x/5.0 and relay logs from 4.x/5.0.
+ Should be able to read any file of these categories, even with
+ --start-position.
+ An important fact: the Format_desc event of the log is at most the 3rd event
+ of the log; if it is the 3rd then there is this combination:
+ Format_desc_of_slave, Rotate_of_master, Format_desc_of_master.
+*/
+
#define MYSQL_CLIENT
#undef MYSQL_SERVER
#include "client_priv.h"
#include <my_time.h>
+/* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */
+#include "mysql_priv.h"
#include "log_event.h"
+#include "sql_common.h"
#define BIN_LOG_HEADER_SIZE 4
#define PROBE_HEADER_LEN (EVENT_LEN_OFFSET+4)
@@ -45,11 +62,12 @@ static const char *load_default_groups[]= { "mysqlbinlog","client",0 };
void sql_print_error(const char *format, ...);
static bool one_database=0, to_last_remote_log= 0, disable_log_bin= 0;
+static bool opt_hexdump= 0;
static const char* database= 0;
static my_bool force_opt= 0, short_form= 0, remote_opt= 0;
static ulonglong offset = 0;
static const char* host = 0;
-static int port = MYSQL_PORT;
+static int port= 0;
static const char* sock= 0;
static const char* user = 0;
static char* pass = 0;
@@ -67,8 +85,18 @@ static MYSQL* mysql = NULL;
static const char* dirname_for_local_load= 0;
static bool stop_passed= 0;
-static int dump_local_log_entries(const char* logname);
-static int dump_remote_log_entries(const char* logname);
+/*
+ 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().
+*/
+Format_description_log_event* description_event;
+
+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 int dump_remote_file(NET* net, const char* fname);
static void die(const char* fmt, ...);
@@ -79,6 +107,22 @@ class Load_log_processor
{
char target_dir_name[FN_REFLEN];
int target_dir_name_len;
+
+ /*
+ When we see first event corresponding to some LOAD DATA statement in
+ binlog, we create temporary file to store data to be loaded.
+ We add name of this file to file_names array using its file_id as index.
+ If we have Create_file event (i.e. we have binary log in pre-5.0.3
+ format) we also store save event object to be able which is needed to
+ emit LOAD DATA statement when we will meet Exec_load_data event.
+ If we have Begin_load_query event we simply store 0 in
+ File_name_record::event field.
+ */
+ struct File_name_record
+ {
+ char *fname;
+ Create_file_log_event *event;
+ };
DYNAMIC_ARRAY file_names;
/*
@@ -120,7 +164,7 @@ public:
int init()
{
- return init_dynamic_array(&file_names,sizeof(Create_file_log_event*),
+ return init_dynamic_array(&file_names, sizeof(File_name_record),
100,100 CALLER_INFO);
}
@@ -137,33 +181,91 @@ public:
}
void destroy()
{
- Create_file_log_event **ptr= (Create_file_log_event**)file_names.buffer;
- Create_file_log_event **end= ptr + file_names.elements;
+ File_name_record *ptr= (File_name_record *)file_names.buffer;
+ File_name_record *end= ptr + file_names.elements;
for (; ptr<end; ptr++)
{
- if (*ptr)
+ if (ptr->fname)
{
- my_free((char*)(*ptr)->fname,MYF(MY_WME));
- delete *ptr;
- *ptr= 0;
+ my_free(ptr->fname, MYF(MY_WME));
+ delete ptr->event;
+ bzero((char *)ptr, sizeof(File_name_record));
}
}
}
+
+ /*
+ Obtain Create_file event for LOAD DATA statement by its file_id.
+
+ SYNOPSIS
+ grab_event()
+ file_id - file_id identifiying LOAD DATA statement
+
+ 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.
+
+ RETURN VALUES
+ Pointer to Create_file event or 0 if there was no such event
+ with this file_id.
+ */
Create_file_log_event *grab_event(uint file_id)
{
+ File_name_record *ptr;
+ Create_file_log_event *res;
+
+ if (file_id >= file_names.elements)
+ return 0;
+ ptr= dynamic_element(&file_names, file_id, File_name_record*);
+ if ((res= ptr->event))
+ bzero((char *)ptr, sizeof(File_name_record));
+ 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.
+ */
+ char *grab_fname(uint file_id)
+ {
+ File_name_record *ptr;
+ char *res= 0;
+
if (file_id >= file_names.elements)
return 0;
- Create_file_log_event **ptr=
- (Create_file_log_event**)file_names.buffer + file_id;
- Create_file_log_event *res= *ptr;
- *ptr= 0;
+ ptr= dynamic_element(&file_names, file_id, File_name_record*);
+ if (!ptr->event)
+ {
+ res= ptr->fname;
+ bzero((char *)ptr, sizeof(File_name_record));
+ }
return res;
}
int process(Create_file_log_event *ce);
+ int process(Begin_load_query_log_event *ce);
int 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);
};
@@ -241,22 +343,42 @@ int Load_log_processor::load_old_format_file(NET* net, const char*server_fname,
}
-int Load_log_processor::process(Create_file_log_event *ce)
+/*
+ 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
+*/
+
+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)
{
- const char *bname= ce->fname+dirname_length(ce->fname);
- uint blen= ce->fname_len - (bname-ce->fname);
uint full_len= target_dir_name_len + blen + 9 + 9 + 1;
int error= 0;
char *fname, *ptr;
File file;
- DBUG_ENTER("Load_log_processor::process");
+ File_name_record rec;
+ DBUG_ENTER("Load_log_processor::process_first_event");
- if (set_dynamic(&file_names,(gptr)&ce,ce->file_id))
- {
- sql_print_error("Could not construct local filename %s%s",
- target_dir_name,bname);
- DBUG_RETURN(-1);
- }
if (!(fname= my_malloc(full_len,MYF(MY_WME))))
DBUG_RETURN(-1);
@@ -264,7 +386,7 @@ int Load_log_processor::process(Create_file_log_event *ce)
ptr= fname + target_dir_name_len;
memcpy(ptr,bname,blen);
ptr+= blen;
- ptr+= my_sprintf(ptr,(ptr,"-%x",ce->file_id));
+ ptr+= my_sprintf(ptr, (ptr, "-%x", file_id));
if ((file= create_unique_file(fname,ptr)) < 0)
{
@@ -272,9 +394,21 @@ int Load_log_processor::process(Create_file_log_event *ce)
target_dir_name,bname);
DBUG_RETURN(-1);
}
- ce->set_fname_outside_temp_buf(fname,strlen(fname));
- if (my_write(file,(byte*) ce->block,ce->block_len,MYF(MY_WME|MY_NABP)))
+ rec.fname= fname;
+ rec.event= ce;
+
+ if (set_dynamic(&file_names, (gptr)&rec, file_id))
+ {
+ sql_print_error("Could not construct local filename %s%s",
+ target_dir_name, bname);
+ DBUG_RETURN(-1);
+ }
+
+ if (ce)
+ ce->set_fname_outside_temp_buf(fname, strlen(fname));
+
+ if (my_write(file, (byte*)block, block_len, MYF(MY_WME|MY_NABP)))
error= -1;
if (my_close(file, MYF(MY_WME)))
error= -1;
@@ -282,19 +416,35 @@ int Load_log_processor::process(Create_file_log_event *ce)
}
+int Load_log_processor::process(Create_file_log_event *ce)
+{
+ const char *bname= ce->fname + dirname_length(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)
+{
+ 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)
{
DBUG_ENTER("Load_log_processor::process");
- Create_file_log_event* ce= ((ae->file_id < file_names.elements) ?
- *((Create_file_log_event**)file_names.buffer +
- ae->file_id) :
- 0);
+ const char* fname= ((ae->file_id < file_names.elements) ?
+ dynamic_element(&file_names, ae->file_id,
+ File_name_record*)->fname : 0);
- if (ce)
+ if (fname)
{
File file;
int error= 0;
- if (((file= my_open(ce->fname,
+ 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)))
@@ -306,8 +456,8 @@ int Load_log_processor::process(Append_block_log_event *ae)
/*
There is no Create_file event (a bad binlog or a big
- --position). Assuming it's a big --position, we just do nothing and
- print a warning.
+ --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);
@@ -317,30 +467,58 @@ Create_file event for file_id: %u\n",ae->file_id);
Load_log_processor load_processor;
+
+static bool check_database(const char *log_dbname)
+{
+ return one_database &&
+ (log_dbname != NULL) &&
+ strcmp(log_dbname, database);
+}
+
+
/*
+ 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.
*/
-int process_event(char *last_db, Log_event *ev, my_off_t pos, int old_format)
+
+
+
+int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
+ my_off_t pos)
{
char ll_buff[21];
+ Log_event_type ev_type= ev->get_type_code();
DBUG_ENTER("process_event");
+ print_event_info->short_form= short_form;
+ /*
+ Format events are not concerned by --offset and such, we always need to
+ read them to be able to process the wanted events.
+ */
if ((rec_count >= offset) &&
- ((my_time_t)(ev->when) >= start_datetime))
+ ((my_time_t)(ev->when) >= start_datetime) ||
+ (ev_type == FORMAT_DESCRIPTION_EVENT))
{
- /*
- We have found an event after start_datetime, from now on print
- everything (in case the binlog has timestamps increasing and decreasing,
- we do this to avoid cutting the middle).
- */
- start_datetime= 0;
- offset= 0; // print everything and protect against cycling rec_count
+ if (ev_type != FORMAT_DESCRIPTION_EVENT)
+ {
+ /*
+ We have found an event after start_datetime, from now on print
+ everything (in case the binlog has timestamps increasing and
+ decreasing, we do this to avoid cutting the middle).
+ */
+ start_datetime= 0;
+ offset= 0; // print everything and protect against cycling rec_count
+ }
if (((my_time_t)(ev->when) >= stop_datetime)
|| (pos >= stop_position_mot))
{
@@ -349,32 +527,29 @@ int process_event(char *last_db, Log_event *ev, my_off_t pos, int old_format)
}
if (!short_form)
fprintf(result_file, "# at %s\n",llstr(pos,ll_buff));
-
- switch (ev->get_type_code()) {
+
+ if (!opt_hexdump)
+ print_event_info->hexdump_from= 0; /* Disabled */
+ else
+ print_event_info->hexdump_from= pos;
+
+ switch (ev_type) {
case QUERY_EVENT:
- if (one_database)
- {
- const char * log_dbname = ((Query_log_event*)ev)->db;
- if ((log_dbname != NULL) && (strcmp(log_dbname, database)))
- goto end;
- }
- ev->print(result_file, short_form, last_db);
+ if (check_database(((Query_log_event*)ev)->db))
+ goto end;
+ ev->print(result_file, print_event_info);
break;
case CREATE_FILE_EVENT:
{
Create_file_log_event* ce= (Create_file_log_event*)ev;
- if (one_database)
- {
- /*
- We test if this event has to be ignored. If yes, we don't save
- this event; this will have the good side-effect of ignoring all
- related Append_block and Exec_load.
- Note that Load event from 3.23 is not tested.
- */
- const char * log_dbname = ce->db;
- if ((log_dbname != NULL) && (strcmp(log_dbname, database)))
- goto end; // Next event
- }
+ /*
+ We test if this event has to be ignored. If yes, we don't save
+ this event; this will have the good side-effect of ignoring all
+ related Append_block and Exec_load.
+ Note that Load event from 3.23 is not tested.
+ */
+ if (check_database(ce->db))
+ goto end; // Next event
/*
We print the event, but with a leading '#': this is just to inform
the user of the original command; the command we want to execute
@@ -382,8 +557,10 @@ int process_event(char *last_db, Log_event *ev, my_off_t pos, int old_format)
filename and use LOCAL), prepared in the 'case EXEC_LOAD_EVENT'
below.
*/
- ce->print(result_file, short_form, last_db, TRUE);
- if (!old_format)
+ ce->print(result_file, print_event_info, TRUE);
+
+ // If this binlog is not 3.23 ; why this test??
+ if (description_event->binlog_version >= 3)
{
if (load_processor.process(ce))
break; // Error
@@ -392,23 +569,23 @@ int process_event(char *last_db, Log_event *ev, my_off_t pos, int old_format)
break;
}
case APPEND_BLOCK_EVENT:
- ev->print(result_file, short_form, last_db);
+ ev->print(result_file, print_event_info);
if (load_processor.process((Append_block_log_event*) ev))
break; // Error
break;
case EXEC_LOAD_EVENT:
{
- ev->print(result_file, short_form, last_db);
+ ev->print(result_file, print_event_info);
Execute_load_log_event *exv= (Execute_load_log_event*)ev;
Create_file_log_event *ce= load_processor.grab_event(exv->file_id);
/*
if ce is 0, it probably means that we have not seen the Create_file
- event (a bad binlog, or most probably --position is after the
+ event (a bad binlog, or most probably --start-position is after the
Create_file event). Print a warning comment.
*/
if (ce)
{
- ce->print(result_file, short_form, last_db, TRUE);
+ ce->print(result_file, print_event_info, TRUE);
my_free((char*)ce->fname,MYF(MY_WME));
delete ce;
}
@@ -417,8 +594,47 @@ int process_event(char *last_db, Log_event *ev, my_off_t pos, int old_format)
Create_file event for file_id: %u\n",exv->file_id);
break;
}
+ case FORMAT_DESCRIPTION_EVENT:
+ delete description_event;
+ description_event= (Format_description_log_event*) ev;
+ print_event_info->common_header_len= description_event->common_header_len;
+ ev->print(result_file, print_event_info);
+ /*
+ We don't want this event to be deleted now, so let's hide it (I
+ (Guilhem) should later see if this triggers a non-serious Valgrind
+ error). Not serious error, because we will free description_event
+ later.
+ */
+ ev= 0;
+ break;
+ case BEGIN_LOAD_QUERY_EVENT:
+ ev->print(result_file, print_event_info);
+ load_processor.process((Begin_load_query_log_event*) ev);
+ 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 (fname)
+ my_free(fname, MYF(MY_WME));
+ goto end;
+ }
+
+ if (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;
+ }
default:
- ev->print(result_file, short_form, last_db);
+ ev->print(result_file, print_event_info);
}
}
@@ -437,6 +653,15 @@ static struct my_option my_long_options[] =
{"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
+ /*
+ 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
+ like this:
+ 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},
@@ -456,6 +681,9 @@ static struct my_option my_long_options[] =
0, 0},
{"help", '?', "Display this help and exit.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"hexdump", 'H', "Augment output with hexadecimal and ASCII event dump.",
+ (gptr*) &opt_hexdump, (gptr*) &opt_hexdump, 0, GET_BOOL, NO_ARG,
+ 0, 0, 0, 0, 0, 0},
{"host", 'h', "Get the binlog from server.", (gptr*) &host, (gptr*) &host,
0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"offset", 'o', "Skip the first N entries.", (gptr*) &offset, (gptr*) &offset,
@@ -463,7 +691,7 @@ static struct my_option my_long_options[] =
{"password", 'p', "Password to connect to remote server.",
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"port", 'P', "Use port to connect to the remote server.",
- (gptr*) &port, (gptr*) &port, 0, GET_INT, REQUIRED_ARG, MYSQL_PORT, 0, 0,
+ (gptr*) &port, (gptr*) &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,
@@ -566,7 +794,8 @@ static void die(const char* fmt, ...)
fprintf(stderr, "\n");
va_end(args);
cleanup();
- my_end(0);
+ /* We cannot free DBUG, it is used in global destructors after exit(). */
+ my_end(MY_DONT_FREE_DBUG);
exit(1);
}
@@ -574,7 +803,7 @@ static void die(const char* fmt, ...)
static void print_version()
{
- printf("%s Ver 3.0 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE);
+ printf("%s Ver 3.1 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE);
NETWARE_SET_SCREEN_MODE(1);
}
@@ -600,7 +829,7 @@ static my_time_t convert_str_to_timestamp(const char* str)
int was_cut;
MYSQL_TIME l_time;
long dummy_my_timezone;
- bool dummy_in_dst_time_gap;
+ my_bool dummy_in_dst_time_gap;
/* We require a total specification (date AND time) */
if (str_to_datetime(str, strlen(str), &l_time, 0, &was_cut) !=
MYSQL_TIMESTAMP_DATETIME || was_cut)
@@ -715,23 +944,43 @@ static MYSQL* safe_connect()
mysql_close(local_mysql);
die("failed on connect: %s", errmsg);
}
+ local_mysql->reconnect= 1;
return local_mysql;
}
static int dump_log_entries(const char* logname)
{
- return (remote_opt ? dump_remote_log_entries(logname) :
- dump_local_log_entries(logname));
+ int rc;
+ PRINT_EVENT_INFO print_event_info;
+ /*
+ Set safe delimiter, to dump things
+ like CREATE PROCEDURE safely
+ */
+ fprintf(result_file, "DELIMITER /*!*/;\n");
+ strcpy(print_event_info.delimiter, "/*!*/;");
+
+ rc= (remote_opt ? dump_remote_log_entries(&print_event_info, logname) :
+ dump_local_log_entries(&print_event_info, logname));
+
+ /* Set delimiter back to semicolon */
+ fprintf(result_file, "DELIMITER ;\n");
+ strcpy(print_event_info.delimiter, ";");
+ return rc;
}
-static int check_master_version(MYSQL* mysql)
+/*
+ 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.
+*/
+static int check_master_version(MYSQL* mysql,
+ Format_description_log_event
+ **description_event)
{
MYSQL_RES* res = 0;
MYSQL_ROW row;
const char* version;
- int old_format = 0;
if (mysql_query(mysql, "SELECT VERSION()") ||
!(res = mysql_store_result(mysql)))
@@ -757,11 +1006,18 @@ static int check_master_version(MYSQL* mysql)
switch (*version) {
case '3':
- old_format = 1;
+ *description_event= new Format_description_log_event(1);
break;
case '4':
+ *description_event= new Format_description_log_event(3);
case '5':
- old_format = 0;
+ /*
+ The server is soon going to send us its Format_description log
+ event, unless it is a 5.0 server with 3.23 or 4.0 binlogs.
+ 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);
break;
default:
sql_print_error("Master reported unrecognized MySQL version '%s'",
@@ -771,18 +1027,18 @@ static int check_master_version(MYSQL* mysql)
return 1;
}
mysql_free_result(res);
- return old_format;
+ return 0;
}
-static int dump_remote_log_entries(const char* logname)
+static int dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
+ const char* logname)
+
{
char buf[128];
- char last_db[FN_REFLEN+1] = "";
ulong len;
uint logname_len;
NET* net;
- int old_format;
int error= 0;
my_off_t old_off= start_position_mot;
char fname[FN_REFLEN+1];
@@ -795,7 +1051,18 @@ static int dump_remote_log_entries(const char* logname)
*/
mysql= safe_connect();
net= &mysql->net;
- old_format = check_master_version(mysql);
+
+ if (check_master_version(mysql, &description_event))
+ {
+ fprintf(stderr, "Could not find server version");
+ DBUG_RETURN(1);
+ }
+ if (!description_event || !description_event->is_valid())
+ {
+ fprintf(stderr, "Invalid Format_description log event; \
+could be out of memory");
+ DBUG_RETURN(1);
+ }
/*
COM_BINLOG_DUMP accepts only 4 bytes for the position, so we are forced to
@@ -824,7 +1091,9 @@ static int dump_remote_log_entries(const char* logname)
for (;;)
{
const char *error_msg;
- len = net_safe_read(mysql);
+ Log_event *ev;
+
+ len= cli_safe_read(mysql);
if (len == packet_error)
{
fprintf(stderr, "Got error reading packet from server: %s\n",
@@ -834,11 +1103,11 @@ static int dump_remote_log_entries(const char* logname)
}
if (len < 8 && net->read_pos[0] == 254)
break; // end of data
- DBUG_PRINT("info",( "len= %u, net->read_pos[5] = %d\n",
+ DBUG_PRINT("info",( "len: %lu, net->read_pos[5]: %d\n",
len, net->read_pos[5]));
- Log_event *ev = Log_event::read_log_event((const char*) net->read_pos + 1 ,
- len - 1, &error_msg, old_format);
- if (!ev)
+ if (!(ev= Log_event::read_log_event((const char*) net->read_pos + 1 ,
+ len - 1, &error_msg,
+ description_event)))
{
fprintf(stderr, "Could not construct log event object\n");
error= 1;
@@ -846,25 +1115,27 @@ static int dump_remote_log_entries(const char* logname)
}
Log_event_type type= ev->get_type_code();
- if (!old_format || ( type != LOAD_EVENT && type != CREATE_FILE_EVENT))
+ if (description_event->binlog_version >= 3 ||
+ (type != LOAD_EVENT && type != CREATE_FILE_EVENT))
{
- if (ev->get_type_code() == ROTATE_EVENT)
+ /*
+ If this is a Rotate event, maybe it's the end of the requested binlog;
+ in this case we are done (stop transfer).
+ This is suitable for binlogs, not relay logs (but for now we don't read
+ relay logs remotely because the server is not able to do that). If one
+ day we read relay logs remotely, then we will have a problem with the
+ detection below: relay logs contain Rotate events which are about the
+ binlogs, so which would trigger the end-detection below.
+ */
+ if (type == ROTATE_EVENT)
{
Rotate_log_event *rev= (Rotate_log_event *)ev;
/*
- mysqld is sending us all its binlogs after the requested one, but we
- don't want them.
If this is a fake Rotate event, and not about our log, we can stop
transfer. If this a real Rotate event (so it's not about our log,
it's in our log describing the next log), we print it (because it's
part of our log) and then we will stop when we receive the fake one
soon.
- This is suitable for binlogs, not relay logs (but for now we don't
- read relay logs remotely because the server is not able to do
- that). If one day we read relay logs remotely, then we will have a
- problem with the detection below: relay logs contain Rotate events
- which are about the binlogs, so which would trigger the end-detection
- below.
*/
if (rev->when == 0)
{
@@ -887,7 +1158,7 @@ static int dump_remote_log_entries(const char* logname)
len= 1; // fake Rotate, so don't increment old_off
}
}
- if ((error= process_event(last_db,ev,old_off,old_format)))
+ if ((error= process_event(print_event_info, ev, old_off)))
{
error= ((error < 0) ? 0 : 1);
goto err;
@@ -899,78 +1170,147 @@ static int dump_remote_log_entries(const char* logname)
const char *old_fname= le->fname;
uint old_len= le->fname_len;
File file;
-
+
if ((file= load_processor.prepare_new_file_for_old_format(le,fname)) < 0)
{
error= 1;
goto err;
}
-
- if ((error= process_event(last_db,ev,old_off,old_format)))
+
+ if ((error= process_event(print_event_info, ev, old_off)))
{
- my_close(file,MYF(MY_WME));
+ my_close(file,MYF(MY_WME));
error= ((error < 0) ? 0 : 1);
goto err;
}
- if (load_processor.load_old_format_file(net,old_fname,old_len,file))
+ error= load_processor.load_old_format_file(net,old_fname,old_len,file);
+ my_close(file,MYF(MY_WME));
+ if (error)
{
- my_close(file,MYF(MY_WME));
error= 1;
goto err;
}
- my_close(file,MYF(MY_WME));
}
-
/*
Let's adjust offset for remote log as for local log to produce
similar text.
*/
old_off+= len-1;
}
+
err:
mysql_close(mysql);
DBUG_RETURN(error);
}
-static int check_header(IO_CACHE* file)
+static void check_header(IO_CACHE* file,
+ Format_description_log_event **description_event)
{
byte header[BIN_LOG_HEADER_SIZE];
byte buf[PROBE_HEADER_LEN];
- int old_format=0;
- DBUG_ENTER("check_header");
+ my_off_t tmp_pos, pos;
- my_off_t pos = my_b_tell(file);
+ *description_event= new Format_description_log_event(3);
+ pos= my_b_tell(file);
my_b_seek(file, (my_off_t)0);
if (my_b_read(file, header, sizeof(header)))
die("Failed reading header; Probably an empty file");
if (memcmp(header, BINLOG_MAGIC, sizeof(header)))
die("File is not a binary log file");
- if (!my_b_read(file, buf, sizeof(buf)))
+
+ /*
+ Imagine we are running with --start-position=1000. We still need
+ to know the binlog format's. So we still need to find, if there is
+ one, the Format_desc event, or to know if this is a 3.23
+ binlog. So we need to first read the first events of the log,
+ those around offset 4. Even if we are reading a 3.23 binlog from
+ the start (no --start-position): we need to know the header length
+ (which is 13 in 3.23, 19 in 4.x) to be able to successfully print
+ the first event (Start_log_event_v3). So even in this case, we
+ need to "probe" the first bytes of the log *before* we do a real
+ read_log_event(). Because read_log_event() needs to know the
+ header's length to work fine.
+ */
+ for(;;)
{
- if (buf[4] == START_EVENT)
+ tmp_pos= my_b_tell(file); /* should be 4 the first time */
+ 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);
+ /*
+ Otherwise this is just EOF : this log currently contains 0-2
+ events. Maybe it's going to be filled in the next
+ milliseconds; then we are going to have a problem if this a
+ 3.23 log (imagine we are locally reading a 3.23 binlog which
+ is being written presently): we won't know it in
+ read_log_event() and will fail(). Similar problems could
+ happen with hot relay logs if --start-position is used (but a
+ --start-position which is posterior to the current size of the log).
+ These are rare problems anyway (reading a hot log + when we
+ read the first events there are not all there yet + when we
+ read a bit later there are more events + using a strange
+ --start-position).
+ */
+ break;
+ }
+ else
{
- uint event_len;
- event_len = uint4korr(buf + EVENT_LEN_OFFSET);
- old_format = (event_len < (LOG_EVENT_HEADER_LEN + START_HEADER_LEN));
+ DBUG_PRINT("info",("buf[4]=%d", buf[4]));
+ /* 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 (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);
+ }
+ break;
+ }
+ else if (tmp_pos >= start_position)
+ break;
+ else if (buf[4] == FORMAT_DESCRIPTION_EVENT) /* This is 5.0 */
+ {
+ 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)))
+ /* 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);
+ DBUG_PRINT("info",("Setting description_event"));
+ }
+ else if (buf[4] == 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)))
+ /* 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);
+ delete ev;
+ }
+ else
+ break;
}
}
my_b_seek(file, pos);
- DBUG_RETURN(old_format);
}
-static int dump_local_log_entries(const char* logname)
+static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
+ const char* logname)
{
File fd = -1;
IO_CACHE cache,*file= &cache;
- char last_db[FN_REFLEN+1];
byte tmp_buff[BIN_LOG_HEADER_SIZE];
- bool old_format = 0;
int error= 0;
- last_db[0]= 0;
-
if (logname && logname[0] != '-')
{
if ((fd = my_open(logname, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0)
@@ -979,65 +1319,86 @@ static int dump_local_log_entries(const char* logname)
MYF(MY_WME | MY_NABP)))
{
my_close(fd, MYF(MY_WME));
- exit(1);
+ return 1;
}
- old_format = check_header(file);
+ check_header(file, &description_event);
}
- else
+ else // reading from stdin;
{
- if (init_io_cache(file, fileno(result_file), 0, READ_CACHE, (my_off_t) 0,
+ /*
+ 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.
+ */
+#if defined (__WIN__) || (_WIN64)
+ if (_setmode(fileno(stdin), O_BINARY) == -1)
+ {
+ fprintf(stderr, "Could not set binary mode on stdin.\n");
+ return 1;
+ }
+#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;
- old_format = check_header(file);
+ check_header(file, &description_event);
if (start_position)
{
- /* skip 'start_position' characters from stdout */
+ /* skip 'start_position' characters from stdin */
byte 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= 1;
+ goto end;
+ }
}
}
- file->pos_in_file= start_position_mot;
- file->seek_not_done=0;
}
- if (!start_position)
+ if (!description_event || !description_event->is_valid())
+ die("Invalid Format_description log event; could be out of memory");
+
+ if (!start_position && my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE))
{
- // Skip header
- if (my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE))
- {
- error= 1;
- goto end;
- }
+ error= 1;
+ goto end;
}
-
for (;;)
{
char llbuff[21];
my_off_t old_off = my_b_tell(file);
- Log_event* ev = Log_event::read_log_event(file, old_format);
+ Log_event* ev = Log_event::read_log_event(file, description_event);
if (!ev)
{
- if (file->error)
+ /*
+ if binlog wasn't closed properly ("in use" flag is set) don't complain
+ about a corruption, but treat it as EOF and move to the next binlog.
+ */
+ if (description_event->flags & LOG_EVENT_BINLOG_IN_USE_F)
+ 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;
+ fprintf(stderr,
+ "Could not read entry at offset %s:"
+ "Error in log format or read error\n",
+ llstr(old_off,llbuff));
+ error= 1;
}
// file->error == 0 means EOF, that's OK, we break in this case
break;
}
- if ((error= process_event(last_db,ev,old_off,false)))
+ if ((error= process_event(print_event_info, ev, old_off)))
{
if (error < 0)
error= 0;
@@ -1049,6 +1410,7 @@ end:
if (fd >= 0)
my_close(fd, MYF(MY_WME));
end_io_cache(file);
+ delete description_event;
return error;
}
@@ -1099,6 +1461,14 @@ int main(int argc, char** argv)
fprintf(result_file,
"/*!32316 SET @OLD_SQL_LOG_BIN=@@SQL_LOG_BIN, SQL_LOG_BIN=0*/;\n");
+ /*
+ In mysqlbinlog|mysql, don't want mysql to be disconnected after each
+ transaction (which would be the case with GLOBAL.COMPLETION_TYPE==2).
+ */
+ fprintf(result_file,
+ "/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,"
+ "COMPLETION_TYPE=0*/;\n");
+
if (charset)
fprintf(result_file,
"\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
@@ -1120,6 +1490,13 @@ int main(int argc, char** argv)
start_position= BIN_LOG_HEADER_SIZE;
}
+ /*
+ Issue a ROLLBACK in case the last printed binlog was crashed and had half
+ of transaction.
+ */
+ fprintf(result_file,
+ "# End of log file\nROLLBACK /* added by mysqlbinlog */;\n"
+ "/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;\n");
if (disable_log_bin)
fprintf(result_file, "/*!32316 SET SQL_LOG_BIN=@OLD_SQL_LOG_BIN*/;\n");
@@ -1136,7 +1513,8 @@ int main(int argc, char** argv)
cleanup();
free_defaults(defaults_argv);
my_free_open_file_info();
- my_end(0);
+ /* 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
}
@@ -1146,10 +1524,14 @@ int main(int argc, char** argv)
the server
*/
-#ifdef __WIN__
+#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
-FIX_GCC_LINKING_PROBLEM
diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c
index f0f7c247553..b69e9201a28 100644
--- a/client/mysqlcheck.c
+++ b/client/mysqlcheck.c
@@ -2,8 +2,7 @@
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; either version 2 of the License, or
- (at your option) any later version.
+ 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
@@ -34,7 +33,7 @@ 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;
+ tty_password = 0, opt_frm = 0, opt_upgrade= 0;
static uint verbose = 0, opt_mysql_port=0;
static my_string opt_mysql_unix_port = 0;
static char *opt_password = 0, *current_user = 0,
@@ -78,6 +77,9 @@ static struct my_option my_long_options[] =
{"check-only-changed", 'C',
"Check only tables that have changed since last check or haven't been closed properly.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"check-upgrade", 'g',
+ "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,
0, 0, 0},
@@ -122,7 +124,7 @@ static struct my_option my_long_options[] =
NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
- (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
+ (gptr*) &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},
@@ -146,14 +148,14 @@ static struct my_option my_long_options[] =
#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},
-#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},
-#endif
{"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,
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},
+#endif
{"verbose", 'v', "Print info about the various stages.", 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,
@@ -268,6 +270,10 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case 'r':
what_to_do = DO_REPAIR;
break;
+ case 'g':
+ what_to_do= DO_CHECK;
+ opt_upgrade= 1;
+ break;
case 'W':
#ifdef __WIN__
opt_protocol = MYSQL_PROTOCOL_PIPE;
@@ -451,7 +457,7 @@ static int process_all_tables_in_db(char *database)
LINT_INIT(res);
if (use_db(database))
return 1;
- if (mysql_query(sock, "SHOW TABLES") ||
+ if (mysql_query(sock, "SHOW TABLE STATUS") ||
!((res= mysql_store_result(sock))))
return 1;
@@ -477,8 +483,12 @@ static int process_all_tables_in_db(char *database)
}
for (end = tables + 1; (row = mysql_fetch_row(res)) ;)
{
- end= fix_table_name(end, row[0]);
- *end++= ',';
+ /* Skip tables with an engine of NULL (probably a view). */
+ if (row[1])
+ {
+ end= fix_table_name(end, row[0]);
+ *end++= ',';
+ }
}
*--end = 0;
if (tot_length)
@@ -488,7 +498,11 @@ static int process_all_tables_in_db(char *database)
else
{
while ((row = mysql_fetch_row(res)))
- handle_request_for_tables(row[0], strlen(row[0]));
+ /* Skip tables with an engine of NULL (probably a view). */
+ if (row[1])
+ {
+ handle_request_for_tables(row[0], strlen(row[0]));
+ }
}
mysql_free_result(res);
return 0;
@@ -497,6 +511,9 @@ static int process_all_tables_in_db(char *database)
static int use_db(char *database)
{
+ if (mysql_get_server_version(sock) >= 50003 &&
+ !my_strcasecmp(&my_charset_latin1, database, "information_schema"))
+ return 1;
if (mysql_select_db(sock, database))
{
DBerror(sock, "when selecting the database");
@@ -522,6 +539,7 @@ static int handle_request_for_tables(char *tables, uint length)
if (opt_medium_check) end = strmov(end, " MEDIUM"); /* Default */
if (opt_extended) end = strmov(end, " EXTENDED");
if (opt_check_only_changed) end = strmov(end, " CHANGED");
+ if (opt_upgrade) end = strmov(end, " FOR UPGRADE");
break;
case DO_REPAIR:
op = "REPAIR";
@@ -643,6 +661,7 @@ static int dbConnect(char *host, char *user, char *passwd)
DBerror(&mysql_connection, "when trying to connect");
return 1;
}
+ mysql_connection.reconnect= 1;
return 0;
} /* dbConnect */
diff --git a/client/mysqldump.c b/client/mysqldump.c
index 3bf9fff1b86..0dfc7ee8e3c 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -2,8 +2,7 @@
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; either version 2 of the License, or
- (at your option) any later version.
+ 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
@@ -21,7 +20,7 @@
** AUTHOR: Igor Romanenko (igor@frog.kiev.ua)
** DATE: December 3, 1994
** WARRANTY: None, expressed, impressed, implied
-** or other
+** or other
** STATUS: Public domain
** Adapted and optimized for MySQL by
** Michael Widenius, Sinisa Milivojevic, Jani Tolonen
@@ -30,20 +29,22 @@
** 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.9"
+#define DUMP_VERSION "10.11"
#include <my_global.h>
#include <my_sys.h>
+#include <my_user.h>
#include <m_string.h>
#include <m_ctype.h>
#include <hash.h>
+#include <stdarg.h>
#include "client_priv.h"
#include "mysql.h"
@@ -70,26 +71,34 @@
/* Size of buffer for dump's select query */
#define QUERY_LENGTH 1536
+/* ignore table flags */
+#define IGNORE_NONE 0x00 /* no ignore */
+#define IGNORE_DATA 0x01 /* don't dump data for this table */
+#define IGNORE_INSERT_DELAYED 0x02 /* table doesn't support INSERT DELAYED */
+
static char *add_load_option(char *ptr, const char *object,
- const char *statement);
+ const char *statement);
static ulong find_set(TYPELIB *lib, const char *x, uint length,
- char **err_pos, uint *err_len);
+ char **err_pos, uint *err_len);
+static char *alloc_query_str(ulong size);
static char *field_escape(char *to,const char *from,uint length);
-static my_bool verbose=0,tFlag=0,dFlag=0,quick= 1, extended_insert= 1,
- lock_tables=1,ignore_errors=0,flush_logs=0,
- opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0,
+static my_bool verbose= 0, opt_no_create_info= 0, opt_no_data= 0,
+ quick= 1, extended_insert= 1,
+ lock_tables=1,ignore_errors=0,flush_logs=0,flush_privileges=0,
+ opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0,
opt_delayed=0,create_options=1,opt_quoted=0,opt_databases=0,
opt_alldbs=0,opt_create_db=0,opt_lock_all_tables=0,
opt_set_charset=0,
- opt_autocommit=0,opt_disable_keys=1,opt_xml=0,
- opt_delete_master_logs=0, tty_password=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_autocommit=0,opt_disable_keys=1,opt_xml=0,
+ opt_delete_master_logs=0, tty_password=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;
static ulong opt_max_allowed_packet, opt_net_buffer_length;
-static MYSQL mysql_connection,*sock=0;
-static my_bool insert_pat_inited=0;
+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,
@@ -97,6 +106,7 @@ static char *opt_password=0,*current_user=0,
*where=0, *order_by=0,
*opt_compatible_mode_str= 0,
*err_ptr= 0;
+static char **defaults_argv= 0;
static char compatible_mode_normal_str[255];
static ulong opt_compatible_mode= 0;
#define MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL 1
@@ -106,7 +116,7 @@ static my_string opt_mysql_unix_port=0;
static int first_error=0;
static DYNAMIC_STRING extended_row;
#include <sslopt-vars.h>
-FILE *md_result_file;
+FILE *md_result_file= 0;
#ifdef HAVE_SMEM
static char *shared_memory_base_name=0;
#endif
@@ -121,6 +131,8 @@ static const char *mysql_universal_client_charset=
static char *default_charset;
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[]=
{
@@ -139,7 +151,7 @@ const char *compatible_mode_names[]=
(1<<10) /* ANSI */\
)
TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1,
- "", compatible_mode_names, NULL};
+ "", compatible_mode_names, NULL};
HASH ignore_table;
@@ -203,10 +215,12 @@ static struct my_option my_long_options[] =
{"debug", '#', "Output debug log", (gptr*) &default_dbug_option,
(gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
#endif
+ {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", (gptr*) &info_flag,
+ (gptr*) &info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"default-character-set", OPT_DEFAULT_CHARSET,
"Set the default character set.", (gptr*) &default_charset,
(gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"delayed-insert", OPT_DELAYED, "Insert rows with INSERT DELAYED.",
+ {"delayed-insert", OPT_DELAYED, "Insert rows with INSERT DELAYED; ",
(gptr*) &opt_delayed, (gptr*) &opt_delayed, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0},
{"delete-master-logs", OPT_DELETE_MASTER_LOGS,
@@ -245,6 +259,12 @@ static struct my_option my_long_options[] =
"--lock-all-tables or --master-data with --flush-logs",
(gptr*) &flush_logs, (gptr*) &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,
+ 0, 0},
{"force", 'f', "Continue even if we get an sql-error.",
(gptr*) &ignore_errors, (gptr*) &ignore_errors, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},
@@ -266,7 +286,7 @@ static struct my_option my_long_options[] =
{"lines-terminated-by", OPT_LTB, "Lines in the i.file are terminated by ...",
(gptr*) &lines_terminated, (gptr*) &lines_terminated, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"lock-all-tables", 'x', "Locks all tables across all databases. This "
+ {"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,
@@ -287,7 +307,7 @@ static struct my_option my_long_options[] =
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,
- GET_ULONG, REQUIRED_ARG, 24*1024*1024, 4096,
+ 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,
@@ -302,9 +322,10 @@ static struct my_option my_long_options[] =
(gptr*) &opt_create_db, (gptr*) &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*) &tFlag, (gptr*) &tFlag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"no-data", 'd', "No row information.", (gptr*) &dFlag, (gptr*) &dFlag, 0,
- GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ (gptr*) &opt_no_create_info, (gptr*) &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-set-names", 'N',
"Deprecated. Use --skip-set-charset instead.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -322,7 +343,7 @@ static struct my_option my_long_options[] =
NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
- (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
+ (gptr*) &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},
@@ -334,6 +355,9 @@ static struct my_option my_long_options[] =
{"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,
+ 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,
@@ -371,6 +395,12 @@ static struct my_option my_long_options[] =
(gptr*) &path, (gptr*) &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,
+ 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},
#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,
@@ -384,7 +414,7 @@ static struct my_option my_long_options[] =
(gptr*) &where, (gptr*) &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}
+ {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
static const char *load_default_groups[]= { "mysqldump","client",0 };
@@ -392,25 +422,53 @@ static const char *load_default_groups[]= { "mysqldump","client",0 };
static void safe_exit(int error);
static void write_header(FILE *sql_file, char *db_name);
static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row,
- const char *prefix,const char *name,
- int string_value);
+ const char *prefix,const char *name,
+ int string_value);
static int dump_selected_tables(char *db, char **table_names, int tables);
static int dump_all_tables_in_db(char *db);
-static int init_dumping(char *);
+static int init_dumping_views(char *);
+static int init_dumping_tables(char *);
+static int init_dumping(char *, int init_func(char*));
static int dump_databases(char **);
static int dump_all_databases();
static char *quote_name(const char *name, char *buff, my_bool force);
-static const char *check_if_ignore_table(const char *table_name);
+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);
#include <help_start.h>
/*
+ Print the supplied message if in verbose mode
+
+ SYNOPSIS
+ verbose_msg()
+ fmt format specifier
+ ... variable number of parameters
+*/
+
+static void verbose_msg(const char *fmt, ...)
+{
+ va_list args;
+ DBUG_ENTER("verbose_msg");
+
+ if (!verbose)
+ DBUG_VOID_RETURN;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+
+ DBUG_VOID_RETURN;
+}
+
+/*
exit with message if ferror(file)
-
+
SYNOPSIS
check_io()
- file - checked file
+ file - checked file
*/
void check_io(FILE *file)
@@ -418,6 +476,7 @@ void check_io(FILE *file)
if (ferror(file))
{
fprintf(stderr, "%s: Got errno %d on write\n", my_progname, errno);
+ ignore_errors= 0; /* We can't ignore this error */
safe_exit(EX_EOF);
}
}
@@ -434,7 +493,7 @@ static void short_usage_sub(void)
{
printf("Usage: %s [OPTIONS] database [tables]\n", my_progname);
printf("OR %s [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]\n",
- my_progname);
+ my_progname);
printf("OR %s [OPTIONS] --all-databases [OPTIONS]\n", my_progname);
NETWARE_SET_SCREEN_MODE(1);
}
@@ -467,6 +526,8 @@ 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. */
fputs("<mysqldump ", sql_file);
fputs("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"",
sql_file);
@@ -479,12 +540,12 @@ static void write_header(FILE *sql_file, char *db_name)
{
fprintf(sql_file, "-- MySQL dump %s\n--\n", DUMP_VERSION);
fprintf(sql_file, "-- Host: %s Database: %s\n",
- current_host ? current_host : "localhost", db_name ? db_name :
- "");
+ current_host ? current_host : "localhost", db_name ? db_name :
+ "");
fputs("-- ------------------------------------------------------\n",
- sql_file);
+ sql_file);
fprintf(sql_file, "-- Server version\t%s\n",
- mysql_get_server_info(&mysql_connection));
+ mysql_get_server_info(&mysql_connection));
}
if (opt_set_charset)
fprintf(sql_file,
@@ -492,6 +553,13 @@ static void write_header(FILE *sql_file, char *db_name)
"\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
"\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
"\n/*!40101 SET NAMES %s */;\n",default_charset);
+
+ if (opt_tz_utc)
+ {
+ fprintf(sql_file, "/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;\n");
+ fprintf(sql_file, "/*!40103 SET TIME_ZONE='+00:00' */;\n");
+ }
+
if (!path)
{
fprintf(md_result_file,"\
@@ -500,10 +568,10 @@ static void write_header(FILE *sql_file, char *db_name)
");
}
fprintf(sql_file,
- "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='%s%s%s' */;\n"
- "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n",
- path?"":"NO_AUTO_VALUE_ON_ZERO",compatible_mode_normal_str[0]==0?"":",",
- compatible_mode_normal_str);
+ "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='%s%s%s' */;\n"
+ "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n",
+ path?"":"NO_AUTO_VALUE_ON_ZERO",compatible_mode_normal_str[0]==0?"":",",
+ compatible_mode_normal_str);
check_io(sql_file);
}
} /* write_header */
@@ -518,6 +586,9 @@ static void write_footer(FILE *sql_file)
}
else if (!opt_compact)
{
+ if (opt_tz_utc)
+ fprintf(sql_file,"/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;\n");
+
fprintf(sql_file,"\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n");
if (!path)
{
@@ -531,8 +602,15 @@ static void write_footer(FILE *sql_file)
"/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n"
"/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n");
fprintf(sql_file,
- "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n");
+ "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n");
fputs("\n", sql_file);
+ if (opt_comments)
+ {
+ char time_str[20];
+ get_date(time_str, GETDATE_DATE_TIME, 0);
+ fprintf(sql_file, "-- Dump completed on %s\n",
+ time_str);
+ }
check_io(sql_file);
}
} /* write_footer */
@@ -545,24 +623,16 @@ static void free_table_ent(char *key)
byte* get_table_key(const char *entry, uint *length,
- my_bool not_used __attribute__((unused)))
+ my_bool not_used __attribute__((unused)))
{
*length= strlen(entry);
return (byte*) entry;
}
-void init_table_rule_hash(HASH* h)
-{
- if (hash_init(h, charset_info, 16, 0, 0,
- (hash_get_key) get_table_key,
- (hash_free_key) free_table_ent, 0))
- exit(EX_EOM);
-}
-
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
- char *argument)
+ char *argument)
{
switch (optid) {
#ifdef __NETWARE__
@@ -576,22 +646,22 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
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 */
+ while (*argument) *argument++= 'x'; /* Destroy argument */
if (*start)
- start[1]=0; /* Cut length of argument */
+ start[1]=0; /* Cut length of argument */
tty_password= 0;
}
else
tty_password=1;
break;
case 'r':
- if (!(md_result_file = my_fopen(argument, O_WRONLY | FILE_BINARY,
- MYF(MY_WME))))
+ if (!(md_result_file= my_fopen(argument, O_WRONLY | FILE_BINARY,
+ MYF(MY_WME))))
exit(1);
break;
case 'W':
#ifdef __WIN__
- opt_protocol = MYSQL_PROTOCOL_PIPE;
+ opt_protocol= MYSQL_PROTOCOL_PIPE;
#endif
break;
case 'N':
@@ -602,12 +672,13 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
break;
case '#':
DBUG_PUSH(argument ? argument : default_dbug_option);
+ info_flag= 1;
break;
#include <sslopt-case.h>
case 'V': print_version(); exit(0);
case 'X':
- opt_xml = 1;
- extended_insert= opt_drop= opt_lock=
+ opt_xml= 1;
+ extended_insert= opt_drop= opt_lock=
opt_disable_keys= opt_autocommit= opt_create_db= 0;
break;
case 'I':
@@ -642,9 +713,6 @@ 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 (!hash_inited(&ignore_table))
- init_table_rule_hash(&ignore_table);
-
if (my_hash_insert(&ignore_table, (byte*)my_strdup(argument, MYF(0))))
exit(EX_EOM);
break;
@@ -660,36 +728,36 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
opt_set_charset= 0;
opt_compatible_mode_str= argument;
opt_compatible_mode= find_set(&compatible_mode_typelib,
- argument, strlen(argument),
- &err_ptr, &err_len);
+ argument, strlen(argument),
+ &err_ptr, &err_len);
if (err_len)
{
- strmake(buff, err_ptr, min(sizeof(buff), err_len));
- fprintf(stderr, "Invalid mode to --compatible: %s\n", buff);
- exit(1);
+ strmake(buff, err_ptr, min(sizeof(buff), err_len));
+ fprintf(stderr, "Invalid mode to --compatible: %s\n", buff);
+ exit(1);
}
#if !defined(DBUG_OFF)
{
- uint size_for_sql_mode= 0;
- const char **ptr;
- for (ptr= compatible_mode_names; *ptr; 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);
+ uint size_for_sql_mode= 0;
+ const char **ptr;
+ for (ptr= compatible_mode_names; *ptr; 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);
}
#endif
mode= opt_compatible_mode;
for (i= 0, mode= opt_compatible_mode; mode; mode>>= 1, i++)
{
- if (mode & 1)
- {
- end= strmov(end, compatible_mode_names[i]);
- end= strmov(end, ",");
- }
+ if (mode & 1)
+ {
+ end= strmov(end, compatible_mode_names[i]);
+ end= strmov(end, ",");
+ }
}
if (end!=compatible_mode_normal_str)
- end[-1]= 0;
- /*
+ end[-1]= 0;
+ /*
Set charset to the default compiled value if it hasn't
been reset yet by --default-character-set=xxx.
*/
@@ -701,8 +769,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
{
if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0)
{
- fprintf(stderr, "Unknown option to protocol: %s\n", argument);
- exit(1);
+ fprintf(stderr, "Unknown option to protocol: %s\n", argument);
+ exit(1);
}
break;
}
@@ -720,21 +788,33 @@ static int get_options(int *argc, char ***argv)
md_result_file= stdout;
load_defaults("my",load_default_groups,argc,argv);
+ defaults_argv= *argv;
+
+ if (hash_init(&ignore_table, charset_info, 16, 0, 0,
+ (hash_get_key) get_table_key,
+ (hash_free_key) free_table_ent, 0))
+ return(EX_EOM);
+ /* Don't copy cluster internal log tables */
+ if (my_hash_insert(&ignore_table,
+ (byte*) my_strdup("mysql.apply_status", MYF(MY_WME))) ||
+ my_hash_insert(&ignore_table,
+ (byte*) my_strdup("mysql.schema", MYF(MY_WME))))
+ return(EX_EOM);
- if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
- exit(ho_error);
+ if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
+ return(ho_error);
*mysql_params->p_max_allowed_packet= opt_max_allowed_packet;
*mysql_params->p_net_buffer_length= opt_net_buffer_length;
if (opt_delayed)
- opt_lock=0; /* Can't have lock with delayed */
+ opt_lock=0; /* Can't have lock with delayed */
if (!path && (enclosed || opt_enclosed || escaped || lines_terminated ||
- fields_terminated))
+ fields_terminated))
{
fprintf(stderr,
- "%s: You must use option --tab with --fields-...\n", my_progname);
- return(1);
+ "%s: You must use option --tab with --fields-...\n", my_progname);
+ return(EX_USAGE);
}
/* Ensure consistency of the set of binlog & locking options */
@@ -744,8 +824,8 @@ static int get_options(int *argc, char ***argv)
{
fprintf(stderr, "%s: You can't use --single-transaction and "
"--lock-all-tables at the same time.\n", my_progname);
- return(1);
- }
+ return(EX_USAGE);
+ }
if (opt_master_data)
opt_lock_all_tables= !opt_single_transaction;
if (opt_single_transaction || opt_lock_all_tables)
@@ -753,23 +833,23 @@ static int get_options(int *argc, char ***argv)
if (enclosed && opt_enclosed)
{
fprintf(stderr, "%s: You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n", my_progname);
- return(1);
+ return(EX_USAGE);
}
if ((opt_databases || opt_alldbs) && path)
{
fprintf(stderr,
- "%s: --databases or --all-databases can't be used with --tab.\n",
- my_progname);
- return(1);
+ "%s: --databases or --all-databases can't be used with --tab.\n",
+ my_progname);
+ return(EX_USAGE);
}
if (strcmp(default_charset, charset_info->csname) &&
- !(charset_info= get_charset_by_csname(default_charset,
- MY_CS_PRIMARY, MYF(MY_WME))))
+ !(charset_info= get_charset_by_csname(default_charset,
+ MY_CS_PRIMARY, MYF(MY_WME))))
exit(1);
if ((*argc < 1 && !opt_alldbs) || (*argc > 0 && opt_alldbs))
{
short_usage();
- return 1;
+ return EX_USAGE;
}
if (tty_password)
opt_password=get_tty_password(NullS);
@@ -778,17 +858,17 @@ static int get_options(int *argc, char ***argv)
/*
-** DBerror -- prints mysql error message and exits the program.
+** DB_error -- prints mysql error message and exits the program.
*/
-static void DBerror(MYSQL *mysql, const char *when)
+static void DB_error(MYSQL *mysql, const char *when)
{
- DBUG_ENTER("DBerror");
+ DBUG_ENTER("DB_error");
fprintf(stderr, "%s: Got error: %d: %s %s\n", my_progname,
mysql_errno(mysql), mysql_error(mysql), when);
fflush(stderr);
safe_exit(EX_MYSQLERR);
DBUG_VOID_RETURN;
-} /* DBerror */
+} /* DB_error */
/*
@@ -798,14 +878,15 @@ static void DBerror(MYSQL *mysql, const char *when)
SYNOPSIS
mysql_query_with_error_report()
mysql_con connection to use
- res if non zero, result will be put there with mysql_store_result
+ res if non zero, result will be put there with
+ mysql_store_result()
query query to send to server
RETURN VALUES
0 query sending and (if res!=0) result reading went ok
1 error
*/
-
+
static int mysql_query_with_error_report(MYSQL *mysql_con, MYSQL_RES **res,
const char *query)
{
@@ -815,11 +896,50 @@ static int mysql_query_with_error_report(MYSQL *mysql_con, MYSQL_RES **res,
fprintf(stderr, "%s: Couldn't execute '%s': %s (%d)\n",
my_progname, query,
mysql_error(mysql_con), mysql_errno(mysql_con));
+ safe_exit(EX_MYSQLERR);
return 1;
}
return 0;
}
+/*
+ Open a new .sql file to dump the table or view into
+
+ SYNOPSIS
+ open_sql_file_for_table
+ name name of the table or view
+
+ RETURN VALUES
+ 0 Failed to open file
+ > 0 Handle of the open file
+*/
+static FILE* open_sql_file_for_table(const char* table)
+{
+ FILE* res;
+ char filename[FN_REFLEN], tmp_path[FN_REFLEN];
+ convert_dirname(tmp_path,path,NullS);
+ res= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
+ O_WRONLY, MYF(MY_WME));
+ return res;
+}
+
+
+static void free_resources()
+{
+ if (md_result_file && md_result_file != stdout)
+ my_fclose(md_result_file, MYF(0));
+ my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
+ if (hash_inited(&ignore_table))
+ hash_free(&ignore_table);
+ if (extended_insert)
+ dynstr_free(&extended_row);
+ if (insert_pat_inited)
+ dynstr_free(&insert_pat);
+ if (defaults_argv)
+ free_defaults(defaults_argv);
+ my_end(info_flag ? MY_CHECK_ERROR : 0);
+}
+
static void safe_exit(int error)
{
@@ -827,31 +947,32 @@ static void safe_exit(int error)
first_error= error;
if (ignore_errors)
return;
- if (sock)
- mysql_close(sock);
+ if (mysql)
+ mysql_close(mysql);
+ free_resources();
exit(error);
}
-/* safe_exit */
/*
-** dbConnect -- connects to the host and selects DB.
+ db_connect -- connects to the host and selects DB.
*/
-static int dbConnect(char *host, char *user,char *passwd)
+
+static int connect_to_db(char *host, char *user,char *passwd)
{
char buff[20+FN_REFLEN];
- DBUG_ENTER("dbConnect");
- if (verbose)
- {
- fprintf(stderr, "-- Connecting to %s...\n", host ? host : "localhost");
- }
+ DBUG_ENTER("connect_to_db");
+
+ verbose_msg("-- Connecting to %s...\n", host ? host : "localhost");
mysql_init(&mysql_connection);
if (opt_compress)
mysql_options(&mysql_connection,MYSQL_OPT_COMPRESS,NullS);
#ifdef HAVE_OPENSSL
if (opt_use_ssl)
mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
- opt_ssl_capath, opt_ssl_cipher);
+ opt_ssl_capath, opt_ssl_cipher);
+ mysql_options(&mysql_connection,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);
@@ -860,12 +981,12 @@ static int dbConnect(char *host, char *user,char *passwd)
mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
#endif
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)))
+ if (!(mysql= mysql_real_connect(&mysql_connection,host,user,passwd,
+ NULL,opt_mysql_port,opt_mysql_unix_port,
+ 0)))
{
- DBerror(&mysql_connection, "when trying to connect");
- return 1;
+ DB_error(&mysql_connection, "when trying to connect");
+ DBUG_RETURN(1);
}
/*
Don't dump SET NAMES with a pre-4.1 server (bug#7997).
@@ -876,17 +997,29 @@ static int dbConnect(char *host, char *user,char *passwd)
As we're going to set SQL_MODE, it would be lost on reconnect, so we
cannot reconnect.
*/
- sock->reconnect= 0;
+ mysql->reconnect= 0;
my_snprintf(buff, sizeof(buff), "/*!40100 SET @@SQL_MODE='%s' */",
- compatible_mode_normal_str);
- if (mysql_query_with_error_report(sock, 0, buff))
+ compatible_mode_normal_str);
+ if (mysql_query_with_error_report(mysql, 0, buff))
{
- mysql_close(sock);
safe_exit(EX_MYSQLERR);
- return 1;
+ DBUG_RETURN(1);
}
- return 0;
-} /* dbConnect */
+ /*
+ set time_zone to UTC to allow dumping date types between servers with
+ different time zone settings
+ */
+ if (opt_tz_utc)
+ {
+ my_snprintf(buff, sizeof(buff), "/*!40103 SET TIME_ZONE='+00:00' */");
+ if (mysql_query_with_error_report(mysql, 0, buff))
+ {
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN(0);
+} /* connect_to_db */
/*
@@ -894,9 +1027,8 @@ static int dbConnect(char *host, char *user,char *passwd)
*/
static void dbDisconnect(char *host)
{
- if (verbose)
- fprintf(stderr, "-- Disconnecting from %s...\n", host ? host : "localhost");
- mysql_close(sock);
+ verbose_msg("-- Disconnecting from %s...\n", host ? host : "localhost");
+ mysql_close(mysql);
} /* dbDisconnect */
@@ -906,8 +1038,8 @@ static void unescape(FILE *file,char *pos,uint length)
DBUG_ENTER("unescape");
if (!(tmp=(char*) my_malloc(length*2+1, MYF(MY_WME))))
{
- ignore_errors=0; /* Fatal error */
- safe_exit(EX_MYSQLERR); /* Force exit */
+ ignore_errors=0; /* Fatal error */
+ safe_exit(EX_MYSQLERR); /* Force exit */
}
mysql_real_escape_string(&mysql_connection, tmp, pos, length);
fputc('\'', file);
@@ -931,6 +1063,22 @@ static my_bool test_if_special_chars(const char *str)
+/*
+ quote_name(name, buff, force)
+
+ Quotes char string, taking into account compatible mode
+
+ Args
+
+ name Unquoted string containing that which will be quoted
+ buff The buffer that contains the quoted value, also returned
+ force Flag to make it ignore 'test_if_special_chars'
+
+ Returns
+
+ buff quoted string
+
+*/
static char *quote_name(const char *name, char *buff, my_bool force)
{
char *to= buff;
@@ -997,13 +1145,13 @@ static char *quote_for_like(const char *name, char *buff)
/*
Quote and print a string.
-
+
SYNOPSIS
print_quoted_xml()
- output - output file
- str - string to print
- len - its length
-
+ xml_file - output file
+ str - string to print
+ len - its length
+
DESCRIPTION
Quote '<' '>' '&' '\"' chars and print a string to the xml_file.
*/
@@ -1011,7 +1159,7 @@ static char *quote_for_like(const char *name, char *buff)
static void print_quoted_xml(FILE *xml_file, const char *str, ulong len)
{
const char *end;
-
+
for (end= str + len; str != end; str++)
{
switch (*str) {
@@ -1037,34 +1185,63 @@ static void print_quoted_xml(FILE *xml_file, const char *str, ulong len)
/*
- Print xml tag with one attribute.
-
+ Print xml tag. Optionally add attribute(s).
+
SYNOPSIS
- print_xml_tag1()
- xml_file - output file
- sbeg - line beginning
- stag_atr - tag and attribute
- sval - value of attribute
- send - line ending
-
+ print_xml_tag(xml_file, sbeg, send, tag_name, first_attribute_name,
+ ..., attribute_name_n, attribute_value_n, NullS)
+ xml_file - output file
+ sbeg - line beginning
+ send - line ending
+ tag_name - XML tag name.
+ first_attribute_name - tag and first attribute
+ first_attribute_value - (Implied) value of first attribute
+ attribute_name_n - attribute n
+ attribute_value_n - value of attribute n
+
DESCRIPTION
- Print tag with one attribute to the xml_file. Format is:
- sbeg<stag_atr="sval">send
+ Print XML tag with any number of attribute="value" pairs to the xml_file.
+
+ Format is:
+ sbeg<tag_name first_attribute_name="first_attribute_value" ...
+ attribute_name_n="attribute_value_n">send
NOTE
- sval MUST be a NULL terminated string.
- sval string will be qouted before output.
+ Additional arguments must be present in attribute/value pairs.
+ The last argument should be the null character pointer.
+ All attribute_value arguments MUST be NULL terminated strings.
+ All attribute_value arguments will be quoted before output.
*/
-static void print_xml_tag1(FILE * xml_file, const char* sbeg,
- const char* stag_atr, const char* sval,
- const char* send)
+static void print_xml_tag(FILE * xml_file, const char* sbeg, const char* send,
+ const char* tag_name,
+ const char* first_attribute_name, ...)
{
+ va_list arg_list;
+ const char *attribute_name, *attribute_value;
+
fputs(sbeg, xml_file);
- fputs("<", xml_file);
- fputs(stag_atr, xml_file);
- fputs("\"", xml_file);
- print_quoted_xml(xml_file, sval, strlen(sval));
- fputs("\">", xml_file);
+ fputc('<', xml_file);
+ fputs(tag_name, xml_file);
+
+ va_start(arg_list, first_attribute_name);
+ attribute_name= first_attribute_name;
+ while (attribute_name != NullS)
+ {
+ attribute_value= va_arg(arg_list, char *);
+ DBUG_ASSERT(attribute_value != NullS);
+
+ fputc(' ', xml_file);
+ fputs(attribute_name, xml_file);
+ fputc('\"', xml_file);
+
+ print_quoted_xml(xml_file, attribute_value, strlen(attribute_value));
+ fputc('\"', xml_file);
+
+ attribute_name= va_arg(arg_list, char *);
+ }
+ va_end(arg_list);
+
+ fputc('>', xml_file);
fputs(send, xml_file);
check_io(xml_file);
}
@@ -1075,11 +1252,11 @@ static void print_xml_tag1(FILE * xml_file, const char* sbeg,
SYNOPSIS
print_xml_null_tag()
- xml_file - output file
- sbeg - line beginning
- stag_atr - tag and attribute
- sval - value of attribute
- send - line ending
+ xml_file - output file
+ sbeg - line beginning
+ stag_atr - tag and attribute
+ sval - value of attribute
+ send - line ending
DESCRIPTION
Print tag with one attribute to the xml_file. Format is:
@@ -1109,11 +1286,11 @@ static void print_xml_null_tag(FILE * xml_file, const char* sbeg,
SYNOPSIS
print_xml_row()
- xml_file - output file
- row_name - xml tag name
- tableRes - query result
- row - result row
-
+ xml_file - output file
+ row_name - xml tag name
+ tableRes - query result
+ row - result row
+
DESCRIPTION
Print tag with many attribute to the xml_file. Format is:
\t\t<row_name Atr1="Val1" Atr2="Val2"... />
@@ -1122,12 +1299,12 @@ static void print_xml_null_tag(FILE * xml_file, const char* sbeg,
*/
static void print_xml_row(FILE *xml_file, const char *row_name,
- MYSQL_RES *tableRes, MYSQL_ROW *row)
+ MYSQL_RES *tableRes, MYSQL_ROW *row)
{
uint i;
MYSQL_FIELD *field;
ulong *lengths= mysql_fetch_lengths(tableRes);
-
+
fprintf(xml_file, "\t\t<%s", row_name);
check_io(xml_file);
mysql_field_seek(tableRes, 0);
@@ -1147,67 +1324,261 @@ static void print_xml_row(FILE *xml_file, const char *row_name,
check_io(xml_file);
}
+/*
+ Print hex value for blob data.
+
+ SYNOPSIS
+ print_blob_as_hex()
+ output_file - output file
+ str - string to print
+ len - its length
+
+ DESCRIPTION
+ Print hex value for blob data.
+*/
+
+static void print_blob_as_hex(FILE *output_file, const char *str, ulong len)
+{
+ /* sakaik got the idea to to provide blob's in hex notation. */
+ const char *ptr= str, *end= ptr + len;
+ for (; ptr < end ; ptr++)
+ fprintf(output_file, "%02X", *((uchar *)ptr));
+ check_io(output_file);
+}
/*
- getTableStructure -- retrievs database structure, prints out corresponding
- CREATE statement and fills out insert_pat.
+ dump_routines_for_db
+ -- retrievs list of routines for a given db, and prints out
+ the CREATE PROCEDURE definition into the output (the dump).
+
+ This function has logic to print the appropriate syntax depending on whether
+ this is a procedure or functions
+
+ RETURN
+ 0 Success
+ 1 Error
+*/
+
+static uint dump_routines_for_db(char *db)
+{
+ char query_buff[512];
+ const char *routine_type[]= {"FUNCTION", "PROCEDURE"};
+ char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3];
+ char *routine_name;
+ int i;
+ FILE *sql_file= md_result_file;
+ MYSQL_RES *routine_res, *routine_list_res;
+ MYSQL_ROW row, routine_list_row;
+ DBUG_ENTER("dump_routines_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 routines for database '%s'\n--\n", db);
+
+ /*
+ not using "mysql_query_with_error_report" because we may have not
+ enough privileges to lock mysql.proc.
+ */
+ if (lock_tables)
+ mysql_query(mysql, "LOCK TABLES mysql.proc READ");
+
+ fprintf(sql_file, "DELIMITER ;;\n");
+
+ /* 0, retrieve and dump functions, 1, procedures */
+ for (i= 0; i <= 1; i++)
+ {
+ my_snprintf(query_buff, sizeof(query_buff),
+ "SHOW %s STATUS WHERE Db = '%s'",
+ routine_type[i], db_name_buff);
+
+ if (mysql_query_with_error_report(mysql, &routine_list_res, query_buff))
+ DBUG_RETURN(1);
+
+ if (mysql_num_rows(routine_list_res))
+ {
+
+ while ((routine_list_row= mysql_fetch_row(routine_list_res)))
+ {
+ 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);
+
+ if (mysql_query_with_error_report(mysql, &routine_res, query_buff))
+ DBUG_RETURN(1);
+
+ while ((row= mysql_fetch_row(routine_res)))
+ {
+ /*
+ if the user has EXECUTE privilege he see routine names, but NOT the
+ routine body of other routines that are not the creator of!
+ */
+ DBUG_PRINT("info",("length of body for %s row[2] '%s' is %d",
+ routine_name, row[2], (int) strlen(row[2])));
+ if (strlen(row[2]))
+ {
+ char *query_str= NULL;
+ char *definer_begin;
+
+ if (opt_drop)
+ 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.
+ */
+
+ definer_begin= strstr(row[2], " DEFINER");
+
+ if (definer_begin)
+ {
+ char *definer_end= strstr(definer_begin, " PROCEDURE");
+
+ if (!definer_end)
+ definer_end= strstr(definer_begin, " 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(strlen(row[2]) + 23);
+
+ query_str_tail= strnmov(query_str, row[2],
+ definer_begin - row[2]);
+ query_str_tail= strmov(query_str_tail, "*/ /*!50020");
+ query_str_tail= strnmov(query_str_tail, definer_begin,
+ definer_end - definer_begin);
+ query_str_tail= strxmov(query_str_tail, "*/ /*!50003",
+ definer_end, NullS);
+ }
+ }
+
+ /*
+ 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 */
+ } /* end of list of routines */
+ mysql_free_result(routine_res);
+ }
+ mysql_free_result(routine_list_res);
+ } /* end of for i (0 .. 1) */
+ /* set the delimiter back to ';' */
+ fprintf(sql_file, "DELIMITER ;\n");
+
+ if (lock_tables)
+ VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
+ DBUG_RETURN(0);
+}
+
+/*
+ get_table_structure -- retrievs database structure, prints out corresponding
+ CREATE statement and fills out insert_pat if the table is the type we will
+ be dumping.
+
+ ARGS
+ table - table name
+ db - db name
+ table_type - table type, e.g. "MyISAM" or "InnoDB", but also "VIEW"
+ ignore_flag - what we must particularly ignore - see IGNORE_ defines above
RETURN
number of fields in table, 0 if error
*/
-static uint getTableStructure(char *table, char* db)
+static uint get_table_structure(char *table, char *db, char *table_type,
+ char *ignore_flag)
{
- MYSQL_RES *tableRes;
- MYSQL_ROW row;
- my_bool init=0;
- uint numFields;
- char *result_table, *opt_quoted_table;
+ my_bool init=0, delayed, write_data, complete_insert;
+ 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];
- char query_buff[512];
- FILE *sql_file = md_result_file;
+ char name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3];
+ char table_buff2[NAME_LEN*2+3], query_buff[512];
+ FILE *sql_file= md_result_file;
int len;
- DBUG_ENTER("getTableStructure");
- DBUG_PRINT("enter", ("db: %s, table: %s", db, table));
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+
+ DBUG_ENTER("get_table_structure");
+ DBUG_PRINT("enter", ("db: %s table: %s", db, table));
- if (!insert_pat_inited)
+ *ignore_flag= check_if_ignore_table(table, table_type);
+
+ delayed= opt_delayed;
+ if (delayed && (*ignore_flag & IGNORE_INSERT_DELAYED))
{
- insert_pat_inited= init_dynamic_string(&insert_pat, "", 1024, 1024);
+ delayed= 0;
+ verbose_msg("-- Warning: Unable to use delayed inserts for table '%s' "
+ "because it's of type %s\n", table, table_type);
+ }
+
+ complete_insert= 0;
+ if ((write_data= !(*ignore_flag & IGNORE_DATA)))
+ {
+ complete_insert= opt_complete_insert;
+ if (!insert_pat_inited)
+ {
+ insert_pat_inited= 1;
+ if (init_dynamic_string(&insert_pat, "", 1024, 1024))
+ safe_exit(EX_MYSQLERR);
+ }
+ else
+ dynstr_set(&insert_pat, "");
}
- else
- dynstr_set(&insert_pat, "");
- insert_option= ((opt_delayed && opt_ignore) ? " DELAYED IGNORE " :
- opt_delayed ? " DELAYED " :
- opt_ignore ? " IGNORE " : "");
+ insert_option= ((delayed && opt_ignore) ? " DELAYED IGNORE " :
+ delayed ? " DELAYED " : opt_ignore ? " IGNORE " : "");
- if (verbose)
- fprintf(stderr, "-- Retrieving table structure for table %s...\n", table);
+ verbose_msg("-- Retrieving table structure for table %s...\n", table);
len= my_snprintf(query_buff, sizeof(query_buff),
"SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
(opt_quoted || opt_keywords));
if (!create_options)
- strmov(query_buff+len, "/*!40102 ,SQL_MODE=concat(@@sql_mode, _utf8 ',NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS') */");
+ strmov(query_buff+len,
+ "/*!40102 ,SQL_MODE=concat(@@sql_mode, _utf8 ',NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS') */");
result_table= quote_name(table, table_buff, 1);
opt_quoted_table= quote_name(table, table_buff2, 0);
if (opt_order_by_primary)
- order_by = primary_key_fields(opt_quoted_table);
+ order_by= primary_key_fields(result_table);
- if (!opt_xml && !mysql_query_with_error_report(sock, 0, query_buff))
+ if (!opt_xml && !mysql_query_with_error_report(mysql, 0, query_buff))
{
/* using SHOW CREATE statement */
- if (!tFlag)
+ if (!opt_no_create_info)
{
/* Make an sql-file, if path was given iow. option -T was given */
char buff[20+FN_REFLEN];
+ MYSQL_FIELD *field;
my_snprintf(buff, sizeof(buff), "show create table %s", result_table);
- if (mysql_query_with_error_report(sock, 0, buff))
+ if (mysql_query_with_error_report(mysql, 0, buff))
{
safe_exit(EX_MYSQLERR);
DBUG_RETURN(0);
@@ -1215,190 +1586,300 @@ static uint getTableStructure(char *table, char* db)
if (path)
{
- char filename[FN_REFLEN], tmp_path[FN_REFLEN];
- convert_dirname(tmp_path,path,NullS);
- sql_file= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
- O_WRONLY, MYF(MY_WME));
- if (!sql_file) /* If file couldn't be opened */
+ if (!(sql_file= open_sql_file_for_table(table)))
{
- safe_exit(EX_MYSQLERR);
- DBUG_RETURN(0);
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(0);
}
write_header(sql_file, db);
}
if (!opt_xml && opt_comments)
{
+ if (strcmp (table_type, "VIEW") == 0) /* view */
+ fprintf(sql_file, "\n--\n-- Temporary table structure for view %s\n--\n\n",
+ result_table);
+ else
fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
- result_table);
- check_io(sql_file);
+ result_table);
+ check_io(sql_file);
}
if (opt_drop)
{
- fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table);
- check_io(sql_file);
+ /*
+ Even if the "table" is a view, we do a DROP TABLE here. The
+ view-specific code below fills in the DROP VIEW.
+ */
+ fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",
+ opt_quoted_table);
+ check_io(sql_file);
+ }
+
+ result= mysql_store_result(mysql);
+ field= mysql_fetch_field_direct(result, 0);
+ if (strcmp(field->name, "View") == 0)
+ {
+ char *scv_buff= NULL;
+
+ verbose_msg("-- It's a view, create dummy table for view\n");
+
+ /* save "show create" statement for later */
+ if ((row= mysql_fetch_row(result)) && (scv_buff=row[1]))
+ scv_buff= my_strdup(scv_buff, MYF(0));
+
+ mysql_free_result(result);
+
+ /*
+ Create a table with the same name as the view and with columns of
+ the same name in order to satisfy views that depend on this view.
+ The table will be removed when the actual view is created.
+
+ The properties of each column, aside from the data type, are not
+ preserved in this temporary table, because they are not necessary.
+
+ This will not be necessary once we can determine dependencies
+ between views and can simply dump them in the appropriate order.
+ */
+ my_snprintf(query_buff, sizeof(query_buff),
+ "SHOW FIELDS FROM %s", result_table);
+ if (mysql_query_with_error_report(mysql, 0, query_buff))
+ {
+ /*
+ View references invalid or privileged table/col/fun (err 1356),
+ so we cannot create a stand-in table. Be defensive and dump
+ a comment with the view's 'show create' statement. (Bug #17371)
+ */
+
+ if (mysql_errno(mysql) == ER_VIEW_INVALID)
+ fprintf(sql_file, "\n-- failed on view %s: %s\n\n", result_table, scv_buff ? scv_buff : "");
+
+ my_free(scv_buff, MYF(MY_ALLOW_ZERO_PTR));
+
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(0);
+ }
+ else
+ my_free(scv_buff, MYF(MY_ALLOW_ZERO_PTR));
+
+ if ((result= mysql_store_result(mysql)))
+ {
+ if (mysql_num_rows(result))
+ {
+ if (opt_drop)
+ {
+ /*
+ 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 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, " %s %s", quote_name(row[0], name_buff, 0),
+ row[1]);
+
+ while((row= mysql_fetch_row(result)))
+ {
+ /* col name, col type */
+ fprintf(sql_file, ",\n %s %s",
+ quote_name(row[0], name_buff, 0), row[1]);
+ }
+ fprintf(sql_file, "\n) */;\n");
+ check_io(sql_file);
+ }
+ }
+ mysql_free_result(result);
+
+ if (path)
+ my_fclose(sql_file, MYF(MY_WME));
+
+ seen_views= 1;
+ DBUG_RETURN(0);
}
- tableRes=mysql_store_result(sock);
- row=mysql_fetch_row(tableRes);
+ row= mysql_fetch_row(result);
fprintf(sql_file, "%s;\n", row[1]);
check_io(sql_file);
- mysql_free_result(tableRes);
+ mysql_free_result(result);
}
my_snprintf(query_buff, sizeof(query_buff), "show fields from %s",
- result_table);
- if (mysql_query_with_error_report(sock, &tableRes, query_buff))
+ result_table);
+ if (mysql_query_with_error_report(mysql, &result, query_buff))
{
if (path)
- my_fclose(sql_file, MYF(MY_WME));
+ my_fclose(sql_file, MYF(MY_WME));
safe_exit(EX_MYSQLERR);
DBUG_RETURN(0);
}
- dynstr_append_mem(&insert_pat, "INSERT ", 7);
- dynstr_append(&insert_pat, insert_option);
- dynstr_append_mem(&insert_pat, "INTO ", 5);
- dynstr_append(&insert_pat, opt_quoted_table);
- if (opt_complete_insert)
+ /*
+ If write_data is true, then we build up insert statements for
+ the table's data. Note: in subsequent lines of code, this test
+ will have to be performed each time we are appending to
+ insert_pat.
+ */
+ if (write_data)
{
- dynstr_append_mem(&insert_pat, " (", 2);
- }
- else
- {
- dynstr_append_mem(&insert_pat, " VALUES ", 8);
- if (!extended_insert)
- dynstr_append_mem(&insert_pat, "(", 1);
+ dynstr_append_mem(&insert_pat, "INSERT ", 7);
+ dynstr_append(&insert_pat, insert_option);
+ dynstr_append_mem(&insert_pat, "INTO ", 5);
+ dynstr_append(&insert_pat, opt_quoted_table);
+ if (complete_insert)
+ {
+ dynstr_append_mem(&insert_pat, " (", 2);
+ }
+ else
+ {
+ dynstr_append_mem(&insert_pat, " VALUES ", 8);
+ if (!extended_insert)
+ dynstr_append_mem(&insert_pat, "(", 1);
+ }
}
- while ((row=mysql_fetch_row(tableRes)))
+ while ((row= mysql_fetch_row(result)))
{
- if (init)
+ if (complete_insert)
{
- if (opt_complete_insert)
+ if (init)
+ {
dynstr_append_mem(&insert_pat, ", ", 2);
- }
- init=1;
- if (opt_complete_insert)
+ }
+ init=1;
dynstr_append(&insert_pat,
quote_name(row[SHOW_FIELDNAME], name_buff, 0));
+ }
}
- numFields = (uint) mysql_num_rows(tableRes);
- mysql_free_result(tableRes);
+ num_fields= mysql_num_rows(result);
+ mysql_free_result(result);
}
else
{
- if (verbose)
- fprintf(stderr,
- "%s: Warning: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n",
- my_progname, mysql_error(sock));
+ verbose_msg("%s: Warning: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n",
+ my_progname, mysql_error(mysql));
my_snprintf(query_buff, sizeof(query_buff), "show fields from %s",
- result_table);
- if (mysql_query_with_error_report(sock, &tableRes, query_buff))
+ result_table);
+ if (mysql_query_with_error_report(mysql, &result, query_buff))
{
safe_exit(EX_MYSQLERR);
DBUG_RETURN(0);
}
/* Make an sql-file, if path was given iow. option -T was given */
- if (!tFlag)
+ if (!opt_no_create_info)
{
if (path)
{
- char filename[FN_REFLEN], tmp_path[FN_REFLEN];
- convert_dirname(tmp_path,path,NullS);
- sql_file= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
- O_WRONLY, MYF(MY_WME));
- if (!sql_file) /* If file couldn't be opened */
+ if (!(sql_file= open_sql_file_for_table(table)))
{
- safe_exit(EX_MYSQLERR);
- DBUG_RETURN(0);
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(0);
}
write_header(sql_file, db);
}
if (!opt_xml && opt_comments)
- fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
- result_table);
+ fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
+ result_table);
if (opt_drop)
- fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",result_table);
+ fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", result_table);
if (!opt_xml)
- fprintf(sql_file, "CREATE TABLE %s (\n", result_table);
+ fprintf(sql_file, "CREATE TABLE %s (\n", result_table);
else
- print_xml_tag1(sql_file, "\t", "table_structure name=", table, "\n");
+ print_xml_tag(sql_file, "\t", "\n", "table_structure", "name=", table,
+ NullS);
check_io(sql_file);
}
- dynstr_append_mem(&insert_pat, "INSERT ", 7);
- dynstr_append(&insert_pat, insert_option);
- dynstr_append_mem(&insert_pat, "INTO ", 5);
- dynstr_append(&insert_pat, result_table);
- if (opt_complete_insert)
- {
- dynstr_append_mem(&insert_pat, " (", 2);
- }
- else
+ if (write_data)
{
- dynstr_append_mem(&insert_pat, " VALUES ", 8);
- if (!extended_insert)
- dynstr_append_mem(&insert_pat, "(", 1);
+ dynstr_append_mem(&insert_pat, "INSERT ", 7);
+ dynstr_append(&insert_pat, insert_option);
+ dynstr_append_mem(&insert_pat, "INTO ", 5);
+ dynstr_append(&insert_pat, result_table);
+ if (opt_complete_insert)
+ dynstr_append_mem(&insert_pat, " (", 2);
+ else
+ {
+ dynstr_append_mem(&insert_pat, " VALUES ", 8);
+ if (!extended_insert)
+ dynstr_append_mem(&insert_pat, "(", 1);
+ }
}
- while ((row=mysql_fetch_row(tableRes)))
+ while ((row= mysql_fetch_row(result)))
{
- ulong *lengths=mysql_fetch_lengths(tableRes);
+ ulong *lengths= mysql_fetch_lengths(result);
if (init)
{
- if (!opt_xml && !tFlag)
- {
- fputs(",\n",sql_file);
- check_io(sql_file);
- }
- if (opt_complete_insert)
+ if (!opt_xml && !opt_no_create_info)
+ {
+ fputs(",\n",sql_file);
+ check_io(sql_file);
+ }
+ if (complete_insert)
dynstr_append_mem(&insert_pat, ", ", 2);
}
init=1;
if (opt_complete_insert)
dynstr_append(&insert_pat,
quote_name(row[SHOW_FIELDNAME], name_buff, 0));
- if (!tFlag)
+ if (!opt_no_create_info)
{
- if (opt_xml)
- {
- print_xml_row(sql_file, "field", tableRes, &row);
- continue;
- }
+ if (opt_xml)
+ {
+ print_xml_row(sql_file, "field", result, &row);
+ continue;
+ }
if (opt_keywords)
- fprintf(sql_file, " %s.%s %s", result_table,
- quote_name(row[SHOW_FIELDNAME],name_buff, 0),
- row[SHOW_TYPE]);
+ fprintf(sql_file, " %s.%s %s", result_table,
+ quote_name(row[SHOW_FIELDNAME],name_buff, 0),
+ row[SHOW_TYPE]);
else
- fprintf(sql_file, " %s %s", quote_name(row[SHOW_FIELDNAME],
- name_buff, 0),
- row[SHOW_TYPE]);
+ fprintf(sql_file, " %s %s", quote_name(row[SHOW_FIELDNAME],
+ name_buff, 0),
+ row[SHOW_TYPE]);
if (row[SHOW_DEFAULT])
{
- fputs(" DEFAULT ", sql_file);
- unescape(sql_file, row[SHOW_DEFAULT], lengths[SHOW_DEFAULT]);
+ fputs(" DEFAULT ", sql_file);
+ unescape(sql_file, row[SHOW_DEFAULT], lengths[SHOW_DEFAULT]);
}
if (!row[SHOW_NULL][0])
- fputs(" NOT NULL", sql_file);
+ fputs(" NOT NULL", sql_file);
if (row[SHOW_EXTRA][0])
- fprintf(sql_file, " %s",row[SHOW_EXTRA]);
- check_io(sql_file);
+ fprintf(sql_file, " %s",row[SHOW_EXTRA]);
+ check_io(sql_file);
}
}
- numFields = (uint) mysql_num_rows(tableRes);
- mysql_free_result(tableRes);
- if (!tFlag)
+ num_fields= mysql_num_rows(result);
+ mysql_free_result(result);
+ if (!opt_no_create_info)
{
/* Make an sql-file, if path was given iow. option -T was given */
char buff[20+FN_REFLEN];
uint keynr,primary_key;
my_snprintf(buff, sizeof(buff), "show keys from %s", result_table);
- if (mysql_query_with_error_report(sock, &tableRes, buff))
+ if (mysql_query_with_error_report(mysql, &result, buff))
{
+ if (mysql_errno(mysql) == ER_WRONG_OBJECT)
+ {
+ /* it is VIEW */
+ fputs("\t\t<options Comment=\"view\" />\n", sql_file);
+ goto continue_xml;
+ }
+ fprintf(stderr, "%s: Can't get keys for table %s (%s)\n",
+ my_progname, result_table, mysql_error(mysql));
if (path)
- my_fclose(sql_file, MYF(MY_WME));
+ my_fclose(sql_file, MYF(MY_WME));
safe_exit(EX_MYSQLERR);
DBUG_RETURN(0);
}
@@ -1406,108 +1887,104 @@ static uint getTableStructure(char *table, char* db)
/* Find first which key is primary key */
keynr=0;
primary_key=INT_MAX;
- while ((row=mysql_fetch_row(tableRes)))
+ while ((row= mysql_fetch_row(result)))
{
if (atoi(row[3]) == 1)
{
- keynr++;
+ keynr++;
#ifdef FORCE_PRIMARY_KEY
- if (atoi(row[1]) == 0 && primary_key == INT_MAX)
- primary_key=keynr;
+ if (atoi(row[1]) == 0 && primary_key == INT_MAX)
+ primary_key=keynr;
#endif
- if (!strcmp(row[2],"PRIMARY"))
- {
- primary_key=keynr;
- break;
- }
+ if (!strcmp(row[2],"PRIMARY"))
+ {
+ primary_key=keynr;
+ break;
+ }
}
}
- mysql_data_seek(tableRes,0);
+ mysql_data_seek(result,0);
keynr=0;
- while ((row=mysql_fetch_row(tableRes)))
+ while ((row= mysql_fetch_row(result)))
{
- if (opt_xml)
- {
- print_xml_row(sql_file, "key", tableRes, &row);
- continue;
- }
-
+ if (opt_xml)
+ {
+ print_xml_row(sql_file, "key", result, &row);
+ continue;
+ }
+
if (atoi(row[3]) == 1)
{
- if (keynr++)
- putc(')', sql_file);
- if (atoi(row[1])) /* Test if duplicate key */
- /* Duplicate allowed */
- fprintf(sql_file, ",\n KEY %s (",quote_name(row[2],name_buff,0));
- else if (keynr == primary_key)
- fputs(",\n PRIMARY KEY (",sql_file); /* First UNIQUE is primary */
- else
- fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff,
- 0));
+ if (keynr++)
+ putc(')', sql_file);
+ if (atoi(row[1])) /* Test if duplicate key */
+ /* Duplicate allowed */
+ fprintf(sql_file, ",\n KEY %s (",quote_name(row[2],name_buff,0));
+ else if (keynr == primary_key)
+ fputs(",\n PRIMARY KEY (",sql_file); /* First UNIQUE is primary */
+ else
+ fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff,
+ 0));
}
else
- putc(',', sql_file);
+ putc(',', sql_file);
fputs(quote_name(row[4], name_buff, 0), sql_file);
if (row[7])
- fprintf(sql_file, " (%s)",row[7]); /* Sub key */
- check_io(sql_file);
+ fprintf(sql_file, " (%s)",row[7]); /* Sub key */
+ check_io(sql_file);
}
if (!opt_xml)
{
- if (keynr)
- putc(')', sql_file);
- fputs("\n)",sql_file);
- check_io(sql_file);
+ if (keynr)
+ putc(')', sql_file);
+ fputs("\n)",sql_file);
+ check_io(sql_file);
}
/* Get MySQL specific create options */
if (create_options)
{
- char show_name_buff[FN_REFLEN];
+ char show_name_buff[NAME_LEN*2+2+24];
- /* Check memory for quote_for_like() */
- DBUG_ASSERT(2*sizeof(table) < sizeof(show_name_buff));
+ /* Check memory for quote_for_like() */
my_snprintf(buff, sizeof(buff), "show table status like %s",
- quote_for_like(table, show_name_buff));
+ quote_for_like(table, show_name_buff));
- if (mysql_query_with_error_report(sock, &tableRes, buff))
+ if (mysql_query_with_error_report(mysql, &result, buff))
{
- if (mysql_errno(sock) != ER_PARSE_ERROR)
- { /* If old MySQL version */
- if (verbose)
- fprintf(stderr,
- "-- Warning: Couldn't get status information for table %s (%s)\n",
- result_table,mysql_error(sock));
- }
+ if (mysql_errno(mysql) != ER_PARSE_ERROR)
+ { /* If old MySQL version */
+ verbose_msg("-- Warning: Couldn't get status information for " \
+ "table %s (%s)\n", result_table,mysql_error(mysql));
+ }
}
- else if (!(row=mysql_fetch_row(tableRes)))
+ else if (!(row= mysql_fetch_row(result)))
{
- fprintf(stderr,
- "Error: Couldn't read status information for table %s (%s)\n",
- result_table,mysql_error(sock));
+ fprintf(stderr,
+ "Error: Couldn't read status information for table %s (%s)\n",
+ result_table,mysql_error(mysql));
}
else
{
- if (opt_xml)
- {
- print_xml_row(sql_file, "options", tableRes, &row);
- }
- else
- {
- fputs("/*!",sql_file);
- print_value(sql_file,tableRes,row,"engine=","Engine",0);
- print_value(sql_file,tableRes,row,"","Create_options",0);
- print_value(sql_file,tableRes,row,"comment=","Comment",1);
- fputs(" */",sql_file);
- check_io(sql_file);
- }
+ if (opt_xml)
+ print_xml_row(sql_file, "options", result, &row);
+ else
+ {
+ fputs("/*!",sql_file);
+ print_value(sql_file,result,row,"engine=","Engine",0);
+ print_value(sql_file,result,row,"","Create_options",0);
+ print_value(sql_file,result,row,"comment=","Comment",1);
+ fputs(" */",sql_file);
+ check_io(sql_file);
+ }
}
- mysql_free_result(tableRes); /* Is always safe to free */
+ mysql_free_result(result); /* Is always safe to free */
}
+continue_xml:
if (!opt_xml)
- fputs(";\n", sql_file);
+ fputs(";\n", sql_file);
else
- fputs("\t</table_structure>\n", sql_file);
+ fputs("\t</table_structure>\n", sql_file);
check_io(sql_file);
}
}
@@ -1523,12 +2000,106 @@ static uint getTableStructure(char *table, char* db)
write_footer(sql_file);
my_fclose(sql_file, MYF(MY_WME));
}
- DBUG_RETURN(numFields);
-} /* getTableStructure */
+ DBUG_RETURN((uint) num_fields);
+} /* get_table_structure */
+
+
+/*
+
+ dump_triggers_for_table
+ 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
+
+*/
+
+static void dump_triggers_for_table(char *table, char *db)
+{
+ 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;
+ MYSQL_ROW row;
+
+ DBUG_ENTER("dump_triggers_for_table");
+ DBUG_PRINT("enter", ("db: %s, table: %s", db, table));
+
+ /* Do not use ANSI_QUOTES on triggers in dump */
+ opt_compatible_mode&= ~MASK_ANSI_QUOTES;
+ result_table= quote_name(table, table_buff, 1);
+
+ my_snprintf(query_buff, sizeof(query_buff),
+ "SHOW TRIGGERS LIKE %s",
+ quote_for_like(table, name_buff));
+
+ if (mysql_query_with_error_report(mysql, &result, query_buff))
+ {
+ if (path)
+ my_fclose(sql_file, MYF(MY_WME));
+ safe_exit(EX_MYSQLERR);
+ DBUG_VOID_RETURN;
+ }
+ if (mysql_num_rows(result))
+ fprintf(sql_file, "\n/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;\n\
+DELIMITER ;;\n");
+ while ((row= mysql_fetch_row(result)))
+ {
+ fprintf(sql_file,
+ "/*!50003 SET SESSION SQL_MODE=\"%s\" */;;\n"
+ "/*!50003 CREATE */ ",
+ row[6] /* sql_mode */);
+
+ if (mysql_num_fields(result) > 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.
+ */
+
+ 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];
+
+ parse_user(row[7], strlen(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\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=@OLD_SQL_MODE */;\n");
+ mysql_free_result(result);
+ /*
+ make sure to set back opt_compatible mode to
+ original value
+ */
+ opt_compatible_mode=old_opt_compatible_mode;
+ DBUG_VOID_RETURN;
+}
static char *add_load_option(char *ptr,const char *object,
- const char *statement)
+ const char *statement)
{
if (object)
{
@@ -1548,10 +2119,10 @@ static char *add_load_option(char *ptr,const char *object,
/*
-** Allow the user to specify field terminator strings like:
-** "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline)
-** This is done by doubleing ' and add a end -\ if needed to avoid
-** syntax errors from the SQL parser.
+ Allow the user to specify field terminator strings like:
+ "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline)
+ This is done by doubling ' and add a end -\ if needed to avoid
+ syntax errors from the SQL parser.
*/
static char *field_escape(char *to,const char *from,uint length)
@@ -1567,7 +2138,7 @@ static char *field_escape(char *to,const char *from,uint length)
else
{
if (*from == '\'' && !end_backslashes)
- *to++= *from; /* We want a duplicate of "'" for MySQL */
+ *to++= *from; /* We want a duplicate of "'" for MySQL */
end_backslashes=0;
}
}
@@ -1584,42 +2155,88 @@ static char *alloc_query_str(ulong size)
if (!(query= (char*) my_malloc(size, MYF(MY_WME))))
{
- ignore_errors= 0; /* Fatal error */
- safe_exit(EX_MYSQLERR); /* Force exit */
+ ignore_errors= 0; /* Fatal error */
+ safe_exit(EX_MYSQLERR); /* Force exit */
}
return query;
}
+
/*
-** dumpTable saves database contents as a series of INSERT statements.
+
+ SYNOPSIS
+ dump_table()
+
+ dump_table saves database contents as a series of INSERT statements.
+
+ ARGS
+ table - table name
+ db - db name
+
+ RETURNS
+ void
*/
-static void dumpTable(uint numFields, char *table)
+
+static void dump_table(char *table, char *db)
{
+ char ignore_flag;
char query_buf[QUERY_LENGTH], *end, buff[256],table_buff[NAME_LEN+3];
+ char table_type[NAME_LEN];
char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table;
char *query= query_buf;
- MYSQL_RES *res;
- MYSQL_FIELD *field;
- MYSQL_ROW row;
- ulong rownr, row_break, total_length, init_length;
- const char *table_type;
int error= 0;
+ ulong rownr, row_break, total_length, init_length;
+ uint num_fields;
+ MYSQL_RES *res;
+ MYSQL_FIELD *field;
+ MYSQL_ROW row;
+ DBUG_ENTER("dump_table");
- result_table= quote_name(table,table_buff, 1);
- opt_quoted_table= quote_name(table, table_buff2, 0);
+ /*
+ Make sure you get the create table info before the following check for
+ --no-data flag below. Otherwise, the create table info won't be printed.
+ */
+ num_fields= get_table_structure(table, db, table_type, &ignore_flag);
- /* Check table type */
- if ((table_type= check_if_ignore_table(table)))
+ /*
+ The "table" could be a view. If so, we don't do anything here.
+ */
+ if (strcmp (table_type, "VIEW") == 0)
+ DBUG_VOID_RETURN;
+
+ /* Check --no-data flag */
+ if (opt_no_data)
{
- if (verbose)
- fprintf(stderr,
- "-- Skipping data for table '%s' because it's of type %s\n",
- table, table_type);
- return;
+ verbose_msg("-- Skipping dump data for table '%s', --no-data was used\n",
+ table);
+ DBUG_VOID_RETURN;
+ }
+
+ DBUG_PRINT("info",
+ ("ignore_flag: %x num_fields: %d", (int) ignore_flag,
+ num_fields));
+ /*
+ If the table type is a merge table or any type that has to be
+ _completely_ ignored and no data dumped
+ */
+ if (ignore_flag & IGNORE_DATA)
+ {
+ verbose_msg("-- Warning: Skipping data for table '%s' because " \
+ "it's of type %s\n", table, table_type);
+ DBUG_VOID_RETURN;
}
+ /* Check that there are any fields in the table */
+ if (num_fields == 0)
+ {
+ verbose_msg("-- Skipping dump data for table '%s', it has no fields\n",
+ table);
+ DBUG_VOID_RETURN;
+ }
+
+ result_table= quote_name(table,table_buff, 1);
+ opt_quoted_table= quote_name(table, table_buff2, 0);
- if (verbose)
- fprintf(stderr, "-- Sending SELECT query...\n");
+ verbose_msg("-- Sending SELECT query...\n");
if (path)
{
char filename[FN_REFLEN], tmp_path[FN_REFLEN];
@@ -1627,11 +2244,11 @@ static void dumpTable(uint numFields, char *table)
my_load_path(tmp_path, tmp_path, NULL);
fn_format(filename, table, tmp_path, ".txt", 4);
my_delete(filename, MYF(0)); /* 'INTO OUTFILE' doesn't work, if
- filename wasn't deleted */
+ filename wasn't deleted */
to_unix_path(filename);
- my_snprintf(query, QUERY_LENGTH,
- "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '%s'",
- filename);
+ my_snprintf(query, QUERY_LENGTH,
+ "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '%s'",
+ filename);
end= strend(query);
if (fields_terminated || enclosed || opt_enclosed || escaped)
@@ -1647,20 +2264,20 @@ static void dumpTable(uint numFields, char *table)
end= strmov(end,buff);
if (where || order_by)
{
- query = alloc_query_str((ulong) ((end - query) + 1 +
+ query= alloc_query_str((ulong) ((end - query) + 1 +
(where ? strlen(where) + 7 : 0) +
(order_by ? strlen(order_by) + 10 : 0)));
- end = strmov(query, query_buf);
+ end= strmov(query, query_buf);
if (where)
- end = strxmov(end, " WHERE ", where, NullS);
+ end= strxmov(end, " WHERE ", where, NullS);
if (order_by)
- end = strxmov(end, " ORDER BY ", order_by, NullS);
+ end= strxmov(end, " ORDER BY ", order_by, NullS);
}
- if (mysql_real_query(sock, query, (uint) (end - query)))
+ if (mysql_real_query(mysql, query, (uint) (end - query)))
{
- DBerror(sock, "when executing 'SELECT INTO OUTFILE'");
- return;
+ DB_error(mysql, "when executing 'SELECT INTO OUTFILE'");
+ DBUG_VOID_RETURN;
}
}
else
@@ -1668,18 +2285,18 @@ static void dumpTable(uint numFields, char *table)
if (!opt_xml && opt_comments)
{
fprintf(md_result_file,"\n--\n-- Dumping data for table %s\n--\n",
- result_table);
+ result_table);
check_io(md_result_file);
}
my_snprintf(query, QUERY_LENGTH,
- "SELECT /*!40001 SQL_NO_CACHE */ * FROM %s",
- result_table);
+ "SELECT /*!40001 SQL_NO_CACHE */ * FROM %s",
+ result_table);
if (where || order_by)
{
- query = alloc_query_str((ulong) (strlen(query) + 1 +
+ query= alloc_query_str((ulong) (strlen(query) + 1 +
(where ? strlen(where) + 7 : 0) +
(order_by ? strlen(order_by) + 10 : 0)));
- end = strmov(query, query_buf);
+ end= strmov(query, query_buf);
if (where)
{
@@ -1688,7 +2305,7 @@ static void dumpTable(uint numFields, char *table)
fprintf(md_result_file, "-- WHERE: %s\n", where);
check_io(md_result_file);
}
- end = strxmov(end, " WHERE ", where, NullS);
+ end= strxmov(end, " WHERE ", where, NullS);
}
if (order_by)
{
@@ -1697,7 +2314,7 @@ static void dumpTable(uint numFields, char *table)
fprintf(md_result_file, "-- ORDER BY: %s\n", order_by);
check_io(md_result_file);
}
- end = strxmov(end, " ORDER BY ", order_by, NullS);
+ end= strxmov(end, " ORDER BY ", order_by, NullS);
}
}
if (!opt_xml && !opt_compact)
@@ -1705,26 +2322,26 @@ static void dumpTable(uint numFields, char *table)
fputs("\n", md_result_file);
check_io(md_result_file);
}
- if (mysql_query_with_error_report(sock, 0, query))
+ if (mysql_query_with_error_report(mysql, 0, query))
{
- DBerror(sock, "when retrieving data from server");
+ DB_error(mysql, "when retrieving data from server");
goto err;
}
if (quick)
- res=mysql_use_result(sock);
+ res=mysql_use_result(mysql);
else
- res=mysql_store_result(sock);
+ res=mysql_store_result(mysql);
if (!res)
{
- DBerror(sock, "when retrieving data from server");
+ DB_error(mysql, "when retrieving data from server");
goto err;
}
- if (verbose)
- fprintf(stderr, "-- Retrieving rows...\n");
- if (mysql_num_fields(res) != numFields)
+
+ verbose_msg("-- Retrieving rows...\n");
+ if (mysql_num_fields(res) != num_fields)
{
fprintf(stderr,"%s: Error in field count for table: %s ! Aborting.\n",
- my_progname, result_table);
+ my_progname, result_table);
error= EX_CONSCHECK;
goto err;
}
@@ -1742,93 +2359,96 @@ static void dumpTable(uint numFields, char *table)
check_io(md_result_file);
}
- total_length= opt_net_buffer_length; /* Force row break */
+ total_length= opt_net_buffer_length; /* Force row break */
row_break=0;
rownr=0;
init_length=(uint) insert_pat.length+4;
if (opt_xml)
- print_xml_tag1(md_result_file, "\t", "table_data name=", table, "\n");
-
+ print_xml_tag(md_result_file, "\t", "\n", "table_data", "name=", table,
+ NullS);
if (opt_autocommit)
{
fprintf(md_result_file, "set autocommit=0;\n");
check_io(md_result_file);
}
- while ((row=mysql_fetch_row(res)))
+ while ((row= mysql_fetch_row(res)))
{
uint i;
- ulong *lengths=mysql_fetch_lengths(res);
+ ulong *lengths= mysql_fetch_lengths(res);
rownr++;
if (!extended_insert && !opt_xml)
{
- fputs(insert_pat.str,md_result_file);
- check_io(md_result_file);
+ fputs(insert_pat.str,md_result_file);
+ check_io(md_result_file);
}
mysql_field_seek(res,0);
if (opt_xml)
{
fputs("\t<row>\n", md_result_file);
- check_io(md_result_file);
+ check_io(md_result_file);
}
- for (i = 0; i < mysql_num_fields(res); i++)
+ for (i= 0; i < mysql_num_fields(res); i++)
{
int is_blob;
- if (!(field = mysql_fetch_field(res)))
- {
- my_snprintf(query, QUERY_LENGTH,
- "%s: Not enough fields from table %s! Aborting.\n",
- my_progname, result_table);
- fputs(query,stderr);
- error= EX_CONSCHECK;
- goto err;
- }
-
- /*
- 63 is my_charset_bin. If charsetnr is not 63,
- we have not a BLOB but a TEXT column.
- we'll dump in hex only BLOB columns.
- */
+ ulong length= lengths[i];
+
+ if (!(field= mysql_fetch_field(res)))
+ {
+ my_snprintf(query, QUERY_LENGTH,
+ "%s: Not enough fields from table %s! Aborting.\n",
+ my_progname, result_table);
+ fputs(query,stderr);
+ error= EX_CONSCHECK;
+ goto err;
+ }
+
+ /*
+ 63 is my_charset_bin. If charsetnr is not 63,
+ we have not a BLOB but a TEXT column.
+ we'll dump in hex only BLOB columns.
+ */
is_blob= (opt_hex_blob && field->charsetnr == 63 &&
- (field->type == FIELD_TYPE_STRING ||
- field->type == FIELD_TYPE_VAR_STRING ||
- field->type == FIELD_TYPE_BLOB ||
- field->type == FIELD_TYPE_LONG_BLOB ||
- field->type == FIELD_TYPE_MEDIUM_BLOB ||
- field->type == FIELD_TYPE_TINY_BLOB)) ? 1 : 0;
- if (extended_insert)
- {
- ulong length = lengths[i];
- if (i == 0)
- dynstr_set(&extended_row,"(");
- else
- dynstr_append(&extended_row,",");
-
- if (row[i])
- {
- if (length)
- {
- if (!IS_NUM_FIELD(field))
- {
- /*
- "length * 2 + 2" is OK for both HEX and non-HEX modes:
- - In HEX mode we need exactly 2 bytes per character
- plus 2 bytes for '0x' prefix.
- - In non-HEX mode we need up to 2 bytes per character,
- plus 2 bytes for leading and trailing '\'' characters.
- */
- if (dynstr_realloc(&extended_row,length * 2+2))
- {
- fputs("Aborting dump (out of memory)",stderr);
- error= EX_EOM;
- goto err;
- }
+ (field->type == MYSQL_TYPE_BIT ||
+ field->type == MYSQL_TYPE_STRING ||
+ field->type == MYSQL_TYPE_VAR_STRING ||
+ field->type == MYSQL_TYPE_VARCHAR ||
+ field->type == MYSQL_TYPE_BLOB ||
+ field->type == MYSQL_TYPE_LONG_BLOB ||
+ field->type == MYSQL_TYPE_MEDIUM_BLOB ||
+ field->type == MYSQL_TYPE_TINY_BLOB)) ? 1 : 0;
+ if (extended_insert && !opt_xml)
+ {
+ if (i == 0)
+ dynstr_set(&extended_row,"(");
+ else
+ dynstr_append(&extended_row,",");
+
+ if (row[i])
+ {
+ if (length)
+ {
+ if (!IS_NUM_FIELD(field))
+ {
+ /*
+ "length * 2 + 2" is OK for both HEX and non-HEX modes:
+ - In HEX mode we need exactly 2 bytes per character
+ plus 2 bytes for '0x' prefix.
+ - In non-HEX mode we need up to 2 bytes per character,
+ plus 2 bytes for leading and trailing '\'' characters.
+ */
+ if (dynstr_realloc(&extended_row,length * 2+2))
+ {
+ fputs("Aborting dump (out of memory)",stderr);
+ error= EX_EOM;
+ goto err;
+ }
if (opt_hex_blob && is_blob)
{
dynstr_append(&extended_row, "0x");
- extended_row.length+= mysql_hex_string(extended_row.str +
+ extended_row.length+= mysql_hex_string(extended_row.str +
extended_row.length,
row[i], length);
extended_row.str[extended_row.length]= '\0';
@@ -1843,94 +2463,101 @@ static void dumpTable(uint numFields, char *table)
extended_row.str[extended_row.length]='\0';
dynstr_append(&extended_row,"'");
}
- }
- else
- {
- /* change any strings ("inf", "-inf", "nan") into NULL */
- char *ptr = row[i];
- if (my_isalpha(charset_info, *ptr) || (*ptr == '-' &&
- my_isalpha(charset_info, ptr[1])))
- dynstr_append(&extended_row, "NULL");
- else
- {
- if (field->type == FIELD_TYPE_DECIMAL)
- {
- /* add " signs around */
- dynstr_append(&extended_row, "'");
- dynstr_append(&extended_row, ptr);
- dynstr_append(&extended_row, "'");
- }
- else
- dynstr_append(&extended_row, ptr);
- }
- }
- }
- else
- dynstr_append(&extended_row,"''");
- }
- else if (dynstr_append(&extended_row,"NULL"))
- {
- fputs("Aborting dump (out of memory)",stderr);
- error= EX_EOM;
- goto err;
- }
- }
- else
- {
- if (i && !opt_xml)
- {
- fputc(',', md_result_file);
- check_io(md_result_file);
- }
- if (row[i])
- {
- if (!IS_NUM_FIELD(field))
- {
- if (opt_xml)
- {
- print_xml_tag1(md_result_file, "\t\t", "field name=",
- field->name, "");
- print_quoted_xml(md_result_file, row[i], lengths[i]);
- fputs("</field>\n", md_result_file);
- }
- else if (opt_hex_blob && is_blob)
+ }
+ else
+ {
+ /* change any strings ("inf", "-inf", "nan") into NULL */
+ char *ptr= row[i];
+ if (my_isalpha(charset_info, *ptr) || (*ptr == '-' &&
+ my_isalpha(charset_info, ptr[1])))
+ dynstr_append(&extended_row, "NULL");
+ else
+ {
+ if (field->type == FIELD_TYPE_DECIMAL)
+ {
+ /* add " signs around */
+ dynstr_append(&extended_row, "'");
+ dynstr_append(&extended_row, ptr);
+ dynstr_append(&extended_row, "'");
+ }
+ else
+ dynstr_append(&extended_row, ptr);
+ }
+ }
+ }
+ else
+ dynstr_append(&extended_row,"''");
+ }
+ else if (dynstr_append(&extended_row,"NULL"))
+ {
+ fputs("Aborting dump (out of memory)",stderr);
+ error= EX_EOM;
+ goto err;
+ }
+ }
+ else
+ {
+ if (i && !opt_xml)
+ {
+ fputc(',', md_result_file);
+ check_io(md_result_file);
+ }
+ if (row[i])
+ {
+ if (!IS_NUM_FIELD(field))
+ {
+ if (opt_xml)
+ {
+ if (opt_hex_blob && is_blob && length)
+ {
+ /* Define xsi:type="xs:hexBinary" for hex encoded data */
+ print_xml_tag(md_result_file, "\t\t", "", "field", "name=",
+ field->name, "xsi:type=", "xs:hexBinary", NullS);
+ print_blob_as_hex(md_result_file, row[i], length);
+ }
+ else
+ {
+ print_xml_tag(md_result_file, "\t\t", "", "field", "name=",
+ field->name, NullS);
+ print_quoted_xml(md_result_file, row[i], length);
+ }
+ fputs("</field>\n", md_result_file);
+ }
+ else if (opt_hex_blob && is_blob && length)
{
- /* sakaik got the idea to to provide blob's in hex notation. */
- char *ptr= row[i], *end= ptr+ lengths[i];
fputs("0x", md_result_file);
- for (; ptr < end ; ptr++)
- fprintf(md_result_file, "%02X", *((uchar *)ptr));
+ print_blob_as_hex(md_result_file, row[i], length);
+ }
+ else
+ unescape(md_result_file, row[i], length);
+ }
+ else
+ {
+ /* change any strings ("inf", "-inf", "nan") into NULL */
+ char *ptr= row[i];
+ if (opt_xml)
+ {
+ print_xml_tag(md_result_file, "\t\t", "", "field", "name=",
+ field->name, NullS);
+ fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL",
+ md_result_file);
+ fputs("</field>\n", md_result_file);
+ }
+ 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)
+ {
+ /* add " signs around */
+ fputc('\'', md_result_file);
+ fputs(ptr, md_result_file);
+ fputc('\'', md_result_file);
}
else
- unescape(md_result_file, row[i], lengths[i]);
- }
- else
- {
- /* change any strings ("inf", "-inf", "nan") into NULL */
- char *ptr = row[i];
- if (opt_xml)
- {
- print_xml_tag1(md_result_file, "\t\t", "field name=",
- field->name, "");
- fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL",
- md_result_file);
- fputs("</field>\n", md_result_file);
- }
- 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)
- {
- /* add " signs around */
- fputc('\'', md_result_file);
- fputs(ptr, md_result_file);
- fputc('\'', md_result_file);
- }
- else
- fputs(ptr, md_result_file);
- }
- }
- else
+ fputs(ptr, md_result_file);
+ }
+ }
+ else
{
/* The field value is NULL */
if (!opt_xml)
@@ -1940,61 +2567,61 @@ static void dumpTable(uint numFields, char *table)
field->name, "\n");
}
check_io(md_result_file);
- }
+ }
}
if (opt_xml)
{
fputs("\t</row>\n", md_result_file);
- check_io(md_result_file);
+ check_io(md_result_file);
}
if (extended_insert)
{
- ulong row_length;
- dynstr_append(&extended_row,")");
- row_length = 2 + extended_row.length;
+ ulong row_length;
+ dynstr_append(&extended_row,")");
+ row_length= 2 + extended_row.length;
if (total_length + row_length < opt_net_buffer_length)
{
- total_length += row_length;
- fputc(',',md_result_file); /* Always row break */
- fputs(extended_row.str,md_result_file);
- }
+ total_length+= row_length;
+ fputc(',',md_result_file); /* Always row break */
+ fputs(extended_row.str,md_result_file);
+ }
else
{
- if (row_break)
- fputs(";\n", md_result_file);
- row_break=1; /* This is first row */
+ if (row_break)
+ fputs(";\n", md_result_file);
+ row_break=1; /* This is first row */
fputs(insert_pat.str,md_result_file);
fputs(extended_row.str,md_result_file);
- total_length = row_length+init_length;
+ total_length= row_length+init_length;
}
- check_io(md_result_file);
+ check_io(md_result_file);
}
else if (!opt_xml)
{
- fputs(");\n", md_result_file);
- check_io(md_result_file);
+ fputs(");\n", md_result_file);
+ check_io(md_result_file);
}
}
/* XML - close table tag and supress regular output */
if (opt_xml)
- fputs("\t</table_data>\n", md_result_file);
+ fputs("\t</table_data>\n", md_result_file);
else if (extended_insert && row_break)
- fputs(";\n", md_result_file); /* If not empty table */
+ fputs(";\n", md_result_file); /* If not empty table */
fflush(md_result_file);
check_io(md_result_file);
- if (mysql_errno(sock))
+ if (mysql_errno(mysql))
{
my_snprintf(query, QUERY_LENGTH,
- "%s: Error %d: %s when dumping table %s at row: %ld\n",
- my_progname,
- mysql_errno(sock),
- mysql_error(sock),
- result_table,
- rownr);
+ "%s: Error %d: %s when dumping table %s at row: %ld\n",
+ my_progname,
+ mysql_errno(mysql),
+ mysql_error(mysql),
+ result_table,
+ rownr);
fputs(query,stderr);
error= EX_CONSCHECK;
goto err;
@@ -2004,7 +2631,7 @@ static void dumpTable(uint numFields, char *table)
if (opt_disable_keys)
{
fprintf(md_result_file,"/*!40000 ALTER TABLE %s ENABLE KEYS */;\n",
- opt_quoted_table);
+ opt_quoted_table);
check_io(md_result_file);
}
if (opt_lock)
@@ -2020,28 +2647,28 @@ static void dumpTable(uint numFields, char *table)
mysql_free_result(res);
if (query != query_buf)
my_free(query, MYF(MY_ALLOW_ZERO_PTR));
- }
- return;
+ }
+ DBUG_VOID_RETURN;
err:
if (query != query_buf)
my_free(query, MYF(MY_ALLOW_ZERO_PTR));
safe_exit(error);
- return;
-} /* dumpTable */
+ DBUG_VOID_RETURN;
+} /* dump_table */
static char *getTableName(int reset)
{
- static MYSQL_RES *res = NULL;
+ static MYSQL_RES *res= NULL;
MYSQL_ROW row;
if (!res)
{
- if (!(res = mysql_list_tables(sock,NullS)))
+ if (!(res= mysql_list_tables(mysql,NullS)))
return(NULL);
}
- if ((row = mysql_fetch_row(res)))
+ if ((row= mysql_fetch_row(res)))
return((char*) row[0]);
if (reset)
@@ -2049,7 +2676,7 @@ static char *getTableName(int reset)
else
{
mysql_free_result(res);
- res = NULL;
+ res= NULL;
}
return(NULL);
} /* getTableName */
@@ -2061,13 +2688,28 @@ static int dump_all_databases()
MYSQL_RES *tableres;
int result=0;
- if (mysql_query_with_error_report(sock, &tableres, "SHOW DATABASES"))
+ if (mysql_query_with_error_report(mysql, &tableres, "SHOW DATABASES"))
return 1;
- while ((row = mysql_fetch_row(tableres)))
+ while ((row= mysql_fetch_row(tableres)))
{
if (dump_all_tables_in_db(row[0]))
result=1;
}
+ if (seen_views)
+ {
+ if (mysql_query(mysql, "SHOW DATABASES") ||
+ !(tableres= mysql_store_result(mysql)))
+ {
+ my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s",
+ MYF(0), mysql_error(mysql));
+ return 1;
+ }
+ while ((row= mysql_fetch_row(tableres)))
+ {
+ if (dump_all_views_in_db(row[0]))
+ result=1;
+ }
+ }
return result;
}
/* dump_all_databases */
@@ -2076,70 +2718,124 @@ static int dump_all_databases()
static int dump_databases(char **db_names)
{
int result=0;
- for ( ; *db_names ; db_names++)
+ char **db;
+ DBUG_ENTER("dump_databases");
+
+ for (db= db_names ; *db ; db++)
{
- if (dump_all_tables_in_db(*db_names))
+ if (dump_all_tables_in_db(*db))
result=1;
}
- return result;
+ if (!result && seen_views)
+ {
+ for (db= db_names ; *db ; db++)
+ {
+ if (dump_all_views_in_db(*db))
+ result=1;
+ }
+ }
+ DBUG_RETURN(result);
} /* dump_databases */
-static int init_dumping(char *database)
+/*
+View Specific database initalization.
+
+SYNOPSIS
+ init_dumping_views
+ qdatabase quoted name of the database
+
+RETURN VALUES
+ 0 Success.
+ 1 Failure.
+*/
+int init_dumping_views(char *qdatabase __attribute__((unused)))
{
- if (mysql_select_db(sock, database))
+ return 0;
+} /* init_dumping_views */
+
+
+/*
+Table Specific database initalization.
+
+SYNOPSIS
+ init_dumping_tables
+ qdatabase quoted name of the database
+
+RETURN VALUES
+ 0 Success.
+ 1 Failure.
+*/
+int init_dumping_tables(char *qdatabase)
+{
+ if (!opt_create_db)
{
- DBerror(sock, "when selecting the database");
- return 1; /* If --force */
+ char qbuf[256];
+ MYSQL_ROW row;
+ MYSQL_RES *dbinfo;
+
+ my_snprintf(qbuf, sizeof(qbuf),
+ "SHOW CREATE DATABASE IF NOT EXISTS %s",
+ qdatabase);
+
+ if (mysql_query(mysql, qbuf) || !(dbinfo = mysql_store_result(mysql)))
+ {
+ /* Old server version, dump generic CREATE DATABASE */
+ if (opt_drop_database)
+ fprintf(md_result_file,
+ "\n/*!40000 DROP DATABASE IF EXISTS %s;*/\n",
+ qdatabase);
+ fprintf(md_result_file,
+ "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n",
+ qdatabase);
+ }
+ else
+ {
+ if (opt_drop_database)
+ fprintf(md_result_file,
+ "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n",
+ qdatabase);
+ row = mysql_fetch_row(dbinfo);
+ if (row[1])
+ {
+ fprintf(md_result_file,"\n%s;\n",row[1]);
+ }
+ }
+ }
+
+ return 0;
+} /* init_dumping_tables */
+
+
+static int init_dumping(char *database, int init_func(char*))
+{
+ if (mysql_get_server_version(mysql) >= 50003 &&
+ !my_strcasecmp(&my_charset_latin1, database, "information_schema"))
+ return 1;
+
+ if (mysql_select_db(mysql, database))
+ {
+ DB_error(mysql, "when selecting the database");
+ return 1; /* If --force */
}
if (!path && !opt_xml)
{
if (opt_databases || opt_alldbs)
{
/*
- length of table name * 2 (if name contains quotes), 2 quotes and 0
+ length of table name * 2 (if name contains quotes), 2 quotes and 0
*/
- char quoted_database_buf[64*2+3];
+ char quoted_database_buf[NAME_LEN*2+3];
char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted);
if (opt_comments)
{
- fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase);
- check_io(md_result_file);
+ fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase);
+ check_io(md_result_file);
}
- if (!opt_create_db)
- {
- char qbuf[256];
- MYSQL_ROW row;
- MYSQL_RES *dbinfo;
- my_snprintf(qbuf, sizeof(qbuf),
- "SHOW CREATE DATABASE IF NOT EXISTS %s",
- qdatabase);
+ /* Call the view or table specific function */
+ init_func(qdatabase);
- if (mysql_query(sock, qbuf) || !(dbinfo = mysql_store_result(sock)))
- {
- /* Old server version, dump generic CREATE DATABASE */
- if (opt_drop_database)
- fprintf(md_result_file,
- "\n/*!40000 DROP DATABASE IF EXISTS %s;*/\n",
- qdatabase);
- fprintf(md_result_file,
- "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n",
- qdatabase);
- }
- else
- {
- if (opt_drop_database)
- fprintf(md_result_file,
- "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n",
- qdatabase);
- row = mysql_fetch_row(dbinfo);
- if (row[1])
- {
- fprintf(md_result_file,"\n%s;\n",row[1]);
- }
- }
- }
fprintf(md_result_file,"\nUSE %s;\n", qdatabase);
check_io(md_result_file);
}
@@ -2150,12 +2846,11 @@ static int init_dumping(char *database)
} /* init_dumping */
+/* Return 1 if we should copy the table */
+
my_bool include_table(byte* hash_key, uint len)
{
- if (hash_search(&ignore_table, (byte*) hash_key, len))
- return FALSE;
-
- return TRUE;
+ return !hash_search(&ignore_table, (byte*) hash_key, len);
}
@@ -2164,17 +2859,18 @@ static int dump_all_tables_in_db(char *database)
char *table;
uint numrows;
char table_buff[NAME_LEN*2+3];
-
char hash_key[2*NAME_LEN+2]; /* "db.tablename" */
char *afterdot;
+ int using_mysql_db= my_strcasecmp(&my_charset_latin1, database, "mysql");
+ DBUG_ENTER("dump_all_tables_in_db");
afterdot= strmov(hash_key, database);
*afterdot++= '.';
- if (init_dumping(database))
- return 1;
+ if (init_dumping(database, init_dumping_tables))
+ DBUG_RETURN(1);
if (opt_xml)
- print_xml_tag1(md_result_file, "", "database name=", database, "\n");
+ print_xml_tag(md_result_file, "", "\n", "database", "name=", database, NullS);
if (lock_tables)
{
DYNAMIC_STRING query;
@@ -2184,15 +2880,15 @@ static int dump_all_tables_in_db(char *database)
dynstr_append(&query, quote_name(table, table_buff, 1));
dynstr_append(&query, " READ /*!32311 LOCAL */,");
}
- if (numrows && mysql_real_query(sock, query.str, query.length-1))
- DBerror(sock, "when using LOCK TABLES");
+ if (numrows && mysql_real_query(mysql, query.str, query.length-1))
+ DB_error(mysql, "when using LOCK TABLES");
/* We shall continue here, if --force was given */
dynstr_free(&query);
}
if (flush_logs)
{
- if (mysql_refresh(sock, REFRESH_LOG))
- DBerror(sock, "when doing refresh");
+ if (mysql_refresh(mysql, REFRESH_LOG))
+ DB_error(mysql, "when doing refresh");
/* We shall continue here, if --force was given */
}
while ((table= getTableName(0)))
@@ -2200,30 +2896,97 @@ static int dump_all_tables_in_db(char *database)
char *end= strmov(afterdot, table);
if (include_table(hash_key, end - hash_key))
{
- numrows = getTableStructure(table, database);
- if (!dFlag && numrows > 0)
- dumpTable(numrows,table);
+ 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 (opt_routines && !opt_xml &&
+ mysql_get_server_version(mysql) >= 50009)
+ {
+ DBUG_PRINT("info", ("Dumping routines for database %s", database));
+ dump_routines_for_db(database);
+ }
+ if (opt_xml)
+ {
+ fputs("</database>\n", md_result_file);
+ check_io(md_result_file);
+ }
+ if (lock_tables)
+ VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
+ if (flush_privileges && using_mysql_db == 0)
+ {
+ fprintf(md_result_file,"\n--\n-- Flush Grant Tables \n--\n");
+ fprintf(md_result_file,"\n/*! FLUSH PRIVILEGES */;\n");
+ }
+ DBUG_RETURN(0);
+} /* dump_all_tables_in_db */
+
+
+/*
+ dump structure of views of database
+
+ SYNOPSIS
+ dump_all_views_in_db()
+ database database name
+
+ RETURN
+ 0 OK
+ 1 ERROR
+*/
+
+static my_bool dump_all_views_in_db(char *database)
+{
+ char *table;
+ uint numrows;
+ char table_buff[NAME_LEN*2+3];
+
+ if (init_dumping(database, init_dumping_views))
+ return 1;
+ if (opt_xml)
+ print_xml_tag(md_result_file, "", "\n", "database", "name=", database, NullS);
+ if (lock_tables)
+ {
+ DYNAMIC_STRING query;
+ init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
+ for (numrows= 0 ; (table= getTableName(1)); numrows++)
+ {
+ dynstr_append(&query, quote_name(table, table_buff, 1));
+ dynstr_append(&query, " READ /*!32311 LOCAL */,");
}
+ if (numrows && mysql_real_query(mysql, query.str, query.length-1))
+ DB_error(mysql, "when using LOCK TABLES");
+ /* We shall continue here, if --force was given */
+ dynstr_free(&query);
+ }
+ if (flush_logs)
+ {
+ if (mysql_refresh(mysql, REFRESH_LOG))
+ DB_error(mysql, "when doing refresh");
+ /* We shall continue here, if --force was given */
}
+ while ((table= getTableName(0)))
+ get_view_structure(table, database);
if (opt_xml)
{
fputs("</database>\n", md_result_file);
check_io(md_result_file);
}
if (lock_tables)
- mysql_query_with_error_report(sock, 0, "UNLOCK TABLES");
+ VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
return 0;
} /* dump_all_tables_in_db */
/*
- get_actual_table_name -- executes a SHOW TABLES LIKE '%s' to get the actual
- table name from the server for the table name given on the command line.
- we do this because the table name given on the command line may be a
+ get_actual_table_name -- executes a SHOW TABLES LIKE '%s' to get the actual
+ table name from the server for the table name given on the command line.
+ we do this because the table name given on the command line may be a
different case (e.g. T1 vs t1)
-
+
RETURN
pointer to the table name
0 if error
@@ -2232,35 +2995,37 @@ static int dump_all_tables_in_db(char *database)
static char *get_actual_table_name(const char *old_table_name, MEM_ROOT *root)
{
char *name= 0;
- ulong *lengths;
- MYSQL_RES *tableRes;
+ MYSQL_RES *table_res;
MYSQL_ROW row;
char query[50 + 2*NAME_LEN];
char show_name_buff[FN_REFLEN];
DBUG_ENTER("get_actual_table_name");
- DBUG_PRINT("enter", ("old_table_name: %s", old_table_name));
/* Check memory for quote_for_like() */
DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff));
- my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s",
- quote_for_like(old_table_name, show_name_buff));
+ my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s",
+ quote_for_like(old_table_name, show_name_buff));
- if (mysql_query_with_error_report(sock, 0, query))
+ if (mysql_query_with_error_report(mysql, 0, query))
{
safe_exit(EX_MYSQLERR);
}
- tableRes= mysql_store_result( sock );
- if (tableRes != NULL)
+ if ((table_res= mysql_store_result(mysql)))
{
- my_ulonglong numRows= mysql_num_rows(tableRes);
- if (numRows > 0)
+ my_ulonglong num_rows= mysql_num_rows(table_res);
+ if (num_rows > 0)
{
- row= mysql_fetch_row( tableRes );
- lengths= mysql_fetch_lengths(tableRes);
+ ulong *lengths;
+ /*
+ Return first row
+ TODO: Return all matching rows
+ */
+ row= mysql_fetch_row(table_res);
+ lengths= mysql_fetch_lengths(table_res);
name= strmake_root(root, row[0], lengths[0]);
}
- mysql_free_result(tableRes);
+ mysql_free_result(table_res);
}
DBUG_PRINT("exit", ("new_table_name: %s", name));
DBUG_RETURN(name);
@@ -2269,32 +3034,29 @@ 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)
{
- uint numrows;
char table_buff[NAME_LEN*+3];
DYNAMIC_STRING lock_tables_query;
MEM_ROOT root;
- char **dump_tables, **pos;
+ char **dump_tables, **pos, **end;
DBUG_ENTER("dump_selected_tables");
- if (init_dumping(db))
+ if (init_dumping(db, init_dumping_tables))
return 1;
init_alloc_root(&root, 8192, 0);
if (!(dump_tables= pos= (char**) alloc_root(&root, tables * sizeof(char *))))
- exit(EX_EOM);
+ exit(EX_EOM);
init_dynamic_string(&lock_tables_query, "LOCK TABLES ", 256, 1024);
for (; tables > 0 ; tables-- , table_names++)
{
-
/* the table name passed on commandline may be wrong case */
if ((*pos= get_actual_table_name(*table_names, &root)))
{
/* Add found table name to lock_tables_query */
if (lock_tables)
{
- dynstr_append(&lock_tables_query,
- quote_name(*pos, table_buff, 1));
+ dynstr_append(&lock_tables_query, quote_name(*pos, table_buff, 1));
dynstr_append(&lock_tables_query, " READ /*!32311 LOCAL */,");
}
pos++;
@@ -2307,31 +3069,47 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
/* We shall countinue here, if --force was given */
}
}
+ end= pos;
if (lock_tables)
{
- if (mysql_real_query(sock, lock_tables_query.str,
+ if (mysql_real_query(mysql, lock_tables_query.str,
lock_tables_query.length-1))
- DBerror(sock, "when doing LOCK TABLES");
+ 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(sock, REFRESH_LOG))
- DBerror(sock, "when doing refresh");
+ if (mysql_refresh(mysql, REFRESH_LOG))
+ DB_error(mysql, "when doing refresh");
/* We shall countinue here, if --force was given */
}
if (opt_xml)
- print_xml_tag1(md_result_file, "", "database name=", db, "\n");
+ print_xml_tag(md_result_file, "", "\n", "database", "name=", db, NullS);
/* Dump each selected table */
- for (; dump_tables < pos; dump_tables++)
+ for (pos= dump_tables; pos < end; pos++)
+ {
+ DBUG_PRINT("info",("Dumping table %s", *pos));
+ dump_table(*pos, db);
+ if (opt_dump_triggers &&
+ mysql_get_server_version(mysql) >= 50009)
+ dump_triggers_for_table(*pos, db);
+ }
+
+ /* Dump each selected view */
+ if (seen_views)
+ {
+ for (pos= dump_tables; pos < end; pos++)
+ get_view_structure(*pos, db);
+ }
+ /* obtain dump of routines (procs/functions) */
+ if (opt_routines && !opt_xml &&
+ mysql_get_server_version(mysql) >= 50009)
{
- DBUG_PRINT("info",("Dumping table %s", *dump_tables));
- numrows= getTableStructure(*dump_tables, db);
- if (!dFlag && numrows > 0)
- dumpTable(numrows, *dump_tables);
+ DBUG_PRINT("info", ("Dumping routines for database %s", db));
+ dump_routines_for_db(db);
}
free_root(&root, MYF(0));
my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
@@ -2342,7 +3120,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
check_io(md_result_file);
}
if (lock_tables)
- mysql_query_with_error_report(sock, 0, "UNLOCK TABLES");
+ VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
DBUG_RETURN(0);
} /* dump_selected_tables */
@@ -2355,13 +3133,11 @@ static int do_show_master_status(MYSQL *mysql_con)
(opt_master_data == MYSQL_OPT_MASTER_DATA_COMMENTED_SQL) ? "-- " : "";
if (mysql_query_with_error_report(mysql_con, &master, "SHOW MASTER STATUS"))
{
- my_printf_error(0, "Error: Couldn't execute 'SHOW MASTER STATUS': %s",
- MYF(0), mysql_error(mysql_con));
return 1;
}
else
{
- row = mysql_fetch_row(master);
+ row= mysql_fetch_row(master);
if (row && row[0] && row[1])
{
/* SHOW MASTER STATUS reports file and position */
@@ -2371,14 +3147,14 @@ static int do_show_master_status(MYSQL *mysql_con)
"recovery from\n--\n\n");
fprintf(md_result_file,
"%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n",
- comment_prefix, row[0], row[1]);
+ comment_prefix, row[0], row[1]);
check_io(md_result_file);
}
else if (!ignore_errors)
{
/* SHOW MASTER STATUS reports nothing and --force is not enabled */
- my_printf_error(0, "Error: Binlogging on server not active",
- MYF(0));
+ my_printf_error(0, "Error: Binlogging on server not active",
+ MYF(0));
mysql_free_result(master);
return 1;
}
@@ -2398,7 +3174,7 @@ static int do_flush_tables_read_lock(MYSQL *mysql_con)
and most client connections are stalled. Of course, if a second long
update starts between the two FLUSHes, we have that bad stall.
*/
- return
+ return
( mysql_query_with_error_report(mysql_con, 0, "FLUSH TABLES") ||
mysql_query_with_error_report(mysql_con, 0,
"FLUSH TABLES WITH READ LOCK") );
@@ -2438,7 +3214,7 @@ static int start_transaction(MYSQL *mysql_con)
static ulong find_set(TYPELIB *lib, const char *x, uint length,
- char **err_pos, uint *err_len)
+ char **err_pos, uint *err_len)
{
const char *end= x + length;
ulong found= 0;
@@ -2480,90 +3256,119 @@ static ulong find_set(TYPELIB *lib, const char *x, uint length,
/* Print a value with a prefix on file */
static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row,
- const char *prefix, const char *name,
- int string_value)
+ const char *prefix, const char *name,
+ int string_value)
{
- MYSQL_FIELD *field;
+ MYSQL_FIELD *field;
mysql_field_seek(result, 0);
- for ( ; (field = mysql_fetch_field(result)) ; row++)
+ for ( ; (field= mysql_fetch_field(result)) ; row++)
{
if (!strcmp(field->name,name))
{
if (row[0] && row[0][0] && strcmp(row[0],"0")) /* Skip default */
{
- fputc(' ',file);
- fputs(prefix, file);
- if (string_value)
- unescape(file,row[0],(uint) strlen(row[0]));
- else
- fputs(row[0], file);
- check_io(file);
- return;
+ fputc(' ',file);
+ fputs(prefix, file);
+ if (string_value)
+ unescape(file,row[0],(uint) strlen(row[0]));
+ else
+ fputs(row[0], file);
+ check_io(file);
+ return;
}
}
}
- return; /* This shouldn't happen */
+ return; /* This shouldn't happen */
} /* print_value */
/*
+ SYNOPSIS
+
Check if we the table is one of the table types that should be ignored:
- MRG_ISAM, MRG_MYISAM
+ MRG_ISAM, MRG_MYISAM, if opt_delayed, if that table supports delayed inserts.
+ If the table should be altogether ignored, it returns a TRUE, FALSE if it
+ should not be ignored. If the user has selected to use INSERT DELAYED, it
+ sets the value of the bool pointer supports_delayed_inserts to 0 if not
+ supported, 1 if it is supported.
+
+ ARGS
- SYNOPSIS
check_if_ignore_table()
- table_name Table name to check
+ table_name Table name to check
+ table_type Type of table
GLOBAL VARIABLES
- sock MySQL socket
- verbose Write warning messages
+ mysql MySQL connection
+ verbose Write warning messages
RETURN
- 0 Table should be backuped
- # Type of table (that should be skipped)
+ char (bit value) See IGNORE_ values at top
*/
-static const char *check_if_ignore_table(const char *table_name)
+char check_if_ignore_table(const char *table_name, char *table_type)
{
+ char result= IGNORE_NONE;
char buff[FN_REFLEN+80], show_name_buff[FN_REFLEN];
MYSQL_RES *res;
MYSQL_ROW row;
- const char *result= 0;
+ DBUG_ENTER("check_if_ignore_table");
/* Check memory for quote_for_like() */
DBUG_ASSERT(2*sizeof(table_name) < sizeof(show_name_buff));
my_snprintf(buff, sizeof(buff), "show table status like %s",
- quote_for_like(table_name, show_name_buff));
- if (mysql_query_with_error_report(sock, &res, buff))
+ quote_for_like(table_name, show_name_buff));
+ if (mysql_query_with_error_report(mysql, &res, buff))
{
- if (mysql_errno(sock) != ER_PARSE_ERROR)
- { /* If old MySQL version */
- if (verbose)
- fprintf(stderr,
- "-- Warning: Couldn't get status information for table %s (%s)\n",
- table_name,mysql_error(sock));
- return 0; /* assume table is ok */
+ if (mysql_errno(mysql) != ER_PARSE_ERROR)
+ { /* If old MySQL version */
+ verbose_msg("-- Warning: Couldn't get status information for "
+ "table %s (%s)\n", table_name, mysql_error(mysql));
+ DBUG_RETURN(result); /* assume table is ok */
}
}
if (!(row= mysql_fetch_row(res)))
{
fprintf(stderr,
- "Error: Couldn't read status information for table %s (%s)\n",
- table_name, mysql_error(sock));
+ "Error: Couldn't read status information for table %s (%s)\n",
+ table_name, mysql_error(mysql));
mysql_free_result(res);
- return 0; /* assume table is ok */
- }
- /* Some forward-compatibility: don't dump data from a VIEW */
- if (!row[1])
- result= "VIEW";
- else if (strcmp(row[1], (result= "MRG_MyISAM")) &&
- strcmp(row[1], (result= "MRG_ISAM")))
- result= 0;
+ DBUG_RETURN(result); /* assume table is ok */
+ }
+ if (!(row[1]))
+ strmake(table_type, "VIEW", NAME_LEN-1);
+ else
+ {
+ /*
+ If the table type matches any of these, we do support delayed inserts.
+ Note: we do not want to skip dumping this table if if is not one of
+ these types, but we do want to use delayed inserts in the dump if
+ the table type is _NOT_ one of these types
+ */
+ strmake(table_type, row[1], NAME_LEN-1);
+ if (opt_delayed)
+ {
+ if (strcmp(table_type,"MyISAM") &&
+ strcmp(table_type,"ISAM") &&
+ strcmp(table_type,"ARCHIVE") &&
+ strcmp(table_type,"HEAP") &&
+ strcmp(table_type,"MEMORY"))
+ result= IGNORE_INSERT_DELAYED;
+ }
+
+ /*
+ 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")))
+ result= IGNORE_DATA;
+ }
mysql_free_result(res);
- return result;
+ DBUG_RETURN(result);
}
+
/*
Get string of comma-separated primary key field names
@@ -2581,25 +3386,26 @@ static const char *check_if_ignore_table(const char *table_name)
or if there is some failure. It is better to continue to dump
the table unsorted, rather than exit without dumping the data.
*/
+
static char *primary_key_fields(const char *table_name)
{
- MYSQL_RES *res = NULL;
+ MYSQL_RES *res= NULL;
MYSQL_ROW row;
/* SHOW KEYS FROM + table name * 2 (escaped) + 2 quotes + \0 */
- char show_keys_buff[15 + 64 * 2 + 3];
- uint result_length = 0;
- char *result = 0;
+ char show_keys_buff[15 + NAME_LEN * 2 + 3];
+ uint result_length= 0;
+ char *result= 0;
char buff[NAME_LEN * 2 + 3];
char *quoted_field;
- my_snprintf(show_keys_buff, sizeof(show_keys_buff),
- "SHOW KEYS FROM %s", table_name);
- if (mysql_query(sock, show_keys_buff) ||
- !(res = mysql_store_result(sock)))
+ my_snprintf(show_keys_buff, sizeof(show_keys_buff),
+ "SHOW KEYS FROM %s", table_name);
+ if (mysql_query(mysql, show_keys_buff) ||
+ !(res= mysql_store_result(mysql)))
{
fprintf(stderr, "Warning: Couldn't read keys from table %s;"
" records are NOT sorted (%s)\n",
- table_name, mysql_error(sock));
+ table_name, mysql_error(mysql));
/* Don't exit, because it's better to print out unsorted records */
goto cleanup;
}
@@ -2610,7 +3416,7 @@ static char *primary_key_fields(const char *table_name)
* row, and UNIQUE keys come before others. So we only need to check
* the first key, not all keys.
*/
- if ((row = mysql_fetch_row(res)) && atoi(row[1]) == 0)
+ if ((row= mysql_fetch_row(res)) && atoi(row[1]) == 0)
{
/* Key is unique */
do
@@ -2621,16 +3427,18 @@ static char *primary_key_fields(const char *table_name)
}
/* Build the ORDER BY clause result */
- if (result_length) {
+ if (result_length)
+ {
char *end;
/* result (terminating \0 is already in result_length) */
- result = my_malloc(result_length + 10, MYF(MY_WME));
- if (!result) {
+ result= my_malloc(result_length + 10, MYF(MY_WME));
+ if (!result)
+ {
fprintf(stderr, "Error: Not enough memory to store ORDER BY clause\n");
goto cleanup;
}
mysql_data_seek(res, 0);
- row = mysql_fetch_row(res);
+ row= mysql_fetch_row(res);
quoted_field= quote_name(row[4], buff, 0);
end= strmov(result, quoted_field);
while ((row= mysql_fetch_row(res)) && atoi(row[3]) > 1)
@@ -2648,39 +3456,266 @@ cleanup:
}
+/*
+ Replace a substring
+
+ SYNOPSIS
+ replace
+ ds_str The string to search and perform the replace in
+ search_str The string to search for
+ search_len Length of the string to search for
+ replace_str The string to replace with
+ replace_len Length of the string to replace with
+
+ RETURN
+ 0 String replaced
+ 1 Could not find search_str in str
+*/
+
+static int replace(DYNAMIC_STRING *ds_str,
+ const char *search_str, ulong search_len,
+ const char *replace_str, ulong replace_len)
+{
+ DYNAMIC_STRING ds_tmp;
+ const char *start= strstr(ds_str->str, search_str);
+ if (!start)
+ return 1;
+ init_dynamic_string(&ds_tmp, "",
+ ds_str->length + replace_len, 256);
+ 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);
+ dynstr_free(&ds_tmp);
+ return 0;
+}
+
+
+/*
+ Getting VIEW structure
+
+ SYNOPSIS
+ get_view_structure()
+ table view name
+ db db name
+
+ RETURN
+ 0 OK
+ 1 ERROR
+*/
+
+static my_bool get_view_structure(char *table, char* db)
+{
+ MYSQL_RES *table_res;
+ MYSQL_ROW row;
+ MYSQL_FIELD *field;
+ char *result_table, *opt_quoted_table;
+ char table_buff[NAME_LEN*2+3];
+ char table_buff2[NAME_LEN*2+3];
+ char query[QUERY_LENGTH];
+ FILE *sql_file= md_result_file;
+ DBUG_ENTER("get_view_structure");
+
+ if (opt_no_create_info) /* Don't write table creation info */
+ DBUG_RETURN(0);
+
+ verbose_msg("-- Retrieving view structure for table %s...\n", table);
+
+#ifdef NOT_REALLY_USED_YET
+ sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
+ (opt_quoted || opt_keywords));
+#endif
+
+ result_table= quote_name(table, table_buff, 1);
+ opt_quoted_table= quote_name(table, table_buff2, 0);
+
+ my_snprintf(query, sizeof(query), "SHOW CREATE TABLE %s", result_table);
+ if (mysql_query_with_error_report(mysql, &table_res, query))
+ {
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(0);
+ }
+
+ /* Check if this is a view */
+ field= mysql_fetch_field_direct(table_res, 0);
+ if (strcmp(field->name, "View") != 0)
+ {
+ verbose_msg("-- It's base table, skipped\n");
+ DBUG_RETURN(0);
+ }
+
+ /* If requested, open separate .sql file for this view */
+ if (path)
+ {
+ if (!(sql_file= open_sql_file_for_table(table)))
+ {
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(1);
+ }
+ write_header(sql_file, db);
+ }
+
+ if (!opt_xml && opt_comments)
+ {
+ fprintf(sql_file, "\n--\n-- Final view structure for view %s\n--\n\n",
+ result_table);
+ check_io(sql_file);
+ }
+ if (opt_drop)
+ {
+ fprintf(sql_file, "/*!50001 DROP TABLE IF EXISTS %s*/;\n",
+ opt_quoted_table);
+ fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n",
+ opt_quoted_table);
+ check_io(sql_file);
+ }
+
+
+ my_snprintf(query, sizeof(query),
+ "SELECT CHECK_OPTION, DEFINER, SECURITY_TYPE " \
+ "FROM information_schema.views " \
+ "WHERE table_name=\"%s\" AND table_schema=\"%s\"", table, db);
+ if (mysql_query(mysql, query))
+ {
+ /*
+ Use the raw output from SHOW CREATE TABLE if
+ information_schema query fails.
+ */
+ row= mysql_fetch_row(table_res);
+ fprintf(sql_file, "/*!50001 %s */;\n", row[1]);
+ check_io(sql_file);
+ mysql_free_result(table_res);
+ }
+ else
+ {
+ char *ptr;
+ ulong *lengths;
+ char search_buf[256], replace_buf[256];
+ ulong search_len, replace_len;
+ DYNAMIC_STRING ds_view;
+
+ /* Save the result of SHOW CREATE TABLE in ds_view */
+ row= mysql_fetch_row(table_res);
+ lengths= mysql_fetch_lengths(table_res);
+ init_dynamic_string(&ds_view, row[1], lengths[1] + 1, 1024);
+ mysql_free_result(table_res);
+
+ /* Get the result from "select ... information_schema" */
+ if (!(table_res= mysql_store_result(mysql)) ||
+ !(row= mysql_fetch_row(table_res)))
+ {
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(1);
+ }
+
+ lengths= mysql_fetch_lengths(table_res);
+
+ /*
+ "WITH %s CHECK OPTION" is available from 5.0.2
+ Surround it with !50002 comments
+ */
+ if (strcmp(row[0], "NONE"))
+ {
+
+ ptr= search_buf;
+ search_len= (ulong)(strxmov(ptr, "WITH ", row[0],
+ " CHECK OPTION", NullS) - ptr);
+ ptr= replace_buf;
+ replace_len=(ulong)(strxmov(ptr, "*/\n/*!50002 WITH ", row[0],
+ " CHECK OPTION", NullS) - ptr);
+ replace(&ds_view, search_buf, search_len, replace_buf, replace_len);
+ }
+
+ /*
+ "DEFINER=%s SQL SECURITY %s" is available from 5.0.13
+ Surround it with !50013 comments
+ */
+ {
+ 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];
+
+ parse_user(row[1], lengths[1], user_name_str, &user_name_len,
+ host_name_str, &host_name_len);
+
+ ptr= search_buf;
+ search_len=
+ (ulong)(strxmov(ptr, "DEFINER=",
+ quote_name(user_name_str, quoted_user_name_str, FALSE),
+ "@",
+ quote_name(host_name_str, quoted_host_name_str, FALSE),
+ " SQL SECURITY ", row[2], NullS) - ptr);
+ ptr= replace_buf;
+ replace_len=
+ (ulong)(strxmov(ptr, "*/\n/*!50013 DEFINER=",
+ quote_name(user_name_str, quoted_user_name_str, FALSE),
+ "@",
+ quote_name(host_name_str, quoted_host_name_str, FALSE),
+ " SQL SECURITY ", row[2],
+ " */\n/*!50001", NullS) - ptr);
+ replace(&ds_view, search_buf, search_len, replace_buf, replace_len);
+ }
+
+ /* Dump view structure to file */
+ fprintf(sql_file, "/*!50001 %s */;\n", ds_view.str);
+ check_io(sql_file);
+ mysql_free_result(table_res);
+ dynstr_free(&ds_view);
+ }
+
+ /* If a separate .sql file was opened, close it now */
+ if (sql_file != md_result_file)
+ {
+ fputs("\n", sql_file);
+ write_footer(sql_file);
+ my_fclose(sql_file, MYF(MY_WME));
+ }
+ DBUG_RETURN(0);
+}
+
+
int main(int argc, char **argv)
{
+ int exit_code;
+ MY_INIT("mysqldump");
+
compatible_mode_normal_str[0]= 0;
default_charset= (char *)mysql_universal_client_charset;
bzero((char*) &ignore_table, sizeof(ignore_table));
- MY_INIT("mysqldump");
- if (get_options(&argc, &argv))
+ exit_code= get_options(&argc, &argv);
+ if (exit_code)
{
- my_end(0);
- exit(EX_USAGE);
+ free_resources(0);
+ exit(exit_code);
}
- if (dbConnect(current_host, current_user, opt_password))
+ if (connect_to_db(current_host, current_user, opt_password))
+ {
+ free_resources(0);
exit(EX_MYSQLERR);
+ }
if (!path)
write_header(md_result_file, *argv);
if ((opt_lock_all_tables || opt_master_data) &&
- do_flush_tables_read_lock(sock))
+ do_flush_tables_read_lock(mysql))
goto err;
- if (opt_single_transaction && start_transaction(sock))
+ if (opt_single_transaction && start_transaction(mysql))
goto err;
- if (opt_delete_master_logs && do_reset_master(sock))
+ if (opt_delete_master_logs && do_reset_master(mysql))
goto err;
if (opt_lock_all_tables || opt_master_data)
{
- if (flush_logs && mysql_refresh(sock, REFRESH_LOG))
+ if (flush_logs && mysql_refresh(mysql, REFRESH_LOG))
goto err;
flush_logs= 0; /* not anymore; that would not be sensible */
}
- if (opt_master_data && do_show_master_status(sock))
+ if (opt_master_data && do_show_master_status(mysql))
goto err;
- if (opt_single_transaction && do_unlock_tables(sock)) /* unlock but no commit! */
+ if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */
goto err;
if (opt_alldbs)
@@ -2708,15 +3743,6 @@ err:
dbDisconnect(current_host);
if (!path)
write_footer(md_result_file);
- if (md_result_file != stdout)
- my_fclose(md_result_file, MYF(0));
- my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
- if (hash_inited(&ignore_table))
- hash_free(&ignore_table);
- if (extended_insert)
- dynstr_free(&extended_row);
- if (insert_pat_inited)
- dynstr_free(&insert_pat);
- my_end(0);
+ free_resources();
return(first_error);
} /* main */
diff --git a/client/mysqlimport.c b/client/mysqlimport.c
index a7872740c0c..e7bf1cfd889 100644
--- a/client/mysqlimport.c
+++ b/client/mysqlimport.c
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB
+/* 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; either version 2 of the License, or
- (at your option) any later version.
+ 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
@@ -121,7 +120,7 @@ static struct my_option my_long_options[] =
NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
- (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
+ (gptr*) &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},
@@ -165,7 +164,7 @@ static void print_version(void)
static void usage(void)
{
print_version();
- puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB");
+ puts("Copyright (C) 2000-2006 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");
printf("\
Loads tables from text files in various formats. The base name of the\n\
@@ -384,6 +383,8 @@ static MYSQL *db_connect(char *host, char *database, char *user, char *passwd)
if (opt_use_ssl)
mysql_ssl_set(&mysql_connection, 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,
+ (char*)&opt_ssl_verify_server_cert);
#endif
if (opt_protocol)
mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
@@ -398,6 +399,7 @@ static MYSQL *db_connect(char *host, char *database, char *user, char *passwd)
ignore_errors=0; /* NO RETURN FROM db_error */
db_error(&mysql_connection);
}
+ mysql_connection.reconnect= 0;
if (verbose)
fprintf(stdout, "Selecting database %s\n", database);
if (mysql_select_db(sock, database))
@@ -518,7 +520,7 @@ int main(int argc, char **argv)
return(1); /* purecov: deadcode */
}
- if (mysql_query(sock, "set @@character_set_database=binary;"))
+ if (mysql_query(sock, "/*!40101 set @@character_set_database=binary */;"))
{
db_error(sock); /* We shall countinue here, if --force was given */
return(1);
diff --git a/client/mysqlmanager-pwgen.c b/client/mysqlmanager-pwgen.c
index 1d942e207ad..716a1e4bf4e 100644
--- a/client/mysqlmanager-pwgen.c
+++ b/client/mysqlmanager-pwgen.c
@@ -2,8 +2,7 @@
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; either version 2 of the License, or
- (at your option) any later version.
+ 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
diff --git a/client/mysqlmanagerc.c b/client/mysqlmanagerc.c
index 0001a0266e6..1fdedab97fb 100644
--- a/client/mysqlmanagerc.c
+++ b/client/mysqlmanagerc.c
@@ -2,8 +2,7 @@
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; either version 2 of the License, or
- (at your option) any later version.
+ 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
diff --git a/client/mysqlshow.c b/client/mysqlshow.c
index 3b714c20ba7..5be01cc5a52 100644
--- a/client/mysqlshow.c
+++ b/client/mysqlshow.c
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB
+/* 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; either version 2 of the License, or
- (at your option) any later version.
+ 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
@@ -28,7 +27,8 @@
#include <sslopt-vars.h>
static my_string host=0,opt_password=0,user=0;
-static my_bool opt_show_keys=0,opt_compress=0,opt_status=0, tty_password=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 uint opt_verbose=0;
static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
@@ -70,8 +70,7 @@ int main(int argc, char **argv)
char *pos= argv[argc-1], *to;
for (to= pos ; *pos ; pos++, to++)
{
- switch (*pos)
- {
+ switch (*pos) {
case '*':
*pos= '%';
first_argument_uses_wildcards= 1;
@@ -109,6 +108,8 @@ int main(int argc, char **argv)
if (opt_use_ssl)
mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
opt_ssl_capath, opt_ssl_cipher);
+ mysql_options(&mysql,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
+ (char*)&opt_ssl_verify_server_cert);
#endif
if (opt_protocol)
mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
@@ -125,6 +126,7 @@ int main(int argc, char **argv)
fprintf(stderr,"%s: %s\n",my_progname,mysql_error(&mysql));
exit(1);
}
+ mysql.reconnect= 1;
switch (argc)
{
@@ -165,6 +167,10 @@ static struct my_option my_long_options[] =
{"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},
+ {"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,
+ 0, 0, 0},
{"compress", 'C', "Use compression in server/client protocol.",
(gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
0, 0, 0},
@@ -183,7 +189,7 @@ static struct my_option my_long_options[] =
"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},
{"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
- (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
+ (gptr*) &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,
@@ -196,6 +202,9 @@ static struct my_option my_long_options[] =
"Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name,
0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
+ {"show-table-type", 't', "Show table type column.",
+ (gptr*) &opt_table_type, (gptr*) &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,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -226,7 +235,7 @@ static void print_version(void)
static void usage(void)
{
print_version();
- puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB");
+ puts("Copyright (C) 2000-2006 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("Shows the structure of a mysql database (databases,tables and columns)\n");
printf("Usage: %s [OPTIONS] [database [table [column]]]\n",my_progname);
@@ -312,6 +321,14 @@ get_options(int *argc,char ***argv)
if (tty_password)
opt_password=get_tty_password(NullS);
+ if (opt_count)
+ {
+ /*
+ We need to set verbose to 2 as we need to change the output to include
+ the number-of-rows column
+ */
+ opt_verbose= 2;
+ }
return;
}
@@ -326,7 +343,7 @@ list_dbs(MYSQL *mysql,const char *wild)
char query[255];
MYSQL_FIELD *field;
MYSQL_RES *result;
- MYSQL_ROW row, trow, rrow;
+ MYSQL_ROW row= NULL, rrow;
if (!(result=mysql_list_dbs(mysql,wild)))
{
@@ -334,6 +351,26 @@ list_dbs(MYSQL *mysql,const char *wild)
mysql_error(mysql));
return 1;
}
+
+ /*
+ If a wildcard was used, but there was only one row and it's name is an
+ exact match, we'll assume they really wanted to see the contents of that
+ database. This is because it is fairly common for database names to
+ contain the underscore (_), like INFORMATION_SCHEMA.
+ */
+ if (wild && mysql_num_rows(result) == 1)
+ {
+ row= mysql_fetch_row(result);
+ if (!my_strcasecmp(&my_charset_latin1, row[0], wild))
+ {
+ mysql_free_result(result);
+ if (opt_status)
+ return list_table_status(mysql, wild, NULL);
+ else
+ return list_tables(mysql, wild, NULL);
+ }
+ }
+
if (wild)
printf("Wildcard: %s\n",wild);
@@ -350,17 +387,13 @@ list_dbs(MYSQL *mysql,const char *wild)
else
print_header(header,length,"Tables",6,"Total Rows",12,NullS);
- while ((row = mysql_fetch_row(result)))
+ /* The first row may have already been read up above. */
+ while (row || (row= mysql_fetch_row(result)))
{
counter++;
if (opt_verbose)
{
- /*
- * Original code by MG16373; Slightly modified by Monty.
- * Print now the count of tables and rows for each database.
- */
-
if (!(mysql_select_db(mysql,row[0])))
{
MYSQL_RES *tresult = mysql_list_tables(mysql,(char*)NULL);
@@ -370,6 +403,8 @@ list_dbs(MYSQL *mysql,const char *wild)
rowcount = 0;
if (opt_verbose > 1)
{
+ /* Print the count of tables and rows for each database */
+ MYSQL_ROW trow;
while ((trow = mysql_fetch_row(tresult)))
{
sprintf(query,"SELECT COUNT(*) FROM `%s`",trow[0]);
@@ -407,6 +442,8 @@ list_dbs(MYSQL *mysql,const char *wild)
print_row(row[0],length,tables,6,NullS);
else
print_row(row[0],length,tables,6,rows,12,NullS);
+
+ row= NULL;
}
print_trailer(length,
@@ -426,7 +463,7 @@ list_tables(MYSQL *mysql,const char *db,const char *table)
{
const char *header;
uint head_length, counter = 0;
- char query[255], rows[64], fields[16];
+ char query[255], rows[NAME_LEN], fields[16];
MYSQL_FIELD *field;
MYSQL_RES *result;
MYSQL_ROW row, rrow;
@@ -437,7 +474,20 @@ list_tables(MYSQL *mysql,const char *db,const char *table)
mysql_error(mysql));
return 1;
}
- if (!(result=mysql_list_tables(mysql,table)))
+ if (table)
+ {
+ /*
+ We just hijack the 'rows' variable for a bit to store the escaped
+ table name
+ */
+ mysql_real_escape_string(mysql, rows, table, (unsigned long)strlen(table));
+ my_snprintf(query, sizeof(query), "show%s tables like '%s'",
+ opt_table_type ? " full" : "", rows);
+ }
+ else
+ my_snprintf(query, sizeof(query), "show%s tables",
+ opt_table_type ? " full" : "");
+ if (mysql_query(mysql, query) || !(result= mysql_store_result(mysql)))
{
fprintf(stderr,"%s: Cannot list tables in %s: %s\n",my_progname,db,
mysql_error(mysql));
@@ -454,19 +504,30 @@ list_tables(MYSQL *mysql,const char *db,const char *table)
if (head_length < field->max_length)
head_length=field->max_length;
- if (!opt_verbose)
- print_header(header,head_length,NullS);
- else if (opt_verbose == 1)
- print_header(header,head_length,"Columns",8,NullS);
+ if (opt_table_type)
+ {
+ if (!opt_verbose)
+ print_header(header,head_length,"table_type",10,NullS);
+ else if (opt_verbose == 1)
+ print_header(header,head_length,"table_type",10,"Columns",8,NullS);
+ else
+ {
+ print_header(header,head_length,"table_type",10,"Columns",8,
+ "Total Rows",10,NullS);
+ }
+ }
else
- print_header(header,head_length,"Columns",8, "Total Rows",10,NullS);
+ {
+ if (!opt_verbose)
+ print_header(header,head_length,NullS);
+ else if (opt_verbose == 1)
+ print_header(header,head_length,"Columns",8,NullS);
+ else
+ print_header(header,head_length,"Columns",8, "Total Rows",10,NullS);
+ }
while ((row = mysql_fetch_row(result)))
{
- /*
- * Modified by MG16373
- * Print now the count of rows for each table.
- */
counter++;
if (opt_verbose > 0)
{
@@ -486,6 +547,7 @@ list_tables(MYSQL *mysql,const char *db,const char *table)
if (opt_verbose > 1)
{
+ /* Print the count of rows for each table */
sprintf(query,"SELECT COUNT(*) FROM `%s`",row[0]);
if (!(mysql_query(mysql,query)))
{
@@ -508,17 +570,31 @@ list_tables(MYSQL *mysql,const char *db,const char *table)
strmov(rows,"N/A");
}
}
- if (!opt_verbose)
- print_row(row[0],head_length,NullS);
- else if (opt_verbose == 1)
- print_row(row[0],head_length, fields,8, NullS);
- else
- print_row(row[0],head_length, fields,8, rows,10, NullS);
+ if (opt_table_type)
+ {
+ if (!opt_verbose)
+ print_row(row[0],head_length,row[1],10,NullS);
+ else if (opt_verbose == 1)
+ print_row(row[0],head_length,row[1],10,fields,8,NullS);
+ else
+ print_row(row[0],head_length,row[1],10,fields,8,rows,10,NullS);
+ }
+ else
+ {
+ if (!opt_verbose)
+ print_row(row[0],head_length,NullS);
+ else if (opt_verbose == 1)
+ print_row(row[0],head_length, fields,8, NullS);
+ else
+ print_row(row[0],head_length, fields,8, rows,10, NullS);
+ }
}
print_trailer(head_length,
- (opt_verbose > 0 ? 8 : 0),
- (opt_verbose > 1 ? 10 :0),
+ (opt_table_type ? 10 : opt_verbose > 0 ? 8 : 0),
+ (opt_table_type ? (opt_verbose > 0 ? 8 : 0)
+ : (opt_verbose > 1 ? 10 :0)),
+ !opt_table_type ? 0 : opt_verbose > 1 ? 10 :0,
0);
if (counter && opt_verbose)
@@ -536,7 +612,7 @@ list_table_status(MYSQL *mysql,const char *db,const char *wild)
MYSQL_RES *result;
MYSQL_ROW row;
- end=strxmov(query,"show table status from ",db,NullS);
+ end=strxmov(query,"show table status from `",db,"`",NullS);
if (wild && wild[0])
strxmov(end," like '",wild,"'",NullS);
if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
@@ -562,8 +638,8 @@ list_table_status(MYSQL *mysql,const char *db,const char *wild)
}
/*
-** list fields uses field interface as an example of how to parse
-** a MYSQL FIELD
+ list fields uses field interface as an example of how to parse
+ a MYSQL FIELD
*/
static int
@@ -573,6 +649,8 @@ list_fields(MYSQL *mysql,const char *db,const char *table,
char query[1024],*end;
MYSQL_RES *result;
MYSQL_ROW row;
+ ulong rows;
+ LINT_INIT(rows);
if (mysql_select_db(mysql,db))
{
@@ -580,6 +658,21 @@ list_fields(MYSQL *mysql,const char *db,const char *table,
mysql_error(mysql));
return 1;
}
+
+ if (opt_count)
+ {
+ sprintf(query,"select count(*) from `%s`", table);
+ if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
+ {
+ fprintf(stderr,"%s: Cannot get record count for db: %s, table: %s: %s\n",
+ my_progname,db,table,mysql_error(mysql));
+ return 1;
+ }
+ row= mysql_fetch_row(result);
+ rows= (ulong) strtoull(row[0], (char**) 0, 10);
+ mysql_free_result(result);
+ }
+
end=strmov(strmov(strmov(query,"show /*!32332 FULL */ columns from `"),table),"`");
if (wild && wild[0])
strxmov(end," like '",wild,"'",NullS);
@@ -590,8 +683,9 @@ list_fields(MYSQL *mysql,const char *db,const char *table,
return 1;
}
- printf("Database: %s Table: %s Rows: %lu", db,table,
- (ulong) mysql->extra_info);
+ printf("Database: %s Table: %s", db, table);
+ if (opt_count)
+ printf(" Rows: %lu", rows);
if (wild && wild[0])
printf(" Wildcard: %s",wild);
putchar('\n');
@@ -625,7 +719,7 @@ list_fields(MYSQL *mysql,const char *db,const char *table,
/*****************************************************************************
-** General functions to print a nice ascii-table from data
+ General functions to print a nice ascii-table from data
*****************************************************************************/
static void
diff --git a/client/mysqltest.c b/client/mysqltest.c
index 1a8e14a7244..919f0f90e44 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -2,8 +2,7 @@
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; either version 2 of the License, or
- (at your option) any later version.
+ 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
@@ -103,6 +102,7 @@ static my_bool disable_query_log= 0, disable_result_log= 0;
static my_bool disable_warnings= 0, disable_ps_warnings= 0;
static my_bool disable_info= 1;
static my_bool abort_on_error= 1;
+static my_bool server_initialized= 0;
static my_bool is_windows= 0;
static char **default_argv;
static const char *load_default_groups[]= { "mysqltest", "client", 0 };
@@ -354,6 +354,7 @@ const char *command_names[]=
"copy_file",
"perl",
"die",
+
/* Don't execute any more commands, compare result */
"exit",
"chmod",
@@ -486,7 +487,6 @@ void handle_error(struct st_command*,
const char *err_sqlstate, DYNAMIC_STRING *ds);
void handle_no_error(struct st_command*);
-
#ifdef EMBEDDED_LIBRARY
/*
send_one_query executes query in separate thread what is
@@ -495,7 +495,7 @@ void handle_no_error(struct st_command*);
by mysql_send_query. It's technically possible, though
i don't see where it is needed.
*/
-pthread_handler_decl(send_one_query, arg)
+pthread_handler_t send_one_query(void *arg)
{
struct st_connection *cn= (struct st_connection*)arg;
@@ -732,6 +732,20 @@ void close_connections()
}
+void close_statements()
+{
+ struct st_connection *con;
+ DBUG_ENTER("close_statements");
+ for (con= connections; con < next_con; con++)
+ {
+ if (con->stmt)
+ mysql_stmt_close(con->stmt);
+ con->stmt= 0;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
void close_files()
{
DBUG_ENTER("close_files");
@@ -778,13 +792,18 @@ void free_used_memory()
free_all_replace();
my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
free_defaults(default_argv);
- mysql_server_end();
free_re();
#ifdef __WIN__
free_tmp_sh_file();
free_win_path_patterns();
#endif
- DBUG_VOID_RETURN;
+
+ /* Only call mysql_server_end if mysql_server_init has been called */
+ if (server_initialized)
+ mysql_server_end();
+
+ /* Don't use DBUG after mysql_server_end() */
+ return;
}
@@ -978,8 +997,8 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
die(NullS);
if (!eval_result && (uint) stat_info.st_size != ds->length)
{
- DBUG_PRINT("info",("Size differs: result size: %u file size: %llu",
- ds->length, stat_info.st_size));
+ DBUG_PRINT("info",("Size differs: result size: %u file size: %lu",
+ ds->length, (ulong) stat_info.st_size));
DBUG_PRINT("info",("result: '%s'", ds->str));
DBUG_RETURN(RESULT_LENGTH_MISMATCH);
}
@@ -3121,6 +3140,10 @@ void do_close_connection(struct st_command *command)
}
}
#endif
+ if (next_con->stmt)
+ mysql_stmt_close(next_con->stmt);
+ next_con->stmt= 0;
+
mysql_close(&con->mysql);
if (con->util_mysql)
mysql_close(con->util_mysql);
@@ -3403,14 +3426,15 @@ void do_connect(struct st_command *command)
else if (!strncmp(con_options, "COMPRESS", 8))
con_compress= 1;
else
- die("Illegal option to connect: %.*s", end - con_options, con_options);
+ die("Illegal option to connect: %.*s",
+ (int) (end - con_options), con_options);
/* Process next option */
con_options= end;
}
if (next_con == connections_end)
die("Connection limit exhausted, you can have max %d connections",
- (sizeof(connections)/sizeof(struct st_connection)));
+ (int) (sizeof(connections)/sizeof(struct st_connection)));
if (find_connection_by_name(ds_connection_name.str))
die("Connection %s already exists", ds_connection_name.str);
@@ -3731,10 +3755,10 @@ int read_line(char *buf, int size)
DBUG_RETURN(0);
}
else if ((c == '{' &&
- (!my_strnncoll_simple(charset_info, "while", 5,
- buf, min(5, p - buf), 0) ||
- !my_strnncoll_simple(charset_info, "if", 2,
- buf, min(2, p - buf), 0))))
+ (!my_strnncoll_simple(charset_info, (const uchar*) "while", 5,
+ (uchar*) buf, min(5, p - buf), 0) ||
+ !my_strnncoll_simple(charset_info, (const uchar*) "if", 2,
+ (uchar*) buf, min(2, p - buf), 0))))
{
/* Only if and while commands can be terminated by { */
*p++= c;
@@ -4874,8 +4898,8 @@ void run_query_normal(struct st_connection *cn, struct st_command *command,
int flags, char *query, int query_len,
DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings)
{
- MYSQL *mysql= &cn->mysql;
MYSQL_RES *res= 0;
+ MYSQL *mysql= &cn->mysql;
int err= 0, counter= 0;
DBUG_ENTER("run_query_normal");
DBUG_PRINT("enter",("flags: %d", flags));
@@ -5338,6 +5362,14 @@ end:
dynstr_free(&ds_execute_warnings);
}
+
+ /* Close the statement if - no reconnect, need new prepare */
+ if (mysql->reconnect)
+ {
+ mysql_stmt_close(stmt);
+ cur_con->stmt= NULL;
+ }
+
/*
We save the return code (mysql_stmt_errno(stmt)) from the last call sent
to the server into the mysqltest builtin variable $mysql_errno. This
@@ -5345,10 +5377,7 @@ end:
*/
var_set_errno(mysql_stmt_errno(stmt));
-#ifndef BUG15518_FIXED
- mysql_stmt_close(stmt);
- cur_con->stmt= NULL;
-#endif
+
DBUG_VOID_RETURN;
}
@@ -5870,6 +5899,7 @@ int main(int argc, char **argv)
embedded_server_args,
(char**) embedded_server_groups))
die("Can't initialize MySQL server");
+ server_initialized= 1;
if (cur_file == file_stack && cur_file->file == 0)
{
cur_file->file= stdin;
@@ -6138,6 +6168,8 @@ int main(int argc, char **argv)
break;
case Q_DISABLE_PS_PROTOCOL:
ps_protocol_enabled= 0;
+ /* Close any open statements */
+ close_statements();
break;
case Q_ENABLE_PS_PROTOCOL:
ps_protocol_enabled= ps_protocol;
@@ -6147,6 +6179,8 @@ int main(int argc, char **argv)
break;
case Q_ENABLE_RECONNECT:
set_reconnect(&cur_con->mysql, 1);
+ /* Close any open statements - no reconnect, need new prepare */
+ close_statements();
break;
case Q_DISABLE_PARSING:
if (parsing_disabled == 0)
diff --git a/client/readline.cc b/client/readline.cc
index 3d524633d69..ad42ed2ee10 100644
--- a/client/readline.cc
+++ b/client/readline.cc
@@ -2,8 +2,7 @@
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; either version 2 of the License, or
- (at your option) any later version.
+ 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
@@ -51,7 +50,8 @@ char *batch_readline(LINE_BUFFER *line_buff)
if (!(pos=intern_read_line(line_buff,&out_length)))
return 0;
if (out_length && pos[out_length-1] == '\n')
- out_length--; /* Remove '\n' */
+ if (--out_length && pos[out_length-1] == '\r') /* Remove '\n' */
+ out_length--; /* Remove '\r' */
line_buff->read_length=out_length;
pos[out_length]=0;
return pos;
diff --git a/client/sql_string.cc b/client/sql_string.cc
index 690997152f1..7d7d5d70754 100644
--- a/client/sql_string.cc
+++ b/client/sql_string.cc
@@ -2,8 +2,7 @@
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; either version 2 of the License, or
- (at your option) any later version.
+ 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
@@ -28,6 +27,11 @@
#include <floatingpoint.h>
#endif
+/*
+ The following extern declarations are ok as these are interface functions
+ required by the string function
+*/
+
extern gptr sql_alloc(unsigned size);
extern void sql_element_free(void *ptr);
@@ -97,14 +101,7 @@ bool String::set(longlong num, CHARSET_INFO *cs)
if (alloc(l))
return TRUE;
- if (cs->cset->snprintf == my_snprintf_8bit)
- {
- str_length=(uint32) (longlong10_to_str(num,Ptr,-10)-Ptr);
- }
- else
- {
- str_length=cs->cset->snprintf(cs,Ptr,l,"%d",num);
- }
+ str_length=(uint32) (cs->cset->longlong10_to_str)(cs,Ptr,l,-10,num);
str_charset=cs;
return FALSE;
}
@@ -115,14 +112,7 @@ bool String::set(ulonglong num, CHARSET_INFO *cs)
if (alloc(l))
return TRUE;
- if (cs->cset->snprintf == my_snprintf_8bit)
- {
- str_length=(uint32) (longlong10_to_str(num,Ptr,10)-Ptr);
- }
- else
- {
- str_length=cs->cset->snprintf(cs,Ptr,l,"%d",num);
- }
+ str_length=(uint32) (cs->cset->longlong10_to_str)(cs,Ptr,l,10,num);
str_charset=cs;
return FALSE;
}
@@ -130,12 +120,13 @@ bool String::set(ulonglong num, CHARSET_INFO *cs)
bool String::set(double num,uint decimals, CHARSET_INFO *cs)
{
char buff[331];
+ uint dummy_errors;
str_charset=cs;
if (decimals >= NOT_FIXED_DEC)
{
- sprintf(buff,"%.14g",num); // Enough for a DATETIME
- return copy(buff, (uint32) strlen(buff), &my_charset_latin1, cs);
+ uint32 len= my_sprintf(buff,(buff, "%.14g",num));// Enough for a DATETIME
+ return copy(buff, len, &my_charset_latin1, cs, &dummy_errors);
}
#ifdef HAVE_FCONVERT
int decpt,sign;
@@ -150,7 +141,8 @@ bool String::set(double num,uint decimals, CHARSET_INFO *cs)
buff[0]='-';
pos=buff;
}
- return copy(pos,(uint32) strlen(pos), &my_charset_latin1, cs);
+ uint dummy_errors;
+ return copy(pos,(uint32) strlen(pos), &my_charset_latin1, cs, &dummy_errors);
}
if (alloc((uint32) ((uint32) decpt+3+decimals)))
return TRUE;
@@ -200,7 +192,8 @@ end:
#else
sprintf(buff,"%.*f",(int) decimals,num);
#endif
- return copy(buff,(uint32) strlen(buff), &my_charset_latin1, cs);
+ return copy(buff,(uint32) strlen(buff), &my_charset_latin1, cs,
+ &dummy_errors);
#endif
}
@@ -237,55 +230,163 @@ bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *cs)
return FALSE;
}
-/* Copy with charset convertion */
-bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *from, CHARSET_INFO *to)
+
+/*
+ Checks that the source string can be just copied to the destination string
+ without conversion.
+
+ SYNPOSIS
+
+ needs_conversion()
+ arg_length Length of string to copy.
+ from_cs Character set to copy from
+ to_cs Character set to copy to
+ uint32 *offset Returns number of unaligned characters.
+
+ RETURN
+ 0 No conversion needed
+ 1 Either character set conversion or adding leading zeros
+ (e.g. for UCS-2) must be done
+*/
+
+bool String::needs_conversion(uint32 arg_length,
+ CHARSET_INFO *from_cs,
+ CHARSET_INFO *to_cs,
+ uint32 *offset)
+{
+ *offset= 0;
+ if ((to_cs == &my_charset_bin) ||
+ (to_cs == from_cs) ||
+ my_charset_same(from_cs, to_cs) ||
+ ((from_cs == &my_charset_bin) &&
+ (!(*offset=(arg_length % to_cs->mbminlen)))))
+ return FALSE;
+ return TRUE;
+}
+
+
+/*
+ Copy a multi-byte character sets with adding leading zeros.
+
+ SYNOPSIS
+
+ copy_aligned()
+ str String to copy
+ arg_length Length of string. This should NOT be dividable with
+ cs->mbminlen.
+ offset arg_length % cs->mb_minlength
+ cs Character set for 'str'
+
+ NOTES
+ For real multi-byte, ascii incompatible charactser sets,
+ like UCS-2, add leading zeros if we have an incomplete character.
+ Thus,
+ SELECT _ucs2 0xAA
+ will automatically be converted into
+ SELECT _ucs2 0x00AA
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+bool String::copy_aligned(const char *str,uint32 arg_length, uint32 offset,
+ CHARSET_INFO *cs)
{
- uint32 new_length=to->mbmaxlen*arg_length;
- int cnvres;
- my_wc_t wc;
- const uchar *s=(const uchar *)str;
- const uchar *se=s+arg_length;
- uchar *d, *de;
+ /* How many bytes are in incomplete character */
+ offset= cs->mbmaxlen - offset; /* How many zeros we should prepend */
+ DBUG_ASSERT(offset && offset != cs->mbmaxlen);
- if (alloc(new_length))
+ uint32 aligned_length= arg_length + offset;
+ if (alloc(aligned_length))
return TRUE;
+
+ /*
+ Note, this is only safe for little-endian UCS-2.
+ If we add big-endian UCS-2 sometimes, this code
+ will be more complicated. But it's OK for now.
+ */
+ bzero((char*) Ptr, offset);
+ memcpy(Ptr + offset, str, arg_length);
+ Ptr[aligned_length]=0;
+ /* str_length is always >= 0 as arg_length is != 0 */
+ str_length= aligned_length;
+ str_charset= cs;
+ return FALSE;
+}
+
- d=(uchar *)Ptr;
- de=d+new_length;
+bool String::set_or_copy_aligned(const char *str,uint32 arg_length,
+ CHARSET_INFO *cs)
+{
+ /* How many bytes are in incomplete character */
+ uint32 offset= (arg_length % cs->mbminlen);
- for (str_length=new_length ; s < se && d < de ; )
+ if (!offset) /* All characters are complete, just copy */
{
- if ((cnvres=from->cset->mb_wc(from,&wc,s,se)) > 0 )
- {
- s+=cnvres;
- }
- else if (cnvres==MY_CS_ILSEQ)
- {
- s++;
- wc='?';
- }
- else
- break;
+ set(str, arg_length, cs);
+ return FALSE;
+ }
+ return copy_aligned(str, arg_length, offset, cs);
+}
-outp:
- if((cnvres=to->cset->wc_mb(to,wc,d,de)) >0 )
- {
- d+=cnvres;
- }
- else if (cnvres==MY_CS_ILUNI && wc!='?')
- {
- wc='?';
- goto outp;
- }
- else
- break;
+ /* Copy with charset convertion */
+
+bool String::copy(const char *str, uint32 arg_length,
+ CHARSET_INFO *from_cs, CHARSET_INFO *to_cs, uint *errors)
+{
+ uint32 offset;
+ if (!needs_conversion(arg_length, from_cs, to_cs, &offset))
+ {
+ *errors= 0;
+ return copy(str, arg_length, to_cs);
+ }
+ if ((from_cs == &my_charset_bin) && offset)
+ {
+ *errors= 0;
+ return copy_aligned(str, arg_length, offset, to_cs);
}
- Ptr[new_length]=0;
- length((uint32) (d-(uchar *)Ptr));
- str_charset=to;
+ uint32 new_length= to_cs->mbmaxlen*arg_length;
+ if (alloc(new_length))
+ return TRUE;
+ str_length=copy_and_convert((char*) Ptr, new_length, to_cs,
+ str, arg_length, from_cs, errors);
+ str_charset=to_cs;
return FALSE;
}
+
+/*
+ Set a string to the value of a latin1-string, keeping the original charset
+
+ SYNOPSIS
+ copy_or_set()
+ str String of a simple charset (latin1)
+ arg_length Length of string
+
+ IMPLEMENTATION
+ If string object is of a simple character set, set it to point to the
+ given string.
+ If not, make a copy and convert it to the new character set.
+
+ RETURN
+ 0 ok
+ 1 Could not allocate result buffer
+
+*/
+
+bool String::set_ascii(const char *str, uint32 arg_length)
+{
+ if (str_charset->mbminlen == 1)
+ {
+ set(str, arg_length, str_charset);
+ return 0;
+ }
+ uint dummy_errors;
+ return copy(str, arg_length, &my_charset_latin1, str_charset, &dummy_errors);
+}
+
+
/* This is used by mysql.cc */
bool String::fill(uint32 max_length,char fill_char)
@@ -320,11 +421,34 @@ bool String::append(const String &s)
return FALSE;
}
+
+/*
+ Append an ASCII string to the a string of the current character set
+*/
+
bool String::append(const char *s,uint32 arg_length)
{
- if (!arg_length) // Default argument
- if (!(arg_length= (uint32) strlen(s)))
- return FALSE;
+ if (!arg_length)
+ return FALSE;
+
+ /*
+ For an ASCII incompatible string, e.g. UCS-2, we need to convert
+ */
+ if (str_charset->mbminlen > 1)
+ {
+ uint32 add_length=arg_length * str_charset->mbmaxlen;
+ uint dummy_errors;
+ if (realloc(str_length+ add_length))
+ return TRUE;
+ str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset,
+ s, arg_length, &my_charset_latin1,
+ &dummy_errors);
+ return FALSE;
+ }
+
+ /*
+ For an ASCII compatinble string we can just append.
+ */
if (realloc(str_length+arg_length))
return TRUE;
memcpy(Ptr+str_length,s,arg_length);
@@ -332,6 +456,46 @@ bool String::append(const char *s,uint32 arg_length)
return FALSE;
}
+
+/*
+ Append a 0-terminated ASCII string
+*/
+
+bool String::append(const char *s)
+{
+ return append(s, strlen(s));
+}
+
+
+/*
+ Append a string in the given charset to the string
+ with character set recoding
+*/
+
+bool String::append(const char *s,uint32 arg_length, CHARSET_INFO *cs)
+{
+ uint32 dummy_offset;
+
+ if (needs_conversion(arg_length, cs, str_charset, &dummy_offset))
+ {
+ uint32 add_length= arg_length / cs->mbminlen * str_charset->mbmaxlen;
+ uint dummy_errors;
+ if (realloc(str_length + add_length))
+ return TRUE;
+ str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset,
+ s, arg_length, cs, &dummy_errors);
+ }
+ else
+ {
+ if (realloc(str_length + arg_length))
+ return TRUE;
+ memcpy(Ptr + str_length, s, arg_length);
+ str_length+= arg_length;
+ }
+ return FALSE;
+}
+
+
#ifdef TO_BE_REMOVED
bool String::append(FILE* file, uint32 arg_length, myf my_flags)
{
@@ -360,48 +524,33 @@ bool String::append(IO_CACHE* file, uint32 arg_length)
return FALSE;
}
-uint32 String::numchars()
+bool String::append_with_prefill(const char *s,uint32 arg_length,
+ uint32 full_length, char fill_char)
{
-#ifdef USE_MB
- register uint32 n=0,mblen;
- register const char *mbstr=Ptr;
- register const char *end=mbstr+str_length;
- if (use_mb(str_charset))
+ int t_length= arg_length > full_length ? arg_length : full_length;
+
+ if (realloc(str_length + t_length))
+ return TRUE;
+ t_length= full_length - arg_length;
+ if (t_length > 0)
{
- while (mbstr < end) {
- if ((mblen=my_ismbchar(str_charset, mbstr,end))) mbstr+=mblen;
- else ++mbstr;
- ++n;
- }
- return n;
+ bfill(Ptr+str_length, t_length, fill_char);
+ str_length=str_length + t_length;
}
- else
-#endif
- return str_length;
+ append(s, arg_length);
+ return FALSE;
+}
+
+uint32 String::numchars()
+{
+ return str_charset->cset->numchars(str_charset, Ptr, Ptr+str_length);
}
int String::charpos(int i,uint32 offset)
{
-#ifdef USE_MB
- register uint32 mblen;
- register const char *mbstr=Ptr+offset;
- register const char *end=Ptr+str_length;
- if (use_mb(str_charset))
- {
- if (i<=0) return i;
- while (i && mbstr < end) {
- if ((mblen=my_ismbchar(str_charset, mbstr,end))) mbstr+=mblen;
- else ++mbstr;
- --i;
- }
- if ( INT_MAX32-i <= (int) (mbstr-Ptr-offset))
- return INT_MAX32;
- else
- return (int) ((mbstr-Ptr-offset)+i);
- }
- else
-#endif
+ if (i <= 0)
return i;
+ return str_charset->cset->charpos(str_charset,Ptr+offset,Ptr+str_length,i);
}
int String::strstr(const String &s,uint32 offset)
@@ -432,40 +581,6 @@ skip:
}
/*
- Search after a string without regarding to case
- This needs to be replaced when we have character sets per string
-*/
-
-int String::strstr_case(const String &s,uint32 offset)
-{
- if (s.length()+offset <= str_length)
- {
- if (!s.length())
- return ((int) offset); // Empty string is always found
-
- register const char *str = Ptr+offset;
- register const char *search=s.ptr();
- const char *end=Ptr+str_length-s.length()+1;
- const char *search_end=s.ptr()+s.length();
-skip:
- while (str != end)
- {
- if (str_charset->sort_order[*str++] == str_charset->sort_order[*search])
- {
- register char *i,*j;
- i=(char*) str; j=(char*) search+1;
- while (j != search_end)
- if (str_charset->sort_order[*i++] !=
- str_charset->sort_order[*j++])
- goto skip;
- return (int) (str-Ptr) -1;
- }
- }
- }
- return -1;
-}
-
-/*
** Search string from end. Offset is offset to the end of string
*/
@@ -504,14 +619,20 @@ skip:
bool String::replace(uint32 offset,uint32 arg_length,const String &to)
{
- long diff = (long) to.length()-(long) arg_length;
+ return replace(offset,arg_length,to.ptr(),to.length());
+}
+
+bool String::replace(uint32 offset,uint32 arg_length,
+ const char *to,uint32 length)
+{
+ long diff = (long) length-(long) arg_length;
if (offset+arg_length <= str_length)
{
if (diff < 0)
{
- if (to.length())
- memcpy(Ptr+offset,to.ptr(),to.length());
- bmove(Ptr+offset+to.length(),Ptr+offset+arg_length,
+ if (length)
+ memcpy(Ptr+offset,to,length);
+ bmove(Ptr+offset+length,Ptr+offset+arg_length,
str_length-offset-arg_length);
}
else
@@ -523,14 +644,15 @@ bool String::replace(uint32 offset,uint32 arg_length,const String &to)
bmove_upp(Ptr+str_length+diff,Ptr+str_length,
str_length-offset-arg_length);
}
- if (to.length())
- memcpy(Ptr+offset,to.ptr(),to.length());
+ if (length)
+ memcpy(Ptr+offset,to,length);
}
str_length+=(uint32) diff;
}
return FALSE;
}
+
// added by Holyfoot for "geometry" needs
int String::reserve(uint32 space_needed, uint32 grow_by)
{
@@ -542,9 +664,8 @@ int String::reserve(uint32 space_needed, uint32 grow_by)
return FALSE;
}
-void String::qs_append(const char *str)
+void String::qs_append(const char *str, uint32 len)
{
- int len = (int)strlen(str);
memcpy(Ptr + str_length, str, len + 1);
str_length += len;
}
@@ -552,8 +673,7 @@ void String::qs_append(const char *str)
void String::qs_append(double d)
{
char *buff = Ptr + str_length;
- sprintf(buff,"%.14g", d);
- str_length += (int)strlen(buff);
+ str_length+= my_sprintf(buff, (buff, "%.14g", d));
}
void String::qs_append(double *d)
@@ -563,90 +683,70 @@ void String::qs_append(double *d)
qs_append(ld);
}
-void String::qs_append(const char &c)
+void String::qs_append(int i)
{
- Ptr[str_length] = c;
- str_length += sizeof(c);
+ char *buff= Ptr + str_length;
+ char *end= int10_to_str(i, buff, -10);
+ str_length+= (int) (end-buff);
}
-
-int sortcmp(const String *x,const String *y)
+void String::qs_append(uint i)
{
- const char *s= x->ptr();
- const char *t= y->ptr();
- uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len);
-
- if (use_strnxfrm(x->str_charset))
- {
-#ifndef CMP_ENDSPACE
- while (x_len && my_isspace(x->str_charset,s[x_len-1]))
- x_len--;
- while (y_len && my_isspace(x->str_charset,t[y_len-1]))
- y_len--;
-#endif
- return my_strnncoll(x->str_charset,
- (unsigned char *)s,x_len,(unsigned char *)t,y_len);
- }
- else
- {
- x_len-=len; // For easy end space test
- y_len-=len;
- if (x->str_charset->sort_order)
- {
- while (len--)
- {
- if (x->str_charset->sort_order[(uchar) *s++] !=
- x->str_charset->sort_order[(uchar) *t++])
- return ((int) x->str_charset->sort_order[(uchar) s[-1]] -
- (int) x->str_charset->sort_order[(uchar) t[-1]]);
- }
- }
- else
- {
- while (len--)
- {
- if (*s++ != *t++)
- return ((int) s[-1] - (int) t[-1]);
- }
- }
-#ifndef CMP_ENDSPACE
- /* Don't compare end space in strings */
- {
- if (y_len)
- {
- const char *end=t+y_len;
- for (; t != end ; t++)
- if (!my_isspace(x->str_charset,*t))
- return -1;
- }
- else
- {
- const char *end=s+x_len;
- for (; s != end ; s++)
- if (!my_isspace(x->str_charset,*s))
- return 1;
- }
- return 0;
- }
-#else
- return (int) (x_len-y_len);
-#endif /* CMP_ENDSPACE */
- }
+ char *buff= Ptr + str_length;
+ char *end= int10_to_str(i, buff, 10);
+ str_length+= (int) (end-buff);
}
+/*
+ Compare strings according to collation, without end space.
+
+ SYNOPSIS
+ sortcmp()
+ s First string
+ t Second string
+ cs Collation
+
+ NOTE:
+ Normally this is case sensitive comparison
-int stringcmp(const String *x,const String *y)
+ RETURN
+ < 0 s < t
+ 0 s == t
+ > 0 s > t
+*/
+
+
+int sortcmp(const String *s,const String *t, CHARSET_INFO *cs)
{
- const char *s= x->ptr();
- const char *t= y->ptr();
- uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len);
+ return cs->coll->strnncollsp(cs,
+ (unsigned char *) s->ptr(),s->length(),
+ (unsigned char *) t->ptr(),t->length(), 0);
+}
- while (len--)
- {
- if (*s++ != *t++)
- return ((int) (uchar) s[-1] - (int) (uchar) t[-1]);
- }
- return (int) (x_len-y_len);
+
+/*
+ Compare strings byte by byte. End spaces are also compared.
+
+ SYNOPSIS
+ stringcmp()
+ s First string
+ t Second string
+
+ NOTE:
+ Strings are compared as a stream of unsigned chars
+
+ RETURN
+ < 0 s < t
+ 0 s == t
+ > 0 s > t
+*/
+
+
+int stringcmp(const String *s,const String *t)
+{
+ uint32 s_len=s->length(),t_len=t->length(),len=min(s_len,t_len);
+ int cmp= memcmp(s->ptr(), t->ptr(), len);
+ return (cmp) ? cmp : (int) (s_len - t_len);
}
@@ -668,4 +768,124 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length)
}
+/****************************************************************************
+ Help functions
+****************************************************************************/
+/*
+ copy a string from one character set to another
+
+ SYNOPSIS
+ copy_and_convert()
+ to Store result here
+ to_cs Character set of result string
+ from Copy from here
+ from_length Length of from string
+ from_cs From character set
+
+ NOTES
+ 'to' must be big enough as form_length * to_cs->mbmaxlen
+
+ RETURN
+ length of bytes copied to 'to'
+*/
+
+
+uint32
+copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
+ const char *from, uint32 from_length, CHARSET_INFO *from_cs,
+ uint *errors)
+{
+ int cnvres;
+ my_wc_t wc;
+ 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;
+ uint error_count= 0;
+
+ while (1)
+ {
+ if ((cnvres= (*mb_wc)(from_cs, &wc, (uchar*) from,
+ from_end)) > 0)
+ from+= cnvres;
+ else if (cnvres == MY_CS_ILSEQ)
+ {
+ error_count++;
+ from++;
+ wc= '?';
+ }
+ else
+ break; // Impossible char.
+
+outp:
+ if ((cnvres= (*wc_mb)(to_cs, wc, (uchar*) to, to_end)) > 0)
+ to+= cnvres;
+ else if (cnvres == MY_CS_ILUNI && wc != '?')
+ {
+ error_count++;
+ wc= '?';
+ goto outp;
+ }
+ else
+ break;
+ }
+ *errors= error_count;
+ return (uint32) (to - to_start);
+}
+
+
+void String::print(String *str)
+{
+ char *st= (char*)Ptr, *end= st+str_length;
+ for (; st < end; st++)
+ {
+ uchar c= *st;
+ switch (c)
+ {
+ case '\\':
+ str->append("\\\\", 2);
+ break;
+ case '\0':
+ str->append("\\0", 2);
+ break;
+ case '\'':
+ str->append("\\'", 2);
+ break;
+ case '\n':
+ str->append("\\n", 2);
+ break;
+ case '\r':
+ str->append("\\r", 2);
+ break;
+ case 26: //Ctrl-Z
+ str->append("\\z", 2);
+ break;
+ default:
+ str->append(c);
+ }
+ }
+}
+
+
+/*
+ Exchange state of this object and argument.
+
+ SYNOPSIS
+ String::swap()
+
+ RETURN
+ Target string will contain state of this object and vice versa.
+*/
+
+void String::swap(String &s)
+{
+ swap_variables(char *, Ptr, s.Ptr);
+ swap_variables(uint32, str_length, s.str_length);
+ swap_variables(uint32, Alloced_length, s.Alloced_length);
+ swap_variables(bool, alloced, s.alloced);
+ swap_variables(CHARSET_INFO*, str_charset, s.str_charset);
+}
diff --git a/client/sql_string.h b/client/sql_string.h
index fd6d3ef59d9..0e0d2452297 100644
--- a/client/sql_string.h
+++ b/client/sql_string.h
@@ -2,8 +2,7 @@
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; either version 2 of the License, or
- (at your option) any later version.
+ 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
@@ -25,9 +24,11 @@
#endif
class String;
-int sortcmp(const String *a,const String *b);
-int stringcmp(const String *a,const String *b);
+int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
+uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
+ const char *from, uint32 from_length,
+ CHARSET_INFO *from_cs, uint *errors);
class String
{
@@ -39,12 +40,12 @@ public:
String()
{
Ptr=0; str_length=Alloced_length=0; alloced=0;
- str_charset= &my_charset_latin1;
+ str_charset= &my_charset_bin;
}
String(uint32 length_arg)
{
alloced=0; Alloced_length=0; (void) real_alloc(length_arg);
- str_charset= &my_charset_latin1;
+ str_charset= &my_charset_bin;
}
String(const char *str, CHARSET_INFO *cs)
{
@@ -67,12 +68,15 @@ public:
Alloced_length=str.Alloced_length; alloced=0;
str_charset=str.str_charset;
}
- static void *operator new(size_t size) { return (void*) sql_alloc((uint) size); }
- static void operator delete(void *ptr_arg,size_t size) /*lint -e715 */
- { sql_element_free(ptr_arg); }
+ static void *operator new(size_t size, MEM_ROOT *mem_root)
+ { return (void*) alloc_root(mem_root, (uint) size); }
+ static void operator delete(void *ptr_arg,size_t size)
+ { TRASH(ptr_arg, size); }
+ static void operator delete(void *ptr_arg, MEM_ROOT *mem_root)
+ { /* never called */ }
~String() { free(); }
- inline void set_charset(CHARSET_INFO *charset) { str_charset=charset; }
+ inline void set_charset(CHARSET_INFO *charset) { str_charset= charset; }
inline CHARSET_INFO *charset() const { return str_charset; }
inline uint32 length() const { return str_length;}
inline uint32 alloced_length() const { return Alloced_length;}
@@ -103,6 +107,7 @@ public:
void set(String &str,uint32 offset,uint32 arg_length)
{
+ DBUG_ASSERT(&str != this);
free();
Ptr=(char*) str.ptr()+offset; str_length=arg_length; alloced=0;
if (str.Alloced_length)
@@ -123,6 +128,7 @@ public:
Ptr=(char*) str; str_length=arg_length; Alloced_length=0 ; alloced=0;
str_charset=cs;
}
+ bool set_ascii(const char *str, uint32 arg_length);
inline void set_quick(char *str,uint32 arg_length, CHARSET_INFO *cs)
{
if (!alloced)
@@ -134,6 +140,34 @@ public:
bool set(longlong num, CHARSET_INFO *cs);
bool set(ulonglong num, CHARSET_INFO *cs);
bool set(double num,uint decimals, CHARSET_INFO *cs);
+
+ /*
+ PMG 2004.11.12
+ This is a method that works the same as perl's "chop". It simply
+ drops the last character of a string. This is useful in the case
+ of the federated storage handler where I'm building a unknown
+ number, list of values and fields to be used in a sql insert
+ statement to be run on the remote server, and have a comma after each.
+ When the list is complete, I "chop" off the trailing comma
+
+ ex.
+ String stringobj;
+ stringobj.append("VALUES ('foo', 'fi', 'fo',");
+ stringobj.chop();
+ stringobj.append(")");
+
+ In this case, the value of string was:
+
+ VALUES ('foo', 'fi', 'fo',
+ VALUES ('foo', 'fi', 'fo'
+ VALUES ('foo', 'fi', 'fo')
+
+ */
+ inline void chop()
+ {
+ Ptr[str_length--]= '\0';
+ }
+
inline void free()
{
if (alloced)
@@ -175,6 +209,11 @@ public:
{
if (&s != this)
{
+ /*
+ It is forbidden to do assignments like
+ some_string = substring_of_that_string
+ */
+ DBUG_ASSERT(!s.uses_buffer_owned_by(this));
free();
Ptr=s.Ptr ; str_length=s.str_length ; Alloced_length=s.Alloced_length;
alloced=0;
@@ -185,13 +224,24 @@ public:
bool copy(); // Alloc string if not alloced
bool copy(const String &s); // Allocate new string
bool copy(const char *s,uint32 arg_length, CHARSET_INFO *cs); // Allocate new string
- bool copy(const char*s,uint32 arg_length, CHARSET_INFO *csfrom, CHARSET_INFO *csto);
+ static bool needs_conversion(uint32 arg_length,
+ CHARSET_INFO *cs_from, CHARSET_INFO *cs_to,
+ uint32 *offset);
+ bool copy_aligned(const char *s, uint32 arg_length, uint32 offset,
+ CHARSET_INFO *cs);
+ bool set_or_copy_aligned(const char *s, uint32 arg_length, CHARSET_INFO *cs);
+ bool copy(const char*s,uint32 arg_length, CHARSET_INFO *csfrom,
+ CHARSET_INFO *csto, uint *errors);
bool append(const String &s);
- bool append(const char *s,uint32 arg_length=0);
+ bool append(const char *s);
+ bool append(const char *s,uint32 arg_length);
+ bool append(const char *s,uint32 arg_length, CHARSET_INFO *cs);
bool append(IO_CACHE* file, uint32 arg_length);
+ bool append_with_prefill(const char *s, uint32 arg_length,
+ uint32 full_length, char fill_char);
int strstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
- int strstr_case(const String &s,uint32 offset=0);
int strrstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
+ bool replace(uint32 offset,uint32 arg_length,const char *to,uint32 length);
bool replace(uint32 offset,uint32 arg_length,const String &to);
inline bool append(char chr)
{
@@ -209,9 +259,7 @@ public:
}
bool fill(uint32 max_length,char fill);
void strip_sp();
- inline void caseup() { my_caseup(str_charset,Ptr,str_length); }
- inline void casedn() { my_casedn(str_charset,Ptr,str_length); }
- friend int sortcmp(const String *a,const String *b);
+ friend int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
friend int stringcmp(const String *a,const String *b);
friend String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
uint32 numchars();
@@ -228,11 +276,11 @@ public:
q_*** methods writes values of parameters itself
qs_*** methods writes string representation of value
*/
- void q_append(const char &c)
+ void q_append(const char c)
{
Ptr[str_length++] = c;
}
- void q_append(const uint32 &n)
+ void q_append(const uint32 n)
{
int4store(Ptr + str_length, n);
str_length += 4;
@@ -253,13 +301,53 @@ public:
str_length += data_len;
}
- void WriteAtPosition(int position, uint32 value)
+ void write_at_position(int position, uint32 value)
{
int4store(Ptr + position,value);
}
- void qs_append(const char *str);
+ void qs_append(const char *str, uint32 len);
void qs_append(double d);
void qs_append(double *d);
- void qs_append(const char &c);
+ inline void qs_append(const char c)
+ {
+ Ptr[str_length]= c;
+ str_length++;
+ }
+ void qs_append(int i);
+ void qs_append(uint i);
+
+ /* Inline (general) functions used by the protocol functions */
+
+ inline char *prep_append(uint32 arg_length, uint32 step_alloc)
+ {
+ uint32 new_length= arg_length + str_length;
+ if (new_length > Alloced_length)
+ {
+ if (realloc(new_length + step_alloc))
+ return 0;
+ }
+ uint32 old_length= str_length;
+ str_length+= arg_length;
+ return Ptr+ old_length; /* Area to use */
+ }
+
+ inline bool append(const char *s, uint32 arg_length, uint32 step_alloc)
+ {
+ uint32 new_length= arg_length + str_length;
+ if (new_length > Alloced_length && realloc(new_length + step_alloc))
+ return TRUE;
+ memcpy(Ptr+str_length, s, arg_length);
+ str_length+= arg_length;
+ return FALSE;
+ }
+ void print(String *print);
+
+ /* Swap two string objects. Efficient way to exchange data without memcpy. */
+ void swap(String &s);
+
+ inline bool uses_buffer_owned_by(const String *s) const
+ {
+ return (s->alloced && Ptr >= s->Ptr && Ptr < s->Ptr + s->str_length);
+ }
};