summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authorunknown <msvensson@pilot.(none)>2007-08-13 11:35:10 +0200
committerunknown <msvensson@pilot.(none)>2007-08-13 11:35:10 +0200
commit0dcf2ea1d1f6f3e232c510cd79369caf4c630071 (patch)
tree4ad45c05c3b618e1b0f77ec442e59eb160229225 /client
parentb35cad86d43b26a2236c715645bf2737af20c890 (diff)
parent7f9883fab578234d6a8b9e0a0e6fa6bc0a29a31e (diff)
downloadmariadb-git-0dcf2ea1d1f6f3e232c510cd79369caf4c630071.tar.gz
Merge bk-internal:/home/bk/mysql-5.1-maint
into pilot.(none):/data/msvensson/mysql/mysql-5.1-new-maint client/mysql_upgrade.c: Auto merged client/mysqltest.c: Auto merged mysql-test/lib/mtr_report.pl: Auto merged mysql-test/mysql-test-run.pl: Auto merged mysql-test/r/show_check.result: Auto merged mysql-test/t/show_check.test: Auto merged
Diffstat (limited to 'client')
-rw-r--r--client/mysql_upgrade.c1
-rw-r--r--client/mysqltest.c736
2 files changed, 552 insertions, 185 deletions
diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c
index 5da0235c913..7a36a382c97 100644
--- a/client/mysql_upgrade.c
+++ b/client/mysql_upgrade.c
@@ -468,6 +468,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 7ba57f7515c..a854becbda7 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -60,16 +60,10 @@
#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=OPT_MAX_CLIENT_OPTION,
OPT_PS_PROTOCOL, OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL,
- OPT_MAX_CONNECT_RETRIES, OPT_MARK_PROGRESS, OPT_LOG_DIR
+ OPT_MAX_CONNECT_RETRIES, OPT_MARK_PROGRESS, OPT_LOG_DIR, OPT_TAIL_LINES
};
static int record= 0, opt_sleep= -1;
@@ -103,6 +97,9 @@ static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer;
static uint start_lineno= 0; /* Start line of current command */
static uint my_end_arg= 0;
+/* 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;
@@ -224,7 +221,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
@@ -441,7 +438,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];
@@ -489,11 +485,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)
{
@@ -594,6 +590,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,
@@ -672,6 +739,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;
}
@@ -865,6 +941,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);
@@ -873,6 +967,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);
}
@@ -976,11 +1077,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);
@@ -993,77 +1093,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, (uchar*)&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",
- (uint) 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, (uchar*)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(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, (uchar*)&buff,
+ sizeof(buff), MYF(0))) > 0)
+ {
+ if ((len2= my_read(fd2, (uchar*)&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, (uchar*)&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);
}
@@ -1081,20 +1476,33 @@ 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()");
}
@@ -1109,7 +1517,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
@@ -1439,40 +1847,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]);
}
@@ -1514,7 +1904,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;
@@ -1586,7 +1976,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)))
@@ -1953,7 +2343,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);
dynstr_free(&ds_cmd);
die("command \"%s\" failed", command->first_argument);
@@ -2196,8 +2586,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>
*/
@@ -2207,8 +2597,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");
@@ -2303,8 +2693,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);
@@ -2342,6 +2746,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));
@@ -2374,7 +2784,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
@@ -2431,9 +2841,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" }
@@ -2448,37 +2855,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, (uchar*)&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
@@ -2494,9 +2877,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[] = {
@@ -2511,39 +2891,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, (uchar*)&buff,
- sizeof(buff), MYF(0))) > 0)
- {
- if ((len2= my_read(fd2, (uchar*)&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, (uchar*)&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);
@@ -2614,8 +2969,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[] = {
@@ -2638,14 +2995,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);
@@ -2663,6 +3023,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);
@@ -3788,7 +4152,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
@@ -4401,7 +4765,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)
@@ -4449,9 +4813,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))
@@ -4541,6 +4909,10 @@ static struct my_option my_long_options[] =
{"sp-protocol", OPT_SP_PROTOCOL, "Use stored procedures for select",
(uchar**) &sp_protocol, (uchar**) &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",
+ (uchar**) &opt_tail_lines, (uchar**) &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},
@@ -4797,14 +5169,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];
@@ -4812,6 +5176,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)
@@ -5793,7 +6159,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);
/*
@@ -6225,7 +6591,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 */
@@ -6301,6 +6666,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)
@@ -6425,7 +6791,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: