diff options
Diffstat (limited to 'client/mysqltest.c')
-rw-r--r-- | client/mysqltest.c | 297 |
1 files changed, 227 insertions, 70 deletions
diff --git a/client/mysqltest.c b/client/mysqltest.c index bb1151fa178..be5dac1c9d9 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -109,6 +109,7 @@ MYSQL_MANAGER* manager=0; static char **default_argv; static const char *load_default_groups[]= { "mysqltest","client",0 }; +static char line_buffer[MAX_DELIMITER], *line_buffer_pos= line_buffer;; static FILE* file_stack[MAX_INCLUDE_DEPTH]; static FILE** cur_file; @@ -128,6 +129,8 @@ static CHARSET_INFO *charset_info= &my_charset_latin1; static int embedded_server_arg_count=0; static char *embedded_server_args[MAX_SERVER_ARGS]; +static my_bool display_result_vertically= FALSE, display_metadata= FALSE; + static const char *embedded_server_groups[] = { "server", "embedded", @@ -212,7 +215,10 @@ Q_WAIT_FOR_SLAVE_TO_STOP, Q_REQUIRE_VERSION, Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS, Q_ENABLE_INFO, Q_DISABLE_INFO, +Q_ENABLE_METADATA, Q_DISABLE_METADATA, Q_EXEC, Q_DELIMITER, +Q_DISPLAY_VERTICAL_RESULTS, Q_DISPLAY_HORIZONTAL_RESULTS, +Q_QUERY_VERTICAL, Q_QUERY_HORIZONTAL, Q_UNKNOWN, /* Unknown command. */ Q_COMMENT, /* Comments, ignored. */ @@ -284,8 +290,14 @@ const char *command_names[]= "disable_warnings", "enable_info", "disable_info", + "enable_metadata", + "disable_metadata", "exec", "delimiter", + "vertical_results", + "horizontal_results", + "query_vertical", + "query_horizontal", 0 }; @@ -441,10 +453,10 @@ static void free_used_memory() my_free((gptr) (*q),MYF(0)); } for (i=0; i < 10; i++) - { - if (var_reg[i].alloced_len) - my_free(var_reg[i].str_val, MYF(MY_WME)); - } + { + if (var_reg[i].alloced_len) + my_free(var_reg[i].str_val, MYF(MY_WME)); + } while (embedded_server_arg_count > 1) my_free(embedded_server_args[--embedded_server_arg_count],MYF(0)); delete_dynamic(&q_lines); @@ -862,44 +874,59 @@ int do_exec(struct st_query* q) char buf[1024]; FILE *res_file; char *cmd= q->first_argument; + DBUG_ENTER("do_exec"); while (*cmd && my_isspace(charset_info, *cmd)) cmd++; if (!*cmd) die("Missing argument in exec\n"); - if (q->record_file[0]) - { - init_dynamic_string(&ds_tmp, "", 16384, 65536); - ds= &ds_tmp; - } - else - ds= &ds_res; + DBUG_PRINT("info", ("Executing '%s'", cmd)); if (!(res_file= popen(cmd, "r")) && q->abort_on_error) die("popen() failed\n"); - while (fgets(buf, sizeof(buf), res_file)) - replace_dynstr_append_mem(ds, buf, strlen(buf)); - pclose(res_file); - - if (glob_replace) - free_replace(); - if (record) + if (disable_result_log) { - 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); + while (fgets(buf, sizeof(buf), res_file)) + { + buf[strlen(buf)-1]=0; + DBUG_PRINT("exec_result",("%s", buf)); + } } - else if (q->record_file[0]) + else { - error= check_result(ds, q->record_file, q->require_file); + if (q->record_file[0]) + { + init_dynamic_string(&ds_tmp, "", 16384, 65536); + ds= &ds_tmp; + } + else + ds= &ds_res; + + while (fgets(buf, sizeof(buf), res_file)) + replace_dynstr_append_mem(ds, buf, strlen(buf)); + + 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 (ds == &ds_tmp) + dynstr_free(&ds_tmp); } - if (ds == &ds_tmp) - dynstr_free(&ds_tmp); + pclose(res_file); - return error; + DBUG_RETURN(error); } int var_query_set(VAR* v, const char* p, const char** p_end) @@ -1034,7 +1061,7 @@ int do_system(struct st_query* q) eval_expr(&v, p, 0); /* NULL terminated */ if (v.str_val_len) { - char expr_buf[512]; + char expr_buf[1024]; if ((uint)v.str_val_len > sizeof(expr_buf) - 1) v.str_val_len = sizeof(expr_buf) - 1; memcpy(expr_buf, v.str_val, v.str_val_len); @@ -1628,24 +1655,49 @@ int do_while(struct st_query* q) } -my_bool end_of_query(int c, char* p) +/* + Read characters from line buffer or file. This is needed to allow + my_ungetc() to buffer MAX_DELIMITER characters for a file + + NOTE: + This works as long as one doesn't change files (with 'source file_name') + when there is things pushed into the buffer. This should however not + happen for any tests in the test suite. +*/ + +int my_getc(FILE *file) +{ + if (line_buffer_pos == line_buffer) + return fgetc(file); + return *--line_buffer_pos; +} + +void my_ungetc(int c) +{ + *line_buffer_pos++= (char) c; +} + + +my_bool end_of_query(int c) { - uint i, j; - int tmp[MAX_DELIMITER]= {0}; + uint i; + char tmp[MAX_DELIMITER]; + + if (c != *delimiter) + return 0; - for (i= 0; c == *(delimiter + i) && i < delimiter_length; - i++, c= fgetc(*cur_file)) + for (i= 1; i < delimiter_length && + (c= my_getc(*cur_file)) == *(delimiter + i); + i++) 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[i], *cur_file); - *p= 0; - return 1; - } + return 1; /* Found delimiter */ + + /* didn't find delimiter, push back things that we read */ + my_ungetc(c); + while (i > 1) + my_ungetc(tmp[--i]); return 0; } @@ -1663,7 +1715,7 @@ int read_line(char* buf, int size) for (; p < buf_end ;) { no_save= 0; - c= fgetc(*cur_file); + c= my_getc(*cur_file); if (feof(*cur_file)) { if ((*cur_file) != stdin) @@ -1678,8 +1730,11 @@ int read_line(char* buf, int size) switch(state) { case R_NORMAL: /* Only accept '{' in the beginning of a line */ - if (end_of_query(c, p)) + if (end_of_query(c)) + { + *p= 0; return 0; + } else if (c == '\'') state = R_Q1; else if (c == '"') @@ -1715,7 +1770,7 @@ int read_line(char* buf, int size) *buf= 0; return 0; } - else if (end_of_query(c, p) || c == '{') + else if (end_of_query(c) || c == '{') { *p= 0; return 0; @@ -1735,8 +1790,11 @@ int read_line(char* buf, int size) state= R_ESC_SLASH_Q1; break; case R_ESC_Q_Q1: - if (end_of_query(c, p)) + if (end_of_query(c)) + { + *p= 0; return 0; + } if (c != '\'') state= R_NORMAL; else @@ -1753,8 +1811,11 @@ int read_line(char* buf, int size) state= R_ESC_SLASH_Q2; break; case R_ESC_Q_Q2: - if (end_of_query(c, p)) + if (end_of_query(c)) + { + *p= 0; return 0; + } if (c != '"') state= R_NORMAL; else @@ -1772,6 +1833,7 @@ int read_line(char* buf, int size) return feof(*cur_file); } + static char read_query_buf[MAX_QUERY]; int read_query(struct st_query** q_ptr) @@ -1779,11 +1841,12 @@ int read_query(struct st_query** q_ptr) char *p = read_query_buf, * p1 ; int expected_errno; struct st_query* q; + DBUG_ENTER("read_query"); if (parser.current_line < parser.read_lines) { get_dynamic(&q_lines, (gptr) q_ptr, parser.current_line) ; - return 0; + DBUG_RETURN(0); } if (!(*q_ptr= q= (struct st_query*) my_malloc(sizeof(*q), MYF(MY_WME))) || insert_dynamic(&q_lines, (gptr) &q)) @@ -1795,14 +1858,14 @@ int read_query(struct st_query** q_ptr) 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; + q->abort_on_error= global_expected_errors == 0; bzero((gptr) global_expected_errno, sizeof(global_expected_errno)); global_expected_errors=0; q->type = Q_UNKNOWN; q->query_buf= q->query= 0; if (read_line(read_query_buf, sizeof(read_query_buf))) - return 1; + DBUG_RETURN(1); if (*p == '#') { @@ -1856,7 +1919,7 @@ int read_query(struct st_query** q_ptr) q->first_argument= p; q->end= strend(q->query); parser.read_lines++; - return 0; + DBUG_RETURN(0); } @@ -1894,7 +1957,7 @@ static struct my_option my_long_options[] = {"password", 'p', "Password to use when connecting to server.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Port number to use for connection.", (gptr*) &port, - (gptr*) &port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + (gptr*) &port, 0, GET_INT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0}, {"quiet", 's', "Suppress all normal output.", (gptr*) &silent, (gptr*) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"record", 'r', "Record output of test_file into result file.", @@ -2110,6 +2173,7 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) { MYSQL_ROW row; uint num_fields= mysql_num_fields(res); + MYSQL_FIELD *fields= !display_result_vertically ? 0 : mysql_fetch_fields(res); unsigned long *lengths; while ((row = mysql_fetch_row(res))) { @@ -2130,11 +2194,22 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) val= "NULL"; len= 4; } - if (i) + if (!display_result_vertically) + { + if (i) + dynstr_append_mem(ds, "\t", 1); + replace_dynstr_append_mem(ds, val, len); + } + else + { + dynstr_append(ds, fields[i].name); dynstr_append_mem(ds, "\t", 1); - replace_dynstr_append_mem(ds, val, len); + replace_dynstr_append_mem(ds, val, len); + dynstr_append_mem(ds, "\n", 1); + } } - dynstr_append_mem(ds, "\n", 1); + if (!display_result_vertically) + dynstr_append_mem(ds, "\n", 1); } free_replace_column(); } @@ -2149,7 +2224,8 @@ 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, err= 0, counter= 0; + uint i; + int error= 0, err= 0, counter= 0; DYNAMIC_STRING *ds; DYNAMIC_STRING ds_tmp; DYNAMIC_STRING eval_query; @@ -2233,7 +2309,8 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) goto end; /* Ok */ } } - DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors)); + 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))); @@ -2276,16 +2353,65 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) { if (res) { - int num_fields= mysql_num_fields(res); - MYSQL_FIELD *fields= mysql_fetch_fields(res); + MYSQL_FIELD *field, *field_end; + uint num_fields= mysql_num_fields(res); - for (i = 0; i < num_fields; i++) + if (display_metadata) { - if (i) + dynstr_append(ds,"Catalog\tDatabase\tTable\tTable_alias\tColumn\tColumn_alias\tName\tType\tLength\tMax length\tIs_null\tFlags\tDecimals\tCharsetnr\n"); + for (field= mysql_fetch_fields(res), field_end= field+num_fields ; + field < field_end ; + field++) + { + char buff[22]; + dynstr_append_mem(ds, field->catalog, field->catalog_length); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, field->db, field->db_length); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, field->org_table, field->org_table_length); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, field->table, field->table_length); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, field->org_name, field->org_name_length); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, field->name, field->name_length); + dynstr_append_mem(ds, "\t", 1); + int10_to_str((int) field->type, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\t", 1); + int10_to_str((int) field->length, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\t", 1); + int10_to_str((int) field->max_length, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, (char*) (IS_NOT_NULL(field->flags) ? + "N" : "Y"), 1); dynstr_append_mem(ds, "\t", 1); - dynstr_append(ds, fields[i].name); + + int10_to_str((int) field->flags, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\t", 1); + int10_to_str((int) field->decimals, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\t", 1); + int10_to_str((int) field->charsetnr, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\n", 1); + } + } + if (!display_result_vertically) + { + field= mysql_fetch_fields(res); + for (i = 0; i < num_fields; i++) + { + if (i) + dynstr_append_mem(ds, "\t", 1); + replace_dynstr_append_mem(ds, field[i].name, + strlen(field[i].name)); + } + dynstr_append_mem(ds, "\n", 1); } - dynstr_append_mem(ds, "\n", 1); append_result(ds, res); } @@ -2308,17 +2434,20 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) mysql_free_result(warn_res); } } - if (!disable_info && mysql_info(mysql)) + if (!disable_info) { - dynstr_append(ds, "info: "); - dynstr_append(ds, mysql_info(mysql)); - dynstr_append_mem(ds, "\n", 1); + char buf[40]; + sprintf(buf,"affected rows: %lu\n",(ulong) mysql_affected_rows(mysql)); + dynstr_append(ds, buf); + if (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 (record) { if (!q->record_file[0] && !result_file) @@ -2339,6 +2468,7 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) mysql_error(mysql); end: + free_replace(); last_result=0; if (ds == &ds_tmp) dynstr_free(&ds_tmp); @@ -2352,10 +2482,12 @@ void get_query_type(struct st_query* q) { char save; uint type; + DBUG_ENTER("get_query_type"); + if (*q->query == '}') { q->type = Q_END_BLOCK; - return; + DBUG_VOID_RETURN; } if (q->type != Q_COMMENT_WITH_COMMAND) q->type = Q_QUERY; @@ -2366,8 +2498,10 @@ void get_query_type(struct st_query* q) q->query[q->first_word_len]=save; if (type > 0) q->type=(enum enum_commands) type; /* Found command */ + DBUG_VOID_RETURN; } + static byte *get_var_key(const byte* var, uint* len, my_bool __attribute__((unused)) t) { @@ -2539,6 +2673,8 @@ int main(int argc, char **argv) case Q_DISABLE_WARNINGS: disable_warnings=1; break; case Q_ENABLE_INFO: disable_info=0; break; case Q_DISABLE_INFO: disable_info=1; break; + case Q_ENABLE_METADATA: display_metadata=1; break; + case Q_DISABLE_METADATA: display_metadata=0; break; case Q_SOURCE: do_source(q); break; case Q_SLEEP: do_sleep(q, 0); break; case Q_REAL_SLEEP: do_sleep(q, 1); break; @@ -2557,12 +2693,33 @@ int main(int argc, char **argv) strmake(delimiter, q->first_argument, sizeof(delimiter) - 1); delimiter_length= strlen(delimiter); break; + case Q_DISPLAY_VERTICAL_RESULTS: display_result_vertically= TRUE; break; + case Q_DISPLAY_HORIZONTAL_RESULTS: + display_result_vertically= FALSE; break; case Q_LET: do_let(q); break; case Q_EVAL_RESULT: eval_result = 1; break; case Q_EVAL: if (q->query == q->query_buf) q->query= q->first_argument; /* fall through */ + case Q_QUERY_VERTICAL: + case Q_QUERY_HORIZONTAL: + { + my_bool old_display_result_vertically= display_result_vertically; + if (!q->query[q->first_word_len]) + { + /* This happens when we use 'query_..' on it's own line */ + q_send_flag=1; + break; + } + /* fix up query pointer if this is * first iteration for this line */ + if (q->query == q->query_buf) + q->query += q->first_word_len + 1; + display_result_vertically= (q->type==Q_QUERY_VERTICAL); + error |= run_query(&cur_con->mysql, q, QUERY_REAP|QUERY_SEND); + display_result_vertically= old_display_result_vertically; + break; + } case Q_QUERY: case Q_REAP: { |