diff options
author | unknown <sasha@mysql.sashanet.com> | 2000-12-02 10:11:50 -0700 |
---|---|---|
committer | unknown <sasha@mysql.sashanet.com> | 2000-12-02 10:11:50 -0700 |
commit | 758567104ca22931476f81dda64031606d740f68 (patch) | |
tree | 94e8cdffde8949a7e3a58f3e9de286a7c513553c /client | |
parent | 98501adef90d44b258b98e0d229ac37ba85e70ee (diff) | |
download | mariadb-git-758567104ca22931476f81dda64031606d740f68.tar.gz |
added loops and other cool stuff to mysqltest
fixed slave to preserve temp tables on slave stop; slave start
added abort-slave-event-count option to mysqld to test the above
added a test case for temp tables with a contantly aborting slave
removed warning in sql_parse.cc
fixed thimble.cc to compile
BitKeeper/etc/ignore:
Added client/thimble support-files/mysql-3.23.29-gamma.spec to the ignore list
client/mysqltest.c:
added while, let, and echo, added fractional sec sleep support
client/thimble.cc:
fixes to make it compile
mysql-test/t/3.23/rpl000001.test:
sleep less
mysql-test/t/3.23/rpl000002.test:
sleep less
mysql-test/t/3.23/rpl000003.test:
sleep less
mysql-test/t/3.23/rpl000005.test:
sleep less
sql/mysqld.cc:
--abort-slave-event count
sql/slave.cc:
remember temp tables when slave thread termintates and restore them on
slave start
sql/slave.h:
--abort-slave-event-count
sql/sql_parse.cc:
remove warning
Diffstat (limited to 'client')
-rw-r--r-- | client/mysqltest.c | 386 | ||||
-rw-r--r-- | client/thimble.cc | 6 |
2 files changed, 369 insertions, 23 deletions
diff --git a/client/mysqltest.c b/client/mysqltest.c index dd024bb339b..8e5848734ee 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -46,6 +46,9 @@ #define MAX_CONS 1024 #define MAX_INCLUDE_DEPTH 16 #define LAZY_GUESS_BUF_SIZE 8192 +#define INIT_Q_LINES 1024 +#define MIN_VAR_ALLOC 32 +#define BLOCK_STACK_DEPTH 32 int record = 0, verbose = 0, silent = 0; const char* record_mode = "r"; @@ -58,15 +61,44 @@ FILE* file_stack[MAX_INCLUDE_DEPTH]; FILE** cur_file; FILE** file_stack_end; +int block_stack[BLOCK_STACK_DEPTH]; +int *cur_block, *block_stack_end; + +DYNAMIC_ARRAY q_lines; + struct connection { MYSQL mysql; char *name; }; +typedef + struct + { + int read_lines,current_line; + } PARSER; + +PARSER parser; +int block_ok = 1; /* set to 0 if the current block should not be executed */ +int false_block_depth = 0; + +typedef struct +{ + char* name; + char* str_val; + int str_val_len; + int int_val; + int alloced_len; + int int_dirty; /* do not update string if int is updated until first read */ +} VAR; + +VAR var_reg[10]; +/*Perl/shell-like variable registers */ + struct connection cons[MAX_CONS]; struct connection* cur_con, *next_con, *cons_end; +/* this should really be called command*/ struct query { char q[MAX_QUERY]; @@ -75,11 +107,21 @@ struct query int abort_on_error; uint expected_errno; char record_file[MAX_RECORD_FILE]; + enum {Q_CONNECTION, Q_QUERY, Q_CONNECT, + Q_SLEEP, Q_INC, Q_DEC,Q_SOURCE, + Q_DISCONNECT,Q_LET, Q_ECHO, Q_WHILE, Q_END_BLOCK, + Q_UNKNOWN} type; }; static void die(const char* fmt, ...); int close_connection(struct query* q); +VAR* var_get(char* var_name, char* var_name_end, int raw); +void init_parser() +{ + parser.current_line = parser.read_lines = 0; + memset(&var_reg,0, sizeof(var_reg)); +} int hex_val(int c) { @@ -91,6 +133,69 @@ int hex_val(int c) return -1; } +VAR* var_get(char* var_name, char* var_name_end, int raw) +{ + int digit; + VAR* v; + if(*var_name++ != '$') + { + --var_name; + goto err; + } + digit = *var_name - '0'; + if(!(digit < 10 && digit >= 0)) + { + --var_name; + goto err; + } + v = var_reg + digit; + if(!raw && v->int_dirty) + { + sprintf(v->str_val, "%d", v->int_val); + v->int_dirty = 0; + } + return v; + err: + if(var_name_end) + *var_name_end = 0; + die("Unsupported variable name: %s", var_name); + return 0; +} + +int var_set(char* var_name, char* var_name_end, char* var_val, + char* var_val_end) +{ + int digit; + int val_len; + VAR* v; + if(*var_name++ != '$') + { + --var_name; + *var_name_end = 0; + die("Variable name in %s does not start with '$'", var_name); + } + digit = *var_name - '0'; + if(!(digit < 10 && digit >= 0)) + { + *var_name_end = 0; + die("Unsupported variable name: %s", var_name); + } + v = var_reg + digit; + if(v->alloced_len < (val_len = (int)(var_val_end - var_val)+1)) + { + v->alloced_len = (val_len < MIN_VAR_ALLOC) ? MIN_VAR_ALLOC : val_len; + if(!(v->str_val = + v->str_val ? my_realloc(v->str_val, v->alloced_len, MYF(MY_WME)) : + my_malloc(v->alloced_len, MYF(MY_WME)))) + die("Out of memory"); + } + memcpy(v->str_val, var_val, val_len-1); + v->str_val_len = val_len; + v->str_val[val_len] = 0; + v->int_val = atoi(v->str_val); + return 0; +} + int open_file(const char* name) { if(*cur_file && ++cur_file == file_stack_end) @@ -116,19 +221,118 @@ int do_source(struct query* q) return open_file(name); } + +int eval_expr(VAR* v, char* p, char* p_end) +{ + VAR* vp; + if((vp = var_get(p,p_end,0))) + { + memcpy(v, vp, sizeof(VAR)); + return 0; + } + if(p_end) + *p_end = 0; + die("Invalid expr: %s", p); + return 1; +} + +int do_inc(struct query* q) +{ + char* p; + VAR* v; + p = (char*)q->q + q->first_word_len; + while(*p && isspace(*p)) p++; + v = var_get(p, 0, 1); + v->int_val++; + v->int_dirty = 1; + return 0; +} + +int do_dec(struct query* q) +{ + char* p; + VAR* v; + p = (char*)q->q + q->first_word_len; + while(*p && isspace(*p)) p++; + v = var_get(p, 0, 1); + v->int_val--; + v->int_dirty = 1; + return 0; +} + + +int do_echo(struct query* q) +{ + char* p; + VAR v; + p = (char*)q->q + q->first_word_len; + while(*p && isspace(*p)) p++; + eval_expr(&v, p, 0); /* NULL terminated */ + if(v.str_val_len > 1) + { + fflush(stdout); + write(1, v.str_val, v.str_val_len - 1); + } + write(1, "\n", 1); + return 0; +} + +int do_let(struct query* q) +{ + char* p, *var_name, *var_name_end, *var_val_start; + p = (char*)q->q + q->first_word_len; + while(*p && isspace(*p)) p++; + if(!*p) + die("Missing variable name in let\n"); + var_name = p; + while(*p && (*p != '=' || isspace(*p))) + p++; + var_name_end = p; + if(*p == '=') p++; + while(*p && isspace(*p)) + p++; + var_val_start = p; + while(*p && !isspace(*p)) + p++; + return var_set(var_name, var_name_end, var_val_start, p); +} + int do_sleep(struct query* q) { char* p, *arg; + struct timeval t; + int dec_mul = 1000000; p = (char*)q->q + q->first_word_len; while(*p && isspace(*p)) p++; if(!*p) die("Missing agument in sleep\n"); arg = p; - while(*p && !isspace(*p)) + t.tv_sec = atoi(arg); + t.tv_usec = 0; + while(*p && *p != '.' && !isspace(*p)) p++; + if(*p == '.') + { + char c; + char *p_end; + p++; + p_end = p + 6; + + for(;p <= p_end; ++p) + { + c = *p - '0'; + if(c < 10 && c >= 0) + { + t.tv_usec = t.tv_usec * 10 + c; + dec_mul /= 10; + } + else + break; + } + } *p = 0; - - return sleep(atoi(arg)); + t.tv_usec *= dec_mul; + return select(0,0,0,0, &t); } @@ -238,6 +442,50 @@ int do_connect(struct query* q) return 0; } +int do_done(struct query* q) +{ + q->type = Q_END_BLOCK; + if(cur_block == block_stack) + die("Stray '}' - end of block before beginning"); + if(block_ok) + parser.current_line = *--cur_block; + else + { + if(!--false_block_depth) + block_ok = 1; + ++parser.current_line; + } + return 0; +} + +int do_while(struct query* q) +{ + char *p = q->q + q->first_word_len; + char* expr_start, *expr_end; + VAR v; + if(cur_block == block_stack_end) + die("Nesting too deep"); + if(!block_ok) + { + ++false_block_depth; + return 0; + } + expr_start = strchr(p, '('); + if(!expr_start) + die("missing '(' in while"); + expr_end = strrchr(expr_start, ')'); + if(!expr_end) + die("missing ')' in while"); + eval_expr(&v, ++expr_start, --expr_end); + *cur_block++ = parser.current_line++; + if(!v.int_val) + { + block_ok = 0; + false_block_depth = 1; + } + return 0; +} + void close_cons() { for(--next_con; next_con >= cons; --next_con) @@ -328,7 +576,9 @@ int read_line(char* buf, int size) switch(state) { case R_NORMAL: - if(c == ';') + if(c == ';' || c == '{') /* '{' allows some interesting syntax + * but we don't care, as long as the + * correct sytnax gets parsed right */ { *p = 0; return 0; @@ -355,6 +605,17 @@ int read_line(char* buf, int size) } else if(isspace(c)) no_save = 1; + else if(c == '}') + { + *buf++ = '}'; + *buf = 0; + return 0; + } + else if(c == ';' || c == '{') + { + *p = 0; + return 0; + } else state = R_NORMAL; break; @@ -404,18 +665,28 @@ int read_line(char* buf, int size) return feof(*cur_file); } -int read_query(struct query* q) +int read_query(struct query** q_ptr) { char buf[MAX_QUERY]; char* p = buf,* p1 ; int c, expected_errno; + struct query* q; + if(parser.current_line < parser.read_lines) + { + get_dynamic(&q_lines, (gptr)q_ptr, parser.current_line) ; + return 0; + } + if(!(*q_ptr=q=(struct query*)my_malloc(sizeof(*q), MYF(MY_WME))) + || insert_dynamic(&q_lines, (gptr)&q) + ) + die("Out of memory"); q->record_file[0] = 0; q->abort_on_error = 1; q->has_result_set = 0; q->first_word_len = 0; q->expected_errno = 0; - + q->type = Q_UNKNOWN; if(read_line(buf, sizeof(buf))) return 1; if(*p == '!') @@ -452,7 +723,7 @@ int read_query(struct query* q) q->first_word_len = p1 - q->q; strcpy(p1, p); - + parser.read_lines++; return 0; } @@ -834,12 +1105,56 @@ int check_first_word(struct query* q, const char* word, int len) return 1; } - +void get_query_type(struct query* q) +{ + if(*q->q == '}') + { + q->type = Q_END_BLOCK; + return; + } + q->type = Q_QUERY; + switch(q->first_word_len) + { + case 3: + if(check_first_word(q, "inc", 3)) + q->type = Q_INC; + else if(check_first_word(q, "dec", 3)) + q->type = Q_DEC; + else if(check_first_word(q, "let", 3)) + q->type = Q_LET; + break; + case 4: + if(check_first_word(q, "echo", 4)) + q->type = Q_ECHO; + break; + case 5: + if(check_first_word(q, "sleep", 5)) + q->type = Q_SLEEP; + else if(check_first_word(q, "while", 5)) + q->type = Q_WHILE; + break; + case 6: + if(check_first_word(q, "source", 6)) + q->type = Q_SOURCE; + break; + case 7: + if(check_first_word(q, "connect", 7)) + q->type = Q_CONNECT; + break; + case 10: + if(check_first_word(q, "connection", 10)) + q->type = Q_CONNECTION; + else if(check_first_word(q, "disconnect", 10)) + q->type = Q_DISCONNECT; + break; + + } +} int main(int argc, char** argv) { int error = 0; - struct query q; + struct query* q; MY_INIT(argv[0]); memset(cons, 0, sizeof(cons)); @@ -850,6 +1165,11 @@ int main(int argc, char** argv) memset(file_stack, 0, sizeof(file_stack)); file_stack_end = file_stack + MAX_INCLUDE_DEPTH; cur_file = file_stack; + init_dynamic_array(&q_lines, sizeof(struct query*), INIT_Q_LINES, + INIT_Q_LINES); + memset(block_stack, 0, sizeof(block_stack)); + block_stack_end = block_stack + BLOCK_STACK_DEPTH; + cur_block = block_stack; parse_args(argc, argv); if(!*cur_file) @@ -870,20 +1190,42 @@ int main(int argc, char** argv) if(!cur_con->name) die("Out of memory"); - while(!read_query(&q)) + for(;!read_query(&q);) { - if(check_first_word(&q, "connect", 7)) - do_connect(&q); - else if(check_first_word(&q, "connection", 10)) - select_connection(&q); - else if(check_first_word(&q, "disconnect", 10)) - close_connection(&q); - else if(check_first_word(&q, "source", 6)) - do_source(&q); - else if(check_first_word(&q, "sleep", 5)) - do_sleep(&q); - else - error |= run_query(&cur_con->mysql, &q); + int current_line_inc = 1, processed = 0; + if(q->type == Q_UNKNOWN) + get_query_type(q); + if(block_ok) + { + processed = 1; + switch(q->type) + { + case Q_CONNECT: do_connect(q); break; + case Q_CONNECTION: select_connection(q); break; + case Q_DISCONNECT: close_connection(q); break; + case Q_SOURCE: do_source(q); break; + case Q_SLEEP: do_sleep(q); break; + case Q_INC: do_inc(q); break; + case Q_DEC: do_dec(q); break; + case Q_ECHO: do_echo(q); break; + case Q_LET: do_let(q); break; + case Q_QUERY: error |= run_query(&cur_con->mysql, q); break; + default: processed = 0; break; + } + } + + if(!processed) + { + current_line_inc = 0; + switch(q->type) + { + case Q_WHILE: do_while(q); break; + case Q_END_BLOCK: do_done(q); break; + default: current_line_inc = 1; break; + } + } + + parser.current_line += current_line_inc; } close_cons(); diff --git a/client/thimble.cc b/client/thimble.cc index 1c4fdd97ed2..6d1e8a85559 100644 --- a/client/thimble.cc +++ b/client/thimble.cc @@ -2,6 +2,7 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include "my_global.h" static void spawn_stern_thread(pthread_t *t); static int act_goofy(void); @@ -13,6 +14,7 @@ static struct { int msg; } comm = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0 }; + int main(void) { @@ -65,7 +67,7 @@ static int act_goofy(void) return ret; } -static void *be_stern(void *v __attribute((unused))) +static void *be_stern(void *v __attribute__((unused))) { int msg; for (;;) { @@ -87,3 +89,5 @@ static void *be_stern(void *v __attribute((unused))) fputs("You are NOTHING!\n", stderr); return NULL; } + + |