diff options
Diffstat (limited to 'client')
-rwxr-xr-x | client/CMakeLists.txt | 4 | ||||
-rw-r--r-- | client/Makefile.am | 6 | ||||
-rw-r--r-- | client/mysqladmin.cc | 40 | ||||
-rw-r--r-- | client/mysqltest.cc (renamed from client/mysqltest.c) | 841 |
4 files changed, 547 insertions, 344 deletions
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index cbd4a1f306b..e96437d40d0 100755 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -32,8 +32,8 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ADD_EXECUTABLE(mysql completion_hash.cc mysql.cc readline.cc sql_string.cc ../mysys/my_conio.c) TARGET_LINK_LIBRARIES(mysql mysqlclient_notls wsock32) -ADD_EXECUTABLE(mysqltest mysqltest.c) -SET_SOURCE_FILES_PROPERTIES(mysqltest.c PROPERTIES COMPILE_FLAGS "-DTHREADS") +ADD_EXECUTABLE(mysqltest mysqltest.cc) +SET_SOURCE_FILES_PROPERTIES(mysqltest.cc PROPERTIES COMPILE_FLAGS "-DTHREADS") TARGET_LINK_LIBRARIES(mysqltest mysqlclient mysys regex wsock32 dbug) ADD_EXECUTABLE(mysqlcheck mysqlcheck.c) diff --git a/client/Makefile.am b/client/Makefile.am index c5c82ec0a42..94db565ba37 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -86,9 +86,9 @@ mysqlslap_LDADD = $(CXXLDFLAGS) $(CLIENT_THREAD_LIBS) \ $(LIBMYSQLCLIENT_LA) \ $(top_builddir)/mysys/libmysys.a -mysqltest_SOURCES= mysqltest.c -mysqltest_CFLAGS= -DTHREAD -UUNDEF_THREADS_HACK -mysqltest_LDADD = $(CXXLDFLAGS) \ +mysqltest_SOURCES= mysqltest.cc +mysqltest_CXXFLAGS= -DTHREAD -UUNDEF_THREADS_HACK +mysqltest_LDADD = $(CXXLDFLAGS) $(CLIENT_THREAD_LIBS) \ @CLIENT_EXTRA_LDFLAGS@ \ $(LIBMYSQLCLIENT_LA) \ $(top_builddir)/mysys/libmysys.a \ diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index b3b699f61fd..ea5b92a7c5a 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -23,10 +23,6 @@ #include <sys/stat.h> #include <mysql.h> -#ifdef LATER_HAVE_NDBCLUSTER_DB -#include "../ndb/src/mgmclient/ndb_mgmclient.h" -#endif - #define ADMIN_VERSION "8.42" #define MAX_MYSQL_VAR 256 #define SHUTDOWN_DEF_TIMEOUT 3600 /* Wait for shutdown */ @@ -46,10 +42,6 @@ static uint tcp_port = 0, option_wait = 0, option_silent=0, nr_iterations; static uint opt_count_iterations= 0, my_end_arg; static ulong opt_connect_timeout, opt_shutdown_timeout; static char * unix_port=0; -#ifdef LATER_HAVE_NDBCLUSTER_DB -static my_bool opt_ndbcluster=0; -static char *opt_ndb_connectstring=0; -#endif #ifdef HAVE_SMEM static char *shared_memory_base_name=0; @@ -105,9 +97,6 @@ enum commands { ADMIN_PING, ADMIN_EXTENDED_STATUS, ADMIN_FLUSH_STATUS, ADMIN_FLUSH_PRIVILEGES, ADMIN_START_SLAVE, ADMIN_STOP_SLAVE, ADMIN_FLUSH_THREADS, ADMIN_OLD_PASSWORD -#ifdef LATER_HAVE_NDBCLUSTER_DB - ,ADMIN_NDB_MGM -#endif }; static const char *command_names[]= { "create", "drop", "shutdown", @@ -118,9 +107,6 @@ static const char *command_names[]= { "ping", "extended-status", "flush-status", "flush-privileges", "start-slave", "stop-slave", "flush-threads","old-password", -#ifdef LATER_HAVE_NDBCLUSTER_DB - "ndb-mgm", -#endif NullS }; @@ -224,14 +210,6 @@ static struct my_option my_long_options[] = {"shutdown_timeout", OPT_SHUTDOWN_TIMEOUT, "", (uchar**) &opt_shutdown_timeout, (uchar**) &opt_shutdown_timeout, 0, GET_ULONG, REQUIRED_ARG, SHUTDOWN_DEF_TIMEOUT, 0, 3600*12, 0, 1, 0}, -#ifdef LATER_HAVE_NDBCLUSTER_DB - {"ndbcluster", OPT_NDBCLUSTER, "" - "", (uchar**) &opt_ndbcluster, - (uchar**) &opt_ndbcluster, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"ndb-connectstring", OPT_NDB_CONNECTSTRING, "" - "", (uchar**) &opt_ndb_connectstring, - (uchar**) &opt_ndb_connectstring, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#endif { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -984,24 +962,6 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) } mysql->reconnect=1; /* Automatic reconnect is default */ break; -#ifdef LATER_HAVE_NDBCLUSTER_DB - case ADMIN_NDB_MGM: - { - if (argc < 2) - { - my_printf_error(0, "Too few arguments to ndb-mgm", error_flags); - return 1; - } - { - Ndb_mgmclient_handle cmd= - ndb_mgmclient_handle_create(opt_ndb_connectstring); - ndb_mgmclient_execute(cmd, --argc, ++argv); - ndb_mgmclient_handle_destroy(cmd); - } - argc= 0; - } - break; -#endif default: my_printf_error(0, "Unknown command: '%-.60s'", error_flags, argv[0]); return 1; diff --git a/client/mysqltest.c b/client/mysqltest.cc index 6babc42bcd0..c86b213c238 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.cc @@ -169,7 +169,6 @@ static ulonglong timer_start; static void timer_output(void); static ulonglong timer_now(void); -static ulonglong progress_start= 0; static ulong connection_retry_sleep= 100000; /* Microseconds */ @@ -186,12 +185,12 @@ DYNAMIC_ARRAY q_lines; #include "sslopt-vars.h" -struct +struct Parser { int read_lines,current_line; } parser; -struct +struct MasterPos { char file[FN_REFLEN]; ulong pos; @@ -200,7 +199,7 @@ struct /* if set, all results are concated and compared against this file */ const char *result_file_name= 0; -typedef struct st_var +typedef struct { char *name; int name_len; @@ -278,8 +277,9 @@ enum enum_commands { Q_REPLACE_REGEX, Q_REMOVE_FILE, Q_FILE_EXIST, Q_WRITE_FILE, Q_COPY_FILE, Q_PERL, Q_DIE, Q_EXIT, Q_SKIP, Q_CHMOD_FILE, Q_APPEND_FILE, Q_CAT_FILE, Q_DIFF_FILES, - Q_SEND_QUIT, Q_CHANGE_USER, Q_MKDIR, Q_RMDIR, Q_LIST_FILES, - Q_LIST_FILES_WRITE_FILE, Q_LIST_FILES_APPEND_FILE, + Q_SEND_QUIT, Q_CHANGE_USER, Q_MKDIR, Q_RMDIR, + Q_LIST_FILES, Q_LIST_FILES_WRITE_FILE, Q_LIST_FILES_APPEND_FILE, + Q_SEND_SHUTDOWN, Q_SHUTDOWN_SERVER, Q_UNKNOWN, /* Unknown command. */ Q_COMMENT, /* Comments, ignored. */ @@ -374,6 +374,8 @@ const char *command_names[]= "list_files", "list_files_write_file", "list_files_append_file", + "send_shutdown", + "shutdown_server", 0 }; @@ -423,7 +425,7 @@ struct st_command TYPELIB command_typelib= {array_elements(command_names),"", command_names, 0}; -DYNAMIC_STRING ds_res, ds_progress, ds_warning_messages; +DYNAMIC_STRING ds_res; char builtin_echo[FN_REFLEN]; @@ -433,8 +435,6 @@ void abort_not_supported_test(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2); void verbose_msg(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2); -void warning_msg(const char *fmt, ...) - ATTRIBUTE_FORMAT(printf, 1, 2); void log_msg(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2); @@ -447,15 +447,15 @@ VAR* var_get(const char *var_name, const char** var_name_end, void eval_expr(VAR* v, const char *p, const char** p_end); my_bool match_delimiter(int c, const char *delim, uint length); void dump_result_to_reject_file(char *buf, int size); -void dump_result_to_log_file(char *buf, int size); void dump_warning_messages(); -void dump_progress(); void do_eval(DYNAMIC_STRING *query_eval, const char *query, const char *query_end, my_bool pass_through_escape_chars); void str_to_file(const char *fname, char *str, int size); void str_to_file2(const char *fname, char *str, int size, my_bool append); +void fix_win_paths(const char *val, int len); + #ifdef __WIN__ void free_tmp_sh_file(); void free_win_path_patterns(); @@ -484,6 +484,170 @@ void free_all_replace(){ } +class LogFile { + FILE* m_file; + char m_file_name[FN_REFLEN]; + size_t m_bytes_written; +public: + LogFile() : m_file(NULL), m_bytes_written(0) { + bzero(m_file_name, sizeof(m_file_name)); + } + + ~LogFile() { + close(); + } + + const char* file_name() const { return m_file_name; } + size_t bytes_written() const { return m_bytes_written; } + + void open(const char* dir, const char* name, const char* ext) + { + DBUG_ENTER("LogFile::open"); + DBUG_PRINT("enter", ("dir: %s, name: %s", + name, dir)); + if (!name) + { + m_file= stdout; + DBUG_VOID_RETURN; + } + + fn_format(m_file_name, name, dir, ext, + *dir ? MY_REPLACE_DIR | MY_REPLACE_EXT : + MY_REPLACE_EXT); + + DBUG_PRINT("info", ("file_name: %s", m_file_name)); + + if ((m_file= fopen(m_file_name, "wb+")) == NULL) + die("Failed to open log file %s, errno: %d", m_file_name, errno); + + DBUG_VOID_RETURN; + } + + void close() + { + if (m_file && m_file != stdout) + fclose(m_file); + m_file= NULL; + } + + void flush() + { + if (m_file && m_file != stdout) + fflush(m_file); + } + + void write(DYNAMIC_STRING* ds) + { + DBUG_ENTER("LogFile::write"); + DBUG_ASSERT(m_file); + + if (ds->length == 0) + DBUG_VOID_RETURN; + DBUG_ASSERT(ds->str); + + if (fwrite(ds->str, 1, ds->length, m_file) != ds->length) + die("Failed to write %lu bytes to '%s', errno: %d", + (unsigned long)ds->length, m_file_name, errno); + m_bytes_written+= ds->length; + DBUG_VOID_RETURN; + } + + void show_tail(uint lines) { + DBUG_ENTER("LogFile::show_tail"); + + if (!m_file || m_file == stdout) + DBUG_VOID_RETURN; + + if (lines == 0) + DBUG_VOID_RETURN; + lines++; + + int show_offset= 0; + char buf[256]; + size_t bytes; + bool found_bof= false; + + /* Search backward in file until "lines" newline has been found */ + while (lines && !found_bof) + { + show_offset-= sizeof(buf); + while(fseek(m_file, show_offset, SEEK_END) != 0 && show_offset < 0) + { + found_bof= true; + // Seeking before start of file + show_offset++; + } + + if ((bytes= fread(buf, 1, sizeof(buf), m_file)) <= 0) + { + fprintf(stderr, "Failed to read from '%s', errno: %d\n", + m_file_name, errno); + DBUG_VOID_RETURN; + } + + DBUG_PRINT("info", ("Read %lu bytes from file, buf: %s", + (unsigned long)bytes, buf)); + + char* show_from= buf + bytes; + while(show_from > buf && lines > 0 ) + { + show_from--; + if (*show_from == '\n') + lines--; + } + if (show_from != buf) + { + // The last new line was found in this buf, adjust offset + show_offset+= (show_from - buf) + 1; + DBUG_PRINT("info", ("adjusted offset to %d", show_offset)); + } + DBUG_PRINT("info", ("show_offset: %d", show_offset)); + } + + fprintf(stderr, "\nThe result from queries just before the failure was:\n"); + + DBUG_PRINT("info", ("show_offset: %d", show_offset)); + if (!lines) + { + fprintf(stderr, "< snip >\n"); + + if (fseek(m_file, show_offset, SEEK_END) != 0) + { + fprintf(stderr, "Failed to seek to position %d in '%s', errno: %d", + show_offset, m_file_name, errno); + DBUG_VOID_RETURN; + } + + } + else { + DBUG_PRINT("info", ("Showing the whole file")); + if (fseek(m_file, 0L, SEEK_SET) != 0) + { + fprintf(stderr, "Failed to seek to pos 0 in '%s', errno: %d", + m_file_name, errno); + DBUG_VOID_RETURN; + } + } + + while ((bytes= fread(buf, 1, sizeof(buf), m_file)) > 0) + fwrite(buf, 1, bytes, stderr); + + if (!lines) + { + fprintf(stderr, + "\nMore results from queries before failure can be found in %s\n", + m_file_name); + } + fflush(stderr); + + DBUG_VOID_RETURN; + } +}; + +LogFile log_file; +LogFile progress_file; + + /* Disable functions that only exist in MySQL 4.0 */ #if MYSQL_VERSION_ID < 40000 void mysql_enable_rpl_parse(MYSQL* mysql __attribute__((unused))) {} @@ -623,12 +787,15 @@ void do_eval(DYNAMIC_STRING *query_eval, const char *query, break; } } +#ifdef __WIN__ + fix_win_paths(query_eval->str, query_eval->length); +#endif DBUG_VOID_RETURN; } /* - Run query and dump the result to stdout in vertical format + Run query and dump the result to stderr in vertical format NOTE! This function should be safe to call when an error has occured and thus any further errors will be ignored(although logged) @@ -960,8 +1127,6 @@ void free_used_memory() my_free(embedded_server_args[--embedded_server_arg_count],MYF(0)); delete_dynamic(&q_lines); dynstr_free(&ds_res); - dynstr_free(&ds_progress); - dynstr_free(&ds_warning_messages); free_all_replace(); my_free(opt_pass,MYF(MY_ALLOW_ZERO_PTR)); free_defaults(default_argv); @@ -1039,31 +1204,7 @@ void die(const char *fmt, ...) fprintf(stderr, "\n"); fflush(stderr); - /* Show results from queries just before failure */ - if (ds_res.length && opt_tail_lines) - { - int tail_lines= opt_tail_lines; - char* show_from= ds_res.str + ds_res.length - 1; - while(show_from > ds_res.str && tail_lines > 0 ) - { - show_from--; - if (*show_from == '\n') - tail_lines--; - } - fprintf(stderr, "\nThe result from queries just before the failure was:\n"); - if (show_from > ds_res.str) - fprintf(stderr, "< snip >"); - fprintf(stderr, "%s", show_from); - fflush(stderr); - } - - /* Dump the result that has been accumulated so far to .log file */ - if (result_file_name && ds_res.length) - dump_result_to_log_file(ds_res.str, ds_res.length); - - /* Dump warning messages */ - if (result_file_name && ds_warning_messages.length) - dump_warning_messages(); + log_file.show_tail(opt_tail_lines); /* Help debugging by displaying any warnings that might have @@ -1137,41 +1278,6 @@ void verbose_msg(const char *fmt, ...) } -void warning_msg(const char *fmt, ...) -{ - va_list args; - char buff[512]; - size_t len; - DBUG_ENTER("warning_msg"); - - va_start(args, fmt); - dynstr_append(&ds_warning_messages, "mysqltest: "); - if (start_lineno != 0) - { - dynstr_append(&ds_warning_messages, "Warning detected "); - if (cur_file && cur_file != file_stack) - { - len= my_snprintf(buff, sizeof(buff), "in included file %s ", - cur_file->file_name); - dynstr_append_mem(&ds_warning_messages, - buff, len); - } - len= my_snprintf(buff, sizeof(buff), "at line %d: ", - start_lineno); - dynstr_append_mem(&ds_warning_messages, - buff, len); - } - - len= my_vsnprintf(buff, sizeof(buff), fmt, args); - dynstr_append_mem(&ds_warning_messages, buff, len); - - dynstr_append(&ds_warning_messages, "\n"); - va_end(args); - - DBUG_VOID_RETURN; -} - - void log_msg(const char *fmt, ...) { va_list args; @@ -1345,6 +1451,7 @@ void show_diff(DYNAMIC_STRING* ds, const char* filename1, const char* filename2) { + const char* diff_failed= 0; DYNAMIC_STRING ds_tmp; if (init_dynamic_string(&ds_tmp, "", 256, 256)) @@ -1370,17 +1477,36 @@ void show_diff(DYNAMIC_STRING* ds, "2>&1", NULL) > 1) /* Most "diff" tools return >1 if error */ { - /* - Fallback to dump both files to result file and inform - about installing "diff" - */ dynstr_set(&ds_tmp, ""); - dynstr_append(&ds_tmp, + /* Fallback to plain "diff" */ + if (run_tool("diff", + &ds_tmp, /* Get output from diff in ds_tmp */ + filename1, + filename2, + "2>&1", + NULL) > 1) /* Most "diff" tools return >1 if error */ + { + dynstr_set(&ds_tmp, ""); + + diff_failed= "Could not execute 'diff -u', 'diff -c' or 'diff'"; + } + } + } + + if (diff_failed) + { + /* + Fallback to dump both files to result file and inform + about installing "diff" + */ + dynstr_append(&ds_tmp, "\n"); + dynstr_append(&ds_tmp, diff_failed); + dynstr_append(&ds_tmp, "\n" "The two files differ but it was not possible to execute 'diff' in\n" -"order to show only the difference, tried both 'diff -u' or 'diff -c'.\n" -"Instead the whole content of the two files was shown for you to diff manually. ;)\n\n" +"order to show only the difference. Instead the whole content of the\n" +"two files was shown for you to diff manually.\n\n" "To get a better report you should install 'diff' on your system, which you\n" "for example can get from http://www.gnu.org/software/diffutils/diffutils.html\n" #ifdef __WIN__ @@ -1388,16 +1514,15 @@ void show_diff(DYNAMIC_STRING* ds, #endif "\n"); - dynstr_append(&ds_tmp, " --- "); - dynstr_append(&ds_tmp, filename1); - dynstr_append(&ds_tmp, " >>>\n"); - cat_file(&ds_tmp, filename1); - dynstr_append(&ds_tmp, "<<<\n --- "); - dynstr_append(&ds_tmp, filename1); - dynstr_append(&ds_tmp, " >>>\n"); - cat_file(&ds_tmp, filename2); - dynstr_append(&ds_tmp, "<<<<\n"); - } + dynstr_append(&ds_tmp, " --- "); + dynstr_append(&ds_tmp, filename1); + dynstr_append(&ds_tmp, " >>>\n"); + cat_file(&ds_tmp, filename1); + dynstr_append(&ds_tmp, "<<<\n --- "); + dynstr_append(&ds_tmp, filename1); + dynstr_append(&ds_tmp, " >>>\n"); + cat_file(&ds_tmp, filename2); + dynstr_append(&ds_tmp, "<<<<\n"); } if (ds) @@ -1561,18 +1686,17 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) /* - Check the content of ds against result file + Check the content of log against result file SYNOPSIS check_result - ds - content to be checked RETURN VALUES error - the function will not return */ -void check_result(DYNAMIC_STRING* ds) +void check_result() { const char* mess= "Result content mismatch\n"; @@ -1580,10 +1704,7 @@ void check_result(DYNAMIC_STRING* ds) DBUG_ASSERT(result_file_name); DBUG_PRINT("enter", ("result_file_name: %s", result_file_name)); - if (access(result_file_name, F_OK) != 0) - die("The specified result file does not exist: '%s'", result_file_name); - - switch (dyn_string_cmp(ds, result_file_name)) { + switch (compare_files(log_file.file_name(), result_file_name)) { case RESULT_OK: break; /* ok */ case RESULT_LENGTH_MISMATCH: @@ -1611,9 +1732,10 @@ void check_result(DYNAMIC_STRING* ds) fn_format(reject_file, result_file_name, opt_logdir, ".reject", MY_REPLACE_DIR | MY_REPLACE_EXT); } - str_to_file(reject_file, ds->str, ds->length); - dynstr_set(ds, NULL); /* Don't create a .log file */ + if (my_copy(log_file.file_name(), reject_file, MYF(0)) != 0) + die("Failed to copy '%s' to '%s', errno: %d", + log_file.file_name(), reject_file, errno); show_diff(NULL, result_file_name, reject_file); die(mess); @@ -1727,7 +1849,7 @@ VAR *var_init(VAR *v, const char *name, int name_len, const char *val, tmp_var->name = (name) ? (char*) tmp_var + sizeof(*tmp_var) : 0; tmp_var->alloced = (v == 0); - if (!(tmp_var->str_val = my_malloc(val_alloc_len+1, MYF(MY_WME)))) + if (!(tmp_var->str_val = (char*)my_malloc(val_alloc_len+1, MYF(MY_WME)))) die("Out of memory"); memcpy(tmp_var->name, name, name_len); @@ -2041,9 +2163,9 @@ void var_set_query_get_value(struct st_command *command, VAR *var) static DYNAMIC_STRING ds_col; static DYNAMIC_STRING ds_row; const struct command_arg query_get_value_args[] = { - "query", ARG_STRING, TRUE, &ds_query, "Query to run", - "column name", ARG_STRING, TRUE, &ds_col, "Name of column", - "row number", ARG_STRING, TRUE, &ds_row, "Number for row" + {"query", ARG_STRING, TRUE, &ds_query, "Query to run"}, + {"column name", ARG_STRING, TRUE, &ds_col, "Name of column"}, + {"row number", ARG_STRING, TRUE, &ds_row, "Number for row"} }; DBUG_ENTER("var_set_query_get_value"); @@ -2140,8 +2262,8 @@ void var_copy(VAR *dest, VAR *src) /* Alloc/realloc data for str_val in dest */ if (dest->alloced_len < src->alloced_len && !(dest->str_val= dest->str_val - ? my_realloc(dest->str_val, src->alloced_len, MYF(MY_WME)) - : my_malloc(src->alloced_len, MYF(MY_WME)))) + ? (char*)my_realloc(dest->str_val, src->alloced_len, MYF(MY_WME)) + : (char*)my_malloc(src->alloced_len, MYF(MY_WME)))) die("Out of memory"); else dest->alloced_len= src->alloced_len; @@ -2162,8 +2284,16 @@ void eval_expr(VAR *v, const char *p, const char **p_end) if (*p == '$') { VAR *vp; + const char* expected_end= *p_end; // Remember var end if ((vp= var_get(p, p_end, 0, 0))) var_copy(v, vp); + + /* Make sure there was just a $variable and nothing else */ + const char* end= *p_end + 1; + if (end < expected_end) + die("Found junk '%.*s' after $variable in expression", + (int)(expected_end - end - 1), end); + DBUG_VOID_RETURN; } @@ -2199,9 +2329,9 @@ void eval_expr(VAR *v, const char *p, const char **p_end) v->alloced_len = (new_val_len < MIN_VAR_ALLOC - 1) ? MIN_VAR_ALLOC : new_val_len + 1; if (!(v->str_val = - v->str_val ? my_realloc(v->str_val, v->alloced_len+1, - MYF(MY_WME)) : - my_malloc(v->alloced_len+1, MYF(MY_WME)))) + v->str_val ? + (char*)my_realloc(v->str_val, v->alloced_len+1, MYF(MY_WME)) : + (char*)my_malloc(v->alloced_len+1, MYF(MY_WME)))) die("Out of memory"); } v->str_val_len = new_val_len; @@ -2218,8 +2348,19 @@ void eval_expr(VAR *v, const char *p, const char **p_end) int open_file(const char *name) { char buff[FN_REFLEN]; + size_t length; DBUG_ENTER("open_file"); DBUG_PRINT("enter", ("name: %s", name)); + + /* Extract path from current file and try it as base first */ + if (dirname_part(buff, cur_file->file_name, &length)) + { + strxmov(buff, buff, name, NullS); + if (access(buff, F_OK) == 0){ + DBUG_PRINT("info", ("The file exists")); + name= buff; + } + } if (!test_if_hard_path(name)) { strxmov(buff, opt_basedir, name, NullS); @@ -2233,7 +2374,7 @@ int open_file(const char *name) if (!(cur_file->file = my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0)))) { cur_file--; - die("Could not open '%s' for reading", buff); + die("Could not open '%s' for reading, errno: %d", buff, errno); } cur_file->file_name= my_strdup(buff, MYF(MY_FAE)); cur_file->lineno=1; @@ -2520,7 +2661,7 @@ enum enum_operator SYNOPSIS do_modify_var() query called command - operator operation to perform on the var + op operation to perform on the var DESCRIPTION dec $var_name @@ -2529,7 +2670,7 @@ enum enum_operator */ int do_modify_var(struct st_command *command, - enum enum_operator operator) + enum enum_operator op) { const char *p= command->first_argument; VAR* v; @@ -2539,7 +2680,7 @@ int do_modify_var(struct st_command *command, die("The argument to %.*s must be a variable (start with $)", command->first_word_len, command->query); v= var_get(p, &p, 1, 0); - switch (operator) { + switch (op) { case DO_DEC: v->int_val--; break; @@ -2789,7 +2930,7 @@ void do_mkdir(struct st_command *command) int error; static DYNAMIC_STRING ds_dirname; const struct command_arg mkdir_args[] = { - "dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to create" + {"dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to create"} }; DBUG_ENTER("do_mkdir"); @@ -2819,7 +2960,7 @@ void do_rmdir(struct st_command *command) int error; static DYNAMIC_STRING ds_dirname; const struct command_arg rmdir_args[] = { - "dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to remove" + {"dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to remove"} }; DBUG_ENTER("do_rmdir"); @@ -3194,6 +3335,14 @@ void do_diff_files(struct st_command *command) sizeof(diff_file_args)/sizeof(struct command_arg), ' '); + if (access(ds_filename.str, F_OK) != 0) + die("command \"diff_files\" failed, file '%s' does not exist", + ds_filename.str); + + if (access(ds_filename2.str, F_OK) != 0) + die("command \"diff_files\" failed, file '%s' does not exist", + ds_filename2.str); + if ((error= compare_files(ds_filename.str, ds_filename2.str))) { /* Compare of the two files failed, append them to output @@ -3479,24 +3628,19 @@ void do_wait_for_slave_to_stop(struct st_command *c __attribute__((unused))) } -void do_sync_with_master2(long offset) +void do_sync_with_master2(struct st_command *command, long offset) { MYSQL_RES *res; MYSQL_ROW row; MYSQL *mysql= &cur_con->mysql; char query_buf[FN_REFLEN+128]; - int tries= 0; - int rpl_parse; + int timeout= 300; /* seconds */ if (!master_pos.file[0]) die("Calling 'sync_with_master' without calling 'save_master_pos'"); - rpl_parse= mysql_rpl_parse_enabled(mysql); - mysql_disable_rpl_parse(mysql); - - sprintf(query_buf, "select master_pos_wait('%s', %ld)", master_pos.file, - master_pos.pos + offset); -wait_for_position: + sprintf(query_buf, "select master_pos_wait('%s', %ld, %d)", + master_pos.file, master_pos.pos + offset, timeout); if (mysql_query(mysql, query_buf)) die("failed in '%s': %d: %s", query_buf, mysql_errno(mysql), @@ -3509,30 +3653,48 @@ wait_for_position: mysql_free_result(res); die("empty result in %s", query_buf); } - if (!row[0]) + + int result= -99; + const char* result_str= row[0]; + if (result_str) + result= atoi(result_str); + + mysql_free_result(res); + + if (!result_str || result < 0) { - /* - It may be that the slave SQL thread has not started yet, though START - SLAVE has been issued ? - */ - mysql_free_result(res); - if (tries++ == 30) + /* master_pos_wait returned NULL or < 0 */ + show_query(mysql, "SHOW MASTER STATUS"); + show_query(mysql, "SHOW SLAVE STATUS"); + show_query(mysql, "SHOW PROCESSLIST"); + fprintf(stderr, "analyze: sync_with_master\n"); + + if (!result_str) { - show_query(mysql, "SHOW MASTER STATUS"); - show_query(mysql, "SHOW SLAVE STATUS"); - die("could not sync with master ('%s' returned NULL)", query_buf); + /* + master_pos_wait returned NULL. This indicates that + slave SQL thread is not started, the slave's master + information is not initialized, the arguments are + incorrect, or an error has occured + */ + die("%.*s failed: '%s' returned NULL "\ + "indicating slave SQL thread failure", + command->first_word_len, command->query, query_buf); + } - sleep(1); /* So at most we will wait 30 seconds and make 31 tries */ - goto wait_for_position; + + if (result == -1) + die("%.*s failed: '%s' returned -1 "\ + "indicating timeout after %d seconds", + command->first_word_len, command->query, query_buf, timeout); + else + die("%.*s failed: '%s' returned unknown result :%d", + command->first_word_len, command->query, query_buf, result); } - mysql_free_result(res); - if (rpl_parse) - mysql_enable_rpl_parse(mysql); return; } - void do_sync_with_master(struct st_command *command) { long offset= 0; @@ -3547,7 +3709,7 @@ void do_sync_with_master(struct st_command *command) die("Invalid integer argument \"%s\"", offset_start); command->last_argument= p; } - do_sync_with_master2(offset); + do_sync_with_master2(command, offset); return; } @@ -3897,6 +4059,145 @@ void do_set_charset(struct st_command *command) } +/* + Run query and return one field in the result set from the + first row and <column> +*/ + +int query_get_string(MYSQL* mysql, const char* query, + int column, DYNAMIC_STRING* ds) +{ + MYSQL_RES *res= NULL; + MYSQL_ROW row; + + if (mysql_query(mysql, query)) + die("'%s' failed: %d %s", query, + mysql_errno(mysql), mysql_error(mysql)); + if ((res= mysql_store_result(mysql)) == NULL) + die("Failed to store result: %d %s", + mysql_errno(mysql), mysql_error(mysql)); + + if ((row= mysql_fetch_row(res)) == NULL) + { + mysql_free_result(res); + ds= 0; + return 1; + } + init_dynamic_string(ds, (row[column] ? row[column] : "NULL"), ~0, 32); + mysql_free_result(res); + return 0; +} + + +static int my_kill(int pid, int sig) +{ +#ifdef __WIN__ + HANDLE proc; + if ((proc= OpenProcess(PROCESS_TERMINATE, FALSE, pid)) == NULL) + return -1; + if (sig == 0) + { + CloseHandle(proc); + return 0; + } + (void)TerminateProcess(proc, 201); + CloseHandle(proc); + return 1; +#else + return kill(pid, sig); +#endif +} + + + +/* + Shutdown the server of current connection and + make sure it goes away within <timeout> seconds + + NOTE! Currently only works with local server + + SYNOPSIS + do_shutdown_server() + command called command + + DESCRIPTION + shutdown [<timeout>] + +*/ + +void do_shutdown_server(struct st_command *command) +{ + int timeout=60, pid; + DYNAMIC_STRING ds_pidfile_name; + MYSQL* mysql = &cur_con->mysql; + static DYNAMIC_STRING ds_timeout; + const struct command_arg shutdown_args[] = { + {"timeout", ARG_STRING, FALSE, &ds_timeout, "Timeout before killing server"} + }; + DBUG_ENTER("do_shutdown_server"); + + check_command_args(command, command->first_argument, shutdown_args, + sizeof(shutdown_args)/sizeof(struct command_arg), + ' '); + + if (ds_timeout.length) + { + timeout= atoi(ds_timeout.str); + if (timeout == 0) + die("Illegal argument for timeout: '%s'", ds_timeout.str); + } + dynstr_free(&ds_timeout); + + /* Get the servers pid_file name and use it to read pid */ + if (query_get_string(mysql, "SHOW VARIABLES LIKE 'pid_file'", 1, + &ds_pidfile_name)) + die("Failed to get pid_file from server"); + + /* Read the pid from the file */ + { + int fd; + char buff[32]; + + if ((fd= my_open(ds_pidfile_name.str, O_RDONLY, MYF(0))) < 0) + die("Failed to open file '%s'", ds_pidfile_name.str); + dynstr_free(&ds_pidfile_name); + + if (my_read(fd, (uchar*)&buff, + sizeof(buff), MYF(0)) <= 0){ + my_close(fd, MYF(0)); + die("pid file was empty"); + } + my_close(fd, MYF(0)); + + pid= atoi(buff); + if (pid == 0) + die("Pidfile didn't contain a valid number"); + } + DBUG_PRINT("info", ("Got pid %d", pid)); + + /* Tell server to shutdown if timeout > 0*/ + if (timeout && mysql_shutdown(mysql, SHUTDOWN_DEFAULT)) + die("mysql_shutdown failed"); + + /* Check that server dies */ + while(timeout--){ + if (my_kill(0, pid) < 0){ + DBUG_PRINT("info", ("Process %d does not exist anymore", pid)); + break; + } + DBUG_PRINT("info", ("Sleeping, timeout: %d", timeout)); + my_sleep(1000000L); + } + + /* Kill the server */ + DBUG_PRINT("info", ("Killing server, pid: %d", pid)); + (void)my_kill(9, pid); + + DBUG_VOID_RETURN; + +} + + #if MYSQL_VERSION_ID >= 50000 /* List of error names to error codes, available from 5.0 */ typedef struct @@ -5056,55 +5357,6 @@ void convert_to_format_v1(char* query) /* - Check a command that is about to be sent (or should have been - sent if parsing was enabled) to mysql server for - suspicious things and generate warnings. -*/ - -void scan_command_for_warnings(struct st_command *command) -{ - const char *ptr= command->query; - DBUG_ENTER("scan_command_for_warnings"); - DBUG_PRINT("enter", ("query: %s", command->query)); - - while(*ptr) - { - /* - Look for query's that lines that start with a -- comment - and has a mysqltest command - */ - if (ptr[0] == '\n' && - ptr[1] && ptr[1] == '-' && - ptr[2] && ptr[2] == '-' && - ptr[3]) - { - uint type; - char save; - char *end, *start= (char*)ptr+3; - /* Skip leading spaces */ - while (*start && my_isspace(charset_info, *start)) - start++; - end= start; - /* Find end of command(next space) */ - while (*end && !my_isspace(charset_info, *end)) - end++; - save= *end; - *end= 0; - DBUG_PRINT("info", ("Checking '%s'", start)); - type= find_type(start, &command_typelib, 1+2); - if (type) - warning_msg("Embedded mysqltest command '--%s' detected in " - "query '%s' was this intentional? ", - start, command->query); - *end= save; - } - - ptr++; - } - DBUG_VOID_RETURN; -} - -/* Check for unexpected "junk" after the end of query This is normally caused by missing delimiters or when switching between different delimiters @@ -5161,6 +5413,19 @@ void check_eol_junk(const char *eol) } +bool is_delimiter(const char* p) +{ + uint match= 0; + char* delim= delimiter; + while (*p && *p == *delim++) + { + match++; + p++; + } + + return (match == delimiter_length); +} + /* Create a command from a set of lines @@ -5227,9 +5492,11 @@ int read_command(struct st_command** command_ptr) if (!(command->query_buf= command->query= my_strdup(p, MYF(MY_WME)))) die("Out of memory"); - /* Calculate first word length(the command), terminated by space or ( */ + /* + Calculate first word length(the command), terminated + by 'space' , '(' or 'delimiter' */ p= command->query; - while (*p && !my_isspace(charset_info, *p) && *p != '(') + while (*p && !my_isspace(charset_info, *p) && *p != '(' && !is_delimiter(p)) p++; command->first_word_len= (uint) (p - command->query); DBUG_PRINT("info", ("first_word: %.*s", @@ -5448,7 +5715,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), DBUG_ASSERT(cur_file == file_stack && cur_file->file == 0); if (!(cur_file->file= my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0)))) - die("Could not open '%s' for reading: errno = %d", buff, errno); + die("Could not open '%s' for reading, errno: %d", buff, errno); cur_file->file_name= my_strdup(buff, MYF(MY_FAE)); cur_file->lineno= 1; break; @@ -5494,6 +5761,11 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), die("Can't use server argument"); } break; + case OPT_LOG_DIR: + /* Check that the file exists */ + if (access(opt_logdir, F_OK) != 0) + die("The specified log directory does not exist: '%s'", opt_logdir); + break; case 'F': read_embedded_server_arguments(argument); break; @@ -5535,6 +5807,14 @@ int parse_args(int argc, char **argv) if (debug_check_flag) my_end_arg= MY_CHECK_ERROR; + + if (!record) + { + /* Check that the result file exists */ + if (result_file_name && access(result_file_name, F_OK) != 0) + die("The specified result file '%s' does not exist", result_file_name); + } + return 0; } @@ -5565,11 +5845,11 @@ void str_to_file2(const char *fname, char *str, int size, my_bool append) flags|= O_TRUNC; if ((fd= my_open(buff, flags, MYF(MY_WME | MY_FFNF))) < 0) - die("Could not open '%s' for writing: errno = %d", buff, errno); + die("Could not open '%s' for writing, errno: %d", buff, errno); if (append && my_seek(fd, 0, SEEK_END, MYF(0)) == MY_FILEPOS_ERROR) - die("Could not find end of file '%s': errno = %d", buff, errno); + die("Could not find end of file '%s', errno: %d", buff, errno); if (my_write(fd, (uchar*)str, size, MYF(MY_WME|MY_FNABP))) - die("write failed"); + die("write failed, errno: %d", errno); my_close(fd, MYF(0)); } @@ -5589,37 +5869,6 @@ void str_to_file(const char *fname, char *str, int size) } -void dump_result_to_log_file(char *buf, int size) -{ - char log_file[FN_REFLEN]; - str_to_file(fn_format(log_file, result_file_name, opt_logdir, ".log", - *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT : - MY_REPLACE_EXT), - buf, size); - fprintf(stderr, "\nMore results from queries before failure can be found in %s\n", - log_file); -} - -void dump_progress(void) -{ - char progress_file[FN_REFLEN]; - str_to_file(fn_format(progress_file, result_file_name, - opt_logdir, ".progress", - *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT : - MY_REPLACE_EXT), - ds_progress.str, ds_progress.length); -} - -void dump_warning_messages(void) -{ - char warn_file[FN_REFLEN]; - - str_to_file(fn_format(warn_file, result_file_name, opt_logdir, ".warnings", - *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT : - MY_REPLACE_EXT), - ds_warning_messages.str, ds_warning_messages.length); -} - void check_regerr(my_regex_t* r, int err) { char err_buf[1024]; @@ -5731,7 +5980,7 @@ void fix_win_paths(const char *val, int len) DBUG_PRINT("info", ("pattern: %s", *pattern)); /* Search for the path in string */ - while ((p= strstr(val, *pattern))) + while ((p= strstr((char*)val, *pattern))) { DBUG_PRINT("info", ("Found %s in val p: %s", *pattern, p)); @@ -5864,7 +6113,7 @@ void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt, { uint max_length= fields[i].max_length + 1; my_bind[i].buffer_type= MYSQL_TYPE_STRING; - my_bind[i].buffer= (char *)my_malloc(max_length, MYF(MY_WME | MY_FAE)); + my_bind[i].buffer= my_malloc(max_length, MYF(MY_WME | MY_FAE)); my_bind[i].buffer_length= max_length; my_bind[i].is_null= &is_null[i]; my_bind[i].length= &length[i]; @@ -5880,7 +6129,7 @@ void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt, while (mysql_stmt_fetch(stmt) == 0) { for (i= 0; i < num_fields; i++) - append_field(ds, i, &fields[i], my_bind[i].buffer, + append_field(ds, i, &fields[i], (char*)my_bind[i].buffer, *my_bind[i].length, *my_bind[i].is_null); if (!display_result_vertically) dynstr_append_mem(ds, "\n", 1); @@ -6634,9 +6883,6 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) init_dynamic_string(&ds_warnings, NULL, 0, 256); - /* Scan for warning before sending to server */ - scan_command_for_warnings(command); - /* Evaluate query if this is an eval command */ @@ -6966,28 +7212,10 @@ void get_command_type(struct st_command* command) } else { - /* -- comment that didn't contain a mysqltest command */ - command->type= Q_COMMENT; - warning_msg("Suspicious command '--%s' detected, was this intentional? "\ - "Use # instead of -- to avoid this warning", - command->query); - - if (command->first_word_len && - strcmp(command->query + command->first_word_len - 1, delimiter) == 0) - { - /* - Detect comment with command using extra delimiter - Ex --disable_query_log; - ^ Extra delimiter causing the command - to be skipped - */ - save= command->query[command->first_word_len-1]; - command->query[command->first_word_len-1]= 0; - if (find_type(command->query, &command_typelib, 1+2) > 0) - die("Extra delimiter \";\" found"); - command->query[command->first_word_len-1]= save; - - } + /* -- "comment" that didn't contain a mysqltest command */ + die("Found line beginning with -- that didn't contain "\ + "a valid mysqltest command, check your syntax or "\ + "use # if you intended to write a comment"); } } @@ -7006,22 +7234,25 @@ void get_command_type(struct st_command* command) /* Record how many milliseconds it took to execute the test file - up until the current line and save it in the dynamic string ds_progress. - - The ds_progress will be dumped to <test_name>.progress when - test run completes + up until the current line and write it to .progress file */ void mark_progress(struct st_command* command __attribute__((unused)), int line) { + static ulonglong progress_start= 0; // < Beware + DYNAMIC_STRING ds_progress; + char buf[32], *end; ulonglong timer= timer_now(); if (!progress_start) progress_start= timer; timer-= progress_start; + if (init_dynamic_string(&ds_progress, "", 256, 256)) + die("Out of memory"); + /* Milliseconds since start */ end= longlong2str(timer, buf, 10); dynstr_append_mem(&ds_progress, buf, (int)(end-buf)); @@ -7043,6 +7274,10 @@ void mark_progress(struct st_command* command __attribute__((unused)), dynstr_append_mem(&ds_progress, "\n", 1); + progress_file.write(&ds_progress); + + dynstr_free(&ds_progress); + } #ifdef HAVE_STACKTRACE @@ -7150,7 +7385,6 @@ int main(int argc, char **argv) my_bool q_send_flag= 0, abort_flag= 0; uint command_executed= 0, last_command_executed= 0; char save_file[FN_REFLEN]; - MY_STAT res_info; MY_INIT(argv[0]); save_file[0]= 0; @@ -7209,11 +7443,14 @@ int main(int argc, char **argv) init_win_path_patterns(); #endif - init_dynamic_string(&ds_res, "", 65536, 65536); - init_dynamic_string(&ds_progress, "", 0, 2048); - init_dynamic_string(&ds_warning_messages, "", 0, 2048); + init_dynamic_string(&ds_res, "", 2048, 2048); + parse_args(argc, argv); + log_file.open(opt_logdir, result_file_name, ".log"); + if (opt_mark_progress) + progress_file.open(opt_logdir, result_file_name, ".progress"); + var_set_int("$PS_PROTOCOL", ps_protocol); var_set_int("$SP_PROTOCOL", sp_protocol); var_set_int("$VIEW_PROTOCOL", view_protocol); @@ -7302,8 +7539,8 @@ int main(int argc, char **argv) command->type != Q_ENABLE_PARSING && command->type != Q_DISABLE_PARSING) { + /* Parsing is disabled, silently convert this line to a comment */ command->type= Q_COMMENT; - scan_command_for_warnings(command); } if (cur_block->ok) @@ -7474,15 +7711,23 @@ int main(int argc, char **argv) select_connection(command); else select_connection_name("slave"); - do_sync_with_master2(0); + do_sync_with_master2(command, 0); break; } case Q_COMMENT: /* Ignore row */ command->last_argument= command->end; break; case Q_PING: - (void) mysql_ping(&cur_con->mysql); - break; + handle_command_error(command, mysql_ping(&cur_con->mysql)); + break; + case Q_SEND_SHUTDOWN: + handle_command_error(command, + mysql_shutdown(&cur_con->mysql, + SHUTDOWN_DEFAULT)); + break; + case Q_SHUTDOWN_SERVER: + do_shutdown_server(command); + break; case Q_EXEC: do_exec(command); command_executed++; @@ -7591,8 +7836,14 @@ int main(int argc, char **argv) parser.current_line += current_line_inc; if ( opt_mark_progress ) mark_progress(command, parser.current_line); + + /* Write result from command to log file */ + log_file.write(&ds_res); + dynstr_set(&ds_res, 0); } + log_file.close(); + start_lineno= 0; if (parsing_disabled) @@ -7601,9 +7852,9 @@ int main(int argc, char **argv) /* The whole test has been executed _sucessfully_. Time to compare result or save it to record file. - The entire output from test is now kept in ds_res. + The entire output from test is in the log file */ - if (ds_res.length) + if (log_file.bytes_written()) { if (result_file_name) { @@ -7611,22 +7862,29 @@ int main(int argc, char **argv) if (record) { - /* Recording - dump the output from test to result file */ - str_to_file(result_file_name, ds_res.str, ds_res.length); + /* Recording */ + + /* save a copy of the log to result file */ + if (my_copy(log_file.file_name(), result_file_name, MYF(0)) != 0) + die("Failed to copy '%s' to '%s', errno: %d", + log_file.file_name(), result_file_name, errno); + } else { - /* Check that the output from test is equal to result file - - detect missing result file - - detect zero size result file - */ - check_result(&ds_res); + /* Check that the output from test is equal to result file */ + check_result(); } } else { - /* No result_file_name specified to compare with, print to stdout */ - printf("%s", ds_res.str); + /* + No result_file_name specified, the result + has been printed to stdout, exit with error + unless script has called "exit" to indicate success + */ + if (abort_flag == 0) + die("Exit with failure! Call 'exit' in script to return with sucess"); } } else @@ -7634,25 +7892,8 @@ int main(int argc, char **argv) die("The test didn't produce any output"); } - if (!command_executed && - result_file_name && my_stat(result_file_name, &res_info, 0)) - { - /* - my_stat() successful on result file. Check if we have not run a - single query, but we do have a result file that contains data. - Note that we don't care, if my_stat() fails. For example, for a - non-existing or non-readable file, we assume it's fine to have - no query output from the test file, e.g. regarded as no error. - */ + if (!command_executed && result_file_name) die("No queries executed but result file found!"); - } - - if ( opt_mark_progress && result_file_name ) - dump_progress(); - - /* Dump warning messages */ - if (result_file_name && ds_warning_messages.length) - dump_warning_messages(); timer_output(); /* Yes, if we got this far the test has suceeded! Sakila smiles */ @@ -7721,12 +7962,11 @@ void do_get_replace_column(struct st_command *command) die("Missing argument in %s", command->query); /* Allocate a buffer for results */ - start= buff= my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE)); + start= buff= (char*)my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE)); while (*from) { char *to; uint column_number; - to= get_string(&buff, &from, command); if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS) die("Wrong column number to replace_column in '%s'", command->query); @@ -7804,7 +8044,7 @@ void do_get_replace(struct st_command *command) bzero((char*) &from_array,sizeof(from_array)); if (!*from) die("Missing argument in %s", command->query); - start= buff= my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE)); + start= buff= (char*)my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE)); while (*from) { char *to= buff; @@ -7812,6 +8052,9 @@ void do_get_replace(struct st_command *command) if (!*from) die("Wrong number of arguments to replace_result in '%s'", command->query); +#ifdef __WIN__ + fix_win_paths(to, from - to); +#endif insert_pointer_name(&from_array,to); to= get_string(&buff, &from, command); insert_pointer_name(&to_array,to); |