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)
This commit is contained in:
Sergei Golubchik 2012-05-15 19:35:57 +02:00
parent ddd3e261b2
commit c17bace4f0
4 changed files with 273 additions and 120 deletions

View File

@ -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;
#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;
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;
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);
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,
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,
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,
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)
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;
}
static void make_error_message(char *buf, size_t len, const char *fmt, va_list args)
{
char *s= buf, *end= buf + len;
s+= my_snprintf(s, end - s, "mysqltest: ");
if (cur_file && cur_file != file_stack)
{
s+= my_snprintf(s, end - s, "In included file \"%s\": \n",
cur_file->file_name);
s+= print_file_stack(s, end);
}
if (start_lineno > 0)
s+= my_snprintf(s, end -s, "At line %u: ", start_lineno);
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, ...) void die(const char *fmt, ...)
{ {
static int dying= 0; char buff[DIE_BUFF_SIZE];
va_list args; va_list args;
DBUG_ENTER("die");
DBUG_PRINT("enter", ("start_lineno: %d", start_lineno));
fflush(stdout);
/* Print the error message */
fprintf(stderr, "mysqltest: ");
if (cur_file && cur_file != file_stack)
{
fprintf(stderr, "In included file \"%s\": \n",
cur_file->file_name);
print_file_stack();
}
if (start_lineno > 0)
fprintf(stderr, "At line %u: ", start_lineno);
if (fmt)
{
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, ...)
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, ...)
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,
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)
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)
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()
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()
*/ */
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)
@ -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])
@ -2700,12 +2767,19 @@ void var_set_query_get_value(struct st_command *command, VAR *var)
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)
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)
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)
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)
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)
{ {
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)
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,
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)
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)
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,
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)
/* 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))
{ {
@ -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,
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);
@ -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)
{ {
/* 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,
} }
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,
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,
} }
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,
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)
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;
} }
@ -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)
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)
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)
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)
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));

View File

@ -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 {
'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 ($) {
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
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

View File

@ -0,0 +1,7 @@
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

View File

@ -0,0 +1,16 @@
#
# 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