summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authorunknown <sasha@mysql.sashanet.com>2000-12-02 10:11:50 -0700
committerunknown <sasha@mysql.sashanet.com>2000-12-02 10:11:50 -0700
commit758567104ca22931476f81dda64031606d740f68 (patch)
tree94e8cdffde8949a7e3a58f3e9de286a7c513553c /client
parent98501adef90d44b258b98e0d229ac37ba85e70ee (diff)
downloadmariadb-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.c386
-rw-r--r--client/thimble.cc6
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;
}
+
+