Commit c17bace4 authored by Sergei Golubchik's avatar Sergei Golubchik

Added --continue-on-error to mysqltest and mysql-test-run

This will contune the test case even if there was an error
and makes it easier to run a test that contains many sub tests against one engine.

(originally by Monty)
parent ddd3e261
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
And many others And many others
*/ */
#define MTEST_VERSION "3.3" #define MTEST_VERSION "3.4"
#include "client_priv.h" #include "client_priv.h"
#include <mysql_version.h> #include <mysql_version.h>
...@@ -78,6 +78,8 @@ static my_bool non_blocking_api_enabled= 0; ...@@ -78,6 +78,8 @@ static my_bool non_blocking_api_enabled= 0;
#define MAX_DELIMITER_LENGTH 16 #define MAX_DELIMITER_LENGTH 16
#define DEFAULT_MAX_CONN 64 #define DEFAULT_MAX_CONN 64
#define DIE_BUFF_SIZE 8192
/* Flags controlling send and reap */ /* Flags controlling send and reap */
#define QUERY_SEND_FLAG 1 #define QUERY_SEND_FLAG 1
#define QUERY_REAP_FLAG 2 #define QUERY_REAP_FLAG 2
...@@ -106,6 +108,7 @@ static int opt_port= 0; ...@@ -106,6 +108,7 @@ static int opt_port= 0;
static int opt_max_connect_retries; static int opt_max_connect_retries;
static int opt_result_format_version; static int opt_result_format_version;
static int opt_max_connections= DEFAULT_MAX_CONN; static int opt_max_connections= DEFAULT_MAX_CONN;
static int error_count= 0;
static my_bool opt_compress= 0, silent= 0, verbose= 0; static my_bool opt_compress= 0, silent= 0, verbose= 0;
static my_bool debug_info_flag= 0, debug_check_flag= 0; static my_bool debug_info_flag= 0, debug_check_flag= 0;
static my_bool tty_password= 0; static my_bool tty_password= 0;
...@@ -122,7 +125,7 @@ static my_bool disable_connect_log= 1; ...@@ -122,7 +125,7 @@ static my_bool disable_connect_log= 1;
static my_bool disable_warnings= 0, disable_column_names= 0; static my_bool disable_warnings= 0, disable_column_names= 0;
static my_bool prepare_warnings_enabled= 0; static my_bool prepare_warnings_enabled= 0;
static my_bool disable_info= 1; static my_bool disable_info= 1;
static my_bool abort_on_error= 1; static my_bool abort_on_error= 1, opt_continue_on_error= 0;
static my_bool server_initialized= 0; static my_bool server_initialized= 0;
static my_bool is_windows= 0; static my_bool is_windows= 0;
static char **default_argv; static char **default_argv;
...@@ -559,14 +562,15 @@ const char *from, int len); ...@@ -559,14 +562,15 @@ const char *from, int len);
static void cleanup_and_exit(int exit_code) __attribute__((noreturn)); static void cleanup_and_exit(int exit_code) __attribute__((noreturn));
void die(const char *fmt, ...) void really_die(const char *msg) __attribute__((noreturn));
ATTRIBUTE_FORMAT(printf, 1, 2) __attribute__((noreturn)); void report_or_die(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
void abort_not_supported_test(const char *fmt, ...) void die(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2)
ATTRIBUTE_FORMAT(printf, 1, 2) __attribute__((noreturn)); __attribute__((noreturn));
void verbose_msg(const char *fmt, ...) static void make_error_message(char *buf, size_t len, const char *fmt, va_list args);
ATTRIBUTE_FORMAT(printf, 1, 2); void abort_not_supported_test(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2)
void log_msg(const char *fmt, ...) __attribute__((noreturn));
ATTRIBUTE_FORMAT(printf, 1, 2); void verbose_msg(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
void log_msg(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
VAR* var_from_env(const char *, const char *); VAR* var_from_env(const char *, const char *);
VAR* var_init(VAR* v, const char *name, int name_len, const char *val, VAR* var_init(VAR* v, const char *name, int name_len, const char *val,
...@@ -983,7 +987,10 @@ void do_eval(DYNAMIC_STRING *query_eval, const char *query, ...@@ -983,7 +987,10 @@ void do_eval(DYNAMIC_STRING *query_eval, const char *query,
else else
{ {
if (!(v= var_get(p, &p, 0, 0))) if (!(v= var_get(p, &p, 0, 0)))
die("Bad variable in eval"); {
report_or_die( "Bad variable in eval");
return;
}
dynstr_append_mem(query_eval, v->str_val, v->str_val_len); dynstr_append_mem(query_eval, v->str_val, v->str_val_len);
} }
break; break;
...@@ -1270,9 +1277,13 @@ void handle_command_error(struct st_command *command, uint error, ...@@ -1270,9 +1277,13 @@ void handle_command_error(struct st_command *command, uint error,
int i; int i;
if (command->abort_on_error) if (command->abort_on_error)
die("command \"%.*s\" failed with error: %u my_errno: %d errno: %d", {
report_or_die("command \"%.*s\" failed with error: %u my_errno: %d "
"errno: %d",
command->first_word_len, command->query, error, my_errno, command->first_word_len, command->query, error, my_errno,
sys_errno); sys_errno);
return;
}
i= match_expected_error(command, error, NULL); i= match_expected_error(command, error, NULL);
...@@ -1285,14 +1296,17 @@ void handle_command_error(struct st_command *command, uint error, ...@@ -1285,14 +1296,17 @@ void handle_command_error(struct st_command *command, uint error,
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
if (command->expected_errors.count > 0) if (command->expected_errors.count > 0)
die("command \"%.*s\" failed with wrong error: %u my_errno: %d errno: %d", report_or_die("command \"%.*s\" failed with wrong error: %u "
command->first_word_len, command->query, error, my_errno, sys_errno); "my_errno: %d errno: %d",
command->first_word_len, command->query, error, my_errno,
sys_errno);
} }
else if (command->expected_errors.err[0].type == ERR_ERRNO && else if (command->expected_errors.err[0].type == ERR_ERRNO &&
command->expected_errors.err[0].code.errnum != 0) command->expected_errors.err[0].code.errnum != 0)
{ {
/* Error code we wanted was != 0, i.e. not an expected success */ /* Error code we wanted was != 0, i.e. not an expected success */
die("command \"%.*s\" succeeded - should have failed with errno %d...", report_or_die("command \"%.*s\" succeeded - should have failed with "
"errno %d...",
command->first_word_len, command->query, command->first_word_len, command->query,
command->expected_errors.err[0].code.errnum); command->expected_errors.err[0].code.errnum);
} }
...@@ -1437,50 +1451,59 @@ static void cleanup_and_exit(int exit_code) ...@@ -1437,50 +1451,59 @@ static void cleanup_and_exit(int exit_code)
exit(exit_code); exit(exit_code);
} }
void print_file_stack() size_t print_file_stack(char *s, const char *end)
{ {
char *start= s;
struct st_test_file* err_file= cur_file; struct st_test_file* err_file= cur_file;
if (err_file == file_stack) if (err_file == file_stack)
return; return 0;
for (;;) for (;;)
{ {
err_file--; err_file--;
fprintf(stderr, "included from %s at line %d:\n", s+= my_snprintf(s, end - s, "included from %s at line %d:\n",
err_file->file_name, err_file->lineno); err_file->file_name, err_file->lineno);
if (err_file == file_stack) if (err_file == file_stack)
break; break;
} }
return s - start;
} }
void die(const char *fmt, ...)
{
static int dying= 0;
va_list args;
DBUG_ENTER("die");
DBUG_PRINT("enter", ("start_lineno: %d", start_lineno));
fflush(stdout); static void make_error_message(char *buf, size_t len, const char *fmt, va_list args)
/* Print the error message */ {
fprintf(stderr, "mysqltest: "); char *s= buf, *end= buf + len;
s+= my_snprintf(s, end - s, "mysqltest: ");
if (cur_file && cur_file != file_stack) if (cur_file && cur_file != file_stack)
{ {
fprintf(stderr, "In included file \"%s\": \n", s+= my_snprintf(s, end - s, "In included file \"%s\": \n",
cur_file->file_name); cur_file->file_name);
print_file_stack(); s+= print_file_stack(s, end);
} }
if (start_lineno > 0) if (start_lineno > 0)
fprintf(stderr, "At line %u: ", start_lineno); s+= my_snprintf(s, end -s, "At line %u: ", start_lineno);
if (fmt) if (!fmt)
{ fmt= "unknown error";
s+= my_vsnprintf(s, end - s, fmt, args);
s+= my_snprintf(s, end -s, "\n", start_lineno);
}
void die(const char *fmt, ...)
{
char buff[DIE_BUFF_SIZE];
va_list args;
va_start(args, fmt); va_start(args, fmt);
vfprintf(stderr, fmt, args); make_error_message(buff, sizeof(buff), fmt, args);
va_end(args); really_die(buff);
} }
else
fprintf(stderr, "unknown error"); void really_die(const char *msg)
fprintf(stderr, "\n"); {
static int dying= 0;
fflush(stdout);
fprintf(stderr, "%s", msg);
fflush(stderr); fflush(stderr);
/* /*
...@@ -1504,6 +1527,28 @@ void die(const char *fmt, ...) ...@@ -1504,6 +1527,28 @@ void die(const char *fmt, ...)
cleanup_and_exit(1); cleanup_and_exit(1);
} }
void report_or_die(const char *fmt, ...)
{
va_list args;
DBUG_ENTER("report_or_die");
char buff[DIE_BUFF_SIZE];
va_start(args, fmt);
make_error_message(buff, sizeof(buff), fmt, args);
va_end(args);
if (opt_continue_on_error)
{
/* Just log the error and continue */
replace_dynstr_append(&ds_res, buff);
error_count++;
DBUG_VOID_RETURN;
}
really_die(buff);
}
void abort_not_supported_test(const char *fmt, ...) void abort_not_supported_test(const char *fmt, ...)
{ {
...@@ -1516,7 +1561,10 @@ void abort_not_supported_test(const char *fmt, ...) ...@@ -1516,7 +1561,10 @@ void abort_not_supported_test(const char *fmt, ...)
file_stack->file_name); file_stack->file_name);
fprintf(stderr, "Detected in file %s at line %d\n", fprintf(stderr, "Detected in file %s at line %d\n",
cur_file->file_name, cur_file->lineno); cur_file->file_name, cur_file->lineno);
print_file_stack();
char buff[DIE_BUFF_SIZE];
print_file_stack(buff, buff + sizeof(buff));
fprintf(stderr, "%s", buff);
/* Print error message */ /* Print error message */
va_start(args, fmt); va_start(args, fmt);
...@@ -1648,7 +1696,10 @@ static int run_command(char* cmd, ...@@ -1648,7 +1696,10 @@ static int run_command(char* cmd,
DBUG_PRINT("enter", ("cmd: %s", cmd)); DBUG_PRINT("enter", ("cmd: %s", cmd));
if (!(res_file= popen(cmd, "r"))) if (!(res_file= popen(cmd, "r")))
die("popen(\"%s\", \"r\") failed", cmd); {
report_or_die("popen(\"%s\", \"r\") failed", cmd);
return -1;
}
while (fgets(buf, sizeof(buf), res_file)) while (fgets(buf, sizeof(buf), res_file))
{ {
...@@ -1748,7 +1799,10 @@ static int diff_check(const char *diff_name) ...@@ -1748,7 +1799,10 @@ static int diff_check(const char *diff_name)
if (!(res_file= popen(buf, "r"))) if (!(res_file= popen(buf, "r")))
die("popen(\"%s\", \"r\") failed", buf); die("popen(\"%s\", \"r\") failed", buf);
/* if diff is not present, nothing will be in stdout to increment have_diff */ /*
if diff is not present, nothing will be in stdout to increment
have_diff
*/
if (fgets(buf, sizeof(buf), res_file)) if (fgets(buf, sizeof(buf), res_file))
have_diff= 1; have_diff= 1;
...@@ -2061,7 +2115,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) ...@@ -2061,7 +2115,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
void check_result() void check_result()
{ {
const char* mess= "Result content mismatch\n"; const char *mess= 0;
DBUG_ENTER("check_result"); DBUG_ENTER("check_result");
DBUG_ASSERT(result_file_name); DBUG_ASSERT(result_file_name);
...@@ -2069,8 +2123,12 @@ void check_result() ...@@ -2069,8 +2123,12 @@ void check_result()
switch (compare_files(log_file.file_name(), result_file_name)) { switch (compare_files(log_file.file_name(), result_file_name)) {
case RESULT_OK: case RESULT_OK:
if (!error_count)
break; /* ok */ break; /* ok */
mess= "Got errors while running test";
/* Fallthrough */
case RESULT_LENGTH_MISMATCH: case RESULT_LENGTH_MISMATCH:
if (!mess)
mess= "Result length mismatch\n"; mess= "Result length mismatch\n";
/* Fallthrough */ /* Fallthrough */
case RESULT_CONTENT_MISMATCH: case RESULT_CONTENT_MISMATCH:
...@@ -2081,6 +2139,10 @@ void check_result() ...@@ -2081,6 +2139,10 @@ void check_result()
*/ */
char reject_file[FN_REFLEN]; char reject_file[FN_REFLEN];
size_t reject_length; size_t reject_length;
if (!mess)
mess= "Result content mismatch\n";
dirname_part(reject_file, result_file_name, &reject_length); dirname_part(reject_file, result_file_name, &reject_length);
if (access(reject_file, W_OK) == 0) if (access(reject_file, W_OK) == 0)
...@@ -2518,7 +2580,7 @@ void var_query_set(VAR *var, const char *query, const char** query_end) ...@@ -2518,7 +2580,7 @@ void var_query_set(VAR *var, const char *query, const char** query_end)
if (mysql_real_query(mysql, ds_query.str, ds_query.length)) if (mysql_real_query(mysql, ds_query.str, ds_query.length))
{ {
handle_error (curr_command, mysql_errno(mysql), mysql_error(mysql), handle_error(curr_command, mysql_errno(mysql), mysql_error(mysql),
mysql_sqlstate(mysql), &ds_res); mysql_sqlstate(mysql), &ds_res);
/* If error was acceptable, return empty string */ /* If error was acceptable, return empty string */
dynstr_free(&ds_query); dynstr_free(&ds_query);
...@@ -2527,7 +2589,12 @@ void var_query_set(VAR *var, const char *query, const char** query_end) ...@@ -2527,7 +2589,12 @@ void var_query_set(VAR *var, const char *query, const char** query_end)
} }
if (!(res= mysql_store_result(mysql))) if (!(res= mysql_store_result(mysql)))
die("Query '%s' didn't return a result set", ds_query.str); {
report_or_die("Query '%s' didn't return a result set", ds_query.str);
dynstr_free(&ds_query);
eval_expr(var, "", 0);
return;
}
dynstr_free(&ds_query); dynstr_free(&ds_query);
if ((row= mysql_fetch_row(res)) && row[0]) if ((row= mysql_fetch_row(res)) && row[0])
...@@ -2696,16 +2763,23 @@ void var_set_query_get_value(struct st_command *command, VAR *var) ...@@ -2696,16 +2763,23 @@ void var_set_query_get_value(struct st_command *command, VAR *var)
/* Run the query */ /* Run the query */
if (mysql_real_query(mysql, ds_query.str, ds_query.length)) if (mysql_real_query(mysql, ds_query.str, ds_query.length))
{ {
handle_error (curr_command, mysql_errno(mysql), mysql_error(mysql), handle_error(curr_command, mysql_errno(mysql), mysql_error(mysql),
mysql_sqlstate(mysql), &ds_res); mysql_sqlstate(mysql), &ds_res);
/* If error was acceptable, return empty string */ /* If error was acceptable, return empty string */
dynstr_free(&ds_query); dynstr_free(&ds_query);
dynstr_free(&ds_col);
eval_expr(var, "", 0); eval_expr(var, "", 0);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
if (!(res= mysql_store_result(mysql))) if (!(res= mysql_store_result(mysql)))
die("Query '%s' didn't return a result set", ds_query.str); {
report_or_die("Query '%s' didn't return a result set", ds_query.str);
dynstr_free(&ds_query);
dynstr_free(&ds_col);
eval_expr(var, "", 0);
return;
}
{ {
/* Find column number from the given column name */ /* Find column number from the given column name */
...@@ -2725,8 +2799,11 @@ void var_set_query_get_value(struct st_command *command, VAR *var) ...@@ -2725,8 +2799,11 @@ void var_set_query_get_value(struct st_command *command, VAR *var)
if (col_no == -1) if (col_no == -1)
{ {
mysql_free_result(res); mysql_free_result(res);
die("Could not find column '%s' in the result of '%s'", report_or_die("Could not find column '%s' in the result of '%s'",
ds_col.str, ds_query.str); ds_col.str, ds_query.str);
dynstr_free(&ds_query);
dynstr_free(&ds_col);
return;
} }
DBUG_PRINT("info", ("Found column %d with name '%s'", DBUG_PRINT("info", ("Found column %d with name '%s'",
i, fields[i].name)); i, fields[i].name));
...@@ -3165,7 +3242,10 @@ void do_exec(struct st_command *command) ...@@ -3165,7 +3242,10 @@ void do_exec(struct st_command *command)
while (*cmd && my_isspace(charset_info, *cmd)) while (*cmd && my_isspace(charset_info, *cmd))
cmd++; cmd++;
if (!*cmd) if (!*cmd)
die("Missing argument in exec"); {
report_or_die("Missing argument in exec");
return;
}
command->last_argument= command->end; command->last_argument= command->end;
init_dynamic_string(&ds_cmd, 0, command->query_len+256, 256); init_dynamic_string(&ds_cmd, 0, command->query_len+256, 256);
...@@ -3197,10 +3277,12 @@ void do_exec(struct st_command *command) ...@@ -3197,10 +3277,12 @@ void do_exec(struct st_command *command)
DBUG_PRINT("info", ("Executing '%s' as '%s'", DBUG_PRINT("info", ("Executing '%s' as '%s'",
command->first_argument, ds_cmd.str)); command->first_argument, ds_cmd.str));
if (!(res_file= my_popen(&ds_cmd, "r")) && command->abort_on_error) if (!(res_file= my_popen(&ds_cmd, "r")))
{ {
dynstr_free(&ds_cmd); dynstr_free(&ds_cmd);
die("popen(\"%s\", \"r\") failed", command->first_argument); if (command->abort_on_error)
report_or_die("popen(\"%s\", \"r\") failed", command->first_argument);
return;
} }
ds_result= &ds_res; ds_result= &ds_res;
...@@ -3237,11 +3319,12 @@ void do_exec(struct st_command *command) ...@@ -3237,11 +3319,12 @@ void do_exec(struct st_command *command)
if (command->abort_on_error) if (command->abort_on_error)
{ {
log_msg("exec of '%s' failed, error: %d, status: %d, errno: %d", report_or_die("exec of '%s' failed, error: %d, status: %d, errno: %d\n"
ds_cmd.str, error, status, errno); "Output from before failure:\n%s\n",
ds_cmd.str, error, status, errno,
ds_res.str);
dynstr_free(&ds_cmd); dynstr_free(&ds_cmd);
die("command \"%s\" failed\n\nOutput from before failure:\n%s\n", return;
command->first_argument, ds_res.str);
} }
DBUG_PRINT("info", DBUG_PRINT("info",
...@@ -3256,7 +3339,7 @@ void do_exec(struct st_command *command) ...@@ -3256,7 +3339,7 @@ void do_exec(struct st_command *command)
{ {
dynstr_free(&ds_cmd); dynstr_free(&ds_cmd);
if (command->expected_errors.count > 0) if (command->expected_errors.count > 0)
die("command \"%s\" failed with wrong error: %d", report_or_die("command \"%s\" failed with wrong error: %d",
command->first_argument, status); command->first_argument, status);
} }
} }
...@@ -3267,8 +3350,10 @@ void do_exec(struct st_command *command) ...@@ -3267,8 +3350,10 @@ void do_exec(struct st_command *command)
log_msg("exec of '%s failed, error: %d, errno: %d", log_msg("exec of '%s failed, error: %d, errno: %d",
ds_cmd.str, error, errno); ds_cmd.str, error, errno);
dynstr_free(&ds_cmd); dynstr_free(&ds_cmd);
die("command \"%s\" succeeded - should have failed with errno %d...", report_or_die("command \"%s\" succeeded - should have failed with "
command->first_argument, command->expected_errors.err[0].code.errnum); "errno %d...",
command->first_argument,
command->expected_errors.err[0].code.errnum);
} }
dynstr_free(&ds_cmd); dynstr_free(&ds_cmd);
...@@ -3302,7 +3387,8 @@ int do_modify_var(struct st_command *command, ...@@ -3302,7 +3387,8 @@ int do_modify_var(struct st_command *command,
const char *p= command->first_argument; const char *p= command->first_argument;
VAR* v; VAR* v;
if (!*p) if (!*p)
die("Missing argument to %.*s", command->first_word_len, command->query); die("Missing argument to %.*s", command->first_word_len,
command->query);
if (*p != '$') if (*p != '$')
die("The argument to %.*s must be a variable (start with $)", die("The argument to %.*s must be a variable (start with $)",
command->first_word_len, command->query); command->first_word_len, command->query);
...@@ -3368,7 +3454,10 @@ void do_system(struct st_command *command) ...@@ -3368,7 +3454,10 @@ void do_system(struct st_command *command)
DBUG_ENTER("do_system"); DBUG_ENTER("do_system");
if (strlen(command->first_argument) == 0) if (strlen(command->first_argument) == 0)
die("Missing arguments to system, nothing to do!"); {
report_or_die("Missing arguments to system, nothing to do!");
return;
}
init_dynamic_string(&ds_cmd, 0, command->query_len + 64, 256); init_dynamic_string(&ds_cmd, 0, command->query_len + 64, 256);
...@@ -3389,13 +3478,15 @@ void do_system(struct st_command *command) ...@@ -3389,13 +3478,15 @@ void do_system(struct st_command *command)
if (my_system(&ds_cmd)) if (my_system(&ds_cmd))
{ {
if (command->abort_on_error) if (command->abort_on_error)
die("system command '%s' failed", command->first_argument); report_or_die("system command '%s' failed", command->first_argument);
else
{
/* If ! abort_on_error, log message and continue */ /* If ! abort_on_error, log message and continue */
dynstr_append(&ds_res, "system command '"); dynstr_append(&ds_res, "system command '");
replace_dynstr_append(&ds_res, command->first_argument); replace_dynstr_append(&ds_res, command->first_argument);
dynstr_append(&ds_res, "' failed\n"); dynstr_append(&ds_res, "' failed\n");
} }
}
command->last_argument= command->end; command->last_argument= command->end;
dynstr_free(&ds_cmd); dynstr_free(&ds_cmd);
...@@ -3941,11 +4032,11 @@ void read_until_delimiter(DYNAMIC_STRING *ds, ...@@ -3941,11 +4032,11 @@ void read_until_delimiter(DYNAMIC_STRING *ds,
No characters except \n are allowed on No characters except \n are allowed on
the same line as the command the same line as the command
*/ */
die("Trailing characters found after command"); report_or_die("Trailing characters found after command");
} }
if (feof(cur_file->file)) if (feof(cur_file->file))
die("End of file encountered before '%s' delimiter was found", report_or_die("End of file encountered before '%s' delimiter was found",
ds_delimiter->str); ds_delimiter->str);
if (match_delimiter(c, ds_delimiter->str, ds_delimiter->length)) if (match_delimiter(c, ds_delimiter->str, ds_delimiter->length))
...@@ -4350,8 +4441,13 @@ void do_perl(struct st_command *command) ...@@ -4350,8 +4441,13 @@ void do_perl(struct st_command *command)
/* Format the "perl <filename>" command */ /* Format the "perl <filename>" command */
my_snprintf(buf, sizeof(buf), "perl %s", temp_file_path); my_snprintf(buf, sizeof(buf), "perl %s", temp_file_path);
if (!(res_file= popen(buf, "r")) && command->abort_on_error) if (!(res_file= popen(buf, "r")))
{
if (command->abort_on_error)
die("popen(\"%s\", \"r\") failed", buf); die("popen(\"%s\", \"r\") failed", buf);
dynstr_free(&ds_delimiter);
return;
}
while (fgets(buf, sizeof(buf), res_file)) while (fgets(buf, sizeof(buf), res_file))
{ {
...@@ -4506,14 +4602,14 @@ void do_sync_with_master2(struct st_command *command, long offset) ...@@ -4506,14 +4602,14 @@ void do_sync_with_master2(struct st_command *command, long offset)
information is not initialized, the arguments are information is not initialized, the arguments are
incorrect, or an error has occured incorrect, or an error has occured
*/ */
die("%.*s failed: '%s' returned NULL "\ die("%.*s failed: '%s' returned NULL " \
"indicating slave SQL thread failure", "indicating slave SQL thread failure",
command->first_word_len, command->query, query_buf); command->first_word_len, command->query, query_buf);
} }
if (result == -1) if (result == -1)
die("%.*s failed: '%s' returned -1 "\ die("%.*s failed: '%s' returned -1 " \
"indicating timeout after %d seconds", "indicating timeout after %d seconds",
command->first_word_len, command->query, query_buf, timeout); command->first_word_len, command->query, query_buf, timeout);
else else
...@@ -4808,7 +4904,8 @@ int do_sleep(struct st_command *command, my_bool real_sleep) ...@@ -4808,7 +4904,8 @@ int do_sleep(struct st_command *command, my_bool real_sleep)
while (my_isspace(charset_info, *p)) while (my_isspace(charset_info, *p))
p++; p++;
if (!*p) if (!*p)
die("Missing argument to %.*s", command->first_word_len, command->query); die("Missing argument to %.*s", command->first_word_len,
command->query);
sleep_start= p; sleep_start= p;
/* Check that arg starts with a digit, not handled by my_strtod */ /* Check that arg starts with a digit, not handled by my_strtod */
if (!my_isdigit(charset_info, *sleep_start)) if (!my_isdigit(charset_info, *sleep_start))
...@@ -4880,16 +4977,21 @@ int query_get_string(MYSQL* mysql, const char* query, ...@@ -4880,16 +4977,21 @@ int query_get_string(MYSQL* mysql, const char* query,
MYSQL_ROW row; MYSQL_ROW row;
if (mysql_query(mysql, query)) if (mysql_query(mysql, query))
die("'%s' failed: %d %s", query, {
report_or_die("'%s' failed: %d %s", query,
mysql_errno(mysql), mysql_error(mysql)); mysql_errno(mysql), mysql_error(mysql));
return 1;
}
if ((res= mysql_store_result(mysql)) == NULL) if ((res= mysql_store_result(mysql)) == NULL)
die("Failed to store result: %d %s", {
report_or_die("Failed to store result: %d %s",
mysql_errno(mysql), mysql_error(mysql)); mysql_errno(mysql), mysql_error(mysql));
return 1;
}
if ((row= mysql_fetch_row(res)) == NULL) if ((row= mysql_fetch_row(res)) == NULL)
{ {
mysql_free_result(res); mysql_free_result(res);
ds= 0;
return 1; return 1;
} }
init_dynamic_string(ds, (row[column] ? row[column] : "NULL"), ~0, 32); init_dynamic_string(ds, (row[column] ? row[column] : "NULL"), ~0, 32);
...@@ -5161,7 +5263,7 @@ void do_get_errcodes(struct st_command *command) ...@@ -5161,7 +5263,7 @@ void do_get_errcodes(struct st_command *command)
while (*p && p != end) while (*p && p != end)
{ {
if (!my_isdigit(charset_info, *p)) if (!my_isdigit(charset_info, *p))
die("Invalid argument to error: '%s' - "\ die("Invalid argument to error: '%s' - " \
"the errno may only consist of digits[0-9]", "the errno may only consist of digits[0-9]",
command->first_argument); command->first_argument);
p++; p++;
...@@ -6084,7 +6186,7 @@ void do_block(enum block_cmd cmd, struct st_command* command) ...@@ -6084,7 +6186,7 @@ void do_block(enum block_cmd cmd, struct st_command* command)
eval_expr(&v2, curr_ptr, &expr_end); eval_expr(&v2, curr_ptr, &expr_end);
if ((operand!=EQ_OP && operand!=NE_OP) && ! (v.is_int && v2.is_int)) if ((operand!=EQ_OP && operand!=NE_OP) && ! (v.is_int && v2.is_int))
die ("Only == and != are supported for string values"); die("Only == and != are supported for string values");
/* Now we overwrite the first variable with 0 or 1 (for false or true) */ /* Now we overwrite the first variable with 0 or 1 (for false or true) */
...@@ -6675,6 +6777,12 @@ static struct my_option my_long_options[] = ...@@ -6675,6 +6777,12 @@ static struct my_option my_long_options[] =
{"compress", 'C', "Use the compressed server/client protocol.", {"compress", 'C', "Use the compressed server/client protocol.",
&opt_compress, &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, &opt_compress, &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
0, 0, 0}, 0, 0, 0},
{"continue-on-error", 0,
"Continue test even if we got an error. "
"This is mostly useful when testing a storage engine to see what from a test file it can execute, "
"or to find all syntax errors in a newly created big test file",
&opt_continue_on_error, &opt_continue_on_error, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"cursor-protocol", 0, "Use cursors for prepared statements.", {"cursor-protocol", 0, "Use cursors for prepared statements.",
&cursor_protocol, &cursor_protocol, 0, &cursor_protocol, &cursor_protocol, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
...@@ -7006,7 +7114,8 @@ int parse_args(int argc, char **argv) ...@@ -7006,7 +7114,8 @@ int parse_args(int argc, char **argv)
{ {
/* Check that the result file exists */ /* Check that the result file exists */
if (result_file_name && access(result_file_name, F_OK) != 0) if (result_file_name && access(result_file_name, F_OK) != 0)
die("The specified result file '%s' does not exist", result_file_name); die("The specified result file '%s' does not exist",
result_file_name);
} }
return 0; return 0;
...@@ -7333,8 +7442,8 @@ void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt, ...@@ -7333,8 +7442,8 @@ void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt,
} }
if (error != MYSQL_NO_DATA) if (error != MYSQL_NO_DATA)
die("mysql_fetch didn't end with MYSQL_NO_DATA from statement: error: %d", die("mysql_fetch didn't end with MYSQL_NO_DATA from statement: "
error); "error: %d", error);
if (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) if (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
die("mysql_fetch didn't end with MYSQL_NO_DATA from statement: %d %s", die("mysql_fetch didn't end with MYSQL_NO_DATA from statement: %d %s",
mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
...@@ -7666,7 +7775,8 @@ static int match_expected_error(struct st_command *command, ...@@ -7666,7 +7775,8 @@ static int match_expected_error(struct st_command *command,
NULL is quite likely, but not in conjunction with a SQL-state expect! NULL is quite likely, but not in conjunction with a SQL-state expect!
*/ */
if (unlikely(err_sqlstate == NULL)) if (unlikely(err_sqlstate == NULL))
die("expecting a SQL-state (%s) from query '%s' which cannot produce one...", die("expecting a SQL-state (%s) from query '%s' which cannot "
"produce one...",
command->expected_errors.err[i].code.sqlstate, command->query); command->expected_errors.err[i].code.sqlstate, command->query);
if (strncmp(command->expected_errors.err[i].code.sqlstate, if (strncmp(command->expected_errors.err[i].code.sqlstate,
...@@ -7720,7 +7830,11 @@ void handle_error(struct st_command *command, ...@@ -7720,7 +7830,11 @@ void handle_error(struct st_command *command,
} }
if (command->abort_on_error) if (command->abort_on_error)
die("query '%s' failed: %d: %s", command->query, err_errno, err_error); {
report_or_die("query '%s' failed: %d: %s", command->query, err_errno,
err_error);
DBUG_VOID_RETURN;
}
DBUG_PRINT("info", ("expected_errors.count: %d", DBUG_PRINT("info", ("expected_errors.count: %d",
command->expected_errors.count)); command->expected_errors.count));
...@@ -7766,11 +7880,13 @@ void handle_error(struct st_command *command, ...@@ -7766,11 +7880,13 @@ void handle_error(struct st_command *command,
if (command->expected_errors.count > 0) if (command->expected_errors.count > 0)
{ {
if (command->expected_errors.err[0].type == ERR_ERRNO) if (command->expected_errors.err[0].type == ERR_ERRNO)
die("query '%s' failed with wrong errno %d: '%s', instead of %d...", report_or_die("query '%s' failed with wrong errno %d: '%s', instead of "
"%d...",
command->query, err_errno, err_error, command->query, err_errno, err_error,
command->expected_errors.err[0].code.errnum); command->expected_errors.err[0].code.errnum);
else else
die("query '%s' failed with wrong sqlstate %s: '%s', instead of %s...", report_or_die("query '%s' failed with wrong sqlstate %s: '%s', "
"instead of %s...",
command->query, err_sqlstate, err_error, command->query, err_sqlstate, err_error,
command->expected_errors.err[0].code.sqlstate); command->expected_errors.err[0].code.sqlstate);
} }
...@@ -7799,15 +7915,17 @@ void handle_no_error(struct st_command *command) ...@@ -7799,15 +7915,17 @@ void handle_no_error(struct st_command *command)
command->expected_errors.err[0].code.errnum != 0) command->expected_errors.err[0].code.errnum != 0)
{ {
/* Error code we wanted was != 0, i.e. not an expected success */ /* Error code we wanted was != 0, i.e. not an expected success */
die("query '%s' succeeded - should have failed with errno %d...", report_or_die("query '%s' succeeded - should have failed with errno %d...",
command->query, command->expected_errors.err[0].code.errnum); command->query, command->expected_errors.err[0].code.errnum);
} }
else if (command->expected_errors.err[0].type == ERR_SQLSTATE && else if (command->expected_errors.err[0].type == ERR_SQLSTATE &&
strcmp(command->expected_errors.err[0].code.sqlstate,"00000") != 0) strcmp(command->expected_errors.err[0].code.sqlstate,"00000") != 0)
{ {
/* SQLSTATE we wanted was != "00000", i.e. not an expected success */ /* SQLSTATE we wanted was != "00000", i.e. not an expected success */
die("query '%s' succeeded - should have failed with sqlstate %s...", report_or_die("query '%s' succeeded - should have failed with "
command->query, command->expected_errors.err[0].code.sqlstate); "sqlstate %s...",
command->query,
command->expected_errors.err[0].code.sqlstate);
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -8105,10 +8223,10 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) ...@@ -8105,10 +8223,10 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
DBUG_ENTER("run_query"); DBUG_ENTER("run_query");
if (cn->pending && (flags & QUERY_SEND_FLAG)) if (cn->pending && (flags & QUERY_SEND_FLAG))
die ("Cannot run query on connection between send and reap"); die("Cannot run query on connection between send and reap");
if (!(flags & QUERY_SEND_FLAG) && !cn->pending) if (!(flags & QUERY_SEND_FLAG) && !cn->pending)
die ("Cannot reap on a connection without pending send"); die("Cannot reap on a connection without pending send");
init_dynamic_string(&ds_warnings, NULL, 0, 256); init_dynamic_string(&ds_warnings, NULL, 0, 256);
ds_warn= &ds_warnings; ds_warn= &ds_warnings;
...@@ -8293,13 +8411,14 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) ...@@ -8293,13 +8411,14 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
if (sp_created) if (sp_created)
{ {
if (util_query(mysql, "DROP PROCEDURE mysqltest_tmp_sp ")) if (util_query(mysql, "DROP PROCEDURE mysqltest_tmp_sp "))
die("Failed to drop sp: %d: %s", mysql_errno(mysql), mysql_error(mysql)); report_or_die("Failed to drop sp: %d: %s", mysql_errno(mysql),
mysql_error(mysql));
} }
if (view_created) if (view_created)
{ {
if (util_query(mysql, "DROP VIEW mysqltest_tmp_v ")) if (util_query(mysql, "DROP VIEW mysqltest_tmp_v "))
die("Failed to drop view: %d: %s", report_or_die("Failed to drop view: %d: %s",
mysql_errno(mysql), mysql_error(mysql)); mysql_errno(mysql), mysql_error(mysql));
} }
...@@ -8463,9 +8582,10 @@ void get_command_type(struct st_command* command) ...@@ -8463,9 +8582,10 @@ void get_command_type(struct st_command* command)
else else
{ {
/* -- "comment" that didn't contain a mysqltest command */ /* -- "comment" that didn't contain a mysqltest command */
die("Found line beginning with -- that didn't contain "\ report_or_die("Found line beginning with -- that didn't contain " \
"a valid mysqltest command, check your syntax or "\ "a valid mysqltest command, check your syntax or " \
"use # if you intended to write a comment"); "use # if you intended to write a comment");
command->type= Q_COMMENT;
} }
} }
...@@ -9190,7 +9310,7 @@ int main(int argc, char **argv) ...@@ -9190,7 +9310,7 @@ int main(int argc, char **argv)
if (parsing_disabled == 0) if (parsing_disabled == 0)
parsing_disabled= 1; parsing_disabled= 1;
else else
die("Parsing is already disabled"); report_or_die("Parsing is already disabled");
break; break;
case Q_ENABLE_PARSING: case Q_ENABLE_PARSING:
/* /*
...@@ -9200,7 +9320,7 @@ int main(int argc, char **argv) ...@@ -9200,7 +9320,7 @@ int main(int argc, char **argv)
if (parsing_disabled == 1) if (parsing_disabled == 1)
parsing_disabled= 0; parsing_disabled= 0;
else else
die("Parsing is already enabled"); report_or_die("Parsing is already enabled");
break; break;
case Q_DIE: case Q_DIE:
/* Abort test with error code and error message */ /* Abort test with error code and error message */
...@@ -9404,7 +9524,8 @@ void do_get_replace_column(struct st_command *command) ...@@ -9404,7 +9524,8 @@ void do_get_replace_column(struct st_command *command)
if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS) if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS)
die("Wrong column number to replace_column in '%s'", command->query); die("Wrong column number to replace_column in '%s'", command->query);
if (!*from) if (!*from)
die("Wrong number of arguments to replace_column in '%s'", command->query); die("Wrong number of arguments to replace_column in '%s'",
command->query);
to= get_string(&buff, &from, command); to= get_string(&buff, &from, command);
my_free(replace_column[column_number-1]); my_free(replace_column[column_number-1]);
replace_column[column_number-1]= my_strdup(to, MYF(MY_WME | MY_FAE)); replace_column[column_number-1]= my_strdup(to, MYF(MY_WME | MY_FAE));
......
...@@ -230,7 +230,7 @@ my %opts_extern; ...@@ -230,7 +230,7 @@ my %opts_extern;
sub using_extern { return (keys %opts_extern > 0);}; sub using_extern { return (keys %opts_extern > 0);};
our $opt_fast= 0; our $opt_fast= 0;
our $opt_force; our $opt_force= 0;
our $opt_mem= $ENV{'MTR_MEM'}; our $opt_mem= $ENV{'MTR_MEM'};
our $opt_clean_vardir= $ENV{'MTR_CLEAN_VARDIR'}; our $opt_clean_vardir= $ENV{'MTR_CLEAN_VARDIR'};
...@@ -1136,7 +1136,7 @@ sub command_line_setup { ...@@ -1136,7 +1136,7 @@ sub command_line_setup {
'defaults-extra-file=s' => \&collect_option, 'defaults-extra-file=s' => \&collect_option,
# Control what test suites or cases to run # Control what test suites or cases to run
'force' => \$opt_force, 'force+' => \$opt_force,
'with-ndbcluster-only' => \&collect_option, 'with-ndbcluster-only' => \&collect_option,
'include-ndbcluster' => \$opt_include_ndbcluster, 'include-ndbcluster' => \$opt_include_ndbcluster,
'skip-ndbcluster|skip-ndb' => \$opt_skip_ndbcluster, 'skip-ndbcluster|skip-ndb' => \$opt_skip_ndbcluster,
...@@ -5856,6 +5856,11 @@ sub start_mysqltest ($) { ...@@ -5856,6 +5856,11 @@ sub start_mysqltest ($) {
mtr_add_arg($args, "%s", $_) for @args_saved; mtr_add_arg($args, "%s", $_) for @args_saved;
} }
if ($opt_force > 1)
{
mtr_add_arg($args, "--continue-on-error");
}
my $suite = $tinfo->{suite}; my $suite = $tinfo->{suite};
if ($suite->{parent}) { if ($suite->{parent}) {
mtr_add_arg($args, "--overlay-dir=%s/", $suite->{dir}); mtr_add_arg($args, "--overlay-dir=%s/", $suite->{dir});
...@@ -6285,7 +6290,11 @@ Options to control directories to use ...@@ -6285,7 +6290,11 @@ Options to control directories to use
Options to control what test suites or cases to run Options to control what test suites or cases to run
force Continue to run the suite after failure force Continue after a failure. When specified once, a
failure in a test file will abort this test file, and
the execution will continue from the next test file.
When specified twice, execution will continue executing
the failed test file from the next command.
with-ndbcluster-only Run only tests that include "ndb" in the filename with-ndbcluster-only Run only tests that include "ndb" in the filename
skip-ndb[cluster] Skip all tests that need cluster. Default. skip-ndb[cluster] Skip all tests that need cluster. Default.
include-ndb[cluster] Enable all tests that need cluster include-ndb[cluster] Enable all tests that need cluster
......
select error;
mysqltest: At line 1: query 'select error' failed: 1054: Unknown column 'error' in 'field list'
SELECT ERROR;
mysqltest: At line 1: query 'SELECT ERROR' failed: 1054: Unknown column 'ERROR' in 'field list'
SELECT 2;
2
2
#
# mysqltest --continue-on-error
#
-- source include/not_embedded.inc
#
# with or without --continue-on-error the failing test should return an error
# but with --continue-on-error, the failing line does not abort the test
#
--error 1
--exec echo "select error; select 1;" | $MYSQL_TEST 2>&1
--exec echo "SELECT ERROR; SELECT 2;" | $MYSQL_TEST --continue-on-error 2>&1
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment