diff options
Diffstat (limited to 'client/mysqltest.c')
-rw-r--r-- | client/mysqltest.c | 117 |
1 files changed, 86 insertions, 31 deletions
diff --git a/client/mysqltest.c b/client/mysqltest.c index c172d18cbd0..a7f9420df6d 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -60,6 +60,7 @@ #include <sys/stat.h> #include <violite.h> #include <regex.h> /* Our own version of lib */ +#include <sys/wait.h> #define MAX_QUERY 131072 #define MAX_VAR_NAME 256 #define MAX_COLUMNS 256 @@ -164,10 +165,17 @@ static char TMPDIR[FN_REFLEN]; static char delimiter[MAX_DELIMITER]= DEFAULT_DELIMITER; static uint delimiter_length= 1; -static int *cur_block, *block_stack_end; -static int block_stack[BLOCK_STACK_DEPTH]; +/* Block stack */ +enum block_cmd { cmd_none, cmd_if, cmd_while }; +typedef struct +{ + int line; /* Start line of block */ + my_bool ok; /* Should block be executed */ + enum block_cmd cmd; /* Command owning the block */ +} BLOCK; +static BLOCK block_stack[BLOCK_STACK_DEPTH]; +static BLOCK *cur_block, *block_stack_end; -static int block_ok_stack[BLOCK_STACK_DEPTH]; static CHARSET_INFO *charset_info= &my_charset_latin1; /* Default charset */ static const char *charset_name= "latin1"; /* Default character set name */ @@ -221,8 +229,6 @@ MYSQL_RES *last_result=0; PARSER parser; MASTER_POS master_pos; -int *block_ok; /* set to 0 if the current block should not be executed */ -int false_block_depth = 0; /* if set, all results are concated and compared against this file */ const char *result_file = 0; @@ -296,6 +302,7 @@ Q_START_TIMER, Q_END_TIMER, Q_CHARACTER_SET, Q_DISABLE_PS_PROTOCOL, Q_ENABLE_PS_PROTOCOL, Q_EXIT, Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT, +Q_IF, Q_UNKNOWN, /* Unknown command. */ Q_COMMENT, /* Comments, ignored. */ @@ -386,6 +393,7 @@ const char *command_names[]= "exit", "disable_reconnect", "enable_reconnect", + "if", 0 }; @@ -979,9 +987,38 @@ static void do_exec(struct st_query* q) replace_dynstr_append(ds, buf); } error= pclose(res_file); - if (error != 0) - die("command \"%s\" failed", cmd); + { + uint status= WEXITSTATUS(error); + if(q->abort_on_error) + die("At line %u: command \"%s\" failed", start_lineno, cmd); + else + { + bool ok= 0; + uint i; + DBUG_PRINT("info", + ("error: %d, status: %d", error, status)); + for (i=0 ; (uint) i < q->expected_errors ; i++) + { + DBUG_PRINT("info", ("expected error: %d", q->expected_errno[i].code.errnum)); + if ((q->expected_errno[i].type == ERR_ERRNO) && + (q->expected_errno[i].code.errnum == status)) + ok= 1; + verbose_msg("At line %u: command \"%s\" failed with expected error: %d", + start_lineno, cmd, status); + } + if (!ok) + die("At line: %u: command \"%s\" failed with wrong error: %d", + start_lineno, cmd, status); + } + } + else if (q->expected_errno[0].type == ERR_ERRNO && + q->expected_errno[0].code.errnum != 0) + { + /* Error code we wanted was != 0, i.e. not an expected success */ + die("At line: %u: command \"%s\" succeeded - should have failed with errno %d...", + start_lineno, cmd, q->expected_errno[0].code.errnum); + } if (!disable_result_log) { @@ -1924,36 +1961,54 @@ int do_connect(struct st_query* q) int do_done(struct st_query* q) { + /* Dummy statement to eliminate compiler warning */ q->type = Q_END_BLOCK; + + /* Check if empty block stack */ if (cur_block == block_stack) die("Stray '}' - end of block before beginning"); - if (*block_ok--) + + /* Test if inner block has been executed */ + if (cur_block->ok && cur_block->cmd == cmd_while) { - parser.current_line = *--cur_block; + /* Pop block from stack, re-execute outer block */ + cur_block--; + parser.current_line = cur_block->line; } else { - ++parser.current_line; - --cur_block; + /* Pop block from stack, goto next line */ + cur_block--; + parser.current_line++; } return 0; } -int do_while(struct st_query* q) + +int do_block(enum block_cmd cmd, struct st_query* q) { char* p=q->first_argument; const char* expr_start, *expr_end; VAR v; + + /* Check stack overflow */ if (cur_block == block_stack_end) die("Nesting too deeply"); - if (!*block_ok) + + /* Set way to find outer block again, increase line counter */ + cur_block->line= parser.current_line++; + + /* If this block is ignored */ + if (!cur_block->ok) { - ++false_block_depth; - *++block_ok = 0; - *cur_block++ = parser.current_line++; + /* Inner block should be ignored too */ + cur_block++; + cur_block->cmd= cmd; + cur_block->ok= FALSE; return 0; } + /* Parse and evaluate test expression */ expr_start = strchr(p, '('); if (!expr_start) die("missing '(' in while"); @@ -1962,14 +2017,12 @@ int do_while(struct st_query* q) die("missing ')' in while"); var_init(&v,0,0,0,0); eval_expr(&v, ++expr_start, &expr_end); - *cur_block++ = parser.current_line++; - if (!v.int_val) - { - *++block_ok = 0; - false_block_depth++; - } - else - *++block_ok = 1; + + /* Define inner block */ + cur_block++; + cur_block->cmd= cmd; + cur_block->ok= (v.int_val ? TRUE : FALSE); + var_free(&v); return 0; } @@ -3653,12 +3706,13 @@ int main(int argc, char **argv) lineno = lineno_stack; my_init_dynamic_array(&q_lines, sizeof(struct st_query*), INIT_Q_LINES, INIT_Q_LINES); + memset(block_stack, 0, sizeof(block_stack)); - block_stack_end = block_stack + BLOCK_STACK_DEPTH; - memset(block_ok_stack, 0, sizeof(block_stack)); - cur_block = block_stack; - block_ok = block_ok_stack; - *block_ok = 1; + block_stack_end= block_stack + BLOCK_STACK_DEPTH; + cur_block= block_stack; + cur_block->ok= TRUE; /* Outer block should always be executed */ + cur_block->cmd= cmd_none; + init_dynamic_string(&ds_res, "", 0, 65536); parse_args(argc, argv); @@ -3712,7 +3766,7 @@ int main(int argc, char **argv) int current_line_inc = 1, processed = 0; if (q->type == Q_UNKNOWN || q->type == Q_COMMENT_WITH_COMMAND) get_query_type(q); - if (*block_ok) + if (cur_block->ok) { processed = 1; switch (q->type) { @@ -3915,7 +3969,8 @@ int main(int argc, char **argv) { current_line_inc = 0; switch (q->type) { - case Q_WHILE: do_while(q); break; + case Q_WHILE: do_block(cmd_while, q); break; + case Q_IF: do_block(cmd_if, q); break; case Q_END_BLOCK: do_done(q); break; default: current_line_inc = 1; break; } |