diff options
author | unknown <msvensson@pilot.(none)> | 2007-08-13 11:29:58 +0200 |
---|---|---|
committer | unknown <msvensson@pilot.(none)> | 2007-08-13 11:29:58 +0200 |
commit | c2f6f8b6aa86fb719419c2a1d574015ab1e1ecd2 (patch) | |
tree | 527f81e4adb254bdce4c48e0c1b16e71071f270c /client | |
parent | db73e34fb884b61ff87be742520264a38e720458 (diff) | |
parent | ff985f06903c6a3c393c26c64a944f19337fcd36 (diff) | |
download | mariadb-git-c2f6f8b6aa86fb719419c2a1d574015ab1e1ecd2.tar.gz |
Merge bk-internal:/home/bk/mysql-5.0-maint
into pilot.(none):/data/msvensson/mysql/mysql-5.0-maint
mysql-test/mysql-test-run.pl:
Auto merged
Diffstat (limited to 'client')
-rw-r--r-- | client/mysql_upgrade.c | 1 | ||||
-rw-r--r-- | client/mysqltest.c | 736 |
2 files changed, 552 insertions, 185 deletions
diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index 64de3d19882..13f5d2606a9 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -457,6 +457,7 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res, NULL); my_close(fd, MYF(0)); + my_delete(query_file_path, MYF(0)); DBUG_RETURN(ret); } diff --git a/client/mysqltest.c b/client/mysqltest.c index d1ec753b54b..1ce52cd8527 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -74,18 +74,12 @@ #define QUERY_SEND_FLAG 1 #define QUERY_REAP_FLAG 2 - enum { - RESULT_OK= 0, - RESULT_CONTENT_MISMATCH= 1, - RESULT_LENGTH_MISMATCH= 2 - }; - enum { OPT_SKIP_SAFEMALLOC=256, OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, OPT_SSL_CA, OPT_SSL_CAPATH, OPT_SSL_CIPHER, OPT_PS_PROTOCOL, OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL, OPT_SSL_VERIFY_SERVER_CERT, OPT_MAX_CONNECT_RETRIES, - OPT_MARK_PROGRESS, OPT_CHARSETS_DIR, OPT_LOG_DIR + OPT_MARK_PROGRESS, OPT_CHARSETS_DIR, OPT_LOG_DIR, OPT_TAIL_LINES }; static int record= 0, opt_sleep= -1; @@ -117,6 +111,9 @@ static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer; static uint start_lineno= 0; /* Start line of current command */ +/* Number of lines of the result to include in failure report */ +static uint opt_tail_lines= 0; + static char delimiter[MAX_DELIMITER_LENGTH]= ";"; static uint delimiter_length= 1; @@ -238,7 +235,7 @@ struct st_connection #endif /*EMBEDDED_LIBRARY*/ }; struct st_connection connections[128]; -struct st_connection* cur_con, *next_con, *connections_end; +struct st_connection* cur_con= NULL, *next_con, *connections_end; /* List of commands in mysqltest @@ -455,7 +452,6 @@ void free_tmp_sh_file(); void free_win_path_patterns(); #endif -static int eval_result = 0; /* For replace_column */ static char *replace_column[MAX_COLUMNS]; @@ -503,11 +499,11 @@ void handle_no_error(struct st_command*); pthread_attr_t cn_thd_attrib; /* - send_one_query executes query in separate thread what is + send_one_query executes query in separate thread, which is necessary in embedded library to run 'send' in proper way. This implementation doesn't handle errors returned by mysql_send_query. It's technically possible, though - i don't see where it is needed. + I don't see where it is needed. */ pthread_handler_t send_one_query(void *arg) { @@ -608,6 +604,77 @@ void do_eval(DYNAMIC_STRING *query_eval, const char *query, } +/* + Show any warnings just before the error. Since the last error + is added to the warning stack, only print @@warning_count-1 warnings. + + NOTE! This function should be safe to call when an error + has occured and this any further errors will be ignored(although logged) + + SYNOPSIS + show_warnings_before_error + mysql - connection to use + +*/ + +static void show_warnings_before_error(MYSQL* mysql) +{ + MYSQL_RES* res; + const char* query= "SHOW WARNINGS"; + DBUG_ENTER("show_warnings_before_error"); + + if (!mysql) + DBUG_VOID_RETURN; + + if (mysql_query(mysql, query)) + { + log_msg("Error running query '%s': %d %s", + query, mysql_errno(mysql), mysql_error(mysql)); + DBUG_VOID_RETURN; + } + + if ((res= mysql_store_result(mysql)) == NULL) + { + /* No result set returned */ + DBUG_VOID_RETURN; + } + + if (mysql_num_rows(res) <= 1) + { + /* Don't display the last row, it's "last error" */ + } + else + { + MYSQL_ROW row; + unsigned int row_num= 0; + unsigned int num_fields= mysql_num_fields(res); + + fprintf(stderr, "\nWarnings from just before the error:\n"); + while ((row= mysql_fetch_row(res))) + { + unsigned int i; + unsigned long *lengths= mysql_fetch_lengths(res); + + if (++row_num >= mysql_num_rows(res)) + { + /* Don't display the last row, it's "last error" */ + break; + } + + for(i= 0; i < num_fields; i++) + { + fprintf(stderr, "%.*s ", (int)lengths[i], + row[i] ? row[i] : "NULL"); + } + fprintf(stderr, "\n"); + } + } + mysql_free_result(res); + + DBUG_VOID_RETURN; +} + + enum arg_type { ARG_STRING, @@ -686,6 +753,15 @@ void check_command_args(struct st_command *command, command->first_word_len, command->query); } + /* Check for too many arguments passed */ + ptr= command->last_argument; + while(ptr <= command->end) + { + if (*ptr && *ptr != ' ') + die("Extra argument '%s' passed to '%.*s'", + ptr, command->first_word_len, command->query); + ptr++; + } DBUG_VOID_RETURN; } @@ -881,6 +957,24 @@ 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); @@ -889,6 +983,13 @@ void die(const char *fmt, ...) if (result_file_name && ds_warning_messages.length) dump_warning_messages(); + /* + Help debugging by displaying any warnings that might have + been produced prior to the error + */ + if (cur_con) + show_warnings_before_error(&cur_con->mysql); + cleanup_and_exit(1); } @@ -992,11 +1093,10 @@ void warning_msg(const char *fmt, ...) void log_msg(const char *fmt, ...) { va_list args; - char buff[512]; + char buff[1024]; size_t len; DBUG_ENTER("log_msg"); - memset(buff, 0, sizeof(buff)); va_start(args, fmt); len= my_vsnprintf(buff, sizeof(buff)-1, fmt, args); va_end(args); @@ -1009,77 +1109,372 @@ void log_msg(const char *fmt, ...) /* - Compare content of the string ds to content of file fname + Read a file and append it to ds + + SYNOPSIS + cat_file + ds - pointer to dynamic string where to add the files content + filename - name of the file to read + */ -int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) +void cat_file(DYNAMIC_STRING* ds, const char* filename) { - MY_STAT stat_info; - char *tmp, *res_ptr; - char eval_file[FN_REFLEN]; - int res; - uint res_len; int fd; - DYNAMIC_STRING res_ds; - DBUG_ENTER("dyn_string_cmp"); + uint len; + char buff[512]; - if (!test_if_hard_path(fname)) + if ((fd= my_open(filename, O_RDONLY, MYF(0))) < 0) + die("Failed to open file %s", filename); + while((len= my_read(fd, (byte*)&buff, + sizeof(buff), MYF(0))) > 0) { - strxmov(eval_file, opt_basedir, fname, NullS); - fn_format(eval_file, eval_file, "", "", MY_UNPACK_FILENAME); + char *p= buff, *start= buff; + while (p < buff+len) + { + /* Convert cr/lf to lf */ + if (*p == '\r' && *(p+1) && *(p+1)== '\n') + { + /* Add fake newline instead of cr and output the line */ + *p= '\n'; + p++; /* Step past the "fake" newline */ + dynstr_append_mem(ds, start, p-start); + p++; /* Step past the "fake" newline */ + start= p; + } + else + p++; + } + /* Output any chars that migh be left */ + dynstr_append_mem(ds, start, p-start); } - else - fn_format(eval_file, fname, "", "", MY_UNPACK_FILENAME); + my_close(fd, MYF(0)); +} - if (!my_stat(eval_file, &stat_info, MYF(MY_WME))) - die(NullS); - if (!eval_result && (uint) stat_info.st_size != ds->length) + +/* + Run the specified command with popen + + SYNOPSIS + run_command + cmd - command to execute(should be properly quoted + ds_res- pointer to dynamic string where to store the result + +*/ + +static int run_command(char* cmd, + DYNAMIC_STRING *ds_res) +{ + char buf[512]= {0}; + FILE *res_file; + int error; + + if (!(res_file= popen(cmd, "r"))) + die("popen(\"%s\", \"r\") failed", cmd); + + while (fgets(buf, sizeof(buf), res_file)) + { + DBUG_PRINT("info", ("buf: %s", buf)); + if(ds_res) + { + /* Save the output of this command in the supplied string */ + dynstr_append(ds_res, buf); + } + else + { + /* Print it directly on screen */ + fprintf(stdout, "%s", buf); + } + } + + error= pclose(res_file); + return WEXITSTATUS(error); +} + + +/* + Run the specified tool with variable number of arguments + + SYNOPSIS + run_tool + tool_path - the name of the tool to run + ds_res - pointer to dynamic string where to store the result + ... - variable number of arguments that will be properly + quoted and appended after the tool's name + +*/ + +static int run_tool(const char *tool_path, DYNAMIC_STRING *ds_res, ...) +{ + int ret; + const char* arg; + va_list args; + DYNAMIC_STRING ds_cmdline; + + DBUG_ENTER("run_tool"); + DBUG_PRINT("enter", ("tool_path: %s", tool_path)); + + if (init_dynamic_string(&ds_cmdline, IF_WIN("\"", ""), FN_REFLEN, FN_REFLEN)) + die("Out of memory"); + + dynstr_append_os_quoted(&ds_cmdline, tool_path, NullS); + dynstr_append(&ds_cmdline, " "); + + va_start(args, ds_res); + + while ((arg= va_arg(args, char *))) { - DBUG_PRINT("info",("Size differs: result size: %u file size: %lu", - ds->length, (ulong) stat_info.st_size)); - DBUG_PRINT("info",("result: '%s'", ds->str)); - DBUG_RETURN(RESULT_LENGTH_MISMATCH); + /* Options should be os quoted */ + if (strncmp(arg, "--", 2) == 0) + dynstr_append_os_quoted(&ds_cmdline, arg, NullS); + else + dynstr_append(&ds_cmdline, arg); + dynstr_append(&ds_cmdline, " "); } - if (!(tmp = (char*) my_malloc(stat_info.st_size + 1, MYF(MY_WME)))) + + va_end(args); + +#ifdef __WIN__ + dynstr_append(&ds_cmdline, "\""); +#endif + + DBUG_PRINT("info", ("Running: %s", ds_cmdline.str)); + ret= run_command(ds_cmdline.str, ds_res); + DBUG_PRINT("exit", ("ret: %d", ret)); + dynstr_free(&ds_cmdline); + DBUG_RETURN(ret); +} + + +/* + Show the diff of two files using the systems builtin diff + command. If no such diff command exist, just dump the content + of the two files and inform about how to get "diff" + + SYNOPSIS + show_diff + ds - pointer to dynamic string where to add the diff(may be NULL) + filename1 - name of first file + filename2 - name of second file + +*/ + +void show_diff(DYNAMIC_STRING* ds, + const char* filename1, const char* filename2) +{ + + DYNAMIC_STRING ds_tmp; + + if (init_dynamic_string(&ds_tmp, "", 256, 256)) die("Out of memory"); - if ((fd = my_open(eval_file, O_RDONLY, MYF(MY_WME))) < 0) - die("Failed to open file %s", eval_file); - if (my_read(fd, (byte*)tmp, stat_info.st_size, MYF(MY_WME|MY_NABP))) - die("Failed to read from file %s, errno: %d", eval_file, errno); - tmp[stat_info.st_size] = 0; - init_dynamic_string(&res_ds, "", stat_info.st_size+256, 256); - if (eval_result) - { - do_eval(&res_ds, tmp, tmp + stat_info.st_size, FALSE); - res_ptr= res_ds.str; - res_len= res_ds.length; - if (res_len != ds->length) + /* First try with unified diff */ + if (run_tool("diff", + &ds_tmp, /* Get output from diff in ds_tmp */ + "-u", + filename1, + filename2, + "2>&1", + NULL) > 1) /* Most "diff" tools return >1 if error */ + { + dynstr_set(&ds_tmp, ""); + + /* Fallback to context diff with "diff -c" */ + if (run_tool("diff", + &ds_tmp, /* Get output from diff in ds_tmp */ + "-c", + filename1, + filename2, + "2>&1", + NULL) > 1) /* Most "diff" tools return >1 if error */ { - res= RESULT_LENGTH_MISMATCH; - goto err; + /* + Fallback to dump both files to result file and inform + about installing "diff" + */ + dynstr_set(&ds_tmp, ""); + + 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" +"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__ +"or http://gnuwin32.sourceforge.net/packages/diffutils.htm\n" +#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"); } } + + if (ds) + { + /* Add the diff to output */ + dynstr_append_mem(ds, ds_tmp.str, ds_tmp.length); + } else { - res_ptr = tmp; - res_len = stat_info.st_size; + /* Print diff directly to stdout */ + fprintf(stderr, "%s\n", ds_tmp.str); } + + dynstr_free(&ds_tmp); - res= (memcmp(res_ptr, ds->str, res_len)) ? - RESULT_CONTENT_MISMATCH : RESULT_OK; +} -err: - if (res && eval_result) - str_to_file(fn_format(eval_file, fname, "", ".eval", - MY_REPLACE_EXT), - res_ptr, res_len); - dynstr_free(&res_ds); - my_free((gptr) tmp, MYF(0)); - my_close(fd, MYF(MY_WME)); +enum compare_files_result_enum { + RESULT_OK= 0, + RESULT_CONTENT_MISMATCH= 1, + RESULT_LENGTH_MISMATCH= 2 +}; + +/* + Compare two files, given a fd to the first file and + name of the second file + + SYNOPSIS + compare_files2 + fd - Open file descriptor of the first file + filename2 - Name of second file + + RETURN VALUES + According to the values in "compare_files_result_enum" + +*/ + +int compare_files2(File fd, const char* filename2) +{ + int error= RESULT_OK; + File fd2; + uint len, len2; + char buff[512], buff2[512]; + + if ((fd2= my_open(filename2, O_RDONLY, MYF(0))) < 0) + { + my_close(fd, MYF(0)); + die("Failed to open second file: %s", filename2); + } + while((len= my_read(fd, (byte*)&buff, + sizeof(buff), MYF(0))) > 0) + { + if ((len2= my_read(fd2, (byte*)&buff2, + sizeof(buff2), MYF(0))) < len) + { + /* File 2 was smaller */ + error= RESULT_LENGTH_MISMATCH; + break; + } + if (len2 > len) + { + /* File 1 was smaller */ + error= RESULT_LENGTH_MISMATCH; + break; + } + if ((memcmp(buff, buff2, len))) + { + /* Content of this part differed */ + error= RESULT_CONTENT_MISMATCH; + break; + } + } + if (!error && my_read(fd2, (byte*)&buff2, + sizeof(buff2), MYF(0)) > 0) + { + /* File 1 was smaller */ + error= RESULT_LENGTH_MISMATCH; + } + + my_close(fd2, MYF(0)); - DBUG_RETURN(res); + return error; +} + + +/* + Compare two files, given their filenames + + SYNOPSIS + compare_files + filename1 - Name of first file + filename2 - Name of second file + + RETURN VALUES + See 'compare_files2' + +*/ + +int compare_files(const char* filename1, const char* filename2) +{ + File fd; + int error; + + if ((fd= my_open(filename1, O_RDONLY, MYF(0))) < 0) + die("Failed to open first file: %s", filename1); + + error= compare_files2(fd, filename2); + + my_close(fd, MYF(0)); + + return error; +} + + +/* + Compare content of the string in ds to content of file fname + + SYNOPSIS + dyn_string_cmp + ds - Dynamic string containing the string o be compared + fname - Name of file to compare with + + RETURN VALUES + See 'compare_files2' +*/ + +int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) +{ + int error; + File fd; + char ds_temp_file_path[FN_REFLEN]; + + DBUG_ENTER("dyn_string_cmp"); + DBUG_PRINT("enter", ("fname: %s", fname)); + + if ((fd= create_temp_file(ds_temp_file_path, NULL, + "tmp", O_CREAT | O_SHARE | O_RDWR, + MYF(MY_WME))) < 0) + die("Failed to create temporary file for ds"); + + /* Write ds to temporary file and set file pos to beginning*/ + if (my_write(fd, ds->str, ds->length, + MYF(MY_FNABP | MY_WME)) || + my_seek(fd, 0, SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR) + { + my_close(fd, MYF(0)); + /* Remove the temporary file */ + my_delete(ds_temp_file_path, MYF(0)); + die("Failed to write to '%s'", ds_temp_file_path); + } + + error= compare_files2(fd, fname); + + my_close(fd, MYF(0)); + /* Remove the temporary file */ + my_delete(ds_temp_file_path, MYF(0)); + + DBUG_RETURN(error); } @@ -1097,21 +1492,34 @@ err: void check_result(DYNAMIC_STRING* ds) { + const char* mess= "Result content mismatch\n"; + DBUG_ENTER("check_result"); DBUG_ASSERT(result_file_name); + DBUG_PRINT("enter", ("result_file_name: %s", result_file_name)); switch (dyn_string_cmp(ds, result_file_name)) { case RESULT_OK: break; /* ok */ case RESULT_LENGTH_MISMATCH: - dump_result_to_reject_file(ds->str, ds->length); - die("Result length mismatch"); - break; + mess= "Result length mismatch\n"; + /* Fallthrough */ case RESULT_CONTENT_MISMATCH: - dump_result_to_reject_file(ds->str, ds->length); - die("Result content mismatch"); + { + /* Result mismatched, dump results to .reject file and then show the diff */ + char reject_file[FN_REFLEN]; + fn_format(reject_file, result_file_name, "", ".reject", + MY_REPLACE_EXT); + DBUG_PRINT("enter", ("reject_file_name: %s", reject_file)); + str_to_file(reject_file, ds->str, ds->length); + + dynstr_set(ds, NULL); /* Don't create a .log file */ + + show_diff(NULL, result_file_name, reject_file); + die(mess); break; + } default: /* impossible */ die("Unknown error code from dyn_string_cmp()"); } @@ -1126,7 +1534,7 @@ void check_result(DYNAMIC_STRING* ds) indicating that test is not supported SYNOPSIS - check_result + check_require ds - content to be checked fname - name of file to check against @@ -1455,40 +1863,22 @@ void var_query_set(VAR *var, const char *query, const char** query_end) die("Query '%s' didn't return a result set", ds_query.str); dynstr_free(&ds_query); - if ((row = mysql_fetch_row(res)) && row[0]) + if ((row= mysql_fetch_row(res)) && row[0]) { /* - Concatenate all row results with tab in between to allow us to work - with results from many columns (for example from SHOW VARIABLES) + Concatenate all fields in the first row with tab in between + and assign that string to the $variable */ DYNAMIC_STRING result; uint i; ulong *lengths; -#ifdef NOT_YET - MYSQL_FIELD *fields= mysql_fetch_fields(res); -#endif - init_dynamic_string(&result, "", 2048, 2048); + init_dynamic_string(&result, "", 512, 512); lengths= mysql_fetch_lengths(res); - for (i=0; i < mysql_num_fields(res); i++) + for (i= 0; i < mysql_num_fields(res); i++) { - if (row[0]) + if (row[i]) { -#ifdef NOT_YET - /* Add to <var_name>_<col_name> */ - uint j; - char var_col_name[MAX_VAR_NAME_LENGTH]; - uint length= snprintf(var_col_name, MAX_VAR_NAME_LENGTH, - "$%s_%s", var->name, fields[i].name); - /* Convert characters not allowed in variable names to '_' */ - for (j= 1; j < length; j++) - { - if (!my_isvar(charset_info,var_col_name[j])) - var_col_name[j]= '_'; - } - var_set(var_col_name, var_col_name + length, - row[i], row[i] + lengths[i]); -#endif /* Add column to tab separated string */ dynstr_append_mem(&result, row[i], lengths[i]); } @@ -1530,7 +1920,7 @@ void var_query_set(VAR *var, const char *query, const char** query_end) void var_set_query_get_value(struct st_command *command, VAR *var) { - ulong row_no; + long row_no; int col_no= -1; MYSQL_RES* res; MYSQL* mysql= &cur_con->mysql; @@ -1602,7 +1992,7 @@ void var_set_query_get_value(struct st_command *command, VAR *var) { /* Get the value */ MYSQL_ROW row; - ulong rows= 0; + long rows= 0; const char* value= "No such row"; while ((row= mysql_fetch_row(res))) @@ -1965,7 +2355,7 @@ void do_exec(struct st_command *command) if (command->abort_on_error) { - log_msg("exec of '%s failed, error: %d, status: %d, errno: %d", + log_msg("exec of '%s' failed, error: %d, status: %d, errno: %d", ds_cmd.str, error, status, errno); die("command \"%s\" failed", command->first_argument); } @@ -2203,8 +2593,8 @@ void do_copy_file(struct st_command *command) command command handle DESCRIPTION - chmod <octal> <file> - Change file permission of <file> + chmod_file <octal> <file_name> + Change file permission of <file_name> */ @@ -2214,8 +2604,8 @@ void do_chmod_file(struct st_command *command) static DYNAMIC_STRING ds_mode; static DYNAMIC_STRING ds_file; const struct command_arg chmod_file_args[] = { - "mode", ARG_STRING, TRUE, &ds_mode, "Mode of file", - "file", ARG_STRING, TRUE, &ds_file, "Filename of file to modify" + "mode", ARG_STRING, TRUE, &ds_mode, "Mode of file(octal) ex. 0660", + "filename", ARG_STRING, TRUE, &ds_file, "Filename of file to modify" }; DBUG_ENTER("do_chmod_file"); @@ -2310,8 +2700,22 @@ void read_until_delimiter(DYNAMIC_STRING *ds, c= my_getc(cur_file->file); if (c == '\n') + { cur_file->lineno++; + /* Skip newline from the same line as the command */ + if (start_lineno == (cur_file->lineno - 1)) + continue; + } + else if (start_lineno == cur_file->lineno) + { + /* + No characters except \n are allowed on + the same line as the command + */ + die("Trailing characters found after command"); + } + if (feof(cur_file->file)) die("End of file encountered before '%s' delimiter was found", ds_delimiter->str); @@ -2349,6 +2753,12 @@ void do_write_file_command(struct st_command *command, my_bool append) if (ds_delimiter.length == 0) dynstr_set(&ds_delimiter, "EOF"); + if (!append && access(ds_filename.str, F_OK) == 0) + { + /* The file should not be overwritten */ + die("File already exist: '%s'", ds_filename.str); + } + init_dynamic_string(&ds_content, "", 1024, 1024); read_until_delimiter(&ds_content, &ds_delimiter); DBUG_PRINT("info", ("Writing to file: %s", ds_filename.str)); @@ -2381,7 +2791,7 @@ void do_write_file_command(struct st_command *command, my_bool append) Write everything between the "write_file" command and 'delimiter' to "file_name" - NOTE! Overwrites existing file + NOTE! Will fail if <file_name> exists Default <delimiter> is EOF @@ -2438,9 +2848,6 @@ void do_append_file(struct st_command *command) void do_cat_file(struct st_command *command) { - int fd; - uint len; - char buff[512]; static DYNAMIC_STRING ds_filename; const struct command_arg cat_file_args[] = { "filename", ARG_STRING, TRUE, &ds_filename, "File to read from" @@ -2455,37 +2862,13 @@ void do_cat_file(struct st_command *command) DBUG_PRINT("info", ("Reading from, file: %s", ds_filename.str)); - if ((fd= my_open(ds_filename.str, O_RDONLY, MYF(0))) < 0) - die("Failed to open file %s", ds_filename.str); - while((len= my_read(fd, (byte*)&buff, - sizeof(buff), MYF(0))) > 0) - { - char *p= buff, *start= buff; - while (p < buff+len) - { - /* Convert cr/lf to lf */ - if (*p == '\r' && *(p+1) && *(p+1)== '\n') - { - /* Add fake newline instead of cr and output the line */ - *p= '\n'; - p++; /* Step past the "fake" newline */ - dynstr_append_mem(&ds_res, start, p-start); - p++; /* Step past the "fake" newline */ - start= p; - } - else - p++; - } - /* Output any chars that migh be left */ - dynstr_append_mem(&ds_res, start, p-start); - } - my_close(fd, MYF(0)); + cat_file(&ds_res, ds_filename.str); + dynstr_free(&ds_filename); DBUG_VOID_RETURN; } - /* SYNOPSIS do_diff_files @@ -2501,9 +2884,6 @@ void do_cat_file(struct st_command *command) void do_diff_files(struct st_command *command) { int error= 0; - int fd, fd2; - uint len, len2; - char buff[512], buff2[512]; static DYNAMIC_STRING ds_filename; static DYNAMIC_STRING ds_filename2; const struct command_arg diff_file_args[] = { @@ -2518,39 +2898,14 @@ void do_diff_files(struct st_command *command) sizeof(diff_file_args)/sizeof(struct command_arg), ' '); - if ((fd= my_open(ds_filename.str, O_RDONLY, MYF(0))) < 0) - die("Failed to open first file %s", ds_filename.str); - if ((fd2= my_open(ds_filename2.str, O_RDONLY, MYF(0))) < 0) + if ((error= compare_files(ds_filename.str, ds_filename2.str))) { - my_close(fd, MYF(0)); - die("Failed to open second file %s", ds_filename2.str); - } - while((len= my_read(fd, (byte*)&buff, - sizeof(buff), MYF(0))) > 0) - { - if ((len2= my_read(fd2, (byte*)&buff2, - sizeof(buff2), MYF(0))) != len) - { - /* File 2 was smaller */ - error= 1; - break; - } - if ((memcmp(buff, buff2, len))) - { - /* Content of this part differed */ - error= 1; - break; - } - } - if (my_read(fd2, (byte*)&buff2, - sizeof(buff2), MYF(0)) > 0) - { - /* File 1 was smaller */ - error= 1; + /* Compare of the two files failed, append them to output + so the failure can be analyzed + */ + show_diff(&ds_res, ds_filename.str, ds_filename2.str); } - my_close(fd, MYF(0)); - my_close(fd2, MYF(0)); dynstr_free(&ds_filename); dynstr_free(&ds_filename2); handle_command_error(command, error); @@ -2621,8 +2976,10 @@ void do_send_quit(struct st_command *command) void do_perl(struct st_command *command) { int error; - char buf[FN_REFLEN]; + File fd; FILE *res_file; + char buf[FN_REFLEN]; + char temp_file_path[FN_REFLEN]; static DYNAMIC_STRING ds_script; static DYNAMIC_STRING ds_delimiter; const struct command_arg perl_args[] = { @@ -2645,14 +3002,17 @@ void do_perl(struct st_command *command) DBUG_PRINT("info", ("Executing perl: %s", ds_script.str)); - /* Format a name for a tmp .pl file that is unique for this process */ - my_snprintf(buf, sizeof(buf), "%s/tmp/tmp_%d.pl", - getenv("MYSQLTEST_VARDIR"), getpid()); - str_to_file(buf, ds_script.str, ds_script.length); + /* Create temporary file name */ + if ((fd= create_temp_file(temp_file_path, getenv("MYSQLTEST_VARDIR"), + "tmp", O_CREAT | O_SHARE | O_RDWR, + MYF(MY_WME))) < 0) + die("Failed to create temporary file for perl command"); + my_close(fd, MYF(0)); - /* Format the perl <filename> command */ - my_snprintf(buf, sizeof(buf), "perl %s/tmp/tmp_%d.pl", - getenv("MYSQLTEST_VARDIR"), getpid()); + str_to_file(temp_file_path, ds_script.str, ds_script.length); + + /* Format the "perl <filename>" command */ + my_snprintf(buf, sizeof(buf), "perl %s", temp_file_path); if (!(res_file= popen(buf, "r")) && command->abort_on_error) die("popen(\"%s\", \"r\") failed", buf); @@ -2670,6 +3030,10 @@ void do_perl(struct st_command *command) } } error= pclose(res_file); + + /* Remove the temporary file */ + my_delete(temp_file_path, MYF(0)); + handle_command_error(command, WEXITSTATUS(error)); dynstr_free(&ds_script); dynstr_free(&ds_delimiter); @@ -3795,7 +4159,7 @@ void do_connect(struct st_command *command) mysql_options(&con_slot->mysql, MYSQL_SET_CHARSET_NAME, charset_info->csname); if (opt_charsets_dir) - mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_DIR, + mysql_options(&con_slot->mysql, MYSQL_SET_CHARSET_DIR, opt_charsets_dir); #ifdef HAVE_OPENSSL @@ -4408,7 +4772,7 @@ void check_eol_junk(const char *eol) terminated by new line '\n' regardless how many "delimiter" it contain. */ -#define MAX_QUERY (256*1024) /* 256K -- a test in sp-big is >128K */ +#define MAX_QUERY (256*1024*2) /* 256K -- a test in sp-big is >128K */ static char read_command_buf[MAX_QUERY]; int read_command(struct st_command** command_ptr) @@ -4456,9 +4820,13 @@ 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 and first argument */ - for (p= command->query; *p && !my_isspace(charset_info, *p) ; p++) ; + /* Calculate first word length(the command), terminated by space or ( */ + p= command->query; + while (*p && !my_isspace(charset_info, *p) && *p != '(') + p++; command->first_word_len= (uint) (p - command->query); + DBUG_PRINT("info", ("first_word: %.*s", + command->first_word_len, command->query)); /* Skip spaces between command and first argument */ while (*p && my_isspace(charset_info, *p)) @@ -4542,6 +4910,10 @@ static struct my_option my_long_options[] = {"sp-protocol", OPT_SP_PROTOCOL, "Use stored procedures for select", (gptr*) &sp_protocol, (gptr*) &sp_protocol, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"tail-lines", OPT_TAIL_LINES, + "Number of lines of the resul to include in a failure report", + (gptr*) &opt_tail_lines, (gptr*) &opt_tail_lines, 0, + GET_INT, REQUIRED_ARG, 0, 0, 10000, 0, 0, 0}, #include "sslopt-longopts.h" {"test-file", 'x', "Read test from/in this file (default stdin).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -4793,14 +5165,6 @@ void str_to_file(const char *fname, char *str, int size) } -void dump_result_to_reject_file(char *buf, int size) -{ - char reject_file[FN_REFLEN]; - str_to_file(fn_format(reject_file, result_file_name, "", ".reject", - MY_REPLACE_EXT), - buf, size); -} - void dump_result_to_log_file(char *buf, int size) { char log_file[FN_REFLEN]; @@ -4808,6 +5172,8 @@ void dump_result_to_log_file(char *buf, int size) *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) @@ -5792,7 +6158,7 @@ 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 sendign to server */ + /* Scan for warning before sending to server */ scan_command_for_warnings(command); /* @@ -6224,7 +6590,6 @@ int main(int argc, char **argv) connections_end= connections + (sizeof(connections)/sizeof(struct st_connection)) - 1; next_con= connections + 1; - cur_con= connections; #ifdef EMBEDDED_LIBRARY /* set appropriate stack for the 'query' threads */ @@ -6300,6 +6665,7 @@ int main(int argc, char **argv) if (cursor_protocol_enabled) ps_protocol_enabled= 1; + cur_con= connections; if (!( mysql_init(&cur_con->mysql))) die("Failed in mysql_init()"); if (opt_compress) @@ -6424,7 +6790,7 @@ int main(int argc, char **argv) break; case Q_LET: do_let(command); break; case Q_EVAL_RESULT: - eval_result = 1; break; + die("'eval_result' command is deprecated"); case Q_EVAL: case Q_QUERY_VERTICAL: case Q_QUERY_HORIZONTAL: |