From 96555b5f90bcd753a39ce89d197cbcef102fa6c2 Mon Sep 17 00:00:00 2001 From: "jani@rhols221.adsl.netsonic.fi" <> Date: Tue, 16 Dec 2003 06:09:44 +0200 Subject: [PATCH] Added support for multi statement tests. Use mysqltest internal command delimiter to change the default delimiter (;) to something else, a string upto 16 characters is allowed. Separate the sub queries with ';' and end the whole statement with your own delimiter. --- client/mysqltest.c | 404 +++++++++++++++------------- mysql-test/r/multi_statement.result | 33 +++ mysql-test/t/multi_statement.test | 13 + 3 files changed, 264 insertions(+), 186 deletions(-) create mode 100644 mysql-test/r/multi_statement.result create mode 100644 mysql-test/t/multi_statement.test diff --git a/client/mysqltest.c b/client/mysqltest.c index 9bcef569669..a53e259c726 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -42,7 +42,7 @@ **********************************************************************/ -#define MTEST_VERSION "2.0" +#define MTEST_VERSION "2.1" #include <my_global.h> #include <mysql_embed.h> @@ -86,7 +86,8 @@ #define MAX_CON_TRIES 5 #define SLAVE_POLL_INTERVAL 300000 /* 0.3 of a sec */ - +#define DEFAULT_DELIMITER ";" +#define MAX_DELIMITER 16 enum {OPT_MANAGER_USER=256,OPT_MANAGER_HOST,OPT_MANAGER_PASSWD, OPT_MANAGER_PORT,OPT_MANAGER_WAIT_TIMEOUT, OPT_SKIP_SAFEMALLOC, @@ -114,6 +115,8 @@ static FILE** cur_file; static FILE** file_stack_end; static uint lineno_stack[MAX_INCLUDE_DEPTH]; 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]; @@ -209,7 +212,8 @@ Q_WAIT_FOR_SLAVE_TO_STOP, Q_REQUIRE_VERSION, Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS, Q_ENABLE_INFO, Q_DISABLE_INFO, -Q_EXEC, +Q_EXEC, Q_DELIMITER, + Q_UNKNOWN, /* Unknown command. */ Q_COMMENT, /* Comments, ignored. */ Q_COMMENT_WITH_COMMAND @@ -281,6 +285,7 @@ const char *command_names[]= "enable_info", "disable_info", "exec", + "delimiter", 0 }; @@ -1472,7 +1477,8 @@ int safe_connect(MYSQL* con, const char* host, const char* user, int i; for (i = 0; i < MAX_CON_TRIES; ++i) { - if (mysql_real_connect(con, host,user, pass, db, port, sock, 0)) + if (mysql_real_connect(con, host,user, pass, db, port, sock, + CLIENT_MULTI_STATEMENTS)) { con_error = 0; break; @@ -1622,24 +1628,46 @@ int do_while(struct st_query* q) } +my_bool end_of_query(int c, char* p) +{ + uint i= 0, j; + int tmp[MAX_DELIMITER]= {0}; + + for (i= 0; c == *(delimiter + i) && i < delimiter_length; + i++, c= fgetc(*cur_file)) + tmp[i]= c; + tmp[i]= c; + + for (j= i; j > 0 && i != delimiter_length; j--) + ungetc(tmp[j], *cur_file); + if (i == delimiter_length) + { + ungetc(tmp[j], *cur_file); + *p= 0; + return 1; + } + return 0; +} + + int read_line(char* buf, int size) { int c; - char* p = buf, *buf_end = buf + size-1; - int no_save = 0; + char* p= buf, *buf_end= buf + size - 1; + int no_save= 0; enum {R_NORMAL, R_Q1, R_ESC_Q_Q1, R_ESC_Q_Q2, R_ESC_SLASH_Q1, R_ESC_SLASH_Q2, - R_Q2, R_COMMENT, R_LINE_START} state = R_LINE_START; + R_Q2, R_COMMENT, R_LINE_START} state= R_LINE_START; start_lineno= *lineno; for (; p < buf_end ;) { - no_save = 0; - c = fgetc(*cur_file); + no_save= 0; + c= fgetc(*cur_file); if (feof(*cur_file)) { if ((*cur_file) != stdin) - my_fclose(*cur_file,MYF(0)); + my_fclose(*cur_file, MYF(0)); cur_file--; lineno--; if (cur_file == file_stack) @@ -1650,11 +1678,8 @@ int read_line(char* buf, int size) switch(state) { case R_NORMAL: /* Only accept '{' in the beginning of a line */ - if (c == ';') - { - *p = 0; + if (end_of_query(c, p)) return 0; - } else if (c == '\'') state = R_Q1; else if (c == '"') @@ -1668,7 +1693,7 @@ int read_line(char* buf, int size) case R_COMMENT: if (c == '\n') { - *p=0; + *p= 0; (*lineno)++; return 0; } @@ -1678,78 +1703,72 @@ int read_line(char* buf, int size) { state = R_COMMENT; } - else if (my_isspace(charset_info,c)) + else if (my_isspace(charset_info, c)) { if (c == '\n') start_lineno= ++*lineno; /* Query hasn't started yet */ - no_save = 1; + no_save= 1; } else if (c == '}') { - *buf++ = '}'; - *buf = 0; + *buf++= '}'; + *buf= 0; return 0; } - else if (c == ';' || c == '{') + else if (end_of_query(c, p) || c == '{') { - *p = 0; + *p= 0; return 0; } else if (c == '\'') - state = R_Q1; + state= R_Q1; else if (c == '"') - state = R_Q2; + state= R_Q2; else - state = R_NORMAL; + state= R_NORMAL; break; case R_Q1: if (c == '\'') - state = R_ESC_Q_Q1; + state= R_ESC_Q_Q1; else if (c == '\\') - state = R_ESC_SLASH_Q1; + state= R_ESC_SLASH_Q1; break; case R_ESC_Q_Q1: - if (c == ';') - { - *p = 0; + if (end_of_query(c, p)) return 0; - } if (c != '\'') - state = R_NORMAL; + state= R_NORMAL; else - state = R_Q1; + state= R_Q1; break; case R_ESC_SLASH_Q1: - state = R_Q1; + state= R_Q1; break; case R_Q2: if (c == '"') - state = R_ESC_Q_Q2; + state= R_ESC_Q_Q2; else if (c == '\\') - state = R_ESC_SLASH_Q2; + state= R_ESC_SLASH_Q2; break; case R_ESC_Q_Q2: - if (c == ';') - { - *p = 0; + if (end_of_query(c, p)) return 0; - } if (c != '"') - state = R_NORMAL; + state= R_NORMAL; else - state = R_Q2; + state= R_Q2; break; case R_ESC_SLASH_Q2: - state = R_Q2; + state= R_Q2; break; } if (!no_save) - *p++ = c; + *p++= c; } - *p=0; /* Always end with \0 */ + *p= 0; /* Always end with \0 */ return feof(*cur_file); } @@ -1766,22 +1785,22 @@ int read_query(struct st_query** q_ptr) get_dynamic(&q_lines, (gptr) q_ptr, parser.current_line) ; return 0; } - if (!(*q_ptr=q=(struct st_query*) my_malloc(sizeof(*q), MYF(MY_WME))) || + if (!(*q_ptr= q= (struct st_query*) my_malloc(sizeof(*q), MYF(MY_WME))) || insert_dynamic(&q_lines, (gptr) &q)) die(NullS); - q->record_file[0] = 0; - q->require_file=0; - q->first_word_len = 0; + q->record_file[0]= 0; + q->require_file= 0; + q->first_word_len= 0; memcpy((gptr) q->expected_errno, (gptr) global_expected_errno, sizeof(global_expected_errno)); - q->expected_errors=global_expected_errors; - q->abort_on_error = global_expected_errno[0] == 0; - bzero((gptr) global_expected_errno,sizeof(global_expected_errno)); + q->expected_errors= global_expected_errors; + q->abort_on_error= global_expected_errno[0] == 0; + bzero((gptr) global_expected_errno, sizeof(global_expected_errno)); global_expected_errors=0; q->type = Q_UNKNOWN; - q->query_buf=q->query=0; + q->query_buf= q->query= 0; if (read_line(read_query_buf, sizeof(read_query_buf))) return 1; @@ -1791,20 +1810,20 @@ int read_query(struct st_query** q_ptr) } else if (p[0] == '-' && p[1] == '-') { - q->type = Q_COMMENT_WITH_COMMAND; - p+=2; /* To calculate first word */ + q->type= Q_COMMENT_WITH_COMMAND; + p+= 2; /* To calculate first word */ } else { if (*p == '!') { - q->abort_on_error = 0; + q->abort_on_error= 0; p++; if (*p == '$') { - expected_errno = 0; + expected_errno= 0; p++; - for (;my_isdigit(charset_info,*p);p++) + for (; my_isdigit(charset_info, *p); p++) expected_errno = expected_errno * 10 + *p - '0'; q->expected_errno[0] = expected_errno; q->expected_errno[1] = 0; @@ -1812,30 +1831,30 @@ int read_query(struct st_query** q_ptr) } } - while (*p && my_isspace(charset_info,*p)) + while (*p && my_isspace(charset_info, *p)) p++ ; if (*p == '@') { p++; p1 = q->record_file; - while (!my_isspace(charset_info,*p) && + while (!my_isspace(charset_info, *p) && p1 < q->record_file + sizeof(q->record_file) - 1) *p1++ = *p++; *p1 = 0; } } - while (*p && my_isspace(charset_info,*p)) + while (*p && my_isspace(charset_info, *p)) p++; - if (!(q->query_buf=q->query=my_strdup(p,MYF(MY_WME)))) + if (!(q->query_buf= q->query= my_strdup(p, MYF(MY_WME)))) die(NullS); /* Calculate first word and first argument */ - for (p=q->query; *p && !my_isspace(charset_info,*p) ; p++) ; - q->first_word_len = (uint) (p - q->query); - while (*p && my_isspace(charset_info,*p)) + for (p= q->query; *p && !my_isspace(charset_info, *p) ; p++) ; + q->first_word_len= (uint) (p - q->query); + while (*p && my_isspace(charset_info, *p)) p++; - q->first_argument=p; - q->end = strend(q->query); + q->first_argument= p; + q->end= strend(q->query); parser.read_lines++; return 0; } @@ -2129,12 +2148,12 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) int run_query(MYSQL* mysql, struct st_query* q, int flags) { - MYSQL_RES* res = 0; - int i, error = 0; + MYSQL_RES* res= 0; + int i, error= 0, err= 0, counter= 0; DYNAMIC_STRING *ds; DYNAMIC_STRING ds_tmp; DYNAMIC_STRING eval_query; - char* query; + char* query, buff[MAX_DELIMITER + 1]= {0}; int query_len; DBUG_ENTER("run_query"); @@ -2162,150 +2181,159 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) if ((flags & QUERY_SEND) && mysql_send_query(mysql, query, query_len)) die("At line %u: unable to send query '%s'(mysql_errno=%d,errno=%d)", - start_lineno, query, - mysql_errno(mysql), errno); - if ((flags & QUERY_SEND) && !disable_query_log) - { - replace_dynstr_append_mem(ds,query, query_len); - dynstr_append_mem(ds,";\n",2); - } - if (!(flags & QUERY_REAP)) - DBUG_RETURN(0); + start_lineno, query, mysql_errno(mysql), errno); - if ((*mysql->methods->read_query_result)(mysql) || - (!(last_result = res = mysql_store_result(mysql)) && - mysql_field_count(mysql))) + do { - if (q->require_file) + if ((flags & QUERY_SEND) && !disable_query_log && !counter) { - abort_not_supported_test(); + replace_dynstr_append_mem(ds,query, query_len); + sprintf(buff, "%s\n", delimiter); + dynstr_append_mem(ds, buff, strlen(delimiter) + 1); } - if (q->abort_on_error) - die("At line %u: query '%s' failed: %d: %s", start_lineno, query, - mysql_errno(mysql), mysql_error(mysql)); - else + if (!(flags & QUERY_REAP)) + DBUG_RETURN(0); + + if ((!counter && (*mysql->methods->read_query_result)(mysql)) || + (!(last_result= res= mysql_store_result(mysql)) && + mysql_field_count(mysql))) { - for (i=0 ; (uint) i < q->expected_errors ; i++) + if (q->require_file) { - if ((q->expected_errno[i] == mysql_errno(mysql))) + abort_not_supported_test(); + } + if (q->abort_on_error) + die("At line %u: query '%s' failed: %d: %s", start_lineno, query, + mysql_errno(mysql), mysql_error(mysql)); + else + { + for (i=0 ; (uint) i < q->expected_errors ; i++) { - if (i == 0 && q->expected_errors == 1) + if ((q->expected_errno[i] == mysql_errno(mysql))) { - /* Only log error if there is one possible error */ - dynstr_append_mem(ds,"ERROR ",6); - replace_dynstr_append_mem(ds, mysql_sqlstate(mysql), - strlen(mysql_sqlstate(mysql))); - dynstr_append_mem(ds,": ",2); - replace_dynstr_append_mem(ds,mysql_error(mysql), - strlen(mysql_error(mysql))); - dynstr_append_mem(ds,"\n",1); + if (i == 0 && q->expected_errors == 1) + { + /* Only log error if there is one possible error */ + dynstr_append_mem(ds,"ERROR ",6); + replace_dynstr_append_mem(ds, mysql_sqlstate(mysql), + strlen(mysql_sqlstate(mysql))); + dynstr_append_mem(ds, ": ", 2); + replace_dynstr_append_mem(ds,mysql_error(mysql), + strlen(mysql_error(mysql))); + dynstr_append_mem(ds,"\n",1); + } + /* Don't log error if we may not get an error */ + else if (q->expected_errno[0] != 0) + dynstr_append(ds,"Got one of the listed errors\n"); + goto end; /* Ok */ } - /* Don't log error if we may not get an error */ - else if (q->expected_errno[0] != 0) - dynstr_append(ds,"Got one of the listed errors\n"); - goto end; /* Ok */ } - } - DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors)); - dynstr_append_mem(ds,"ERROR ",6); - replace_dynstr_append_mem(ds, mysql_sqlstate(mysql), - strlen(mysql_sqlstate(mysql))); - dynstr_append_mem(ds,": ",2); - replace_dynstr_append_mem(ds, mysql_error(mysql), - strlen(mysql_error(mysql))); - dynstr_append_mem(ds,"\n",1); - if (i) - { - verbose_msg("query '%s' failed with wrong errno %d instead of %d...", - q->query, mysql_errno(mysql), q->expected_errno[0]); - error= 1; + DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors)); + dynstr_append_mem(ds, "ERROR ",6); + replace_dynstr_append_mem(ds, mysql_sqlstate(mysql), + strlen(mysql_sqlstate(mysql))); + dynstr_append_mem(ds,": ",2); + replace_dynstr_append_mem(ds, mysql_error(mysql), + strlen(mysql_error(mysql))); + dynstr_append_mem(ds,"\n",1); + if (i) + { + verbose_msg("query '%s' failed with wrong errno %d instead of %d...", + q->query, mysql_errno(mysql), q->expected_errno[0]); + error= 1; + goto end; + } + verbose_msg("query '%s' failed: %d: %s", q->query, mysql_errno(mysql), + mysql_error(mysql)); + /* + if we do not abort on error, failure to run the query does + not fail the whole test case + */ goto end; } - verbose_msg("query '%s' failed: %d: %s", q->query, mysql_errno(mysql), - mysql_error(mysql)); - /* - if we do not abort on error, failure to run the query does - not fail the whole test case - */ - goto end; + /*{ + verbose_msg("failed in mysql_store_result for query '%s' (%d)", query, + mysql_errno(mysql)); + error = 1; + goto end; + }*/ } - /*{ - verbose_msg("failed in mysql_store_result for query '%s' (%d)", query, - mysql_errno(mysql)); + + if (q->expected_errno[0]) + { error = 1; + verbose_msg("query '%s' succeeded - should have failed with errno %d...", + q->query, q->expected_errno[0]); goto end; - }*/ - } - - if (q->expected_errno[0]) - { - error = 1; - verbose_msg("query '%s' succeeded - should have failed with errno %d...", - q->query, q->expected_errno[0]); - goto end; - } + } - if (!disable_result_log) - { - if (res) + if (!disable_result_log) { - int num_fields= mysql_num_fields(res); - MYSQL_FIELD *fields= mysql_fetch_fields(res); - for (i = 0; i < num_fields; i++) + if (res) { - if (i) - dynstr_append_mem(ds, "\t", 1); - dynstr_append(ds, fields[i].name); + int num_fields= mysql_num_fields(res); + MYSQL_FIELD *fields= mysql_fetch_fields(res); + + for (i = 0; i < num_fields; i++) + { + if (i) + dynstr_append_mem(ds, "\t", 1); + dynstr_append(ds, fields[i].name); + } + dynstr_append_mem(ds, "\n", 1); + append_result(ds, res); } - dynstr_append_mem(ds, "\n", 1); - append_result(ds, res); - } - /* Add all warnings to the result */ - if (!disable_warnings && mysql_warning_count(mysql)) - { - MYSQL_RES *warn_res=0; - uint count= mysql_warning_count(mysql); - if (!mysql_real_query(mysql, "SHOW WARNINGS", 13)) + /* Add all warnings to the result */ + if (!disable_warnings && mysql_warning_count(mysql)) { - warn_res=mysql_store_result(mysql); + MYSQL_RES *warn_res=0; + uint count= mysql_warning_count(mysql); + if (!mysql_real_query(mysql, "SHOW WARNINGS", 13)) + { + warn_res= mysql_store_result(mysql); + } + if (!warn_res) + verbose_msg("Warning count is %u but didn't get any warnings\n", + count); + else + { + dynstr_append_mem(ds, "Warnings:\n", 10); + append_result(ds, warn_res); + mysql_free_result(warn_res); + } } - if (!warn_res) - verbose_msg("Warning count is %u but didn't get any warnings\n", - count); - else + if (!disable_info && mysql_info(mysql)) { - dynstr_append_mem(ds, "Warnings:\n", 10); - append_result(ds, warn_res); - mysql_free_result(warn_res); + dynstr_append(ds, "info: "); + dynstr_append(ds, mysql_info(mysql)); + dynstr_append_mem(ds, "\n", 1); } } - if (!disable_info && mysql_info(mysql)) - { - dynstr_append(ds, "info: "); - dynstr_append(ds, mysql_info(mysql)); - dynstr_append_mem(ds, "\n", 1); - } - } - if (glob_replace) - free_replace(); + if (glob_replace) + free_replace(); - if (record) - { - if (!q->record_file[0] && !result_file) - die("At line %u: Missing result file", start_lineno); - if (!result_file) - str_to_file(q->record_file, ds->str, ds->length); - } - else if (q->record_file[0]) - { - error = check_result(ds, q->record_file, q->require_file); - } + if (record) + { + if (!q->record_file[0] && !result_file) + die("At line %u: Missing result file", start_lineno); + if (!result_file) + str_to_file(q->record_file, ds->str, ds->length); + } + else if (q->record_file[0]) + { + error = check_result(ds, q->record_file, q->require_file); + } + if (res) + mysql_free_result(res); + last_result= 0; + counter++; + } while (!(err= mysql_next_result(mysql))); + if (err >= 1) + mysql_error(mysql); end: - if (res) - mysql_free_result(res); last_result=0; if (ds == &ds_tmp) dynstr_free(&ds_tmp); @@ -2425,7 +2453,7 @@ int main(int argc, char **argv) my_bool require_file=0, q_send_flag=0; char save_file[FN_REFLEN]; MY_INIT(argv[0]); - { + DBUG_ENTER("main"); DBUG_PROCESS(argv[0]); @@ -2520,6 +2548,10 @@ int main(int argc, char **argv) case Q_DEC: do_dec(q); break; case Q_ECHO: do_echo(q); break; case Q_SYSTEM: do_system(q); break; + case Q_DELIMITER: + strmake(delimiter, q->first_argument, sizeof(delimiter) - 1); + delimiter_length= strlen(delimiter); + break; case Q_LET: do_let(q); break; case Q_EVAL_RESULT: eval_result = 1; break; case Q_EVAL: @@ -2646,9 +2678,9 @@ int main(int argc, char **argv) free_used_memory(); exit(error ? 1 : 0); return error ? 1 : 0; /* Keep compiler happy */ - } } + /* Read arguments for embedded server and put them into embedded_server_args_count and embedded_server_args[] diff --git a/mysql-test/r/multi_statement.result b/mysql-test/r/multi_statement.result new file mode 100644 index 00000000000..4451b0a355e --- /dev/null +++ b/mysql-test/r/multi_statement.result @@ -0,0 +1,33 @@ +select 1; +1 +1 +select 2; +select 3; +select 4|||| +2 +2 +3 +3 +4 +4 +select 5; +select 6; +select 50, 'abc';'abcd' +5 +5 +6 +6 +50 abc +50 abc +select "abcd'";'abcd' +abcd' +abcd' +select "'abcd";'abcd' +'abcd +'abcd +select 5'abcd' +5 +5 +select 'finish'; +finish +finish diff --git a/mysql-test/t/multi_statement.test b/mysql-test/t/multi_statement.test new file mode 100644 index 00000000000..bd90275c9f5 --- /dev/null +++ b/mysql-test/t/multi_statement.test @@ -0,0 +1,13 @@ +select 1; +delimiter ||||; +select 2; +select 3; +select 4|||| +delimiter 'abcd'|||| +select 5; +select 6; +select 50, 'abc';'abcd' +select "abcd'";'abcd'select "'abcd";'abcd' +select 5'abcd' +delimiter ;'abcd' +select 'finish'; -- 2.30.9