summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/Makefile.am30
-rw-r--r--client/client_priv.h1
-rw-r--r--client/completion_hash.cc3
-rw-r--r--client/mysql.cc82
-rw-r--r--client/mysqladmin.cc46
-rw-r--r--client/mysqlbinlog.cc38
-rw-r--r--client/mysqlcheck.c2
-rw-r--r--client/mysqldump.c182
-rw-r--r--client/mysqltest.c484
9 files changed, 667 insertions, 201 deletions
diff --git a/client/Makefile.am b/client/Makefile.am
index 95000fff5c5..d3307f9da42 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -18,10 +18,10 @@
#AUTOMAKE_OPTIONS = nostdinc
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/regex \
- $(openssl_includes) -I$(top_srcdir)/extra
+ $(openssl_includes) -I$(top_builddir)/include
LIBS = @CLIENT_LIBS@
-DEPLIB= ../libmysql/libmysqlclient.la
-LDADD = @CLIENT_EXTRA_LDFLAGS@ $(DEPLIB)
+LDADD= @CLIENT_EXTRA_LDFLAGS@ \
+ $(top_builddir)/libmysql/libmysqlclient.la
bin_PROGRAMS = mysql mysqladmin mysqlcheck mysqlshow \
mysqldump mysqlimport mysqltest mysqlbinlog mysqlmanagerc mysqlmanager-pwgen
noinst_HEADERS = sql_string.h completion_hash.h my_readline.h \
@@ -30,20 +30,12 @@ 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)
-mysql_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB)
-mysqladmin_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB)
-mysqlcheck_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB)
-mysqlshow_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB)
-mysqldump_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB)
-mysqlimport_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB)
-mysqltest_SOURCES= mysqltest.c ../mysys/my_getsystime.c
-mysqltest_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB)
-mysqltest_LDADD = $(LDADD) $(top_builddir)/regex/libregex.a
-mysqlbinlog_SOURCES = mysqlbinlog.cc ../mysys/mf_tempdir.c
-mysqlbinlog_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB)
+mysqltest_SOURCES= mysqltest.c $(top_srcdir)/mysys/my_getsystime.c
+mysqltest_LDADD = $(top_builddir)/regex/libregex.a $(LDADD)
+mysqlbinlog_SOURCES = mysqlbinlog.cc $(top_srcdir)/mysys/mf_tempdir.c
mysqlmanagerc_SOURCES = mysqlmanagerc.c
-mysqlmanagerc_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB)
-sql_src=log_event.h mysql_priv.h log_event.cc
+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
@@ -52,7 +44,11 @@ link_sources:
for f in $(sql_src) ; do \
rm -f $(srcdir)/$$f; \
@LN_CP_F@ $(top_srcdir)/sql/$$f $(srcdir)/$$f; \
- done;
+ done; \
+ for f in $(strings_src) ; do \
+ rm -f $(srcdir)/$$f; \
+ @LN_CP_F@ $(top_srcdir)/strings/$$f $(srcdir)/$$f; \
+ done;
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/client/client_priv.h b/client/client_priv.h
index e86a56f58c1..95f4d105156 100644
--- a/client/client_priv.h
+++ b/client/client_priv.h
@@ -49,4 +49,5 @@ enum options_client
#ifdef HAVE_NDBCLUSTER_DB
,OPT_NDBCLUSTER,OPT_NDB_CONNECTSTRING
#endif
+ ,OPT_IGNORE_TABLE
};
diff --git a/client/completion_hash.cc b/client/completion_hash.cc
index 536e7f9373a..7a3b363c93c 100644
--- a/client/completion_hash.cc
+++ b/client/completion_hash.cc
@@ -79,7 +79,8 @@ int completion_hash_update(HashTable *ht, char *arKey, uint nKeyLength,
if (!memcmp(p->arKey, arKey, nKeyLength)) {
entry *n;
- n = (entry *) alloc_root(&ht->mem_root,sizeof(entry));
+ if (!(n = (entry *) alloc_root(&ht->mem_root,sizeof(entry))))
+ return FAILURE;
n->pNext = p->pData;
n->str = str;
p->pData = n;
diff --git a/client/mysql.cc b/client/mysql.cc
index cb3a56972fa..e387bb26063 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -44,7 +44,7 @@
#include <locale.h>
#endif
-const char *VER= "14.7";
+const char *VER= "14.8";
/* Don't try to make a nice table if the data is too big */
#define MAX_COLUMN_LENGTH 1024
@@ -144,6 +144,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 +155,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"};
@@ -172,7 +175,7 @@ static char *shared_memory_base_name=0;
#endif
static uint opt_protocol=0;
static CHARSET_INFO *charset_info= &my_charset_latin1;
-
+
#include "sslopt-vars.h"
const char *default_dbug_option="d:t:o,/tmp/mysql.trace";
@@ -330,6 +333,16 @@ static sig_handler mysql_end(int sig);
int main(int argc,char *argv[])
{
char buff[80];
+ char *defaults, *extra_defaults;
+ char *emb_argv[3];
+ int emb_argc= 1;
+
+ 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;
MY_INIT(argv[0]);
DBUG_ENTER("main");
@@ -375,7 +388,7 @@ int main(int argc,char *argv[])
my_end(0);
exit(1);
}
- if (mysql_server_init(0, NULL, (char**) server_default_groups))
+ if (mysql_server_init(emb_argc, emb_argv, (char**) server_default_groups))
{
free_defaults(defaults_argv);
my_end(0);
@@ -432,6 +445,13 @@ int main(int argc,char *argv[])
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
@@ -460,7 +480,8 @@ sig_handler mysql_end(int sig)
/* 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);
@@ -475,6 +496,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));
@@ -1420,12 +1442,6 @@ static void build_completion_hash(bool rehash, bool write_info)
if (status.batch || quick || !current_db)
DBUG_VOID_RETURN; // We don't need completion in batches
- if (tables)
- {
- mysql_free_result(tables);
- tables=0;
- }
-
/* hash SQL commands */
while (cmd->name) {
add_word(&ht,(char*) cmd->name);
@@ -1502,12 +1518,15 @@ You can turn off this feature to get a quicker startup with -A\n\n");
if (!(field_names[i] = (char **) alloc_root(&hash_mem_root,
sizeof(char *) *
(num_fields*2+1))))
- break;
+ {
+ mysql_free_result(fields);
+ break;
+ }
field_names[i][num_fields*2]= '\0';
j=0;
while ((sql_field=mysql_fetch_field(fields)))
{
- sprintf(buf,"%s.%s",table_row[0],sql_field->name);
+ sprintf(buf,"%.64s.%.64s",table_row[0],sql_field->name);
field_names[i][j] = strdup_root(&hash_mem_root,buf);
add_word(&ht,field_names[i][j]);
field_names[i][num_fields+j] = strdup_root(&hash_mem_root,
@@ -1584,7 +1603,7 @@ int mysql_real_query_for_lazy(const char *buf, int length)
for (uint retry=0;; retry++)
{
if (!mysql_real_query(&mysql,buf,length))
- return 0;
+ return 0;
int error= put_error(&mysql);
if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1 ||
!opt_reconnect)
@@ -1668,8 +1687,8 @@ static int com_server_help(String *buffer __attribute__((unused)),
else if (num_fields >= 2 && num_rows)
{
init_pager();
- char last_char;
-
+ char last_char= 0;
+
int num_name= 0, num_cat= 0;
LINT_INIT(num_name);
LINT_INIT(num_cat);
@@ -1677,20 +1696,19 @@ static int com_server_help(String *buffer __attribute__((unused)),
if (num_fields == 2)
{
put_info("Many help items for your request exist.", INFO_INFO);
- put_info("To make a more specific request, please type 'help <item>',\nwhere item is one of the following", INFO_INFO);
+ put_info("To make a more specific request, please type 'help <item>',\nwhere <item> is one of the following", INFO_INFO);
num_name= 0;
num_cat= 1;
- last_char= '_';
}
else if ((cur= mysql_fetch_row(result)))
{
tee_fprintf(PAGER, "You asked for help about help category: \"%s\"\n", cur[0]);
- put_info("For more information, type 'help <item>', where item is one of the following", INFO_INFO);
+ put_info("For more information, type 'help <item>', where <item> is one of the following", INFO_INFO);
num_name= 1;
num_cat= 2;
print_help_item(&cur,1,2,&last_char);
}
-
+
while ((cur= mysql_fetch_row(result)))
print_help_item(&cur,num_name,num_cat,&last_char);
tee_fprintf(PAGER, "\n");
@@ -2077,10 +2095,10 @@ print_table_data_html(MYSQL_RES *result)
}
while ((cur = mysql_fetch_row(result)))
{
+ ulong *lengths=mysql_fetch_lengths(result);
(void) tee_fputs("<TR>", PAGER);
for (uint i=0; i < mysql_num_fields(result); i++)
{
- ulong *lengths=mysql_fetch_lengths(result);
(void) tee_fputs("<TD>", PAGER);
safe_put_field(cur[i],lengths[i]);
(void) tee_fputs("</TD>", PAGER);
@@ -2106,17 +2124,15 @@ print_table_data_xml(MYSQL_RES *result)
fields = mysql_fetch_fields(result);
while ((cur = mysql_fetch_row(result)))
{
+ ulong *lengths=mysql_fetch_lengths(result);
(void) tee_fputs("\n <row>\n", PAGER);
for (uint i=0; i < mysql_num_fields(result); i++)
{
- ulong *lengths=mysql_fetch_lengths(result);
- tee_fprintf(PAGER, "\t<%s>", (fields[i].name ?
- (fields[i].name[0] ? fields[i].name :
- " &nbsp; ") : "NULL"));
+ tee_fprintf(PAGER, "\t<field name=\"");
+ xmlencode_print(fields[i].name, strlen(fields[i].name));
+ tee_fprintf(PAGER, "\">");
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, "</field>\n");
}
(void) tee_fputs(" </row>\n", PAGER);
}
@@ -2513,7 +2529,7 @@ com_connect(String *buffer, char *line)
{
sprintf(buff,"Connection id: %lu",mysql_thread_id(&mysql));
put_info(buff,INFO_INFO);
- sprintf(buff,"Current database: %s\n",
+ sprintf(buff,"Current database: %.128s\n",
current_db ? current_db : "*** NONE ***");
put_info(buff,INFO_INFO);
}
@@ -3221,13 +3237,20 @@ static const char* construct_prompt()
break;
}
case 'p':
+ {
#ifndef EMBEDDED_LIBRARY
if (!connected)
{
processed_prompt.append("not_connected");
break;
}
- if (strstr(mysql_get_host_info(&mysql),"TCP/IP") ||
+
+ const char *host_info = mysql_get_host_info(&mysql);
+ if (strstr(host_info, "memory"))
+ {
+ processed_prompt.append( mysql.host );
+ }
+ else if (strstr(host_info,"TCP/IP") ||
!mysql.unix_socket)
add_int_to_prompt(mysql.port);
else
@@ -3236,6 +3259,7 @@ static const char* construct_prompt()
processed_prompt.append(pos ? pos+1 : mysql.unix_socket);
}
#endif
+ }
break;
case 'U':
if (!full_username)
diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc
index 21e8f6ab3e4..24fe14b6675 100644
--- a/client/mysqladmin.cc
+++ b/client/mysqladmin.cc
@@ -33,7 +33,8 @@
#define SHUTDOWN_DEF_TIMEOUT 3600 /* Wait for shutdown */
#define MAX_TRUNC_LENGTH 3
-char *host= NULL, *user= 0, *opt_password= 0;
+char *host= NULL, *user= 0, *opt_password= 0,
+ *default_charset= NULL;
char truncated_var_names[MAX_MYSQL_VAR][MAX_TRUNC_LENGTH];
char ex_var_names[MAX_MYSQL_VAR][FN_REFLEN];
ulonglong last_values[MAX_MYSQL_VAR];
@@ -145,6 +146,9 @@ static struct my_option my_long_options[] =
{"character-sets-dir", OPT_CHARSETS_DIR,
"Directory where character sets are.", (gptr*) &charsets_dir,
(gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"default-character-set", OPT_DEFAULT_CHARSET,
+ "Set the default character set.", (gptr*) &default_charset,
+ (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0},
{"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0, GET_STR,
@@ -343,6 +347,8 @@ int main(int argc,char *argv[])
if (shared_memory_base_name)
mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
#endif
+ if (default_charset)
+ mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset);
if (sql_connect(&mysql, option_wait))
{
unsigned int err= mysql_errno(&mysql);
@@ -827,13 +833,48 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
if (argv[1][0])
{
char *pw= argv[1];
+ bool old= (find_type(argv[0], &command_typelib, 2) ==
+ ADMIN_OLD_PASSWORD);
#ifdef __WIN__
uint pw_len= strlen(pw);
if (pw_len > 1 && pw[0] == '\'' && pw[pw_len-1] == '\'')
printf("Warning: single quotes were not trimmed from the password by"
" your command\nline client, as you might have expected.\n");
#endif
- if (find_type(argv[0], &command_typelib, 2) == ADMIN_OLD_PASSWORD)
+ /*
+ If we don't already know to use an old-style password, see what
+ the server is using
+ */
+ if (!old)
+ {
+ if (mysql_query(mysql, "SHOW VARIABLES LIKE 'old_passwords'"))
+ {
+ my_printf_error(0, "Could not determine old_passwords setting from server; error: '%s'",
+ MYF(ME_BELL),mysql_error(mysql));
+ return -1;
+ }
+ else
+ {
+ MYSQL_RES *res= mysql_store_result(mysql);
+ if (!res)
+ {
+ my_printf_error(0,
+ "Could not get old_passwords setting from "
+ "server; error: '%s'",
+ MYF(ME_BELL),mysql_error(mysql));
+ return -1;
+ }
+ if (!mysql_num_rows(res))
+ old= 1;
+ else
+ {
+ MYSQL_ROW row= mysql_fetch_row(res);
+ old= !strncmp(row[1], "ON", 2);
+ }
+ mysql_free_result(res);
+ }
+ }
+ if (old)
make_scrambled_password_323(crypted_pw, pw);
else
make_scrambled_password(crypted_pw, pw);
@@ -968,6 +1009,7 @@ static void usage(void)
print_defaults("my",load_default_groups);
puts("\nWhere command is a one or more of: (Commands may be shortened)\n\
create databasename Create a new database\n\
+ debug Instruct server to write debug information to log\n\
drop databasename Delete a database and all its tables\n\
extended-status Gives an extended status message from the server\n\
flush-hosts Flush all cached hosts\n\
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index fd5fd88c58d..cedf837c9ab 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -488,6 +488,15 @@ end:
static struct my_option my_long_options[] =
{
+ /*
+ 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},
@@ -744,7 +753,7 @@ static int parse_args(int *argc, char*** argv)
static MYSQL* safe_connect()
{
- MYSQL *local_mysql = mysql_init(NULL);
+ MYSQL *local_mysql= mysql_init(NULL);
if (!local_mysql)
die("Failed on mysql_init");
@@ -752,9 +761,13 @@ static MYSQL* safe_connect()
if (opt_protocol)
mysql_options(local_mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol);
if (!mysql_real_connect(local_mysql, host, user, pass, 0, port, sock, 0))
- die("failed on connect: %s", mysql_error(local_mysql));
+ {
+ char errmsg[256];
+ strmake(errmsg, mysql_error(local_mysql), sizeof(errmsg)-1);
+ mysql_close(local_mysql);
+ die("failed on connect: %s", errmsg);
+ }
local_mysql->reconnect= 1;
-
return local_mysql;
}
@@ -781,9 +794,10 @@ static int check_master_version(MYSQL* mysql,
if (mysql_query(mysql, "SELECT VERSION()") ||
!(res = mysql_store_result(mysql)))
{
+ char errmsg[256];
+ strmake(errmsg, mysql_error(mysql), sizeof(errmsg)-1);
mysql_close(mysql);
- die("Error checking master version: %s",
- mysql_error(mysql));
+ die("Error checking master version: %s", errmsg);
}
if (!(row = mysql_fetch_row(res)))
{
@@ -1116,15 +1130,15 @@ static int dump_local_log_entries(const char* logname)
}
check_header(file, &description_event);
}
- else // reading from stdin; TODO: check that it works
+ else // reading from stdin;
{
- if (init_io_cache(file, fileno(result_file), 0, READ_CACHE, (my_off_t) 0,
+ if (init_io_cache(file, fileno(stdin), 0, READ_CACHE, (my_off_t) 0,
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
return 1;
check_header(file, &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)
@@ -1137,8 +1151,6 @@ static int dump_local_log_entries(const char* logname)
}
}
}
- file->pos_in_file= start_position_mot;
- file->seek_not_done=0;
}
if (!description_event || !description_event->is_valid())
@@ -1273,8 +1285,14 @@ int main(int argc, char** argv)
*/
#ifdef __WIN__
+#include "my_decimal.h"
+#include "decimal.c"
+#include "my_decimal.cpp"
#include "log_event.cpp"
#else
+#include "my_decimal.h"
+#include "decimal.c"
+#include "my_decimal.cc"
#include "log_event.cc"
#endif
diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c
index 980046fe6e6..15be51853cd 100644
--- a/client/mysqlcheck.c
+++ b/client/mysqlcheck.c
@@ -195,7 +195,7 @@ static void usage(void)
puts("and you are welcome to modify and redistribute it under the GPL license.\n");
puts("This program can be used to CHECK (-c,-m,-C), REPAIR (-r), ANALYZE (-a)");
puts("or OPTIMIZE (-o) tables. Some of the options (like -e or -q) can be");
- puts("used at the same time. It works on MyISAM and in some cases on BDB tables.");
+ puts("used at the same time. Not all options are supported by all storage engines.");
puts("Please consult the MySQL manual for latest information about the");
puts("above. The options -c,-r,-a and -o are exclusive to each other, which");
puts("means that the last option will be used, if several was specified.\n");
diff --git a/client/mysqldump.c b/client/mysqldump.c
index 8fb48753a8c..c2b07e2ec20 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -43,6 +43,7 @@
#include <my_sys.h>
#include <m_string.h>
#include <m_ctype.h>
+#include <hash.h>
#include "client_priv.h"
#include "mysql.h"
@@ -105,7 +106,14 @@ FILE *md_result_file;
static char *shared_memory_base_name=0;
#endif
static uint opt_protocol= 0;
-static char *default_charset= (char*) MYSQL_UNIVERSAL_CLIENT_CHARSET;
+/*
+ Constant for detection of default value of default_charset.
+ If default_charset is equal to mysql_universal_client_charset, then
+ it is the default value which assigned at the very beginning of main().
+*/
+static const char *mysql_universal_client_charset=
+ 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";
/* do we met VIEWs during tables scaning */
@@ -130,6 +138,15 @@ const char *compatible_mode_names[]=
TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1,
"", compatible_mode_names, NULL};
+#define TABLE_RULE_HASH_SIZE 16
+
+typedef struct st_table_rule_ent
+{
+ char* key; /* dbname.tablename */
+ uint key_len;
+} TABLE_RULE_ENT;
+
+HASH ignore_table;
static struct my_option my_long_options[] =
{
@@ -160,7 +177,7 @@ static struct my_option my_long_options[] =
(gptr*) &opt_compatible_mode_str, (gptr*) &opt_compatible_mode_str, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"compact", OPT_COMPACT,
- "Give less verbose output (useful for debugging). Disables structure comments and header/footer constructs. Enables options --skip-add-drop-table --no-set-names --skip-disable-keys --skip-lock-tables",
+ "Give less verbose output (useful for debugging). Disables structure comments and header/footer constructs. Enables options --skip-add-drop-table --no-set-names --skip-disable-keys --skip-add-locks",
(gptr*) &opt_compact, (gptr*) &opt_compact, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0},
{"complete-insert", 'c', "Use complete insert statements.", (gptr*) &cFlag,
@@ -235,6 +252,11 @@ static struct my_option my_long_options[] =
(gptr*) &opt_hex_blob, (gptr*) &opt_hex_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"host", 'h', "Connect to host.", (gptr*) &current_host,
(gptr*) &current_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"ignore-table", OPT_IGNORE_TABLE,
+ "Do not dump the specified table. To specify more than one table to ignore, "
+ "use the directive multiple times, once for each table. Each table must "
+ "be specified with both database and table names, e.g. --ignore-table=database.table",
+ 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"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},
@@ -283,6 +305,9 @@ static struct my_option my_long_options[] =
{"opt", OPT_OPTIMIZE,
"Same as --add-drop-table, --add-locks, --create-options, --quick, --extended-insert, --lock-tables, --set-charset, and --disable-keys. Enabled by default, disable with --skip-opt.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"order-by-primary", OPT_ORDER_BY_PRIMARY,
+ "Sorts each table's rows by primary key, or first unique key, if such a key exists. Useful when dumping a MyISAM table to be loaded into an InnoDB table, but will make the dump itself take considerably longer.",
+ (gptr*) &opt_order_by_primary, (gptr*) &opt_order_by_primary, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"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},
@@ -334,9 +359,6 @@ static struct my_option my_long_options[] =
{"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},
- {"order-by-primary", OPT_ORDER_BY_PRIMARY,
- "Sorts each table's rows by primary key, or first unique key, if such a key exists. Useful when dumping a MyISAM table to be loaded into an InnoDB table, but will make the dump itself take considerably longer.",
- (gptr*) &opt_order_by_primary, (gptr*) &opt_order_by_primary, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#include <sslopt-longopts.h>
{"tab",'T',
"Creates tab separated textfile for each table to given path. (creates .sql and .txt files). NOTE: This only works if mysqldump is run on the same machine as the mysqld daemon.",
@@ -471,7 +493,7 @@ 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",
+ "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='%s%s%s' */;\n",
path?"":"NO_AUTO_VALUE_ON_ZERO",compatible_mode_normal_str[0]==0?"":",",
compatible_mode_normal_str);
check_io(sql_file);
@@ -506,6 +528,28 @@ static void write_footer(FILE *sql_file)
} /* write_footer */
+static void free_table_ent(TABLE_RULE_ENT* e)
+{
+ my_free((gptr) e, MYF(0));
+}
+
+
+static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
+ my_bool not_used __attribute__((unused)))
+{
+ *len= e->key_len;
+ return (byte*)e->key;
+}
+
+
+void init_table_rule_hash(HASH* h)
+{
+ if(hash_init(h, charset_info, TABLE_RULE_HASH_SIZE, 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)),
@@ -577,8 +621,32 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case (int) OPT_TABLES:
opt_databases=0;
break;
+ case (int) OPT_IGNORE_TABLE:
+ {
+ uint len= (uint)strlen(argument);
+ TABLE_RULE_ENT* e;
+ if (!strchr(argument, '.'))
+ {
+ fprintf(stderr, "Illegal use of option --ignore-table=<database>.<table>\n");
+ exit(1);
+ }
+ /* len is always > 0 because we know the there exists a '.' */
+ e= (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT) + len, MYF(MY_WME));
+ if (!e)
+ exit(EX_EOM);
+ e->key= (char*)e + sizeof(TABLE_RULE_ENT);
+ e->key_len= len;
+ memcpy(e->key, argument, len);
+
+ if (!hash_inited(&ignore_table))
+ init_table_rule_hash(&ignore_table);
+
+ if(my_hash_insert(&ignore_table, (byte*)e))
+ exit(EX_EOM);
+ break;
+ }
case (int) OPT_COMPATIBLE:
- {
+ {
char buff[255];
char *end= compatible_mode_normal_str;
int i;
@@ -617,6 +685,12 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
}
if (end!=compatible_mode_normal_str)
end[-1]= 0;
+ /*
+ Set charset to the default compiled value if it hasn't
+ been reset yet by --default-character-set=xxx.
+ */
+ if (default_charset == mysql_universal_client_charset)
+ default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
break;
}
case (int) OPT_MYSQL_PROTOCOL:
@@ -793,7 +867,7 @@ static int dbConnect(char *host, char *user,char *passwd)
cannot reconnect.
*/
sock->reconnect= 0;
- sprintf(buff, "/*!40100 SET @@SQL_MODE=\"%s\" */",
+ sprintf(buff, "/*!40100 SET @@SQL_MODE='%s' */",
compatible_mode_normal_str);
if (mysql_query_with_error_report(sock, 0, buff))
{
@@ -1848,8 +1922,6 @@ static void dumpTable(uint numFields, char *table)
err:
if (query != query_buf)
my_free(query, MYF(MY_ALLOW_ZERO_PTR));
- if (order_by)
- my_free(order_by, MYF(0));
safe_exit(error);
return;
} /* dumpTable */
@@ -1967,7 +2039,7 @@ static int init_dumping(char *database)
sprintf(qbuf,"SHOW CREATE DATABASE IF NOT EXISTS %s",
qdatabase);
- if (mysql_query_with_error_report(sock, &dbinfo, qbuf))
+ if (mysql_query(sock, qbuf) || !(dbinfo = mysql_store_result(sock)))
{
/* Old server version, dump generic CREATE DATABASE */
fprintf(md_result_file,
@@ -1993,6 +2065,14 @@ static int init_dumping(char *database)
} /* init_dumping */
+my_bool include_table(byte* hash_key, uint len)
+{
+ if (hash_search(&ignore_table, (byte*) hash_key, len))
+ return FALSE;
+
+ return TRUE;
+}
+
static int dump_all_tables_in_db(char *database)
{
@@ -2000,6 +2080,12 @@ static int dump_all_tables_in_db(char *database)
uint numrows;
char table_buff[NAME_LEN*2+3];
+ char hash_key[2*NAME_LEN+2]; /* "db.tablename" */
+ char *afterdot;
+
+ afterdot= strmov(hash_key, database);
+ *afterdot++= '.';
+
if (init_dumping(database))
return 1;
if (opt_xml)
@@ -2008,7 +2094,7 @@ static int dump_all_tables_in_db(char *database)
{
DYNAMIC_STRING query;
init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
- for (numrows=0 ; (table = getTableName(1)) ; numrows++)
+ for (numrows= 0 ; (table= getTableName(1)) ; numrows++)
{
dynstr_append(&query, quote_name(table, table_buff, 1));
dynstr_append(&query, " READ /*!32311 LOCAL */,");
@@ -2024,11 +2110,17 @@ static int dump_all_tables_in_db(char *database)
DBerror(sock, "when doing refresh");
/* We shall continue here, if --force was given */
}
- while ((table = getTableName(0)))
+ while ((table= getTableName(0)))
{
- numrows = getTableStructure(table, database);
- if (!dFlag && numrows > 0)
- dumpTable(numrows,table);
+ char *end= strmov(afterdot, table);
+ if (include_table(hash_key, end - hash_key))
+ {
+ numrows = getTableStructure(table, database);
+ if (!dFlag && numrows > 0)
+ dumpTable(numrows,table);
+ my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
+ order_by= 0;
+ }
}
if (opt_xml)
{
@@ -2094,6 +2186,38 @@ static my_bool dump_all_views_in_db(char *database)
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
+ different case (e.g. T1 vs t1)
+
+ RETURN
+ void
+*/
+
+static void get_actual_table_name(const char *old_table_name,
+ char *new_table_name,
+ int buf_size)
+{
+ MYSQL_RES *tableRes;
+ MYSQL_ROW row;
+ char query[ NAME_LEN + 50 ];
+ DBUG_ENTER("get_actual_table_name");
+
+ sprintf( query, "SHOW TABLES LIKE '%s'", old_table_name);
+ if (mysql_query_with_error_report(sock, 0, query))
+ {
+ safe_exit(EX_MYSQLERR);
+ }
+
+ tableRes= mysql_store_result( sock );
+ row= mysql_fetch_row( tableRes );
+ strmake(new_table_name, row[0], buf_size-1);
+ mysql_free_result(tableRes);
+}
+
+
static int dump_selected_tables(char *db, char **table_names, int tables)
{
uint numrows;
@@ -2127,9 +2251,16 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
print_xml_tag1(md_result_file, "", "database name=", db, "\n");
for (i=0 ; i < tables ; i++)
{
- numrows = getTableStructure(table_names[i], db);
- if (!dFlag && numrows > 0)
- dumpTable(numrows, table_names[i]);
+ char new_table_name[NAME_LEN];
+
+ /* the table name passed on commandline may be wrong case */
+ get_actual_table_name( table_names[i], new_table_name, sizeof(new_table_name) );
+
+ numrows = getTableStructure(new_table_name, db);
+
+ dumpTable(numrows, new_table_name);
+ my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
+ order_by= 0;
}
if (was_views)
{
@@ -2214,8 +2345,15 @@ static int start_transaction(MYSQL *mysql_con, my_bool consistent_read_now)
We use BEGIN for old servers. --single-transaction --master-data will fail
on old servers, but that's ok as it was already silently broken (it didn't
do a consistent read, so better tell people frankly, with the error).
+
+ We want the first consistent read to be used for all tables to dump so we
+ need the REPEATABLE READ level (not anything lower, for example READ
+ COMMITTED would give one new consistent read per dumped table).
*/
return (mysql_query_with_error_report(mysql_con, 0,
+ "SET SESSION TRANSACTION ISOLATION "
+ "LEVEL REPEATABLE READ") ||
+ mysql_query_with_error_report(mysql_con, 0,
consistent_read_now ?
"START TRANSACTION "
"WITH CONSISTENT SNAPSHOT" :
@@ -2335,8 +2473,7 @@ static const char *check_if_ignore_table(const char *table_name)
fprintf(stderr,
"Error: Couldn't read status information for table %s (%s)\n",
table_name, mysql_error(sock));
- if (res)
- mysql_free_result(res);
+ mysql_free_result(res);
return 0; /* assume table is ok */
}
if (!(row[1]))
@@ -2347,7 +2484,7 @@ static const char *check_if_ignore_table(const char *table_name)
strcmp(row[1], (result= "MRG_ISAM")))
result= 0;
}
- mysql_free_result(res);
+ mysql_free_result(res);
return result;
}
@@ -2523,6 +2660,7 @@ static my_bool getViewStructure(char *table, char* db)
int main(int argc, char **argv)
{
compatible_mode_normal_str[0]= 0;
+ default_charset= (char *)mysql_universal_client_charset;
MY_INIT(argv[0]);
if (get_options(&argc, &argv))
diff --git a/client/mysqltest.c b/client/mysqltest.c
index bd4de026acb..7bdcf6db3e5 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -123,6 +123,17 @@ typedef struct
} code;
} match_err;
+typedef struct
+{
+ const char *name;
+ long code;
+} st_error;
+
+static st_error global_error[] = {
+#include <mysqld_ername.h>
+ { 0, 0 }
+};
+
static match_err global_expected_errno[MAX_EXPECTED_ERRORS];
static uint global_expected_errors;
@@ -227,7 +238,7 @@ typedef struct
int alloced;
} VAR;
-#ifdef __NETWARE__
+#if defined(__NETWARE__) || defined(__WIN__)
/*
Netware doesn't proved environment variable substitution that is done
by the shell in unix environments. We do this in the following function:
@@ -437,6 +448,10 @@ my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; }
#endif
static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
int len);
+static void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val);
+static int normal_handle_error(const char *query, struct st_query *q,
+ MYSQL *mysql, DYNAMIC_STRING *ds);
+static int normal_handle_no_error(struct st_query *q);
static void do_eval(DYNAMIC_STRING* query_eval, const char* query)
{
@@ -718,9 +733,10 @@ VAR* var_get(const char* var_name, const char** var_name_end, my_bool raw,
die("Empty variable");
}
length= (uint) (var_name - save_var_name);
+ if (length >= MAX_VAR_NAME)
+ die("Too long variable name: %s", save_var_name);
- if (!(v = (VAR*) hash_search(&var_hash, save_var_name, length)) &&
- length < MAX_VAR_NAME)
+ if (!(v = (VAR*) hash_search(&var_hash, save_var_name, length)))
{
char buff[MAX_VAR_NAME+1];
strmake(buff, save_var_name, length);
@@ -951,7 +967,7 @@ static void do_exec(struct st_query* q)
ds= &ds_res;
while (fgets(buf, sizeof(buf), res_file))
- replace_dynstr_append_mem(ds, buf, strlen(buf));
+ replace_dynstr_append(ds, buf);
}
error= pclose(res_file);
@@ -1336,6 +1352,7 @@ static uint get_errcodes(match_err *to,struct st_query* q)
{
char* p= q->first_argument;
uint count= 0;
+
DBUG_ENTER("get_errcodes");
if (!*p)
@@ -1346,19 +1363,41 @@ static uint get_errcodes(match_err *to,struct st_query* q)
if (*p == 'S')
{
/* SQLSTATE string */
- int i;
- p++;
- for (i = 0; my_isalnum(charset_info, *p) && i < SQLSTATE_LENGTH; p++, i++)
- to[count].code.sqlstate[i]= *p;
- to[count].code.sqlstate[i]= '\0';
+ char *end= ++p + SQLSTATE_LENGTH;
+ char *to_ptr= to[count].code.sqlstate;
+
+ for (; my_isalnum(charset_info, *p) && p != end; p++)
+ *to_ptr++= *p;
+ *to_ptr= 0;
+
to[count].type= ERR_SQLSTATE;
}
+ else if (*p == 'E')
+ {
+ /* SQL error as string */
+ st_error *e= global_error;
+ char *start= p++;
+
+ for (; *p == '_' || my_isalnum(charset_info, *p); p++)
+ ;
+ for (; e->name; e++)
+ {
+ if (!strncmp(start, e->name, (int) (p - start)))
+ {
+ to[count].code.errnum= (uint) e->code;
+ to[count].type= ERR_ERRNO;
+ break;
+ }
+ }
+ if (!e->name)
+ die("Unknown SQL error '%s'\n", start);
+ }
else
{
long val;
- p=str2int(p,10,(long) INT_MIN, (long) INT_MAX, &val);
- if (p == NULL)
- die("Invalid argument in %s\n", q->query);
+
+ if (!(p= str2int(p,10,(long) INT_MIN, (long) INT_MAX, &val)))
+ die("Invalid argument in %s\n", q->query);
to[count].code.errnum= (uint) val;
to[count].type= ERR_ERRNO;
}
@@ -1613,6 +1652,29 @@ void init_manager()
}
#endif
+
+/*
+ Connect to a server doing several retries if needed.
+
+ SYNOPSIS
+ safe_connect()
+ con - connection structure to be used
+ host, user, pass, - connection parameters
+ db, port, sock
+
+ NOTE
+ This function will try to connect to the given server MAX_CON_TRIES
+ times and sleep CON_RETRY_SLEEP seconds between attempts before
+ finally giving up. This helps in situation when the client starts
+ before the server (which happens sometimes).
+ It will ignore any errors during these retries. One should use
+ connect_n_handle_errors() if he expects a connection error and wants
+ handle as if it was an error from a usual statement.
+
+ RETURN VALUE
+ 0 - success, non-0 - failure
+*/
+
int safe_connect(MYSQL* con, const char* host, const char* user,
const char* pass,
const char* db, int port, const char* sock)
@@ -1634,6 +1696,114 @@ int safe_connect(MYSQL* con, const char* host, const char* user,
}
+/*
+ Connect to a server and handle connection errors in case when they occur.
+
+ SYNOPSIS
+ connect_n_handle_errors()
+ q - context of connect "query" (command)
+ con - connection structure to be used
+ host, user, pass, - connection parameters
+ db, port, sock
+ create_conn - out parameter, set to zero if connection was
+ not established and is not touched otherwise
+
+ DESCRIPTION
+ This function will try to establish a connection to server and handle
+ possible errors in the same manner as if "connect" was usual SQL-statement
+ (If error is expected it will ignore it once it occurs and log the
+ "statement" to the query log).
+ Unlike safe_connect() it won't do several attempts.
+
+ RETURN VALUE
+ 0 - success, non-0 - failure
+*/
+
+int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host,
+ const char* user, const char* pass,
+ const char* db, int port, const char* sock,
+ int* create_conn)
+{
+ DYNAMIC_STRING ds_tmp, *ds;
+ int error= 0;
+
+ /*
+ Altough we ignore --require or --result before connect() command we still
+ need to handle record_file because of "@result_file sql-command" syntax.
+ */
+ if (q->record_file[0])
+ {
+ init_dynamic_string(&ds_tmp, "", 16384, 65536);
+ ds= &ds_tmp;
+ }
+ else
+ ds= &ds_res;
+
+ if (!disable_query_log)
+ {
+ /*
+ It is nice to have connect() statement logged in result file
+ in this case.
+ QQ: Should we do this only if we are expecting an error ?
+ */
+ char port_buff[22]; /* This should be enough for any int */
+ char *port_end;
+ dynstr_append_mem(ds, "connect(", 8);
+ replace_dynstr_append(ds, host);
+ dynstr_append_mem(ds, ",", 1);
+ replace_dynstr_append(ds, user);
+ dynstr_append_mem(ds, ",", 1);
+ replace_dynstr_append(ds, pass);
+ dynstr_append_mem(ds, ",", 1);
+ if (db)
+ replace_dynstr_append(ds, db);
+ dynstr_append_mem(ds, ",", 1);
+ port_end= int10_to_str(port, port_buff, 10);
+ replace_dynstr_append_mem(ds, port_buff, port_end - port_buff);
+ dynstr_append_mem(ds, ",", 1);
+ if (sock)
+ replace_dynstr_append(ds, sock);
+ dynstr_append_mem(ds, ")", 1);
+ dynstr_append_mem(ds, delimiter, delimiter_length);
+ dynstr_append_mem(ds, "\n", 1);
+ }
+ if (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0,
+ CLIENT_MULTI_STATEMENTS))
+ {
+ error= normal_handle_error("connect", q, con, ds);
+ *create_conn= 0;
+ goto err;
+ }
+ else if (normal_handle_no_error(q))
+ {
+ /*
+ Fail if there was no error but we expected it.
+ We also don't want to have connection in this case.
+ */
+ mysql_close(con);
+ *create_conn= 0;
+ error= 1;
+ goto err;
+ }
+
+ if (record)
+ {
+ if (!q->record_file[0] && !result_file)
+ die("At line %u: Missing result file", start_lineno);
+ if (!result_file)
+ str_to_file(q->record_file, ds->str, ds->length);
+ }
+ else if (q->record_file[0])
+ error|= check_result(ds, q->record_file, q->require_file);
+
+err:
+ free_replace();
+ if (ds == &ds_tmp)
+ dynstr_free(&ds_tmp);
+ return error;
+}
+
+
int do_connect(struct st_query* q)
{
char* con_name, *con_user,*con_pass, *con_host, *con_port_str,
@@ -1642,6 +1812,8 @@ int do_connect(struct st_query* q)
char buff[FN_REFLEN];
int con_port;
int free_con_sock = 0;
+ int error= 0;
+ int create_conn= 1;
DBUG_ENTER("do_connect");
DBUG_PRINT("enter",("connect: %s",p));
@@ -1706,18 +1878,28 @@ int do_connect(struct st_query* q)
/* Special database to allow one to connect without a database name */
if (con_db && !strcmp(con_db,"*NO-ONE*"))
con_db=0;
- if ((safe_connect(&next_con->mysql, con_host,
- con_user, con_pass,
- con_db, con_port, con_sock ? con_sock: 0)))
- die("Could not open connection '%s': %s", con_name,
- mysql_error(&next_con->mysql));
- if (!(next_con->name = my_strdup(con_name, MYF(MY_WME))))
- die(NullS);
- cur_con = next_con++;
+ if (q->abort_on_error)
+ {
+ if ((safe_connect(&next_con->mysql, con_host, con_user, con_pass,
+ con_db, con_port, con_sock ? con_sock: 0)))
+ die("Could not open connection '%s': %s", con_name,
+ mysql_error(&next_con->mysql));
+ }
+ else
+ error= connect_n_handle_errors(q, &next_con->mysql, con_host, con_user,
+ con_pass, con_db, con_port, con_sock,
+ &create_conn);
+
+ if (create_conn)
+ {
+ if (!(next_con->name= my_strdup(con_name, MYF(MY_WME))))
+ die(NullS);
+ cur_con= next_con++;
+ }
if (free_con_sock)
my_free(con_sock, MYF(MY_WME));
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
@@ -2174,6 +2356,9 @@ static struct my_option my_long_options[] =
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
+
+#include <help_start.h>
+
static void print_version(void)
{
printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,MTEST_VERSION,
@@ -2192,6 +2377,10 @@ void usage()
my_print_variables(my_long_options);
}
+#include <help_end.h>
+
+#include <help_end.h>
+
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
@@ -2356,6 +2545,13 @@ static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
dynstr_append_mem(ds, val, len);
}
+/* Append zero-terminated string to ds, with optional replace */
+
+static void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val)
+{
+ replace_dynstr_append_mem(ds, val, strlen(val));
+}
+
/*
Append all results to the dynamic string separated with '\t'
@@ -2502,93 +2698,14 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
(!(last_result= res= mysql_store_result(mysql)) &&
mysql_field_count(mysql)))
{
- if (q->require_file)
- {
- abort_not_supported_test();
- }
- if (q->abort_on_error)
- die("At line %u: query '%s' failed: %d: %s", start_lineno, query,
- mysql_errno(mysql), mysql_error(mysql));
- else
- {
- for (i=0 ; (uint) i < q->expected_errors ; i++)
- {
- if (((q->expected_errno[i].type == ERR_ERRNO) &&
- (q->expected_errno[i].code.errnum == mysql_errno(mysql))) ||
- ((q->expected_errno[i].type == ERR_SQLSTATE) &&
- (strcmp(q->expected_errno[i].code.sqlstate,mysql_sqlstate(mysql)) == 0)))
- {
- if (i == 0 && q->expected_errors == 1)
- {
- /* Only log error if there is one possible error */
- dynstr_append_mem(ds,"ERROR ",6);
- replace_dynstr_append_mem(ds, mysql_sqlstate(mysql),
- strlen(mysql_sqlstate(mysql)));
- dynstr_append_mem(ds, ": ", 2);
- replace_dynstr_append_mem(ds,mysql_error(mysql),
- strlen(mysql_error(mysql)));
- dynstr_append_mem(ds,"\n",1);
- }
- /* Don't log error if we may not get an error */
- else if (q->expected_errno[0].type == ERR_SQLSTATE ||
- (q->expected_errno[0].type == ERR_ERRNO &&
- q->expected_errno[0].code.errnum != 0))
- dynstr_append(ds,"Got one of the listed errors\n");
- goto end; /* Ok */
- }
- }
- DBUG_PRINT("info",("i: %d expected_errors: %d", i,
- q->expected_errors));
- dynstr_append_mem(ds, "ERROR ",6);
- replace_dynstr_append_mem(ds, mysql_sqlstate(mysql),
- strlen(mysql_sqlstate(mysql)));
- dynstr_append_mem(ds,": ",2);
- replace_dynstr_append_mem(ds, mysql_error(mysql),
- strlen(mysql_error(mysql)));
- dynstr_append_mem(ds,"\n",1);
- if (i)
- {
- if (q->expected_errno[0].type == ERR_ERRNO)
- verbose_msg("query '%s' failed with wrong errno %d instead of %d...",
- q->query, mysql_errno(mysql), q->expected_errno[0].code.errnum);
- else
- verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...",
- q->query, mysql_sqlstate(mysql), q->expected_errno[0].code.sqlstate);
- error= 1;
- goto end;
- }
- verbose_msg("query '%s' failed: %d: %s", q->query, mysql_errno(mysql),
- mysql_error(mysql));
- /*
- if we do not abort on error, failure to run the query does
- not fail the whole test case
- */
- goto end;
- }
- /*{
- verbose_msg("failed in mysql_store_result for query '%s' (%d)", query,
- mysql_errno(mysql));
- error = 1;
- goto end;
- }*/
- }
-
- if (q->expected_errno[0].type == ERR_ERRNO &&
- q->expected_errno[0].code.errnum != 0)
- {
- /* Error code we wanted was != 0, i.e. not an expected success */
- verbose_msg("query '%s' succeeded - should have failed with errno %d...",
- q->query, q->expected_errno[0].code.errnum);
- error = 1;
+ if (normal_handle_error(query, q, mysql, ds))
+ error= 1;
goto end;
}
- else if (q->expected_errno[0].type == ERR_SQLSTATE &&
- strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0)
+
+ if (normal_handle_no_error(q))
{
- /* SQLSTATE we wanted was != "00000", i.e. not an expected success */
- verbose_msg("query '%s' succeeded - should have failed with sqlstate %s...",
- q->query, q->expected_errno[0].code.sqlstate);
- error = 1;
+ error= 1;
goto end;
}
@@ -2608,8 +2725,7 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
{
if (i)
dynstr_append_mem(ds, "\t", 1);
- replace_dynstr_append_mem(ds, field[i].name,
- strlen(field[i].name));
+ replace_dynstr_append(ds, field[i].name);
}
dynstr_append_mem(ds, "\n", 1);
}
@@ -2686,6 +2802,136 @@ end:
}
+/*
+ Handle errors which occurred after execution of conventional (non-prepared)
+ statement.
+
+ SYNOPSIS
+ normal_handle_error()
+ query - query string
+ q - query context
+ mysql - connection through which query was sent to server
+ ds - dynamic string which is used for output buffer
+
+ NOTE
+ If there is an unexpected error this function will abort mysqltest
+ immediately.
+
+ RETURN VALUE
+ 0 - OK
+ 1 - Some other error was expected.
+*/
+
+static int normal_handle_error(const char *query, struct st_query *q,
+ MYSQL *mysql, DYNAMIC_STRING *ds)
+{
+ uint i;
+
+ DBUG_ENTER("normal_handle_error");
+
+ if (q->require_file)
+ abort_not_supported_test();
+
+ if (q->abort_on_error)
+ die("At line %u: query '%s' failed: %d: %s", start_lineno, query,
+ mysql_errno(mysql), mysql_error(mysql));
+ else
+ {
+ for (i= 0 ; (uint) i < q->expected_errors ; i++)
+ {
+ if (((q->expected_errno[i].type == ERR_ERRNO) &&
+ (q->expected_errno[i].code.errnum == mysql_errno(mysql))) ||
+ ((q->expected_errno[i].type == ERR_SQLSTATE) &&
+ (strcmp(q->expected_errno[i].code.sqlstate, mysql_sqlstate(mysql)) == 0)))
+ {
+ if (q->expected_errors == 1)
+ {
+ /* Only log error if there is one possible error */
+ dynstr_append_mem(ds, "ERROR ", 6);
+ replace_dynstr_append(ds, mysql_sqlstate(mysql));
+ dynstr_append_mem(ds, ": ", 2);
+ replace_dynstr_append(ds, mysql_error(mysql));
+ dynstr_append_mem(ds,"\n",1);
+ }
+ /* Don't log error if we may not get an error */
+ else if (q->expected_errno[0].type == ERR_SQLSTATE ||
+ (q->expected_errno[0].type == ERR_ERRNO &&
+ q->expected_errno[0].code.errnum != 0))
+ dynstr_append(ds,"Got one of the listed errors\n");
+ /* OK */
+ DBUG_RETURN(0);
+ }
+ }
+
+ DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors));
+
+ dynstr_append_mem(ds, "ERROR ",6);
+ replace_dynstr_append(ds, mysql_sqlstate(mysql));
+ dynstr_append_mem(ds, ": ", 2);
+ replace_dynstr_append(ds, mysql_error(mysql));
+ dynstr_append_mem(ds, "\n", 1);
+
+ if (i)
+ {
+ if (q->expected_errno[0].type == ERR_ERRNO)
+ verbose_msg("query '%s' failed with wrong errno %d instead of %d...",
+ q->query, mysql_errno(mysql),
+ q->expected_errno[0].code.errnum);
+ else
+ verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...",
+ q->query, mysql_sqlstate(mysql),
+ q->expected_errno[0].code.sqlstate);
+ DBUG_RETURN(1);
+ }
+
+ /*
+ If we do not abort on error, failure to run the query does not fail the
+ whole test case.
+ */
+ verbose_msg("query '%s' failed: %d: %s", q->query, mysql_errno(mysql),
+ mysql_error(mysql));
+ DBUG_RETURN(0);
+ }
+ return 0; /* Keep compiler happy */
+}
+
+
+/*
+ Handle absence of errors after execution of convetional statement.
+
+ SYNOPSIS
+ normal_handle_error()
+ q - context of query
+
+ RETURN VALUE
+ 0 - OK
+ 1 - Some error was expected from this query.
+*/
+
+static int normal_handle_no_error(struct st_query *q)
+{
+ DBUG_ENTER("normal_handle_no_error");
+
+ if (q->expected_errno[0].type == ERR_ERRNO &&
+ q->expected_errno[0].code.errnum != 0)
+ {
+ /* Error code we wanted was != 0, i.e. not an expected success */
+ verbose_msg("query '%s' succeeded - should have failed with errno %d...",
+ q->query, q->expected_errno[0].code.errnum);
+ DBUG_RETURN(1);
+ }
+ else if (q->expected_errno[0].type == ERR_SQLSTATE &&
+ strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0)
+ {
+ /* SQLSTATE we wanted was != "00000", i.e. not an expected success */
+ verbose_msg("query '%s' succeeded - should have failed with sqlstate %s...",
+ q->query, q->expected_errno[0].code.sqlstate);
+ DBUG_RETURN(1);
+ }
+
+ DBUG_RETURN(0);
+}
+
/****************************************************************************\
* If --ps-protocol run ordinary statements using prepared statemnt C API
\****************************************************************************/
@@ -2879,8 +3125,7 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
{
if (col_idx)
dynstr_append_mem(ds, "\t", 1);
- replace_dynstr_append_mem(ds, field[col_idx].name,
- strlen(field[col_idx].name));
+ replace_dynstr_append(ds, field[col_idx].name);
}
dynstr_append_mem(ds, "\n", 1);
}
@@ -2896,7 +3141,7 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
/* Allocate array with bind structs, lengths and NULL flags */
bind= (MYSQL_BIND*) my_malloc(num_fields * sizeof(MYSQL_BIND),
- MYF(MY_WME | MY_FAE));
+ MYF(MY_WME | MY_FAE | MY_ZEROFILL));
length= (unsigned long*) my_malloc(num_fields * sizeof(unsigned long),
MYF(MY_WME | MY_FAE));
is_null= (my_bool*) my_malloc(num_fields * sizeof(my_bool),
@@ -3148,11 +3393,9 @@ static int run_query_stmt_handle_error(char *query, struct st_query *q,
{
/* Only log error if there is one possible error */
dynstr_append_mem(ds,"ERROR ",6);
- replace_dynstr_append_mem(ds, mysql_stmt_sqlstate(stmt),
- strlen(mysql_stmt_sqlstate(stmt)));
+ replace_dynstr_append(ds, mysql_stmt_sqlstate(stmt));
dynstr_append_mem(ds, ": ", 2);
- replace_dynstr_append_mem(ds,mysql_stmt_error(stmt),
- strlen(mysql_stmt_error(stmt)));
+ replace_dynstr_append(ds,mysql_stmt_error(stmt));
dynstr_append_mem(ds,"\n",1);
}
/* Don't log error if we may not get an error */
@@ -3166,11 +3409,9 @@ static int run_query_stmt_handle_error(char *query, struct st_query *q,
DBUG_PRINT("info",("i: %d expected_errors: %d", i,
q->expected_errors));
dynstr_append_mem(ds, "ERROR ",6);
- replace_dynstr_append_mem(ds, mysql_stmt_sqlstate(stmt),
- strlen(mysql_stmt_sqlstate(stmt)));
+ replace_dynstr_append(ds, mysql_stmt_sqlstate(stmt));
dynstr_append_mem(ds,": ",2);
- replace_dynstr_append_mem(ds, mysql_stmt_error(stmt),
- strlen(mysql_stmt_error(stmt)));
+ replace_dynstr_append(ds, mysql_stmt_error(stmt));
dynstr_append_mem(ds,"\n",1);
if (i)
{
@@ -3452,7 +3693,9 @@ int main(int argc, char **argv)
{
processed = 1;
switch (q->type) {
- case Q_CONNECT: do_connect(q); break;
+ case Q_CONNECT:
+ error|= do_connect(q);
+ break;
case Q_CONNECTION: select_connection(q->first_argument); break;
case Q_DISCONNECT:
case Q_DIRTY_CLOSE:
@@ -4609,6 +4852,9 @@ static char *subst_env_var(const char *str)
*/
#undef popen /* Remove wrapper */
+#ifdef __WIN__
+#define popen _popen /* redefine for windows */
+#endif
FILE *my_popen(const char *cmd, const char *mode __attribute__((unused)))
{