diff options
Diffstat (limited to 'client')
-rw-r--r-- | client/Makefile.am | 30 | ||||
-rw-r--r-- | client/client_priv.h | 1 | ||||
-rw-r--r-- | client/completion_hash.cc | 3 | ||||
-rw-r--r-- | client/mysql.cc | 82 | ||||
-rw-r--r-- | client/mysqladmin.cc | 46 | ||||
-rw-r--r-- | client/mysqlbinlog.cc | 38 | ||||
-rw-r--r-- | client/mysqlcheck.c | 2 | ||||
-rw-r--r-- | client/mysqldump.c | 182 | ||||
-rw-r--r-- | client/mysqltest.c | 484 |
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[] = { "&", "&", "<", "<", + ">", ">", + "\"", """, 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 : - " ") : "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 : - " ") : "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*) ¤t_host, (gptr*) ¤t_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"ignore-table", OPT_IGNORE_TABLE, + "Do not dump the specified table. To specify more than one table to ignore, " + "use the directive multiple times, once for each table. Each table must " + "be specified with both database and table names, e.g. --ignore-table=database.table", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"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))) { |