From 447a11940796a19a05d380278ada083be1bcca9a Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Fri, 15 Jul 2005 17:51:43 +0200 Subject: [PATCH 01/41] BUG#11316 mysqltest, problems when assigning value with '#' to $variable - Fixed problem, only detect comment if the # is on start of line AND starting line of the current command. - Wrote tests for most of the mysqltest commands, added stricter checking of correct syntax. --- client/mysqltest.c | 585 +++++++++++++++++++------ mysql-test/include/mysqltest_while.inc | 137 ++++++ mysql-test/mysql-test-run.pl | 5 + mysql-test/mysql-test-run.sh | 1 + mysql-test/r/mysqltest.result | 121 +++++ mysql-test/r/rpl_flush_log_loop.result | 2 +- mysql-test/t/innodb-deadlock.test | 6 +- mysql-test/t/innodb-lock.test | 2 +- mysql-test/t/mysqltest.test | 386 +++++++++++++++- mysql-test/t/ndb_autodiscover2.test | 2 +- mysql-test/t/rpl_change_master.test | 2 +- mysql-test/t/rpl_deadlock.test | 6 +- mysql-test/t/rpl_drop_temp.test | 2 +- mysql-test/t/rpl_flush_log_loop.test | 4 +- mysql-test/t/rpl_insert_id.test | 2 +- mysql-test/t/rpl_rotate_logs.test | 2 +- mysql-test/t/rpl_until.test | 2 +- 17 files changed, 1124 insertions(+), 143 deletions(-) create mode 100644 mysql-test/include/mysqltest_while.inc diff --git a/client/mysqltest.c b/client/mysqltest.c index b7f4ceb9c20..2455c4adfd3 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -42,7 +42,7 @@ **********************************************************************/ -#define MTEST_VERSION "2.4" +#define MTEST_VERSION "2.5" #include #include @@ -75,7 +75,7 @@ #define LAZY_GUESS_BUF_SIZE 8192 #define INIT_Q_LINES 1024 #define MIN_VAR_ALLOC 32 -#define BLOCK_STACK_DEPTH 32 +#define BLOCK_STACK_DEPTH 16 #define MAX_EXPECTED_ERRORS 10 #define QUERY_SEND 1 #define QUERY_REAP 2 @@ -151,6 +151,8 @@ 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 char* file_name_stack[MAX_INCLUDE_DEPTH]; +static int cur_file_name; static FILE* file_stack[MAX_INCLUDE_DEPTH]; static FILE** cur_file; static FILE** file_stack_end; @@ -307,7 +309,7 @@ const char *command_names[]= "connect", /* the difference between sleep and real_sleep is that sleep will use the delay from command line (--sleep) if there is one. - real_sleep always uses delay from it's argument. + real_sleep always uses delay from mysqltest's command line argument. the logic is that sometimes delays are cpu-dependent (and --sleep can be used to set this delay. real_sleep is used for cpu-independent delays @@ -514,6 +516,9 @@ static void close_files() { if (*cur_file != stdin && *cur_file) my_fclose(*cur_file,MYF(0)); + char* p= file_name_stack[cur_file_name--]= 0; + if (p) + free(p); } DBUG_VOID_RETURN; } @@ -564,6 +569,10 @@ static void die(const char* fmt, ...) if (fmt) { fprintf(stderr, "%s: ", my_progname); + if (*cur_file && cur_file > (file_stack + 1) ) + fprintf(stderr, "In included file \"%s\": ", + file_name_stack[cur_file_name]); + fprintf(stderr, "At line %u: ", start_lineno); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); fflush(stderr); @@ -809,11 +818,38 @@ int open_file(const char* name) if (*cur_file && cur_file == file_stack_end) die("Source directives are nesting too deep"); - if (!(*(cur_file+1) = my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(MY_WME)))) - die(NullS); - cur_file++; + if (!(*++cur_file = my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0)))) + die("Could not open file %s", buff); *++lineno=1; + file_name_stack[++cur_file_name]= strdup(buff); + return 0; +} + +/* + Check for unexpected "junk" after the end of query + This is normally caused by missing delimiters +*/ + +int check_eol_junk(const char *eol) +{ + char *p= (char*)eol; + /* Remove all spacing chars except new line */ + while (*p && my_isspace(charset_info,*p) && (*p != '\n')) + p++; + + /* Check for extra delimiter */ + size_t l= strlen(delimiter); + if (*p && strlen(p) >= l && !strncmp(p, delimiter, l) ) + die("Extra delimiter \"%s\" found", delimiter); + + /* Allow trailing # comment */ + if (*p && *p != '#') + { + if (*p == '\n') + die("Missing delimiter"); + die("End of line junk detected: \"%s\"", p); + } return 0; } @@ -844,24 +880,26 @@ int do_wait_for_slave_to_stop(struct st_query* q __attribute__((unused))) break; my_sleep(SLAVE_POLL_INTERVAL); } - return 0; + return check_eol_junk(q->first_argument); } -int do_require_manager(struct st_query* a __attribute__((unused))) +int do_require_manager(struct st_query* q) { if (!manager) abort_not_supported_test(); - return 0; + return check_eol_junk(q->first_argument); } #ifndef EMBEDDED_LIBRARY int do_server_start(struct st_query* q) { + check_eol_junk(q->first_argument); return do_server_op(q,"start"); } int do_server_stop(struct st_query* q) { + check_eol_junk(q->first_argument); return do_server_op(q,"stop"); } @@ -876,7 +914,7 @@ int do_server_op(struct st_query* q,const char* op) com_p=strmov(com_buf,op); com_p=strmov(com_p,"_exec "); if (!*p) - die("Missing server name in server_%s\n",op); + die("Missing server name in server_%s",op); while (*p && !my_isspace(charset_info,*p)) *com_p++= *p++; *com_p++=' '; @@ -892,23 +930,42 @@ int do_server_op(struct st_query* q,const char* op) manager->last_errno); } - return 0; + return check_eol_junk(p); } #endif + +/* + Source and execute the given file + + SYNOPSIS + do_source() + q called command + + DESCRIPTION + source + + Open the file and execute it + +*/ + int do_source(struct st_query* q) { char* p=q->first_argument, *name; if (!*p) - die("Missing file name in source\n"); + die("Missing file name in source"); name = p; while (*p && !my_isspace(charset_info,*p)) p++; - *p = 0; - + if (*p) + { + *p++= 0; + check_eol_junk(p); + } return open_file(name); } + /* Execute given command. @@ -917,18 +974,19 @@ int do_source(struct st_query* q) q called command DESCRIPTION - If one uses --exec command [args] command in .test file - we will execute the command and record its output. + exec + + Execute the text between exec and end of line in a subprocess. + The error code returned from the subprocess is checked against the + expected error array, previously set with the --error command. + It can thus be used to execute a command that shall fail. - RETURN VALUES - 0 ok - 1 error */ static void do_exec(struct st_query* q) { int error; - DYNAMIC_STRING *ds= NULL; /* Assign just to avoid warning */ + DYNAMIC_STRING *ds= NULL; DYNAMIC_STRING ds_tmp; char buf[1024]; FILE *res_file; @@ -938,12 +996,12 @@ static void do_exec(struct st_query* q) while (*cmd && my_isspace(charset_info, *cmd)) cmd++; if (!*cmd) - die("Missing argument in exec\n"); + die("Missing argument in exec"); DBUG_PRINT("info", ("Executing '%s'", cmd)); if (!(res_file= popen(cmd, "r")) && q->abort_on_error) - die("popen() failed\n"); + die("popen(\"%s\", \"r\") failed", cmd); if (disable_result_log) { @@ -969,34 +1027,36 @@ static void do_exec(struct st_query* q) error= pclose(res_file); if (error != 0) { - uint status= WEXITSTATUS(error), i; + uint i, status= WEXITSTATUS(error); my_bool ok= 0; if (q->abort_on_error) - die("At line %u: command \"%s\" failed", start_lineno, cmd); + die("command \"%s\" failed", cmd); DBUG_PRINT("info", ("error: %d, status: %d", error, status)); - for (i=0 ; (uint) i < q->expected_errors ; i++) + for (i=0 ; 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); + verbose_msg("command \"%s\" failed with expected error: %d", + cmd, status); + } } if (!ok) - die("At line: %u: command \"%s\" failed with wrong error: %d", - start_lineno, cmd, status); + die("command \"%s\" failed with wrong error: %d", + 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); + die("command \"%s\" succeeded - should have failed with errno %d...", + cmd, q->expected_errno[0].code.errnum); } if (!disable_result_log) @@ -1007,7 +1067,7 @@ static void do_exec(struct st_query* q) if (record) { if (!q->record_file[0] && !result_file) - die("At line %u: Missing result file", start_lineno); + die("Missing result file"); if (!result_file) str_to_file(q->record_file, ds->str, ds->length); } @@ -1125,26 +1185,67 @@ int eval_expr(VAR* v, const char* p, const char** p_end) return 1; } + +/* + Increase the value of a variable + + SYNOPSIS + do_inc() + q called command + + DESCRIPTION + inc $var_name + +*/ + int do_inc(struct st_query* q) { char* p=q->first_argument; VAR* v; + if (!*p) + die("Missing arguments to inc"); + if (*p != '$') + die("First argument to inc must be a variable (start with $)"); v = var_get(p, 0, 1, 0); v->int_val++; v->int_dirty = 1; + while (*p && !my_isspace(charset_info,*p)) + p++; + check_eol_junk(p); return 0; } + +/* + Decrease the value of a variable + + SYNOPSIS + do_dec() + q called command + + DESCRIPTION + dec $var_name + +*/ + int do_dec(struct st_query* q) { char* p=q->first_argument; VAR* v; + if (!*p) + die("Missing arguments to dec"); + if (*p != '$') + die("First argument to dec must be a variable (start with $)"); v = var_get(p, 0, 1, 0); v->int_val--; v->int_dirty = 1; + while (*p && !my_isspace(charset_info,*p)) + p++; + check_eol_junk(p); return 0; } + int do_system(struct st_query* q) { char* p=q->first_argument; @@ -1159,26 +1260,63 @@ int do_system(struct st_query* q) memcpy(expr_buf, v.str_val, v.str_val_len); expr_buf[v.str_val_len] = 0; DBUG_PRINT("info", ("running system command '%s'", expr_buf)); - if (system(expr_buf) && q->abort_on_error) - die("system command '%s' failed", expr_buf); + if (system(expr_buf)) + { + if (q->abort_on_error) + die("system command '%s' failed", expr_buf); + /* If ! abort_on_error, display message and continue */ + verbose_msg("system command '%s' failed", expr_buf); + } } + else + die("Missing arguments to system, nothing to do!"); var_free(&v); return 0; } + +/* + Print the content between echo and to result file. + If content is a variable, the variable value will be retrieved + + SYNOPSIS + do_echo() + q called command + + DESCRIPTION + Usage 1: + echo text + Print the text after echo until end of command to result file + + Usage 2: + echo $ + Print the content of the variable to result file + +*/ + int do_echo(struct st_query* q) { char* p=q->first_argument; + DYNAMIC_STRING *ds= NULL; + DYNAMIC_STRING ds_tmp; VAR v; var_init(&v,0,0,0,0); + + if (q->record_file[0]) + { + init_dynamic_string(&ds_tmp, "", 256, 512); + ds = &ds_tmp; + } + else + ds= &ds_res; + eval_expr(&v, p, 0); /* NULL terminated */ if (v.str_val_len) - { - fflush(stdout); - write(1, v.str_val, v.str_val_len); - } - write(1, "\n", 1); + dynstr_append_mem(ds, v.str_val, v.str_val_len); + dynstr_append_mem(ds, "\n", 1); var_free(&v); + if (ds == &ds_tmp) + dynstr_free(&ds_tmp); return 0; } @@ -1199,8 +1337,19 @@ int do_sync_with_master2(const char* p) rpl_parse = mysql_rpl_parse_enabled(mysql); mysql_disable_rpl_parse(mysql); - if (*p) - offset = atoi(p); + const char* offset_str= p; + /* Step until end of integer arg and check it */ + while (*p && !my_isspace(charset_info, *p)) + { + if (!my_isdigit(charset_info, *p)) + die("Invalid integer argument \"%s\"", offset_str); + p++; + } + check_eol_junk(p); + + if (*offset_str) + offset = atoi(offset_str); + sprintf(query_buf, "select master_pos_wait('%s', %ld)", master_pos.file, master_pos.pos + offset); @@ -1256,7 +1405,7 @@ int do_save_master_pos() mysql_disable_rpl_parse(mysql); if (mysql_query(mysql, query= "show master status")) - die("At line %u: failed in show master status: %d: %s", start_lineno, + die("failed in show master status: %d: %s", mysql_errno(mysql), mysql_error(mysql)); if (!(last_result =res = mysql_store_result(mysql))) @@ -1275,20 +1424,52 @@ int do_save_master_pos() } +/* + Assign the variable with + + SYNOPSIS + do_let() + q called command + + DESCRIPTION + let $= + + - is the string string found between the $ and = + - is the content between the = and , it may span + multiple line and contain any characters except + - is a string containing of one or more chars, default is ; + + RETURN VALUES + Program will die if error detected +*/ + int do_let(struct st_query* q) { char* p=q->first_argument; char *var_name, *var_name_end, *var_val_start; + + /* Find */ if (!*p) - die("Missing variable name in let\n"); + die("Missing arguments to let"); var_name = p; - while (*p && (*p != '=' || my_isspace(charset_info,*p))) + while (*p && *p != '=' && !my_isspace(charset_info,*p)) p++; var_name_end = p; - if (*p == '=') p++; + if (var_name+1==var_name_end) + die("Missing variable name in let"); + while (*p && (*p != '=' || my_isspace(charset_info,*p))) + p++; + if (*p == '=') + p++; + else + die("Missing assignment operator in let"); + + /* Find start of */ while (*p && my_isspace(charset_info,*p)) p++; var_val_start = p; + + /* Assign var_val to var_name */ return var_set(var_name, var_name_end, var_val_start, q->end); } @@ -1308,65 +1489,109 @@ int var_set_errno(int sql_errno) } -int do_rpl_probe(struct st_query* q __attribute__((unused))) +int do_rpl_probe(struct st_query* q) { DBUG_ENTER("do_rpl_probe"); if (mysql_rpl_probe(&cur_con->mysql)) die("Failed in mysql_rpl_probe(): '%s'", mysql_error(&cur_con->mysql)); + check_eol_junk(q->first_argument); DBUG_RETURN(0); } -int do_enable_rpl_parse(struct st_query* q __attribute__((unused))) +int do_enable_rpl_parse(struct st_query* q) { mysql_enable_rpl_parse(&cur_con->mysql); + check_eol_junk(q->first_argument); return 0; } -int do_disable_rpl_parse(struct st_query* q __attribute__((unused))) +int do_disable_rpl_parse(struct st_query* q) { mysql_disable_rpl_parse(&cur_con->mysql); + check_eol_junk(q->first_argument); return 0; } +/* + Sleep the number of specifed seconds + + SYNOPSIS + do_sleep() + q called command + real_sleep use the value from opt_sleep as number of seconds to sleep + + DESCRIPTION + sleep + real_sleep + +*/ + int do_sleep(struct st_query* q, my_bool real_sleep) { char *p=q->first_argument; while (*p && my_isspace(charset_info,*p)) p++; if (!*p) - die("Missing argument in sleep\n"); + die("Missing argument to sleep"); if (opt_sleep && !real_sleep) my_sleep(opt_sleep * 1000000L); else - my_sleep((ulong) (atof(p) * 1000000L)); - return 0; + { + int err= 0; + double val=1; + const char* val_str= p; + while (*p && !my_isspace(charset_info,*p)) + { + if (!my_isdigit(charset_info, *p) && !my_ispunct(charset_info, *p)) + err= 1; + p++; + } + if (!err) + val= my_strtod(val_str, &p, &err); + if (err) + die("Invalid argument to sleep \"%s\"", q->first_argument); + my_sleep((ulong) (val * 1000000L)); + } + return check_eol_junk(p++); } static void get_file_name(char *filename, struct st_query* q) { - char* p=q->first_argument; - strnmov(filename, p, FN_REFLEN); - /* Remove end space */ - while (p > filename && my_isspace(charset_info,p[-1])) - p--; - p[0]=0; + + + char* p=q->first_argument, *name; + if (!*p) + die("Missing file name argument"); + name = p; + while (*p && !my_isspace(charset_info,*p)) + p++; + if (*p) + { + *p++= 0; + check_eol_junk(p); + } + strmake(filename, name, FN_REFLEN); } static void set_charset(struct st_query* q) { char* charset_name= q->first_argument; - char* tmp; + char* p; if (!charset_name || !*charset_name) - die("Missing charset name in 'character_set'\n"); + die("Missing charset name in 'character_set'"); /* Remove end space */ - tmp= charset_name; - while (*tmp && !my_isspace(charset_info,*tmp)) - tmp++; - *tmp= 0; + p= charset_name; + while (*p && !my_isspace(charset_info,*p)) + p++; + if(*p) + { + *p++= 0; + check_eol_junk(p); + } charset_info= get_charset_by_csname(charset_name,MY_CS_PRIMARY,MYF(MY_WME)); if (!charset_info) @@ -1380,7 +1605,7 @@ static uint get_errcodes(match_err *to,struct st_query* q) DBUG_ENTER("get_errcodes"); if (!*p) - die("Missing argument in %s\n", q->query); + die("Missing argument in %s", q->query); do { @@ -1399,7 +1624,7 @@ static uint get_errcodes(match_err *to,struct st_query* q) long val; p=str2int(p,10,(long) INT_MIN, (long) INT_MAX, &val); if (p == NULL) - die("Invalid argument in %s\n", q->query); + die("Invalid argument in %s", q->query); to[count].code.errnum= (uint) val; to[count].type= ERR_ERRNO; } @@ -1467,7 +1692,7 @@ static char *get_string(char **to_ptr, char **from_ptr, *to++=c; } if (*from != ' ' && *from) - die("Wrong string argument in %s\n", q->query); + die("Wrong string argument in %s", q->query); while (my_isspace(charset_info,*from)) /* Point to next string */ from++; @@ -1513,14 +1738,14 @@ static void get_replace(struct st_query *q) bzero((char*) &to_array,sizeof(to_array)); bzero((char*) &from_array,sizeof(from_array)); if (!*from) - die("Missing argument in %s\n", q->query); + die("Missing argument in %s", q->query); start=buff=my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE)); while (*from) { char *to=buff; to=get_string(&buff, &from, q); if (!*from) - die("Wrong number of arguments to replace in %s\n", q->query); + die("Wrong number of arguments to replace in %s", q->query); insert_pointer_name(&from_array,to); to=get_string(&buff, &from, q); insert_pointer_name(&to_array,to); @@ -1534,7 +1759,7 @@ static void get_replace(struct st_query *q) (uint) from_array.typelib.count, word_end_chars)) || initialize_replace_buffer()) - die("Can't initialize replace from %s\n", q->query); + die("Can't initialize replace from %s", q->query); free_pointer_array(&from_array); free_pointer_array(&to_array); my_free(start, MYF(0)); @@ -1561,11 +1786,16 @@ int select_connection(char *p) DBUG_PRINT("enter",("name: '%s'",p)); if (!*p) - die("Missing connection name in connect\n"); + die("Missing connection name in connect"); name = p; while (*p && !my_isspace(charset_info,*p)) p++; - *p = 0; + + if (*p) + { + *p++= 0; + check_eol_junk(p); + } for (con = cons; con < next_con; con++) { @@ -1587,11 +1817,16 @@ int close_connection(struct st_query* q) DBUG_PRINT("enter",("name: '%s'",p)); if (!*p) - die("Missing connection name in connect\n"); + die("Missing connection name in connect"); name = p; while (*p && !my_isspace(charset_info,*p)) p++; - *p = 0; + + if (*p) + { + *p++= 0; + check_eol_junk(p); + } for (con = cons; con < next_con; con++) { @@ -1723,6 +1958,7 @@ int do_connect(struct st_query* q) con_sock[var_sock->str_val_len] = 0; } } + check_eol_junk(p); if (next_con == cons_end) die("Connection limit exhausted - increase MAX_CONS in mysqltest.c"); @@ -1783,7 +2019,8 @@ int do_done(struct st_query* q) cur_block--; parser.current_line++; } - return 0; + return check_eol_junk(q->first_argument); +; } @@ -1817,6 +2054,15 @@ int do_block(enum enum_commands cmd, struct st_query* q) expr_end = strrchr(expr_start, ')'); if (!expr_end) die("missing ')' in while"); + p= (char*)expr_end+1; + + while (*p && my_isspace(charset_info, *p)) + p++; + if (*p=='{') + die("Missing newline between while and '{'"); + if (*p) + die("Missing '{' after while. Found \"%s\"", p); + var_init(&v,0,0,0,0); eval_expr(&v, ++expr_start, &expr_end); @@ -1877,6 +2123,30 @@ my_bool end_of_query(int c) } +/* + Read one "line" from the file + + SYNOPSIS + read_line + buf buffer for the read line + size size of the buffer i.e max size to read + + DESCRIPTION + This function actually reads several lines an adds them to the + buffer buf. It will continue to read until it finds what it believes + is a complete query. + + Normally that means it will read lines until it reaches the + "delimiter" that marks end of query. Default delimiter is ';' + The function should be smart enough not to detect delimiter's + found inside strings sorrounded with '"' and '\'' escaped strings. + + If the first line in a query starts with '#' or '-' this line is treated + as a comment. A comment is always terminated when end of line '\n' is + reached. + +*/ + int read_line(char* buf, int size) { int c; @@ -1898,9 +2168,23 @@ int read_line(char* buf, int size) if ((*cur_file) != stdin) my_fclose(*cur_file, MYF(0)); cur_file--; + char* p= file_name_stack[cur_file_name--]= 0; + if (p) + free(p); lineno--; + start_lineno= *lineno; if (cur_file == file_stack) + { + /* We're back at the first file, check if + all { have matching } + */ + if (cur_block != block_stack) + { + start_lineno= *(lineno+1); + die("Missing end of block"); + } DBUG_RETURN(1); + } continue; } @@ -1933,7 +2217,8 @@ int read_line(char* buf, int size) } break; case R_LINE_START: - if (c == '#' || c == '-') + /* Only accept start of comment if this is the first line in query */ + if ((*lineno == start_lineno) && (c == '#' || c == '-')) { state = R_COMMENT; } @@ -2044,6 +2329,26 @@ int read_line(char* buf, int size) DBUG_RETURN(feof(*cur_file)); } +/* + Create a query from a set of lines + + SYNOPSIS + q_ptr pointer where to return the new query + + DESCRIPTION + Converts lines returned by read_line into a query, this involves + parsing the first word in the read line to find the query type. + + If the line starts with !$ or !S the query is setup + to expect that result when query is executed. + + A -- comment may contain a valid query as the first word after the + comment start. Thus it's always checked to see if that is the case. + The advantage with this approach is to be able to execute commands + terminated by new line '\n' regardless how many "delimiter" it contain. + + If query starts with @ this will specify a file to .... +*/ static char read_query_buf[MAX_QUERY]; @@ -2409,7 +2714,7 @@ static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, { len=(int) replace_strings(glob_replace, &out_buff, &out_length, val); if (len == -1) - die("Out of memory in replace\n"); + die("Out of memory in replace"); val=out_buff; } dynstr_append_mem(ds, val, len); @@ -2541,8 +2846,8 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) { got_error_on_send= mysql_send_query(mysql, query, query_len); if (got_error_on_send && q->expected_errno[0].type == ERR_EMPTY) - die("At line %u: unable to send query '%s' (mysql_errno=%d , errno=%d)", - start_lineno, query, mysql_errno(mysql), errno); + die("unable to send query '%s' (mysql_errno=%d , errno=%d)", + query, mysql_errno(mysql), errno); } do @@ -2566,7 +2871,7 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) abort_not_supported_test(); } if (q->abort_on_error) - die("At line %u: query '%s' failed: %d: %s", start_lineno, query, + die("query '%s' failed: %d: %s", query, mysql_errno(mysql), mysql_error(mysql)); else { @@ -2653,7 +2958,7 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) if (!disable_result_log) { - ulong affected_rows; /* Ok to be undef if 'disable_info' is set */ + ulong affected_rows= 0; if (res) { @@ -2720,7 +3025,7 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) if (record) { if (!q->record_file[0] && !result_file) - die("At line %u: Missing result file", start_lineno); + die("Missing result file"); if (!result_file) str_to_file(q->record_file, ds->str, ds->length); } @@ -2782,7 +3087,7 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) may be a new connection. */ if (!(stmt= mysql_stmt_init(mysql))) - die("At line %u: unable init stmt structure"); + die("unable init stmt structure"); if (q->type != Q_EVAL) { @@ -2826,9 +3131,9 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) { if (q->abort_on_error) { - die("At line %u: unable to prepare statement '%s': " + die("unable to prepare statement '%s': " "%s (mysql_stmt_errno=%d returned=%d)", - start_lineno, query, + query, mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); } else @@ -2860,9 +3165,9 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) if (q->abort_on_error) { /* We got an error, unexpected */ - die("At line %u: unable to execute statement '%s': " + die("unable to execute statement '%s': " "%s (mysql_stmt_errno=%d returned=%d)", - start_lineno, query, mysql_stmt_error(stmt), + query, mysql_stmt_error(stmt), mysql_stmt_errno(stmt), got_error_on_execute); } else @@ -2882,9 +3187,9 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) my_bool one= 1; if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one) != 0) - die("At line %u: unable to set stmt attribute " + die("unable to set stmt attribute " "'STMT_ATTR_UPDATE_MAX_LENGTH': %s (returned=%d)", - start_lineno, query, err); + query, err); } /* @@ -2896,9 +3201,9 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) if (q->abort_on_error) { /* We got an error, unexpected */ - die("At line %u: unable to execute statement '%s': " + die("unable to execute statement '%s': " "%s (mysql_stmt_errno=%d returned=%d)", - start_lineno, query, mysql_stmt_error(stmt), + query, mysql_stmt_error(stmt), mysql_stmt_errno(stmt), got_error_on_execute); } else @@ -2989,18 +3294,18 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) /* Fill in the data into the structures created above */ if ((err= mysql_stmt_bind_result(stmt, bind)) != 0) - die("At line %u: unable to bind result to statement '%s': " + die("unable to bind result to statement '%s': " "%s (mysql_stmt_errno=%d returned=%d)", - start_lineno, query, + query, mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); /* Read result from each row */ for (row_idx= 0; row_idx < num_rows; row_idx++) { if ((err= mysql_stmt_fetch(stmt)) != 0) - die("At line %u: unable to fetch all rows from statement '%s': " + die("unable to fetch all rows from statement '%s': " "%s (mysql_stmt_errno=%d returned=%d)", - start_lineno, query, + query, mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); /* Read result from each column */ @@ -3038,9 +3343,9 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) } if ((err= mysql_stmt_fetch(stmt)) != MYSQL_NO_DATA) - die("At line %u: fetch didn't end with MYSQL_NO_DATA from statement " + die("fetch didn't end with MYSQL_NO_DATA from statement " "'%s': %s (mysql_stmt_errno=%d returned=%d)", - start_lineno, query, + query, mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); free_replace_column(); @@ -3077,7 +3382,7 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) if (record) { if (!q->record_file[0] && !result_file) - die("At line %u: Missing result file", start_lineno); + die("Missing result file"); if (!result_file) str_to_file(q->record_file, ds->str, ds->length); } @@ -3198,7 +3503,7 @@ static int run_query_stmt_handle_error(char *query, struct st_query *q, } if (q->abort_on_error) - die("At line %u: query '%s' failed: %d: %s", start_lineno, query, + die("query '%s' failed: %d: %s", query, mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); else { @@ -3438,7 +3743,7 @@ int main(int argc, char **argv) struct st_query *q; my_bool require_file=0, q_send_flag=0; char save_file[FN_REFLEN]; - MY_INIT(argv[0]); + MY_INIT("mysqltest"); { DBUG_ENTER("main"); DBUG_PROCESS(argv[0]); @@ -3454,15 +3759,16 @@ int main(int argc, char **argv) cur_con = cons; memset(file_stack, 0, sizeof(file_stack)); + memset(file_name_stack, 0, sizeof(file_name_stack)); memset(&master_pos, 0, sizeof(master_pos)); - file_stack_end = file_stack + MAX_INCLUDE_DEPTH; + file_stack_end = file_stack + MAX_INCLUDE_DEPTH - 1; cur_file = file_stack; 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; + block_stack_end= block_stack + BLOCK_STACK_DEPTH - 1; cur_block= block_stack; cur_block->ok= TRUE; /* Outer block should always be executed */ cur_block->cmd= Q_UNKNOWN; @@ -3474,7 +3780,10 @@ int main(int argc, char **argv) (char**) embedded_server_groups)) die("Can't initialize MySQL server"); if (cur_file == file_stack) - *++cur_file = stdin; + { + *++cur_file= stdin; + ++cur_file_name; + } *lineno=1; #ifndef EMBEDDED_LIBRARY if (manager_host) @@ -3530,18 +3839,30 @@ int main(int argc, char **argv) case Q_RPL_PROBE: do_rpl_probe(q); break; case Q_ENABLE_RPL_PARSE: do_enable_rpl_parse(q); break; case Q_DISABLE_RPL_PARSE: do_disable_rpl_parse(q); break; - case Q_ENABLE_QUERY_LOG: disable_query_log=0; break; - case Q_DISABLE_QUERY_LOG: disable_query_log=1; break; - case Q_ENABLE_ABORT_ON_ERROR: abort_on_error=1; break; - case Q_DISABLE_ABORT_ON_ERROR: abort_on_error=0; break; - case Q_ENABLE_RESULT_LOG: disable_result_log=0; break; - case Q_DISABLE_RESULT_LOG: disable_result_log=1; break; - case Q_ENABLE_WARNINGS: disable_warnings=0; break; - 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_ENABLE_QUERY_LOG: + disable_query_log=0; check_eol_junk(q->first_argument); break; + case Q_DISABLE_QUERY_LOG: + disable_query_log=1; check_eol_junk(q->first_argument); break; + case Q_ENABLE_ABORT_ON_ERROR: + abort_on_error=1; check_eol_junk(q->first_argument); break; + case Q_DISABLE_ABORT_ON_ERROR: + abort_on_error=0; check_eol_junk(q->first_argument); break; + case Q_ENABLE_RESULT_LOG: + disable_result_log=0; check_eol_junk(q->first_argument); break; + case Q_DISABLE_RESULT_LOG: + disable_result_log=1; check_eol_junk(q->first_argument); break; + case Q_ENABLE_WARNINGS: + disable_warnings=0; check_eol_junk(q->first_argument); break; + case Q_DISABLE_WARNINGS: + disable_warnings=1; check_eol_junk(q->first_argument); break; + case Q_ENABLE_INFO: + disable_info=0; check_eol_junk(q->first_argument); break; + case Q_DISABLE_INFO: + disable_info=1; check_eol_junk(q->first_argument); break; + case Q_ENABLE_METADATA: + display_metadata=1; check_eol_junk(q->first_argument); break; + case Q_DISABLE_METADATA: + display_metadata=0; check_eol_junk(q->first_argument); 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; @@ -3558,12 +3879,19 @@ int main(int argc, char **argv) case Q_DELIMITER: strmake(delimiter, q->first_argument, sizeof(delimiter) - 1); delimiter_length= strlen(delimiter); + check_eol_junk(q->first_argument+delimiter_length); break; - case Q_DISPLAY_VERTICAL_RESULTS: display_result_vertically= TRUE; break; - case Q_DISPLAY_HORIZONTAL_RESULTS: - display_result_vertically= FALSE; break; + case Q_DISPLAY_VERTICAL_RESULTS: + display_result_vertically= TRUE; + check_eol_junk(q->first_argument); + break; + case Q_DISPLAY_HORIZONTAL_RESULTS: + display_result_vertically= FALSE; + check_eol_junk(q->first_argument); + break; case Q_LET: do_let(q); break; - case Q_EVAL_RESULT: eval_result = 1; break; + case Q_EVAL_RESULT: + eval_result = 1; check_eol_junk(q->first_argument); break; case Q_EVAL: if (q->query == q->query_buf) { @@ -3677,33 +4005,40 @@ int main(int argc, char **argv) break; case Q_PING: (void) mysql_ping(&cur_con->mysql); + check_eol_junk(q->first_argument); break; - case Q_EXEC: + case Q_EXEC: do_exec(q); break; case Q_START_TIMER: /* Overwrite possible earlier start of timer */ timer_start= timer_now(); + check_eol_junk(q->first_argument); break; case Q_END_TIMER: /* End timer before ending mysqltest */ timer_output(); got_end_timer= TRUE; + check_eol_junk(q->first_argument); break; - case Q_CHARACTER_SET: + case Q_CHARACTER_SET: set_charset(q); break; case Q_DISABLE_PS_PROTOCOL: ps_protocol_enabled= 0; + check_eol_junk(q->first_argument); break; case Q_ENABLE_PS_PROTOCOL: ps_protocol_enabled= ps_protocol; + check_eol_junk(q->first_argument); break; case Q_DISABLE_RECONNECT: cur_con->mysql.reconnect= 0; + check_eol_junk(q->first_argument); break; case Q_ENABLE_RECONNECT: cur_con->mysql.reconnect= 1; + check_eol_junk(q->first_argument); break; default: processed = 0; break; @@ -3724,7 +4059,7 @@ int main(int argc, char **argv) parser.current_line += current_line_inc; } - if (result_file && ds_res.length) + if (result_file && ds_res.length && !error) { if (!record) error |= check_result(&ds_res, result_file, q->require_file); @@ -4584,7 +4919,7 @@ static void get_replace_column(struct st_query *q) free_replace_column(); if (!*from) - die("Missing argument in %s\n", q->query); + die("Missing argument in %s", q->query); /* Allocate a buffer for results */ start=buff=my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE)); @@ -4595,9 +4930,9 @@ static void get_replace_column(struct st_query *q) to= get_string(&buff, &from, q); if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS) - die("Wrong column number to replace_columns in %s\n", q->query); + die("Wrong column number to replace_columns in %s", q->query); if (!*from) - die("Wrong number of arguments to replace in %s\n", q->query); + die("Wrong number of arguments to replace in %s", q->query); to= get_string(&buff, &from, q); my_free(replace_column[column_number-1], MY_ALLOW_ZERO_PTR); replace_column[column_number-1]= my_strdup(to, MYF(MY_WME | MY_FAE)); @@ -4654,7 +4989,7 @@ static char *subst_env_var(const char *str) if (!(subst= getenv(env_var))) { my_free(result, MYF(0)); - die("MYSQLTEST.NLM: Environment variable %s is not defined\n", + die("MYSQLTEST.NLM: Environment variable %s is not defined", env_var); } diff --git a/mysql-test/include/mysqltest_while.inc b/mysql-test/include/mysqltest_while.inc new file mode 100644 index 00000000000..90b05ee2695 --- /dev/null +++ b/mysql-test/include/mysqltest_while.inc @@ -0,0 +1,137 @@ +let $1 = 10; +while ($1) +{ +while ($1) +{ +while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + echo $1; + dec $1; +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 1a31bbee1d5..f54461aa9b1 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2129,6 +2129,11 @@ sub run_mysqltest ($) { mysqld_arguments($args,'master',0,$tinfo->{'master_opt'},[]); } + # ---------------------------------------------------------------------- + # export MYSQL_TEST variable containing /mysqltest + # ---------------------------------------------------------------------- + $ENV{'MYSQL_TEST'}= "$exe_mysqltest " . join(" ", @$args); + return mtr_run_test($exe,$args,$tinfo->{'path'},"",$path_timefile,""); } diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 537840c1d33..3e7a54fdead 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -714,6 +714,7 @@ if [ x$USE_TIMER = x1 ] ; then fi MYSQL_TEST_BIN=$MYSQL_TEST MYSQL_TEST="$MYSQL_TEST $MYSQL_TEST_ARGS" +export MYSQL_TEST GDB_CLIENT_INIT=$MYSQL_TMP_DIR/gdbinit.client GDB_MASTER_INIT=$MYSQL_TMP_DIR/gdbinit.master GDB_SLAVE_INIT=$MYSQL_TMP_DIR/gdbinit.slave diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index d75dbd5d00c..3b2828c3c6c 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -7,6 +7,7 @@ otto select otto from (select 1 as otto) as t1; otto 1 +mysqltest: At line 1: query 'select friedrich from (select 1 as otto) as t1' failed: 1054: Unknown column 'friedrich' in 'field list' select friedrich from (select 1 as otto) as t1; ERROR 42S22: Unknown column 'friedrich' in 'field list' select otto from (select 1 as otto) as t1; @@ -15,10 +16,12 @@ otto select otto from (select 1 as otto) as t1; otto 1 +mysqltest: At line 1: query 'select otto from (select 1 as otto) as t1' succeeded - should have failed with sqlstate 42S22... select friedrich from (select 1 as otto) as t1; ERROR 42S22: Unknown column 'friedrich' in 'field list' select friedrich from (select 1 as otto) as t1; ERROR 42S22: Unknown column 'friedrich' in 'field list' +mysqltest: At line 1: query 'select friedrich from (select 1 as otto) as t1' failed with wrong sqlstate 42S22 instead of 00000... select otto from (select 1 as otto) as t1; otto 1 @@ -135,6 +138,8 @@ ERROR 42S02: Table 'test.t1' doesn't exist select 1146 as "after_!errno_masked_error" ; after_!errno_masked_error 1146 +mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of 1000... +mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of 1000... garbage ; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'garbage' at line 1 select 1064 as "after_--enable_abort_on_error" ; @@ -142,3 +147,119 @@ after_--enable_abort_on_error 1064 select 3 from t1 ; ERROR 42S02: Table 'test.t1' doesn't exist +mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of 1064... +mysqltest: At line 1: query 'select 3 from t1' failed: 1146: Table 'test.t1' doesn't exist +hello +hello +;;;;;;;; +# MySQL: -- The +mysqltest: At line 1: End of line junk detected: "6" +mysqltest: At line 1: End of line junk detected: "6" +mysqltest: At line 1: Missing delimiter +mysqltest: At line 1: Extra delimiter ";" found +MySQL +"MySQL" +MySQL: The world''s most popular open source database +"MySQL: The world's most popular open source database" +MySQL: The world''s +most popular open +source database +# MySQL: The world''s +# most popular open +# source database +- MySQL: The world''s +- most popular open +- source database +- MySQL: The world''s +-- most popular open +-- source database +# MySQL: The +--world''s +# most popular +-- open +- source database +"MySQL: The world's most popular; open source database" +"MySQL: The world's most popular ; open source database" +"MySQL: The world's most popular ;open source database" +echo message echo message + +mysqltest: At line 1: Empty variable +sh: -c: line 0: syntax error near unexpected token `;' +sh: -c: line 0: `;' +mysqltest: At line 1: command ";" failed +mysqltest: At line 1: Missing argument in exec +MySQL +"MySQL" +MySQL: The +world''s most +popular open +source database +# MySQL: The +# world''s most +# popular open +# source database +-- MySQL: The +-- world''s most +-- popular open +-- source database +# MySQL: The +- world''s most +-- popular open +# source database +'$message' +"$message" +hej +hej +hej +mysqltest: At line 1: Missing arguments to let +mysqltest: At line 1: Missing variable name in let +mysqltest: At line 1: Variable name in hi=hi does not start with '$' +mysqltest: At line 1: Missing assignment operator in let +mysqltest: At line 1: Missing assignment operator in let +mysqltest: At line 1: Missing arguments to let +mysqltest: At line 1: Missing variable name in let +mysqltest: At line 1: Variable name in =hi does not start with '$' +mysqltest: At line 1: Missing assignment operator in let +mysqltest: At line 1: Missing file name in source +mysqltest: At line 1: Could not open file ./non_existingFile +mysqltest: In included file "./var/tmp/recursive.sql": At line 1: Source directives are nesting too deep +mysqltest: In included file "./var/tmp/error.sql": At line 1: query 'garbage ' failed: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'garbage' at line 1 +mysqltest: At line 1: Missing argument to sleep +mysqltest: At line 1: Invalid argument to sleep "abc" +1 +2 +101 +hej +1 +mysqltest: At line 1: Missing arguments to inc +mysqltest: At line 1: First argument to inc must be a variable (start with $) +mysqltest: At line 1: End of line junk detected: "1000" +4 +4 +-1 +-2 +99 +hej +-1 +mysqltest: At line 1: Missing arguments to dec +mysqltest: At line 1: First argument to dec must be a variable (start with $) +mysqltest: At line 1: End of line junk detected: "1000" +mysqltest: At line 1: Missing arguments to system, nothing to do! +mysqltest: At line 1: Missing arguments to system, nothing to do! +sh: NonExistsinfComamdn: command not found +mysqltest: At line 1: system command 'NonExistsinfComamdn' failed +test +test2 +test3 +test4 +1 +mysqltest: In included file "./include/mysqltest_while.inc": At line 32: Nesting too deeply +mysqltest: At line 1: missing '(' in while +mysqltest: At line 1: missing ')' in while +mysqltest: At line 1: Missing '{' after while. Found "dec $i" +mysqltest: At line 1: Stray '}' - end of block before beginning +mysqltest: At line 1: Stray '}' - end of block before beginning +mysqltest: At line 1: query '' failed: 1065: Query was empty +mysqltest: At line 1: Missing '{' after while. Found "echo hej" +mysqltest: At line 3: Missing end of block +mysqltest: At line 1: Missing newline between while and '{' diff --git a/mysql-test/r/rpl_flush_log_loop.result b/mysql-test/r/rpl_flush_log_loop.result index 25177a6bca3..0a2d7e5e72a 100644 --- a/mysql-test/r/rpl_flush_log_loop.result +++ b/mysql-test/r/rpl_flush_log_loop.result @@ -4,10 +4,10 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +stop slave; change master to master_host='127.0.0.1',master_user='root', master_password='',master_port=MASTER_PORT; start slave; -stop slave; change master to master_host='127.0.0.1',master_user='root', master_password='',master_port=SLAVE_PORT; start slave; diff --git a/mysql-test/t/innodb-deadlock.test b/mysql-test/t/innodb-deadlock.test index 7a7f657f35d..a63af1a5132 100644 --- a/mysql-test/t/innodb-deadlock.test +++ b/mysql-test/t/innodb-deadlock.test @@ -25,7 +25,7 @@ set autocommit=0; # The following query should hang because con1 is locking the page --send update t1 set x=2 where id = 0; ---sleep 2; +--sleep 2 connection con1; update t1 set x=1 where id = 0; @@ -63,7 +63,7 @@ set autocommit=0; # The following query should hang because con1 is locking the page --send update t1 set x=2 where id = 0; ---sleep 2; +--sleep 2 connection con1; update t1 set x=1 where id = 0; @@ -97,7 +97,7 @@ update t2 set a=2 where b = 0; select * from t2; --send update t1 set x=2 where id = 0; ---sleep 2; +--sleep 2 connection con1; update t1 set x=1 where id = 0; diff --git a/mysql-test/t/innodb-lock.test b/mysql-test/t/innodb-lock.test index 887a664e262..08f4cf15cc3 100644 --- a/mysql-test/t/innodb-lock.test +++ b/mysql-test/t/innodb-lock.test @@ -39,7 +39,7 @@ set autocommit=0; # The following statement should hang because con1 is locking the page --send lock table t1 write; ---sleep 2; +--sleep 2 connection con1; update t1 set x=1 where id = 0; diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 0802c18ed6c..6e1b24e1232 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -3,6 +3,24 @@ # # Test of mysqltest itself # +# There are three rules that determines what belong to each command +# 1. A normal command is delimited by the which by default is +# set to ';' +# +# ex: | select * +# | from t1; +# | +# Command: "select * from t1" +# +# 2. Special case is a line that starts with "--", this is a comment +# ended when the new line character is reached. But the first word +# in the comment may contain a valid command, which then will be +# executed. This can be useful when sending commands that +# contains +# +# 3. Special case is also a line that starts with '#' which is treated +# as a comment and will be ended by new line character +# # ============================================================================ # ---------------------------------------------------------------------------- @@ -37,7 +55,9 @@ select otto from (select 1 as otto) as t1; # expectation <> response #--error 0 -#select friedrich from (select 1 as otto) as t1; +#select friedrich from (select 1 as otto) as t1 +--error 1 +--exec echo "select friedrich from (select 1 as otto) as t1;" | $MYSQL_TEST 2>&1 # expectation = response --error 1054 @@ -65,6 +85,9 @@ select otto from (select 1 as otto) as t1; #!S42S22 select otto from (select 1 as otto) as t1; #--error S42S22 #select otto from (select 1 as otto) as t1; +--error 1 +--exec echo "error S42S22; select otto from (select 1 as otto) as t1;" | $MYSQL_TEST 2>&1 + # ---------------------------------------------------------------------------- @@ -80,7 +103,8 @@ select friedrich from (select 1 as otto) as t1; #!S00000 select friedrich from (select 1 as otto) as t1; #--error S00000 #select friedrich from (select 1 as otto) as t1; - +--error 1 +--exec echo "error S00000; select friedrich from (select 1 as otto) as t1;" | $MYSQL_TEST 2>&1 # ---------------------------------------------------------------------------- # test cases for $mysql_errno @@ -262,6 +286,8 @@ eval select $mysql_errno as "after_!errno_masked_error" ; # select 3 from t1 ; # --error 1000 # select 3 from t1 ; +--error 1 +--exec echo "disable_abort_on_error; error 1000; select 3 from t1; error 1000; select 3 from t1;" | $MYSQL_TEST 2>&1 # ---------------------------------------------------------------------------- # Switch the abort on error on and check the effect on $mysql_errno @@ -286,3 +312,359 @@ select 3 from t1 ; #select 3 from t1 ; # #select 3 from t1 ; +--error 1 +--exec echo "disable_abort_on_error; enable_abort_on_error; error 1064; select 3 from t1; select 3 from t1;" | $MYSQL_TEST 2>&1 + + +# ---------------------------------------------------------------------------- +# Test comments +# ---------------------------------------------------------------------------- + +# This is a comment +# This is a ; comment +# This is a -- comment +-- This is also a comment +-- # This is also a comment +-- This is also a ; comment + +# ---------------------------------------------------------------------------- +# Test comments with embedded command +# ---------------------------------------------------------------------------- + +--echo hello +-- echo hello +-- echo ;;;;;;;; + +--echo # MySQL: -- The + +# ---------------------------------------------------------------------------- +# Test detect end of line "junk" +# Most likely causes by a missing delimiter +# ---------------------------------------------------------------------------- + +# Too many parameters to function +--error 1 +--exec echo "sleep 5 6;" | $MYSQL_TEST 2>&1 + +# Too many parameters to function +--error 1 +--exec echo "--sleep 5 6" | $MYSQL_TEST 2>&1 + +# +# Missing delimiter +# The comment will be "sucked into" the sleep command since +# delimiter is missing until after "show status" +--error 1 +--exec echo -e "sleep 4\n # A comment\nshow status;" | $MYSQL_TEST 2>&1 + +# +# Extra delimiter +# +--error 1 +--exec echo "--sleep 4;" | $MYSQL_TEST 2>&1 + + +# Allow trailing # comment +--sleep 1 # Wait for insert delayed to be executed. +--sleep 1 # Wait for insert delayed to be executed. + + +# ---------------------------------------------------------------------------- +# Test echo command +# ---------------------------------------------------------------------------- + +echo MySQL; +echo "MySQL"; +echo MySQL: The world''s most popular open source database; +echo "MySQL: The world's most popular open source database"; + +echo MySQL: The world''s + most popular open + source database; + +echo # MySQL: The world''s +# most popular open +# source database; + +echo - MySQL: The world''s +- most popular open +- source database; + +echo - MySQL: The world''s +-- most popular open +-- source database; + +echo # MySQL: The +--world''s +# most popular +-- open +- source database; + +echo "MySQL: The world's most popular; open source database"; +echo "MySQL: The world's most popular ; open source database"; +echo "MySQL: The world's most popular ;open source database"; +echo echo message echo message; + + +echo ; + +# Illegal use of echo + +--error 1 +--exec echo "echo $;" | $MYSQL_TEST 2>&1 + + +# ---------------------------------------------------------------------------- +# Test exec command +# ---------------------------------------------------------------------------- + +# Illegal use of exec +--error 1 +--exec echo "--exec ;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "--exec " | $MYSQL_TEST 2>&1 + +# ---------------------------------------------------------------------------- +# Test let command +# ---------------------------------------------------------------------------- + +let $message=MySQL; +echo $message; + +let $message="MySQL"; +echo $message; + +let $message= MySQL: The + world''s most + popular open + source database; +echo $message; + +let $message= # MySQL: The +# world''s most +# popular open +# source database; +echo $message; + +let $message= -- MySQL: The +-- world''s most +-- popular open +-- source database; +echo $message; + +let $message= # MySQL: The +- world''s most +-- popular open +# source database; +echo $message; + +echo '$message'; +echo "$message"; + +let $1=hej; +echo $1; + +let $1 =hej ; +echo $1; + +let $1 = hej; +echo $1; + + +# Test illegal uses of let + +--error 1 +--exec echo "let ;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "let $=hi;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "let hi=hi;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "let $1 hi;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "let $m hi;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "let $hi;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "let $ hi;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "let =hi;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "let hi;" | $MYSQL_TEST 2>&1 + +# ---------------------------------------------------------------------------- +# Test source command +# ---------------------------------------------------------------------------- + +# Test illegal uses of source + +--error 1 +--exec echo "source ;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "source non_existingFile;" | $MYSQL_TEST 2>&1 + +# Too many source +--exec echo "source var/tmp/recursive.sql;" > var/tmp/recursive.sql +--error 1 +--exec echo "source var/tmp/recursive.sql;" | $MYSQL_TEST 2>&1 + +# Source a file with error +--exec echo "garbage ;" > var/tmp/error.sql +--error 1 +--exec echo "source var/tmp/error.sql;" | $MYSQL_TEST 2>&1 + + +# ---------------------------------------------------------------------------- +# Test sleep command +# ---------------------------------------------------------------------------- + +sleep 0.5; +sleep 1; +real_sleep 1; + +# Missing parameter +--error 1 +--exec echo "sleep ;" | $MYSQL_TEST 2>&1 + +# Illegal parameter +--error 1 +--exec echo "sleep abc;" | $MYSQL_TEST 2>&1 + +# ---------------------------------------------------------------------------- +# Test inc +# ---------------------------------------------------------------------------- +inc $i; +echo $i; +inc $i; +echo $i; +let $i=100; +inc $i; +echo $i; + +let $i=hej; +echo $i; +inc $i; +echo $i; + +--error 1 +--exec echo "inc;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "inc i;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "let \$i=100; inc \$i 1000; echo \$i;" | $MYSQL_TEST 2>&1 + +inc $i; inc $i; inc $i; --echo $i +echo $i; + + +# ---------------------------------------------------------------------------- +# Test dec +# ---------------------------------------------------------------------------- + +dec $d; +echo $d; +dec $d; +echo $d; +let $d=100; +dec $d; +echo $d; + +let $d=hej; +echo $d; +dec $d; +echo $d; + +--error 1 +--exec echo "dec;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "dec i;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "let \$i=100; dec \$i 1000; echo \$i;" | $MYSQL_TEST 2>&1 + + +# ---------------------------------------------------------------------------- +# Test system +# ---------------------------------------------------------------------------- +system ls > /dev/null; +system echo "hej" > /dev/null; +--system ls > /dev/null +--system echo "hej" > /dev/null; + +--error 1 +--exec echo "system;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "system $NONEXISTSINFVAREABLI;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "system NonExistsinfComamdn;" | $MYSQL_TEST 2>&1 + +--disable_abort_on_error +system NonExistsinfComamdn; +--enable_abort_on_error + + +# ---------------------------------------------------------------------------- +# Test delimiter +# ---------------------------------------------------------------------------- + +delimiter stop; +echo teststop +delimiter ;stop +echo test2; +--delimiter stop +echo test3stop +--delimiter ; +echo test4; + +# ---------------------------------------------------------------------------- +# Test while, { and } +# ---------------------------------------------------------------------------- + +let $i=1; +while ($i) +{ + echo $i; + dec $i; +} +# One liner +#let $i=1;while ($i){echo $i;dec $i;} + + + +# Exceed max nesting level +--error 1 +--exec echo "source include/mysqltest_while.inc;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "while \$i;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "while (\$i;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "let \$i=1; while (\$i) dec \$i;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "};" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "end;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "{;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo -e "while (0)\necho hej;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo -e "while (0)\n{echo hej;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo -e "while (0){\n echo hej;" | $MYSQL_TEST 2>&1 + +# ---------------------------------------------------------------------------- +# TODO Test queries, especially their errormessages... so it's easy to debug +# new scripts and diagnose errors +# ---------------------------------------------------------------------------- + + diff --git a/mysql-test/t/ndb_autodiscover2.test b/mysql-test/t/ndb_autodiscover2.test index 76baa31a2a9..29941085df4 100644 --- a/mysql-test/t/ndb_autodiscover2.test +++ b/mysql-test/t/ndb_autodiscover2.test @@ -6,7 +6,7 @@ # The previous step has simply removed the frm file # from disk, but left the table in NDB # ---sleep 3; +--sleep 3 select * from t9 order by a; # handler_discover should be 1 diff --git a/mysql-test/t/rpl_change_master.test b/mysql-test/t/rpl_change_master.test index e6452b5b619..4bc8843aeec 100644 --- a/mysql-test/t/rpl_change_master.test +++ b/mysql-test/t/rpl_change_master.test @@ -8,7 +8,7 @@ insert into t1 values(1+get_lock("a",15)*0); insert into t1 values(2); save_master_pos; connection slave; ---real_sleep 3; # can't sync_with_master as we should be blocked +--real_sleep 3 # can't sync_with_master as we should be blocked stop slave; select * from t1; --replace_result $MASTER_MYPORT MASTER_MYPORT diff --git a/mysql-test/t/rpl_deadlock.test b/mysql-test/t/rpl_deadlock.test index 9ad6362f7e7..41d06d70ccf 100644 --- a/mysql-test/t/rpl_deadlock.test +++ b/mysql-test/t/rpl_deadlock.test @@ -58,7 +58,7 @@ while ($1) enable_query_log; select * from t1 for update; start slave; ---sleep 3; # hope that slave is blocked now +--sleep 3 # hope that slave is blocked now insert into t2 values(22); # provoke deadlock, slave should be victim commit; sync_with_master; @@ -76,7 +76,7 @@ change master to master_log_pos=401; # the BEGIN log event begin; select * from t2 for update; # hold lock start slave; ---sleep 10; # slave should have blocked, and be retrying +--sleep 10 # slave should have blocked, and be retrying commit; sync_with_master; select * from t1; # check that slave succeeded finally @@ -97,7 +97,7 @@ change master to master_log_pos=401; begin; select * from t2 for update; start slave; ---sleep 10; +--sleep 10 commit; sync_with_master; select * from t1; diff --git a/mysql-test/t/rpl_drop_temp.test b/mysql-test/t/rpl_drop_temp.test index 73d691d9d90..513a0e94940 100644 --- a/mysql-test/t/rpl_drop_temp.test +++ b/mysql-test/t/rpl_drop_temp.test @@ -9,5 +9,5 @@ sync_slave_with_master; connection master; disconnect master; connection slave; ---real_sleep 3; # time for DROP to be written +--real_sleep 3 # time for DROP to be written show status like 'Slave_open_temp_tables'; diff --git a/mysql-test/t/rpl_flush_log_loop.test b/mysql-test/t/rpl_flush_log_loop.test index 74920722868..5b52b0f7cef 100644 --- a/mysql-test/t/rpl_flush_log_loop.test +++ b/mysql-test/t/rpl_flush_log_loop.test @@ -1,15 +1,15 @@ # Testing if "flush logs" command bouncing resulting in logs created in a loop # in case of bi-directional replication -source include/master-slave.inc +source include/master-slave.inc; connection slave; +stop slave; --replace_result $MASTER_MYPORT MASTER_PORT eval change master to master_host='127.0.0.1',master_user='root', master_password='',master_port=$MASTER_MYPORT; start slave; connection master; -stop slave; --replace_result $SLAVE_MYPORT SLAVE_PORT eval change master to master_host='127.0.0.1',master_user='root', master_password='',master_port=$SLAVE_MYPORT; diff --git a/mysql-test/t/rpl_insert_id.test b/mysql-test/t/rpl_insert_id.test index a4506e32963..e2aa5c9b890 100644 --- a/mysql-test/t/rpl_insert_id.test +++ b/mysql-test/t/rpl_insert_id.test @@ -4,7 +4,7 @@ # We also check how the foreign_key_check variable is replicated source include/master-slave.inc; -source include/have_innodb.inc +source include/have_innodb.inc; connection master; create table t1(a int auto_increment, key(a)); create table t2(b int auto_increment, c int, key(b)); diff --git a/mysql-test/t/rpl_rotate_logs.test b/mysql-test/t/rpl_rotate_logs.test index da4d5f0bce1..8d75ce5ce16 100644 --- a/mysql-test/t/rpl_rotate_logs.test +++ b/mysql-test/t/rpl_rotate_logs.test @@ -102,7 +102,7 @@ show master logs; purge binary logs to 'master-bin.000002'; show binary logs; # sleeping 10 seconds or more would make the slave believe connection is down ---real_sleep 1; +--real_sleep 1 purge master logs before now(); show binary logs; insert into t2 values (65); diff --git a/mysql-test/t/rpl_until.test b/mysql-test/t/rpl_until.test index 45b343ace14..9e2675646ab 100644 --- a/mysql-test/t/rpl_until.test +++ b/mysql-test/t/rpl_until.test @@ -60,7 +60,7 @@ stop slave; # this should stop immideately start slave until master_log_file='master-bin.000001', master_log_pos=561; # 2 is not enough when running with valgrind -real_sleep 4 +--real_sleep 4 # here the sql slave thread should be stopped --replace_result $MASTER_MYPORT MASTER_MYPORT bin.000005 bin.000004 bin.000006 bin.000004 bin.000007 bin.000004 --replace_column 1 # 9 # 23 # 33 # From 9ed35f83fa66a15dd87834e67d32fa2150efaf7a Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 16 Aug 2005 17:10:52 +0200 Subject: [PATCH 02/41] BUG#10267 mysqltest, wrong number of loops when a script is sourced within a loop --- client/mysqltest.c | 8 ++++- mysql-test/r/mysqltest.result | 55 +++++++++++++++++++++++++++++++++++ mysql-test/t/mysqltest.test | 43 +++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 2455c4adfd3..dff91560b81 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -962,7 +962,13 @@ int do_source(struct st_query* q) *p++= 0; check_eol_junk(p); } + /* If this file has already been sourced, dont source it again. + It's already available in the q_lines cache */ + if (parser.current_line < (parser.read_lines - 1)) + return 0; return open_file(name); + + } @@ -2378,7 +2384,7 @@ int read_query(struct st_query** q_ptr) DBUG_PRINT("warning",("too long query")); DBUG_RETURN(1); } - DBUG_PRINT("info", ("query: %s", read_query_buf)); + DBUG_PRINT("info", ("query: %s", read_query_buf)); if (*p == '#') { q->type = Q_COMMENT; diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 3b2828c3c6c..21c73f2c7bf 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -224,6 +224,61 @@ mysqltest: At line 1: Missing file name in source mysqltest: At line 1: Could not open file ./non_existingFile mysqltest: In included file "./var/tmp/recursive.sql": At line 1: Source directives are nesting too deep mysqltest: In included file "./var/tmp/error.sql": At line 1: query 'garbage ' failed: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'garbage' at line 1 + +2 = outer loop variable after while +here is the sourced script + +2 = outer loop variable before dec + +1 = outer loop variable after dec + +1 = outer loop variable after while +here is the sourced script + +1 = outer loop variable before dec + +0 = outer loop variable after dec + +2 = outer loop variable after while +here is the sourced script + +2 = outer loop variable before dec + +1 = outer loop variable after dec + +1 = outer loop variable after while +here is the sourced script + +1 = outer loop variable before dec + +0 = outer loop variable after dec + +In loop +here is the sourced script + +In loop +here is the sourced script + +In loop +here is the sourced script + +In loop +here is the sourced script + +In loop +here is the sourced script + +In loop +here is the sourced script + +In loop +here is the sourced script + +In loop +here is the sourced script + +In loop +here is the sourced script mysqltest: At line 1: Missing argument to sleep mysqltest: At line 1: Invalid argument to sleep "abc" 1 diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 6e1b24e1232..8099510ecd1 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -524,6 +524,49 @@ echo $1; --exec echo "source var/tmp/error.sql;" | $MYSQL_TEST 2>&1 +# Test execution of source in a while loop +--exec echo "echo here is the sourced script;" > var/tmp/sourced.sql +--disable_query_log +let $outer= 2; # Number of outer loops +while ($outer) +{ + eval SELECT '$outer = outer loop variable after while' AS ""; + + --source var/tmp/sourced.sql + + eval SELECT '$outer = outer loop variable before dec' AS ""; + dec $outer; + eval SELECT '$outer = outer loop variable after dec' AS ""; +} + +let $outer= 2; # Number of outer loops +while ($outer) +{ + eval SELECT '$outer = outer loop variable after while' AS ""; + + echo here is the sourced script; + + eval SELECT '$outer = outer loop variable before dec' AS ""; + dec $outer; + eval SELECT '$outer = outer loop variable after dec' AS ""; +} + + +# Test execution of source in a while loop +--exec echo "--source var/tmp/sourced.sql" > var/tmp/sourced1.sql +--disable_abort_on_error +# Sourcing of a file within while loop, sourced file will +# source other file +let $num= 9; +while ($num) +{ + SELECT 'In loop' AS ""; + --source var/tmp/sourced1.sql + dec $num; +} +--enable_abort_on_error; +--enable_query_log + # ---------------------------------------------------------------------------- # Test sleep command # ---------------------------------------------------------------------------- From c5e51b7c271620ca13bfa18ab724f99bd1a3c841 Mon Sep 17 00:00:00 2001 From: "joerg@mysql.com" <> Date: Tue, 23 Aug 2005 19:16:43 +0200 Subject: [PATCH 03/41] Add the "test-force" target to "Makefile.am". --- Makefile.am | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 96f3561e31c..5900d709dcf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -100,4 +100,10 @@ tags: # Test installation test: - cd mysql-test; perl mysql-test-run.pl && perl mysql-test-run.pl --ps-protocol + cd mysql-test; \ + perl ./mysql-test-run && perl ./mysql-test-run --ps-protocol + +test-force: + cd mysql-test; \ + ./mysql-test-run --force ;\ + ./mysql-test-run --ps-protocol --force From d8a1c90597f4cbebb31a72193ed96a0aa57f2988 Mon Sep 17 00:00:00 2001 From: "joerg@mysql.com" <> Date: Thu, 25 Aug 2005 11:17:54 +0200 Subject: [PATCH 04/41] Correct a typing error: Missing ".pl" suffix is essential. --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 5900d709dcf..a34b3b7099f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -101,7 +101,7 @@ tags: test: cd mysql-test; \ - perl ./mysql-test-run && perl ./mysql-test-run --ps-protocol + perl ./mysql-test-run.pl && perl ./mysql-test-run.pl --ps-protocol test-force: cd mysql-test; \ From 5de225926388c11f21ebcb92db9b7433b9931175 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Mon, 29 Aug 2005 14:04:15 +0200 Subject: [PATCH 05/41] Bug #12527 yassl causes errors in "repair" and "optimize" - Use constant directly to check that enough number of bytes have been written as header of the archive. --- sql/examples/ha_archive.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc index 10712c2e3be..d4e3b961223 100644 --- a/sql/examples/ha_archive.cc +++ b/sql/examples/ha_archive.cc @@ -225,7 +225,7 @@ int ha_archive::write_data_header(gzFile file_to_write) data_buffer[1]= (uchar)ARCHIVE_VERSION; if (gzwrite(file_to_write, &data_buffer, DATA_BUFFER_SIZE) != - sizeof(DATA_BUFFER_SIZE)) + DATA_BUFFER_SIZE) goto error; DBUG_PRINT("ha_archive::write_data_header", ("Check %u", (uint)data_buffer[0])); DBUG_PRINT("ha_archive::write_data_header", ("Version %u", (uint)data_buffer[1])); From 3ff1acb8dbee3096aa67f4fee1fe56b0c52cd04a Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Tue, 30 Aug 2005 17:11:59 +0500 Subject: [PATCH 06/41] Bug#12363 character_set_results is nullable, but value_ptr returns string "NULL" set_var.cc: Create Item_null instead of Item_string for NULL values variables.result, variables.test: adding test case --- mysql-test/r/variables.result | 5 +++++ mysql-test/t/variables.test | 8 ++++++++ sql/set_var.cc | 14 ++++++++++---- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 14260cd04f9..b01a8c1f8bf 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -491,3 +491,8 @@ SHOW VARIABLES LIKE 'table_cache'; Variable_name Value table_cache 1 SET GLOBAL table_cache=DEFAULT; +set character_set_results=NULL; +select ifnull(@@character_set_results,"really null"); +ifnull(@@character_set_results,"really null") +really null +set names latin1; diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 7743b70d0cd..40cade15c9f 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -380,4 +380,12 @@ SET GLOBAL table_cache=-1; SHOW VARIABLES LIKE 'table_cache'; SET GLOBAL table_cache=DEFAULT; +# +# Bugs12363: character_set_results is nullable, +# but value_ptr returns string "NULL" +# +set character_set_results=NULL; +select ifnull(@@character_set_results,"really null"); +set names latin1; + # End of 4.1 tests diff --git a/sql/set_var.cc b/sql/set_var.cc index 99985c3647c..50f5c6b840e 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1598,11 +1598,17 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base) return new Item_int((int32) *(my_bool*) value_ptr(thd, var_type, base),1); case SHOW_CHAR: { - Item_string *tmp; + Item *tmp; pthread_mutex_lock(&LOCK_global_system_variables); char *str= (char*) value_ptr(thd, var_type, base); - tmp= new Item_string(str, strlen(str), - system_charset_info, DERIVATION_SYSCONST); + if (str) + tmp= new Item_string(str, strlen(str), + system_charset_info, DERIVATION_SYSCONST); + else + { + tmp= new Item_null(); + tmp->collation.set(system_charset_info, DERIVATION_SYSCONST); + } pthread_mutex_unlock(&LOCK_global_system_variables); return tmp; } @@ -1892,7 +1898,7 @@ byte *sys_var_character_set::value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) { CHARSET_INFO *cs= ci_ptr(thd,type)[0]; - return cs ? (byte*) cs->csname : (byte*) "NULL"; + return cs ? (byte*) cs->csname : (byte*) NULL; } From 6b4170ab1088de5390aa7c7a9f2888c5f0aaa29c Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Wed, 31 Aug 2005 13:09:18 +0200 Subject: [PATCH 07/41] corrected some erroneous ndb error messages --- ndb/src/ndbapi/ndberror.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ndb/src/ndbapi/ndberror.c b/ndb/src/ndbapi/ndberror.c index 6fdc75fbe7e..69fc47ff70c 100644 --- a/ndb/src/ndbapi/ndberror.c +++ b/ndb/src/ndbapi/ndberror.c @@ -55,9 +55,6 @@ typedef struct ErrorBundle { #define NI ndberror_cl_function_not_implemented #define UE ndberror_cl_unknown_error_code -static const char REDO_BUFFER_MSG[]= -"REDO log buffers overloaded, consult online manual (increase RedoBuffer, and|or decrease TimeBetweenLocalCheckpoints, and|or increase NoOfFragmentLogFiles)"; - static const char* empty_string = ""; /* @@ -164,8 +161,9 @@ ErrorBundle ErrorCodes[] = { { 830, TR, "Out of add fragment operation records" }, { 873, TR, "Out of attrinfo records for scan in tuple manager" }, { 1217, TR, "Out of operation records in local data manager (increase MaxNoOfLocalOperations)" }, - { 1220, TR, REDO_BUFFER_MSG }, + { 1220, TR, "REDO log files overloaded, consult online manual (decrease TimeBetweenLocalCheckpoints, and|or increase NoOfFragmentLogFiles)" }, { 1222, TR, "Out of transaction markers in LQH" }, + { 1224, TR, "Out of Send Buffer space in LQH" }, { 4021, TR, "Out of Send Buffer space in NDB API" }, { 4022, TR, "Out of Send Buffer space in NDB API" }, { 4032, TR, "Out of Send Buffer space in NDB API" }, @@ -194,10 +192,10 @@ ErrorBundle ErrorCodes[] = { /** * OverloadError */ - { 410, OL, REDO_BUFFER_MSG }, + { 410, OL, "REDO log files overloaded, consult online manual (decrease TimeBetweenLocalCheckpoints, and|or increase NoOfFragmentLogFiles)" }, { 677, OL, "Index UNDO buffers overloaded (increase UndoIndexBuffer)" }, { 891, OL, "Data UNDO buffers overloaded (increase UndoDataBuffer)" }, - { 1221, OL, REDO_BUFFER_MSG }, + { 1221, OL, "REDO buffers overloaded, consult online manual (increase RedoBuffer)" }, { 4006, OL, "Connect failure - out of connection objects (increase MaxNoOfConcurrentTransactions)" }, From 9aa5a86a801d6af6ed40e1ce16a8b7b1c83ea3e2 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Wed, 31 Aug 2005 14:17:05 +0300 Subject: [PATCH 08/41] ha_innodb.cc: Fix bug #12852 : do not increment the open handle count to a table if the table does not have an .ibd file and InnoDB decides to return an error from the ::open() function; then the table can be dropped even if the user has tried to open it --- sql/ha_innodb.cc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index e8279982da5..b4e5092ee4a 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1651,6 +1651,8 @@ ha_innobase::open( my_free((char*) upd_buff, MYF(0)); my_errno = ENOENT; + dict_table_decrement_handle_count(ib_table); + DBUG_RETURN(1); } @@ -5439,6 +5441,19 @@ ha_innobase::store_lock( if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) { + if (lock_type == TL_READ && thd->in_lock_tables) { + /* We come here if MySQL is processing LOCK TABLES + ... READ LOCAL. MyISAM under that table lock type + reads the table as it was at the time the lock was + granted (new inserts are allowed, but not seen by the + reader). To get a similar effect on an InnoDB table, + we must use LOCK TABLES ... READ. We convert the lock + type here, so that for InnoDB, READ LOCAL is + equivalent to READ. */ + + lock_type = TL_READ_NO_INSERT; + } + /* If we are not doing a LOCK TABLE or DISCARD/IMPORT TABLESPACE, then allow multiple writers */ From 183feee465e1c159840ff157919649962b2a221e Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Wed, 31 Aug 2005 14:27:44 +0300 Subject: [PATCH 09/41] ha_innodb.cc: Fix bug #12410 : InnoDB was too permissive with LOCK TABLE ... READ LOCAL, and alowed new inserts to the table; we now make READ LOCAL equivalent to READ for InnoDB; note that this will cause slightly more locking in mysqldump, but makes the InnoDB table dumps consistent with MyISAM table dumps; note that the real code change patch was accidentally pushed with my another patch 5 minutes ago --- sql/ha_innodb.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index b4e5092ee4a..b30ddfe8227 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -5449,7 +5449,9 @@ ha_innobase::store_lock( reader). To get a similar effect on an InnoDB table, we must use LOCK TABLES ... READ. We convert the lock type here, so that for InnoDB, READ LOCAL is - equivalent to READ. */ + equivalent to READ. This will change the InnoDB + behavior in mysqldump, so that dumps of InnoDB tables + are consistent with dumps of MyISAM tables. */ lock_type = TL_READ_NO_INSERT; } From 2b11fdba342d88713b2dbc05cf578e2270f404ca Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Wed, 31 Aug 2005 16:15:03 +0200 Subject: [PATCH 10/41] improved error message printing on filesystem refuse signals --- ndb/include/kernel/signaldata/FsRef.hpp | 22 +----- ndb/src/kernel/blocks/backup/BackupInit.cpp | 8 +-- ndb/src/kernel/blocks/dbacc/Dbacc.hpp | 5 -- ndb/src/kernel/blocks/dbacc/DbaccInit.cpp | 5 -- ndb/src/kernel/blocks/dbacc/DbaccMain.cpp | 42 ----------- ndb/src/kernel/blocks/dbdict/Dbdict.cpp | 46 +++++------- ndb/src/kernel/blocks/dbdict/Dbdict.hpp | 2 - ndb/src/kernel/blocks/dbdih/DbdihInit.cpp | 8 +-- ndb/src/kernel/blocks/dbdih/DbdihMain.cpp | 66 +++++++++++------ ndb/src/kernel/blocks/dblqh/Dblqh.hpp | 3 - ndb/src/kernel/blocks/dblqh/DblqhInit.cpp | 7 +- ndb/src/kernel/blocks/dblqh/DblqhMain.cpp | 71 +++---------------- ndb/src/kernel/blocks/dbtup/Dbtup.hpp | 5 -- ndb/src/kernel/blocks/dbtup/DbtupGen.cpp | 30 -------- ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp | 7 -- ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp | 1 - ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp | 1 - ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp | 12 ++-- ndb/src/kernel/vm/SimulatedBlock.cpp | 63 ++++++++++++++++ ndb/src/kernel/vm/SimulatedBlock.hpp | 9 +++ 20 files changed, 158 insertions(+), 255 deletions(-) diff --git a/ndb/include/kernel/signaldata/FsRef.hpp b/ndb/include/kernel/signaldata/FsRef.hpp index 650f6520fb5..2f7038de4ec 100644 --- a/ndb/include/kernel/signaldata/FsRef.hpp +++ b/ndb/include/kernel/signaldata/FsRef.hpp @@ -31,25 +31,7 @@ * SENDER: Ndbfs * RECIVER: */ -class FsRef { - /** - * Reciver(s) - */ - friend class Dbdict; - friend class Backup; - - /** - * Sender(s) - */ - friend class Ndbfs; - friend class VoidFs; - - /** - * For printing - */ - friend bool printFSREF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo); - -public: +struct FsRef { /** * Enum type for errorCode */ @@ -73,8 +55,6 @@ public: */ STATIC_CONST( SignalLength = 4 ); -private: - /** * DATA VARIABLES */ diff --git a/ndb/src/kernel/blocks/backup/BackupInit.cpp b/ndb/src/kernel/blocks/backup/BackupInit.cpp index eae72f43db5..2c36896e34c 100644 --- a/ndb/src/kernel/blocks/backup/BackupInit.cpp +++ b/ndb/src/kernel/blocks/backup/BackupInit.cpp @@ -150,16 +150,16 @@ Backup::Backup(const Configuration & conf) : addRecSignal(GSN_DI_FCOUNTCONF, &Backup::execDI_FCOUNTCONF); addRecSignal(GSN_DIGETPRIMCONF, &Backup::execDIGETPRIMCONF); - addRecSignal(GSN_FSOPENREF, &Backup::execFSOPENREF); + addRecSignal(GSN_FSOPENREF, &Backup::execFSOPENREF, true); addRecSignal(GSN_FSOPENCONF, &Backup::execFSOPENCONF); - addRecSignal(GSN_FSCLOSEREF, &Backup::execFSCLOSEREF); + addRecSignal(GSN_FSCLOSEREF, &Backup::execFSCLOSEREF, true); addRecSignal(GSN_FSCLOSECONF, &Backup::execFSCLOSECONF); - addRecSignal(GSN_FSAPPENDREF, &Backup::execFSAPPENDREF); + addRecSignal(GSN_FSAPPENDREF, &Backup::execFSAPPENDREF, true); addRecSignal(GSN_FSAPPENDCONF, &Backup::execFSAPPENDCONF); - addRecSignal(GSN_FSREMOVEREF, &Backup::execFSREMOVEREF); + addRecSignal(GSN_FSREMOVEREF, &Backup::execFSREMOVEREF, true); addRecSignal(GSN_FSREMOVECONF, &Backup::execFSREMOVECONF); /*****/ diff --git a/ndb/src/kernel/blocks/dbacc/Dbacc.hpp b/ndb/src/kernel/blocks/dbacc/Dbacc.hpp index 246afc5ceb8..ea866aafff9 100644 --- a/ndb/src/kernel/blocks/dbacc/Dbacc.hpp +++ b/ndb/src/kernel/blocks/dbacc/Dbacc.hpp @@ -949,17 +949,12 @@ private: void execACC_TO_REQ(Signal* signal); void execACC_LOCKREQ(Signal* signal); void execFSOPENCONF(Signal* signal); - void execFSOPENREF(Signal* signal); void execFSCLOSECONF(Signal* signal); - void execFSCLOSEREF(Signal* signal); void execFSWRITECONF(Signal* signal); - void execFSWRITEREF(Signal* signal); void execFSREADCONF(Signal* signal); - void execFSREADREF(Signal* signal); void execNDB_STTOR(Signal* signal); void execDROP_TAB_REQ(Signal* signal); void execFSREMOVECONF(Signal* signal); - void execFSREMOVEREF(Signal* signal); void execREAD_CONFIG_REQ(Signal* signal); void execSET_VAR_REQ(Signal* signal); void execDUMP_STATE_ORD(Signal* signal); diff --git a/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp b/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp index 95b336a0a65..c98c072cc89 100644 --- a/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp +++ b/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp @@ -187,17 +187,12 @@ Dbacc::Dbacc(const class Configuration & conf): addRecSignal(GSN_ACC_TO_REQ, &Dbacc::execACC_TO_REQ); addRecSignal(GSN_ACC_LOCKREQ, &Dbacc::execACC_LOCKREQ); addRecSignal(GSN_FSOPENCONF, &Dbacc::execFSOPENCONF); - addRecSignal(GSN_FSOPENREF, &Dbacc::execFSOPENREF); addRecSignal(GSN_FSCLOSECONF, &Dbacc::execFSCLOSECONF); - addRecSignal(GSN_FSCLOSEREF, &Dbacc::execFSCLOSEREF); addRecSignal(GSN_FSWRITECONF, &Dbacc::execFSWRITECONF); - addRecSignal(GSN_FSWRITEREF, &Dbacc::execFSWRITEREF); addRecSignal(GSN_FSREADCONF, &Dbacc::execFSREADCONF); - addRecSignal(GSN_FSREADREF, &Dbacc::execFSREADREF); addRecSignal(GSN_NDB_STTOR, &Dbacc::execNDB_STTOR); addRecSignal(GSN_DROP_TAB_REQ, &Dbacc::execDROP_TAB_REQ); addRecSignal(GSN_FSREMOVECONF, &Dbacc::execFSREMOVECONF); - addRecSignal(GSN_FSREMOVEREF, &Dbacc::execFSREMOVEREF); addRecSignal(GSN_READ_CONFIG_REQ, &Dbacc::execREAD_CONFIG_REQ, true); addRecSignal(GSN_SET_VAR_REQ, &Dbacc::execSET_VAR_REQ); diff --git a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp index 1f0053e209a..a3880e2df1d 100644 --- a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp +++ b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp @@ -248,15 +248,6 @@ void Dbacc::execFSCLOSECONF(Signal* signal) return; }//Dbacc::execFSCLOSECONF() -/* ******************--------------------------------------------------------------- */ -/* FSCLOSEREF OPENFILE CONF */ -/* ******************------------------------------+ */ -/* SENDER: FS, LEVEL B */ -void Dbacc::execFSCLOSEREF(Signal* signal) -{ - jamEntry(); - ndbrequire(false); -}//Dbacc::execFSCLOSEREF() /* ******************--------------------------------------------------------------- */ /* FSOPENCONF OPENFILE CONF */ @@ -304,15 +295,6 @@ void Dbacc::execFSOPENCONF(Signal* signal) return; }//Dbacc::execFSOPENCONF() -/* ******************--------------------------------------------------------------- */ -/* FSOPENREF OPENFILE REF */ -/* ******************------------------------------+ */ -/* SENDER: FS, LEVEL B */ -void Dbacc::execFSOPENREF(Signal* signal) -{ - jamEntry(); - ndbrequire(false); -}//Dbacc::execFSOPENREF() /* ******************--------------------------------------------------------------- */ /* FSREADCONF OPENFILE CONF */ @@ -366,16 +348,6 @@ void Dbacc::execFSREADCONF(Signal* signal) return; }//Dbacc::execFSREADCONF() -/* ******************--------------------------------------------------------------- */ -/* FSREADRREF OPENFILE CONF */ -/* ******************------------------------------+ */ -/* SENDER: FS, LEVEL B */ -void Dbacc::execFSREADREF(Signal* signal) -{ - jamEntry(); - progError(0, __LINE__, "Read of file refused"); - return; -}//Dbacc::execFSREADREF() /* ******************--------------------------------------------------------------- */ /* FSWRITECONF OPENFILE CONF */ @@ -479,16 +451,6 @@ void Dbacc::execFSWRITECONF(Signal* signal) return; }//Dbacc::execFSWRITECONF() -/* ******************--------------------------------------------------------------- */ -/* FSWRITEREF OPENFILE CONF */ -/* ******************------------------------------+ */ -/* SENDER: FS, LEVEL B */ -void Dbacc::execFSWRITEREF(Signal* signal) -{ - jamEntry(); - progError(0, __LINE__, "Write to file refused"); - return; -}//Dbacc::execFSWRITEREF() /* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ @@ -1425,10 +1387,6 @@ void Dbacc::execFSREMOVECONF(Signal* signal) tabPtr.p->tabUserRef = 0; }//Dbacc::execFSREMOVECONF() -void Dbacc::execFSREMOVEREF(Signal* signal) -{ - ndbrequire(false); -}//Dbacc::execFSREMOVEREF() /* -------------------------------------------------------------------------- */ /* ADDFRAGTOTAB */ diff --git a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp index 9eec1d35cdb..3d5eb0c52aa 100644 --- a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp +++ b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp @@ -379,14 +379,6 @@ void Dbdict::execFSCLOSECONF(Signal* signal) }//switch }//execFSCLOSECONF() -/* ---------------------------------------------------------------- */ -// A close file was refused. -/* ---------------------------------------------------------------- */ -void Dbdict::execFSCLOSEREF(Signal* signal) -{ - jamEntry(); - progError(0, 0); -}//execFSCLOSEREF() /* ---------------------------------------------------------------- */ // A file was successfully opened. @@ -449,17 +441,21 @@ void Dbdict::execFSOPENREF(Signal* signal) c_fsConnectRecordPool.getPtr(fsPtr, fsRef->userPointer); switch (fsPtr.p->fsState) { case FsConnectRecord::OPEN_READ_SCHEMA1: + jam(); openReadSchemaRef(signal, fsPtr); - break; + return; case FsConnectRecord::OPEN_READ_TAB_FILE1: jam(); openReadTableRef(signal, fsPtr); - break; + return; default: - jamLine((fsPtr.p->fsState & 0xFFF)); - ndbrequire(false); break; }//switch + { + char msg[100]; + sprintf(msg, "File system open failed during FsConnectRecord state %d", (Uint32)fsPtr.p->fsState); + fsRefError(signal,__LINE__,msg); + } }//execFSOPENREF() /* ---------------------------------------------------------------- */ @@ -499,17 +495,21 @@ void Dbdict::execFSREADREF(Signal* signal) c_fsConnectRecordPool.getPtr(fsPtr, fsRef->userPointer); switch (fsPtr.p->fsState) { case FsConnectRecord::READ_SCHEMA1: + jam(); readSchemaRef(signal, fsPtr); - break; + return; case FsConnectRecord::READ_TAB_FILE1: jam(); readTableRef(signal, fsPtr); - break; + return; default: - jamLine((fsPtr.p->fsState & 0xFFF)); - ndbrequire(false); break; }//switch + { + char msg[100]; + sprintf(msg, "File system read failed during FsConnectRecord state %d", (Uint32)fsPtr.p->fsState); + fsRefError(signal,__LINE__,msg); + } }//execFSREADREF() /* ---------------------------------------------------------------- */ @@ -536,14 +536,6 @@ void Dbdict::execFSWRITECONF(Signal* signal) }//switch }//execFSWRITECONF() -/* ---------------------------------------------------------------- */ -// A write file was refused. -/* ---------------------------------------------------------------- */ -void Dbdict::execFSWRITEREF(Signal* signal) -{ - jamEntry(); - progError(0, 0); -}//execFSWRITEREF() /* ---------------------------------------------------------------- */ // Routines to handle Read/Write of Table Files @@ -1181,13 +1173,11 @@ Dbdict::Dbdict(const class Configuration & conf): addRecSignal(GSN_DICTSTARTREQ, &Dbdict::execDICTSTARTREQ); addRecSignal(GSN_READ_NODESCONF, &Dbdict::execREAD_NODESCONF); addRecSignal(GSN_FSOPENCONF, &Dbdict::execFSOPENCONF); - addRecSignal(GSN_FSOPENREF, &Dbdict::execFSOPENREF); + addRecSignal(GSN_FSOPENREF, &Dbdict::execFSOPENREF, true); addRecSignal(GSN_FSCLOSECONF, &Dbdict::execFSCLOSECONF); - addRecSignal(GSN_FSCLOSEREF, &Dbdict::execFSCLOSEREF); addRecSignal(GSN_FSWRITECONF, &Dbdict::execFSWRITECONF); - addRecSignal(GSN_FSWRITEREF, &Dbdict::execFSWRITEREF); addRecSignal(GSN_FSREADCONF, &Dbdict::execFSREADCONF); - addRecSignal(GSN_FSREADREF, &Dbdict::execFSREADREF); + addRecSignal(GSN_FSREADREF, &Dbdict::execFSREADREF, true); addRecSignal(GSN_LQHFRAGCONF, &Dbdict::execLQHFRAGCONF); addRecSignal(GSN_LQHADDATTCONF, &Dbdict::execLQHADDATTCONF); addRecSignal(GSN_LQHADDATTREF, &Dbdict::execLQHADDATTREF); diff --git a/ndb/src/kernel/blocks/dbdict/Dbdict.hpp b/ndb/src/kernel/blocks/dbdict/Dbdict.hpp index 77a44d0ad24..abe253bcaa7 100644 --- a/ndb/src/kernel/blocks/dbdict/Dbdict.hpp +++ b/ndb/src/kernel/blocks/dbdict/Dbdict.hpp @@ -458,13 +458,11 @@ private: void execSCHEMA_INFOCONF(Signal* signal); void execREAD_NODESCONF(Signal* signal); void execFSCLOSECONF(Signal* signal); - void execFSCLOSEREF(Signal* signal); void execFSOPENCONF(Signal* signal); void execFSOPENREF(Signal* signal); void execFSREADCONF(Signal* signal); void execFSREADREF(Signal* signal); void execFSWRITECONF(Signal* signal); - void execFSWRITEREF(Signal* signal); void execNDB_STTOR(Signal* signal); void execREAD_CONFIG_REQ(Signal* signal); void execSTTOR(Signal* signal); diff --git a/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp b/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp index 9a5efebc56e..1c14163fe76 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp @@ -206,13 +206,13 @@ Dbdih::Dbdih(const class Configuration & config): addRecSignal(GSN_ADD_FRAGCONF, &Dbdih::execADD_FRAGCONF); addRecSignal(GSN_ADD_FRAGREF, &Dbdih::execADD_FRAGREF); addRecSignal(GSN_FSOPENCONF, &Dbdih::execFSOPENCONF); - addRecSignal(GSN_FSOPENREF, &Dbdih::execFSOPENREF); + addRecSignal(GSN_FSOPENREF, &Dbdih::execFSOPENREF, true); addRecSignal(GSN_FSCLOSECONF, &Dbdih::execFSCLOSECONF); - addRecSignal(GSN_FSCLOSEREF, &Dbdih::execFSCLOSEREF); + addRecSignal(GSN_FSCLOSEREF, &Dbdih::execFSCLOSEREF, true); addRecSignal(GSN_FSREADCONF, &Dbdih::execFSREADCONF); - addRecSignal(GSN_FSREADREF, &Dbdih::execFSREADREF); + addRecSignal(GSN_FSREADREF, &Dbdih::execFSREADREF, true); addRecSignal(GSN_FSWRITECONF, &Dbdih::execFSWRITECONF); - addRecSignal(GSN_FSWRITEREF, &Dbdih::execFSWRITEREF); + addRecSignal(GSN_FSWRITEREF, &Dbdih::execFSWRITEREF, true); addRecSignal(GSN_SET_VAR_REQ, &Dbdih::execSET_VAR_REQ); addRecSignal(GSN_START_INFOREQ, diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index 94426c8be3f..669be2b48f0 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -782,29 +782,36 @@ void Dbdih::execFSCLOSEREF(Signal* signal) filePtr.p->reqStatus = FileRecord::IDLE; switch (status) { case FileRecord::CLOSING_GCP: - ndbrequire(false); + jam(); break; case FileRecord::CLOSING_GCP_CRASH: jam(); closingGcpCrashLab(signal, filePtr); - break; + return; case FileRecord::CLOSING_TABLE_CRASH: jam(); closingTableCrashLab(signal, filePtr); - break; + return; case FileRecord::CLOSING_TABLE_SR: - ndbrequire(false); + jam(); break; case FileRecord::TABLE_CLOSE: - ndbrequire(false); + jam(); break; case FileRecord::TABLE_CLOSE_DELETE: - ndbrequire(false); + jam(); break; default: - ndbrequire(false); + jam(); break; + }//switch + { + char msg[100]; + sprintf(msg, "File system close failed during FileRecord status %d", (Uint32)status); + fsRefError(signal,__LINE__,msg); + } + return; }//Dbdih::execFSCLOSEREF() @@ -868,34 +875,39 @@ void Dbdih::execFSOPENREF(Signal* signal) /* WE DID NOT MANAGE TO CREATE A GLOBAL CHECKPOINT FILE. SERIOUS ERROR */ /* WHICH CAUSES A SYSTEM RESTART. */ /* --------------------------------------------------------------------- */ - ndbrequire(false); + jam(); break; case FileRecord::OPENING_COPY_GCI: jam(); openingCopyGciErrorLab(signal, filePtr); - break; + return; case FileRecord::CREATING_COPY_GCI: - ndbrequire(false); + jam(); break; case FileRecord::OPENING_GCP: jam(); openingGcpErrorLab(signal, filePtr); - break; + return; case FileRecord::OPENING_TABLE: jam(); openingTableErrorLab(signal, filePtr); - break; + return; case FileRecord::TABLE_CREATE: - ndbrequire(false); + jam(); break; case FileRecord::TABLE_OPEN_FOR_DELETE: jam(); tableDeleteLab(signal, filePtr); - break; + return; default: - ndbrequire(false); + jam(); break; }//switch + { + char msg[100]; + sprintf(msg, "File system open failed during FileRecord status %d", (Uint32)status); + fsRefError(signal,__LINE__,msg); + } return; }//Dbdih::execFSOPENREF() @@ -935,16 +947,19 @@ void Dbdih::execFSREADREF(Signal* signal) case FileRecord::READING_GCP: jam(); readingGcpErrorLab(signal, filePtr); - break; + return; case FileRecord::READING_TABLE: jam(); readingTableErrorLab(signal, filePtr); - break; + return; default: - ndbrequire(false); break; }//switch - return; + { + char msg[100]; + sprintf(msg, "File system read failed during FileRecord status %d", (Uint32)status); + fsRefError(signal,__LINE__,msg); + } }//Dbdih::execFSREADREF() void Dbdih::execFSWRITECONF(Signal* signal) @@ -989,22 +1004,27 @@ void Dbdih::execFSWRITEREF(Signal* signal) /* EVEN CREATING THE FILE DID NOT WORK. WE WILL THEN CRASH. */ /* ERROR IN WRITING FILE. WE WILL NOT CONTINUE FROM HERE. */ /* --------------------------------------------------------------------- */ - ndbrequire(false); + jam(); break; case FileRecord::WRITE_INIT_GCP: /* --------------------------------------------------------------------- */ /* AN ERROR OCCURRED IN WRITING A GCI FILE WHICH IS A SERIOUS ERROR */ /* THAT CAUSE A SYSTEM RESTART. */ /* --------------------------------------------------------------------- */ - ndbrequire(false); + jam(); break; case FileRecord::TABLE_WRITE: - ndbrequire(false); + jam(); break; default: - ndbrequire(false); + jam(); break; }//switch + { + char msg[100]; + sprintf(msg, "File system write failed during FileRecord status %d", (Uint32)status); + fsRefError(signal,__LINE__,msg); + } return; }//Dbdih::execFSWRITEREF() diff --git a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp index 19e055a3011..836fc9398e5 100644 --- a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp +++ b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp @@ -2175,9 +2175,7 @@ private: void execTUP_SRREF(Signal* signal); void execGCP_SAVEREQ(Signal* signal); void execFSOPENCONF(Signal* signal); - void execFSOPENREF(Signal* signal); void execFSCLOSECONF(Signal* signal); - void execFSCLOSEREF(Signal* signal); void execFSWRITECONF(Signal* signal); void execFSWRITEREF(Signal* signal); void execFSREADCONF(Signal* signal); @@ -2186,7 +2184,6 @@ private: void execSET_VAR_REQ(Signal* signal); void execTIME_SIGNAL(Signal* signal); void execFSSYNCCONF(Signal* signal); - void execFSSYNCREF(Signal* signal); void execALTER_TAB_REQ(Signal* signal); void execALTER_TAB_CONF(Signal* signal); diff --git a/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp b/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp index ec29489180c..f9dd63e782d 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp @@ -311,18 +311,15 @@ Dblqh::Dblqh(const class Configuration & conf): addRecSignal(GSN_TUP_SRREF, &Dblqh::execTUP_SRREF); addRecSignal(GSN_GCP_SAVEREQ, &Dblqh::execGCP_SAVEREQ); addRecSignal(GSN_FSOPENCONF, &Dblqh::execFSOPENCONF); - addRecSignal(GSN_FSOPENREF, &Dblqh::execFSOPENREF); addRecSignal(GSN_FSCLOSECONF, &Dblqh::execFSCLOSECONF); - addRecSignal(GSN_FSCLOSEREF, &Dblqh::execFSCLOSEREF); addRecSignal(GSN_FSWRITECONF, &Dblqh::execFSWRITECONF); - addRecSignal(GSN_FSWRITEREF, &Dblqh::execFSWRITEREF); + addRecSignal(GSN_FSWRITEREF, &Dblqh::execFSWRITEREF, true); addRecSignal(GSN_FSREADCONF, &Dblqh::execFSREADCONF); - addRecSignal(GSN_FSREADREF, &Dblqh::execFSREADREF); + addRecSignal(GSN_FSREADREF, &Dblqh::execFSREADREF, true); addRecSignal(GSN_ACC_ABORTCONF, &Dblqh::execACC_ABORTCONF); addRecSignal(GSN_SET_VAR_REQ, &Dblqh::execSET_VAR_REQ); addRecSignal(GSN_TIME_SIGNAL, &Dblqh::execTIME_SIGNAL); addRecSignal(GSN_FSSYNCCONF, &Dblqh::execFSSYNCCONF); - addRecSignal(GSN_FSSYNCREF, &Dblqh::execFSSYNCREF); addRecSignal(GSN_REMOVE_MARKER_ORD, &Dblqh::execREMOVE_MARKER_ORD); //addRecSignal(GSN_DROP_TAB_REQ, &Dblqh::execDROP_TAB_REQ); diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index 05d76f5fb25..5e2e6dc392c 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -11718,14 +11718,6 @@ Dblqh::execFSSYNCCONF(Signal* signal) ccurrentGcprec = RNIL; }//Dblqh::execFSSYNCCONF() -void -Dblqh::execFSSYNCREF(Signal* signal) -{ - jamEntry(); - systemErrorLab(signal); - return; -}//Dblqh::execFSSYNCREF() - /* ######################################################################### */ /* ####### FILE HANDLING MODULE ####### */ @@ -11796,16 +11788,6 @@ void Dblqh::execFSCLOSECONF(Signal* signal) }//switch }//Dblqh::execFSCLOSECONF() -/* ************>> */ -/* FSCLOSEREF > */ -/* ************>> */ -void Dblqh::execFSCLOSEREF(Signal* signal) -{ - jamEntry(); - terrorCode = signal->theData[1]; - systemErrorLab(signal); - return; -}//Dblqh::execFSCLOSEREF() /* ************>> */ /* FSOPENCONF > */ @@ -11894,16 +11876,6 @@ void Dblqh::execFSOPENCONF(Signal* signal) }//switch }//Dblqh::execFSOPENCONF() -/* ************> */ -/* FSOPENREF > */ -/* ************> */ -void Dblqh::execFSOPENREF(Signal* signal) -{ - jamEntry(); - terrorCode = signal->theData[1]; - systemErrorLab(signal); - return; -}//Dblqh::execFSOPENREF() /* ************>> */ /* FSREADCONF > */ @@ -11981,60 +11953,43 @@ void Dblqh::execFSREADREF(Signal* signal) jamEntry(); lfoPtr.i = signal->theData[0]; ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord); - terrorCode = signal->theData[1]; switch (lfoPtr.p->lfoState) { case LogFileOperationRecord::READ_SR_LAST_MBYTE: jam(); - systemErrorLab(signal); - return; break; case LogFileOperationRecord::READ_SR_FRONTPAGE: jam(); - systemErrorLab(signal); - return; break; case LogFileOperationRecord::READ_SR_LAST_FILE: jam(); - systemErrorLab(signal); - return; break; case LogFileOperationRecord::READ_SR_NEXT_FILE: jam(); - systemErrorLab(signal); - return; break; case LogFileOperationRecord::READ_EXEC_SR: jam(); - systemErrorLab(signal); - return; break; case LogFileOperationRecord::READ_EXEC_LOG: jam(); - systemErrorLab(signal); - return; break; case LogFileOperationRecord::READ_SR_FOURTH_PHASE: jam(); - systemErrorLab(signal); - return; break; case LogFileOperationRecord::READ_SR_FOURTH_ZERO: jam(); - systemErrorLab(signal); - return; break; case LogFileOperationRecord::READ_SR_INVALIDATE_PAGES: jam() - systemErrorLab(signal); - return; break; default: jam(); - systemErrorLab(signal); - return; break; }//switch - return; + { + char msg[100]; + sprintf(msg, "File system read failed during LogFileOperationRecord state %d", (Uint32)lfoPtr.p->lfoState); + fsRefError(signal,__LINE__,msg); + } }//Dblqh::execFSREADREF() /* *************** */ @@ -12115,49 +12070,43 @@ void Dblqh::execFSWRITEREF(Signal* signal) switch (lfoPtr.p->lfoState) { case LogFileOperationRecord::WRITE_PAGE_ZERO: jam(); - systemErrorLab(signal); break; case LogFileOperationRecord::LAST_WRITE_IN_FILE: jam(); - systemErrorLab(signal); break; case LogFileOperationRecord::INIT_WRITE_AT_END: jam(); - systemErrorLab(signal); break; case LogFileOperationRecord::INIT_FIRST_PAGE: jam(); - systemErrorLab(signal); break; case LogFileOperationRecord::WRITE_GCI_ZERO: jam(); - systemErrorLab(signal); break; case LogFileOperationRecord::WRITE_DIRTY: jam(); - systemErrorLab(signal); break; case LogFileOperationRecord::WRITE_INIT_MBYTE: jam(); - systemErrorLab(signal); break; case LogFileOperationRecord::ACTIVE_WRITE_LOG: jam(); - systemErrorLab(signal); break; case LogFileOperationRecord::FIRST_PAGE_WRITE_IN_LOGFILE: jam(); - systemErrorLab(signal); break; case LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES: jam(); systemErrorLab(signal); - break; default: jam(); - systemErrorLab(signal); break; }//switch + { + char msg[100]; + sprintf(msg, "File system write failed during LogFileOperationRecord state %d", (Uint32)lfoPtr.p->lfoState); + fsRefError(signal,__LINE__,msg); + } }//Dblqh::execFSWRITEREF() diff --git a/ndb/src/kernel/blocks/dbtup/Dbtup.hpp b/ndb/src/kernel/blocks/dbtup/Dbtup.hpp index 06cfd420eac..dffafc1ab66 100644 --- a/ndb/src/kernel/blocks/dbtup/Dbtup.hpp +++ b/ndb/src/kernel/blocks/dbtup/Dbtup.hpp @@ -1051,20 +1051,15 @@ private: void execTUP_SRREQ(Signal* signal); void execTUP_PREPLCPREQ(Signal* signal); void execFSOPENCONF(Signal* signal); - void execFSOPENREF(Signal* signal); void execFSCLOSECONF(Signal* signal); - void execFSCLOSEREF(Signal* signal); void execFSWRITECONF(Signal* signal); - void execFSWRITEREF(Signal* signal); void execFSREADCONF(Signal* signal); - void execFSREADREF(Signal* signal); void execNDB_STTOR(Signal* signal); void execREAD_CONFIG_REQ(Signal* signal); void execSET_VAR_REQ(Signal* signal); void execDROP_TAB_REQ(Signal* signal); void execALTER_TAB_REQ(Signal* signal); void execFSREMOVECONF(Signal* signal); - void execFSREMOVEREF(Signal* signal); void execTUP_ALLOCREQ(Signal* signal); void execTUP_DEALLOCREQ(Signal* signal); void execTUP_WRITELOG_REQ(Signal* signal); diff --git a/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp b/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp index 27f817d8abc..af516d53a24 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -117,13 +116,9 @@ Dbtup::Dbtup(const class Configuration & conf) addRecSignal(GSN_TUP_SRREQ, &Dbtup::execTUP_SRREQ); addRecSignal(GSN_TUP_PREPLCPREQ, &Dbtup::execTUP_PREPLCPREQ); addRecSignal(GSN_FSOPENCONF, &Dbtup::execFSOPENCONF); - addRecSignal(GSN_FSOPENREF, &Dbtup::execFSOPENREF); addRecSignal(GSN_FSCLOSECONF, &Dbtup::execFSCLOSECONF); - addRecSignal(GSN_FSCLOSEREF, &Dbtup::execFSCLOSEREF); addRecSignal(GSN_FSWRITECONF, &Dbtup::execFSWRITECONF); - addRecSignal(GSN_FSWRITEREF, &Dbtup::execFSWRITEREF); addRecSignal(GSN_FSREADCONF, &Dbtup::execFSREADCONF); - addRecSignal(GSN_FSREADREF, &Dbtup::execFSREADREF); addRecSignal(GSN_NDB_STTOR, &Dbtup::execNDB_STTOR); addRecSignal(GSN_READ_CONFIG_REQ, &Dbtup::execREAD_CONFIG_REQ, true); addRecSignal(GSN_SET_VAR_REQ, &Dbtup::execSET_VAR_REQ); @@ -133,7 +128,6 @@ Dbtup::Dbtup(const class Configuration & conf) addRecSignal(GSN_DROP_TRIG_REQ, &Dbtup::execDROP_TRIG_REQ); addRecSignal(GSN_DROP_TAB_REQ, &Dbtup::execDROP_TAB_REQ); - addRecSignal(GSN_FSREMOVEREF, &Dbtup::execFSREMOVEREF); addRecSignal(GSN_FSREMOVECONF, &Dbtup::execFSREMOVECONF); addRecSignal(GSN_TUP_ALLOCREQ, &Dbtup::execTUP_ALLOCREQ); @@ -263,12 +257,6 @@ void Dbtup::execFSCLOSECONF(Signal* signal) releasePendingFileOpenInfoRecord(pfoPtr); }//Dbtup::execFSCLOSECONF() -void Dbtup::execFSCLOSEREF(Signal* signal) -{ - ljamEntry(); - ndbrequire(false); -}//Dbtup::execFSCLOSEREF() - void Dbtup::execFSOPENCONF(Signal* signal) { PendingFileOpenInfoPtr pfoPtr; @@ -363,12 +351,6 @@ void Dbtup::execFSOPENCONF(Signal* signal) releasePendingFileOpenInfoRecord(pfoPtr); }//Dbtup::execFSOPENCONF() -void Dbtup::execFSOPENREF(Signal* signal) -{ - ljamEntry(); - ndbrequire(false); -}//Dbtup::execFSOPENREF() - void Dbtup::execFSREADCONF(Signal* signal) { DiskBufferSegmentInfoPtr dbsiPtr; @@ -424,12 +406,6 @@ void Dbtup::execFSREADCONF(Signal* signal) }//switch }//Dbtup::execFSREADCONF() -void Dbtup::execFSREADREF(Signal* signal) -{ - ljamEntry(); - ndbrequire(false); -}//Dbtup::execFSREADREF() - void Dbtup::execFSWRITECONF(Signal* signal) { DiskBufferSegmentInfoPtr dbsiPtr; @@ -478,12 +454,6 @@ void Dbtup::execFSWRITECONF(Signal* signal) return; }//Dbtup::execFSWRITECONF() -void Dbtup::execFSWRITEREF(Signal* signal) -{ - ljamEntry(); - ndbrequire(false); -}//Dbtup::execFSWRITEREF() - void Dbtup::execCONTINUEB(Signal* signal) { ljamEntry(); diff --git a/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp b/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp index 405f790954e..c6e33bdc92b 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp @@ -687,10 +687,3 @@ void Dbtup::execFSREMOVECONF(Signal* signal) initTab(tabPtr.p); }//Dbtup::execFSREMOVECONF() -void Dbtup::execFSREMOVEREF(Signal* signal) -{ - ljamEntry(); - ndbrequire(false); -}//Dbtup::execFSREMOVEREF() - - diff --git a/ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp b/ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp index 639d300d6df..657133bda36 100644 --- a/ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp +++ b/ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp @@ -309,7 +309,6 @@ private: Uint32 c_fsRemoveCount; Uint32 c_nodeGroup; void clearFilesystem(Signal* signal); - void execFSREMOVEREF(Signal* signal); void execFSREMOVECONF(Signal* signal); NdbNodeBitmask c_allDefinedNodes; diff --git a/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp b/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp index c7b472fc91a..97ca3f44b3a 100644 --- a/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp +++ b/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp @@ -100,7 +100,6 @@ Ndbcntr::Ndbcntr(const class Configuration & conf): addRecSignal(GSN_STTORRY, &Ndbcntr::execSTTORRY); addRecSignal(GSN_READ_CONFIG_CONF, &Ndbcntr::execREAD_CONFIG_CONF); - addRecSignal(GSN_FSREMOVEREF, &Ndbcntr::execFSREMOVEREF); addRecSignal(GSN_FSREMOVECONF, &Ndbcntr::execFSREMOVECONF); initData(); diff --git a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp index c80891548cf..2e2c834ad9c 100644 --- a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp +++ b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp @@ -144,6 +144,7 @@ void Ndbcntr::execSYSTEM_ERROR(Signal* signal) const SystemError * const sysErr = (SystemError *)signal->getDataPtr(); char buf[100]; int killingNode = refToNode(sysErr->errorRef); + Uint32 data1 = sysErr->data1; jamEntry(); switch (sysErr->errorCode){ @@ -178,8 +179,9 @@ void Ndbcntr::execSYSTEM_ERROR(Signal* signal) case SystemError::CopyFragRefError: BaseString::snprintf(buf, sizeof(buf), "Node %d killed this node because " - "it could not copy a fragment during node restart", - killingNode); + "it could not copy a fragment during node restart. " + "Copy fragment error code: %u.", + killingNode, data1); break; default: @@ -2395,12 +2397,6 @@ Ndbcntr::clearFilesystem(Signal* signal){ c_fsRemoveCount++; } -void -Ndbcntr::execFSREMOVEREF(Signal* signal){ - jamEntry(); - ndbrequire(0); -} - void Ndbcntr::execFSREMOVECONF(Signal* signal){ jamEntry(); diff --git a/ndb/src/kernel/vm/SimulatedBlock.cpp b/ndb/src/kernel/vm/SimulatedBlock.cpp index 94fd5769406..9b52ac65331 100644 --- a/ndb/src/kernel/vm/SimulatedBlock.cpp +++ b/ndb/src/kernel/vm/SimulatedBlock.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "LongSignal.hpp" @@ -140,6 +141,13 @@ SimulatedBlock::installSimulatedBlockFunctions(){ a[GSN_UTIL_UNLOCK_REF] = &SimulatedBlock::execUTIL_UNLOCK_REF; a[GSN_UTIL_UNLOCK_CONF] = &SimulatedBlock::execUTIL_UNLOCK_CONF; a[GSN_READ_CONFIG_REQ] = &SimulatedBlock::execREAD_CONFIG_REQ; + a[GSN_FSOPENREF] = &SimulatedBlock::execFSOPENREF; + a[GSN_FSCLOSEREF] = &SimulatedBlock::execFSCLOSEREF; + a[GSN_FSWRITEREF] = &SimulatedBlock::execFSWRITEREF; + a[GSN_FSREADREF] = &SimulatedBlock::execFSREADREF; + a[GSN_FSREMOVEREF] = &SimulatedBlock::execFSREMOVEREF; + a[GSN_FSSYNCREF] = &SimulatedBlock::execFSSYNCREF; + a[GSN_FSAPPENDREF] = &SimulatedBlock::execFSAPPENDREF; } void @@ -1781,6 +1789,61 @@ SimulatedBlock::execUPGRADE(Signal* signal){ } } +void +SimulatedBlock::fsRefError(Signal* signal, Uint32 line, const char *msg) +{ + const FsRef *fsRef = (FsRef*)signal->getDataPtr(); + Uint32 errorCode = fsRef->errorCode; + Uint32 osErrorCode = fsRef->osErrorCode; + char msg2[100]; + + sprintf(msg2, "%s: %s. OS errno: %u", getBlockName(number()), msg, osErrorCode); + + progError(line, errorCode, msg2); +} + +void +SimulatedBlock::execFSWRITEREF(Signal* signal) +{ + fsRefError(signal, __LINE__, "File system write failed"); +} + +void +SimulatedBlock::execFSREADREF(Signal* signal) +{ + fsRefError(signal, __LINE__, "File system read failed"); +} + +void +SimulatedBlock::execFSCLOSEREF(Signal* signal) +{ + fsRefError(signal, __LINE__, "File system close failed"); +} + +void +SimulatedBlock::execFSOPENREF(Signal* signal) +{ + fsRefError(signal, __LINE__, "File system open failed"); +} + +void +SimulatedBlock::execFSREMOVEREF(Signal* signal) +{ + fsRefError(signal, __LINE__, "File system remove failed"); +} + +void +SimulatedBlock::execFSSYNCREF(Signal* signal) +{ + fsRefError(signal, __LINE__, "File system sync failed"); +} + +void +SimulatedBlock::execFSAPPENDREF(Signal* signal) +{ + fsRefError(signal, __LINE__, "File system append failed"); +} + #ifdef VM_TRACE void SimulatedBlock::clear_global_variables(){ diff --git a/ndb/src/kernel/vm/SimulatedBlock.hpp b/ndb/src/kernel/vm/SimulatedBlock.hpp index 787d14ca5cb..81b4fe7413e 100644 --- a/ndb/src/kernel/vm/SimulatedBlock.hpp +++ b/ndb/src/kernel/vm/SimulatedBlock.hpp @@ -487,6 +487,15 @@ private: protected: void execUPGRADE(Signal* signal); + void fsRefError(Signal* signal, Uint32 line, const char *msg); + void execFSWRITEREF(Signal* signal); + void execFSREADREF(Signal* signal); + void execFSOPENREF(Signal* signal); + void execFSCLOSEREF(Signal* signal); + void execFSREMOVEREF(Signal* signal); + void execFSSYNCREF(Signal* signal); + void execFSAPPENDREF(Signal* signal); + // Variable for storing inserted errors, see pc.H ERROR_INSERT_VARIABLE; From f1fb30a15f6de6260337beae8e4c6a4230ef4a29 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Wed, 31 Aug 2005 18:26:50 +0400 Subject: [PATCH 11/41] Fix bug #12861 client hang with group_concat insubquery FROM DUAL. Item_func_group_concat::fix_fields() set maybe_null flag to 0, and set it to 1 only if some of it's arguments may be null. When used in subquery in tmp table created field which can't be null. When no data retireved result field have to be set to null and error mentioned in bug report occurs. Also this bug can occur if selecting from not null field in empty table. Function group_concat now marked maybe_null from the very beginning not only if some of it's argument may be null. --- mysql-test/r/func_gconcat.result | 3 +++ mysql-test/t/func_gconcat.test | 5 +++++ sql/item_sum.cc | 4 +--- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 9faee3cbc01..a6c25fcd26c 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -548,3 +548,6 @@ FROM t1 JOIN t2 ON t1.bID = t2.bID; COUNT(*) GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') 2 test DROP TABLE t1,t2; +select * from (select group_concat('c') from DUAL) t; +group_concat('c') +NULL diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 9793d0d0a2c..827a2813718 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -343,4 +343,9 @@ SELECT COUNT(*), GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') DROP TABLE t1,t2; +# +# Bug #12861 hang with group_concat insubquery FROM DUAL +# +select * from (select group_concat('c') from DUAL) t; + # End of 4.1 tests diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 74a7fee113e..000dcdb4997 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1916,7 +1916,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) } thd->allow_sum_func= 0; - maybe_null= 0; + maybe_null= 1; item_thd= thd; /* @@ -1929,8 +1929,6 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) args[i]->fix_fields(thd, tables, args + i)) || args[i]->check_cols(1)) return 1; - if (i < arg_count_field) - maybe_null|= args[i]->maybe_null; } if (agg_item_charsets(collation, func_name(), From 16eecea22e5b3aafb19123d7f6058aacc16c631a Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Wed, 31 Aug 2005 16:28:47 +0200 Subject: [PATCH 12/41] mtr_timer.pl, mtr_report.pl, mtr_process.pl, mysql-test-run.pl: Backporting from 5.0 --- mysql-test/lib/mtr_process.pl | 78 +++++++++++++++++++++++++---------- mysql-test/lib/mtr_report.pl | 5 ++- mysql-test/lib/mtr_timer.pl | 12 ++++++ mysql-test/mysql-test-run.pl | 45 ++++++++++---------- 4 files changed, 95 insertions(+), 45 deletions(-) diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index c9ae92305c2..a7587ce691f 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -12,16 +12,17 @@ use strict; #use POSIX ":sys_wait_h"; use POSIX 'WNOHANG'; -sub mtr_run ($$$$$$); -sub mtr_spawn ($$$$$$); +sub mtr_run ($$$$$$;$); +sub mtr_spawn ($$$$$$;$); sub mtr_stop_mysqld_servers ($); sub mtr_kill_leftovers (); sub mtr_record_dead_children (); sub mtr_exit ($); sub sleep_until_file_created ($$$); +sub mtr_kill_processes ($); # static in C -sub spawn_impl ($$$$$$$); +sub spawn_impl ($$$$$$$$); ############################################################################## # @@ -32,37 +33,43 @@ sub spawn_impl ($$$$$$$); # This function try to mimic the C version used in "netware/mysql_test_run.c" # FIXME learn it to handle append mode as well, a "new" flag or a "append" -sub mtr_run ($$$$$$) { +sub mtr_run ($$$$$$;$) { my $path= shift; my $arg_list_t= shift; my $input= shift; my $output= shift; my $error= shift; my $pid_file= shift; + my $spawn_opts= shift; - return spawn_impl($path,$arg_list_t,'run',$input,$output,$error,$pid_file); + return spawn_impl($path,$arg_list_t,'run',$input,$output,$error,$pid_file, + $spawn_opts); } -sub mtr_run_test ($$$$$$) { +sub mtr_run_test ($$$$$$;$) { my $path= shift; my $arg_list_t= shift; my $input= shift; my $output= shift; my $error= shift; my $pid_file= shift; + my $spawn_opts= shift; - return spawn_impl($path,$arg_list_t,'test',$input,$output,$error,$pid_file); + return spawn_impl($path,$arg_list_t,'test',$input,$output,$error,$pid_file, + $spawn_opts); } -sub mtr_spawn ($$$$$$) { +sub mtr_spawn ($$$$$$;$) { my $path= shift; my $arg_list_t= shift; my $input= shift; my $output= shift; my $error= shift; my $pid_file= shift; + my $spawn_opts= shift; - return spawn_impl($path,$arg_list_t,'spawn',$input,$output,$error,$pid_file); + return spawn_impl($path,$arg_list_t,'spawn',$input,$output,$error,$pid_file, + $spawn_opts); } @@ -72,7 +79,7 @@ sub mtr_spawn ($$$$$$) { # ############################################################################## -sub spawn_impl ($$$$$$$) { +sub spawn_impl ($$$$$$$$) { my $path= shift; my $arg_list_t= shift; my $mode= shift; @@ -80,6 +87,7 @@ sub spawn_impl ($$$$$$$) { my $output= shift; my $error= shift; my $pid_file= shift; # FIXME + my $spawn_opts= shift; if ( $::opt_script_debug ) { @@ -89,6 +97,18 @@ sub spawn_impl ($$$$$$$) { print STDERR "#### ", "STDOUT $output\n" if $output; print STDERR "#### ", "STDERR $error\n" if $error; print STDERR "#### ", "$mode : $path ", join(" ",@$arg_list_t), "\n"; + print STDERR "#### ", "spawn options:\n"; + if ($spawn_opts) + { + foreach my $key (sort keys %{$spawn_opts}) + { + print STDERR "#### ", " - $key: $spawn_opts->{$key}\n"; + } + } + else + { + print STDERR "#### ", " none\n"; + } print STDERR "#### ", "-" x 78, "\n"; } @@ -135,9 +155,16 @@ sub spawn_impl ($$$$$$$) { # $ENV{'COMSPEC'}= "$::glob_cygwin_shell -c"; } + my $log_file_open_mode = '>'; + + if ($spawn_opts and $spawn_opts->{'append_log_file'}) + { + $log_file_open_mode = '>>'; + } + if ( $output ) { - if ( ! open(STDOUT,">",$output) ) + if ( ! open(STDOUT,$log_file_open_mode,$output) ) { mtr_error("can't redirect STDOUT to \"$output\": $!"); } @@ -154,7 +181,7 @@ sub spawn_impl ($$$$$$$) { } else { - if ( ! open(STDERR,">",$error) ) + if ( ! open(STDERR,$log_file_open_mode,$error) ) { mtr_error("can't redirect STDERR to \"$output\": $!"); } @@ -534,16 +561,7 @@ sub mtr_stop_mysqld_servers ($) { start_reap_all(); # Avoid zombies SIGNAL: - foreach my $sig (15,9) - { - my $retries= 20; # FIXME 20 seconds, this is silly! - kill($sig, keys %mysqld_pids); - while ( $retries-- and kill(0, keys %mysqld_pids) ) - { - mtr_debug("Sleep 1 second waiting for processes to die"); - sleep(1) # Wait one second - } - } + mtr_kill_processes(\keys (%mysqld_pids)); stop_reap_all(); # Get into control again @@ -826,6 +844,21 @@ sub sleep_until_file_created ($$$) { } +sub mtr_kill_processes ($) { + my $pids = shift; + + foreach my $sig (15,9) + { + my $retries= 20; # FIXME 20 seconds, this is silly! + kill($sig, @{$pids}); + while ( $retries-- and kill(0, @{$pids}) ) + { + mtr_debug("Sleep 1 second waiting for processes to die"); + sleep(1) # Wait one second + } + } +} + ############################################################################## # # When we exit, we kill off all children @@ -841,6 +874,7 @@ sub sleep_until_file_created ($$$) { sub mtr_exit ($) { my $code= shift; # cluck("Called mtr_exit()"); + mtr_timer_stop_all($::glob_timers); local $SIG{HUP} = 'IGNORE'; kill('HUP', -$$); sleep 2; diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index 5e1a8308505..868653afaa4 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -177,7 +177,7 @@ sub mtr_report_stats ($) { "%.2f\% were successful.\n\n", $ratio; print "The log files in var/log may give you some hint\n", - "of what when wrong.\n", + "of what went wrong.\n", "If you want to report this error, please read first ", "the documentation at\n", "http://www.mysql.com/doc/en/MySQL_test_suite.html\n"; @@ -223,7 +223,8 @@ sub mtr_report_stats ($) { if ( $tot_failed != 0 ) { - print "mysql-test-run: *** Failing the test(s):"; + my $test_mode= join(" ", @::glob_test_mode) || "default"; + print "mysql-test-run in $test_mode mode: *** Failing the test(s):"; foreach my $tinfo (@$tests) { diff --git a/mysql-test/lib/mtr_timer.pl b/mysql-test/lib/mtr_timer.pl index aab57d1bc52..709cebd6407 100644 --- a/mysql-test/lib/mtr_timer.pl +++ b/mysql-test/lib/mtr_timer.pl @@ -15,6 +15,7 @@ use POSIX 'WNOHANG'; sub mtr_init_timers (); sub mtr_timer_start($$$); sub mtr_timer_stop($$); +sub mtr_timer_stop_all($); sub mtr_timer_waitpid($$$); ############################################################################## @@ -113,6 +114,17 @@ sub mtr_timer_stop ($$) { } +sub mtr_timer_stop_all ($) { + my $timers= shift; + + foreach my $name ( keys %{$timers->{'timers'}} ) + { + mtr_timer_stop($timers, $name); + } + return 1; +} + + sub mtr_timer_timeout ($$) { my ($timers,$pid)= @_; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index e72d8f5f683..fffdd9037ec 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -142,6 +142,7 @@ our $glob_timers= undef; our $glob_use_running_server= 0; our $glob_use_running_ndbcluster= 0; our $glob_use_embedded_server= 0; +our @glob_test_mode; our $glob_basedir; @@ -606,6 +607,7 @@ sub command_line_setup () { if ( $opt_embedded_server ) { $glob_use_embedded_server= 1; + push(@glob_test_mode, "embedded"); $opt_skip_rpl= 1; # We never run replication with embedded if ( $opt_extern ) @@ -614,6 +616,11 @@ sub command_line_setup () { } } + if ( $opt_ps_protocol ) + { + push(@glob_test_mode, "ps-protocol"); + } + # FIXME don't understand what this is # if ( $opt_local_master ) # { @@ -999,25 +1006,19 @@ sub kill_and_cleanup () { # FIXME do we really need to create these all, or are they # created for us when tables are created? - rmtree("$master->[0]->{'path_myddir'}"); - mkpath("$master->[0]->{'path_myddir'}/mysql"); - mkpath("$master->[0]->{'path_myddir'}/test"); - - rmtree("$master->[1]->{'path_myddir'}"); - mkpath("$master->[1]->{'path_myddir'}/mysql"); - mkpath("$master->[1]->{'path_myddir'}/test"); - - rmtree("$slave->[0]->{'path_myddir'}"); - mkpath("$slave->[0]->{'path_myddir'}/mysql"); - mkpath("$slave->[0]->{'path_myddir'}/test"); - - rmtree("$slave->[1]->{'path_myddir'}"); - mkpath("$slave->[1]->{'path_myddir'}/mysql"); - mkpath("$slave->[1]->{'path_myddir'}/test"); - - rmtree("$slave->[2]->{'path_myddir'}"); - mkpath("$slave->[2]->{'path_myddir'}/mysql"); - mkpath("$slave->[2]->{'path_myddir'}/test"); + my @data_dir_lst = ( + $master->[0]->{'path_myddir'}, + $master->[1]->{'path_myddir'}, + $slave->[0]->{'path_myddir'}, + $slave->[1]->{'path_myddir'}, + $slave->[2]->{'path_myddir'}); + + foreach my $data_dir (@data_dir_lst) + { + rmtree("$data_dir"); + mkpath("$data_dir/mysql"); + mkpath("$data_dir/test"); + } # To make some old test cases work, we create a soft # link from the old "var" location to the new one @@ -1565,8 +1566,9 @@ sub report_failure_and_restart ($) { print "\n"; if ( ! $opt_force ) { - print "Aborting: $tinfo->{'name'} failed. To continue, re-run with '--force'."; - print "\n"; + my $test_mode= join(" ", @::glob_test_mode) || "default"; + print "Aborting: $tinfo->{'name'} failed in $test_mode mode. "; + print "To continue, re-run with '--force'.\n"; if ( ! $opt_gdb and ! $glob_use_running_server and ! $opt_ddd and ! $glob_use_embedded_server ) { @@ -1612,6 +1614,7 @@ sub do_before_start_master ($$) { } } + # FIXME only remove the ones that are tied to this master # Remove old master.info and relay-log.info files unlink("$master->[0]->{'path_myddir'}/master.info"); unlink("$master->[0]->{'path_myddir'}/relay-log.info"); From 2fc6ef3a409a7ace9ba0083882a43fd74e86ccb2 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 31 Aug 2005 17:16:05 +0200 Subject: [PATCH 13/41] BUG#11316: mysqltest, problems when assigning value with '#' to $variable - Add stricter checking of syntax in mysqltest --- client/mysqltest.c | 863 +++++++++++----------- mysql-test/r/mysqltest.result | 32 +- mysql-test/t/create.test | 2 +- mysql-test/t/create_select_tmp.test | 16 +- mysql-test/t/drop.test | 10 +- mysql-test/t/flush.test | 2 +- mysql-test/t/handler.test | 18 +- mysql-test/t/innodb.test | 2 +- mysql-test/t/mysqltest.test | 63 ++ mysql-test/t/rpl000001.test | 2 +- mysql-test/t/rpl_EE_error.test | 2 +- mysql-test/t/rpl_drop.test | 2 +- mysql-test/t/rpl_error_ignored_table.test | 4 +- mysql-test/t/rpl_loaddata.test | 2 +- 14 files changed, 541 insertions(+), 479 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index dff91560b81..d12eba2c7d1 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -75,7 +75,7 @@ #define LAZY_GUESS_BUF_SIZE 8192 #define INIT_Q_LINES 1024 #define MIN_VAR_ALLOC 32 -#define BLOCK_STACK_DEPTH 16 +#define BLOCK_STACK_DEPTH 32 #define MAX_EXPECTED_ERRORS 10 #define QUERY_SEND 1 #define QUERY_REAP 2 @@ -136,12 +136,12 @@ static uint global_expected_errors; static int record = 0, opt_sleep=0; static char *db = 0, *pass=0; -const char* user = 0, *host = 0, *unix_sock = 0, *opt_basedir="./"; +const char *user = 0, *host = 0, *unix_sock = 0, *opt_basedir="./"; static int port = 0; static my_bool opt_big_test= 0, opt_compress= 0, silent= 0, verbose = 0; static my_bool tty_password= 0, ps_protocol= 0, ps_protocol_enabled= 0; static uint start_lineno, *lineno; -const char* manager_user="root",*manager_host=0; +const char *manager_user="root",*manager_host=0; char *manager_pass=0; int manager_port=MYSQL_MANAGER_PORT; int manager_wait_timeout=3; @@ -151,11 +151,16 @@ 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 char* file_name_stack[MAX_INCLUDE_DEPTH]; -static int cur_file_name; -static FILE* file_stack[MAX_INCLUDE_DEPTH]; -static FILE** cur_file; -static FILE** file_stack_end; +typedef struct +{ + FILE* file; + const char *file_name; +} test_file; + +static test_file file_stack[MAX_INCLUDE_DEPTH]; +static test_file* cur_file; +static test_file* file_stack_end; + static uint lineno_stack[MAX_INCLUDE_DEPTH]; static char TMPDIR[FN_REFLEN]; static char delimiter[MAX_DELIMITER]= DEFAULT_DELIMITER; @@ -293,7 +298,7 @@ Q_COMMENT_WITH_COMMAND /* this should really be called command */ struct st_query { - char *query, *query_buf,*first_argument,*end; + char *query, *query_buf,*first_argument,*last_argument,*end; int first_word_len; my_bool abort_on_error, require_file; match_err expected_errno[MAX_EXPECTED_ERRORS]; @@ -401,7 +406,7 @@ static void var_free(void* v); int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname); void reject_dump(const char *record_file, char *buf, int size); -int close_connection(struct st_query* q); +int close_connection(struct st_query*); static void set_charset(struct st_query*); VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw, my_bool ignore_not_existing); @@ -427,9 +432,9 @@ static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name); void free_pointer_array(POINTER_ARRAY *pa); static int initialize_replace_buffer(void); static void free_replace_buffer(void); -static void do_eval(DYNAMIC_STRING* query_eval, const char *query); +static void do_eval(DYNAMIC_STRING *query_eval, const char *query); void str_to_file(const char *fname, char *str, int size); -int do_server_op(struct st_query* q,const char *op); +int do_server_op(struct st_query *q,const char *op); struct st_replace *glob_replace; static char *out_buff; @@ -453,9 +458,9 @@ my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; } static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, int len); -static void do_eval(DYNAMIC_STRING* query_eval, const char* query) +static void do_eval(DYNAMIC_STRING* query_eval, const char *query) { - const char* p; + const char *p; register char c; register int escaped = 0; VAR* v; @@ -512,13 +517,13 @@ static void close_cons() static void close_files() { DBUG_ENTER("close_files"); - for (; cur_file != file_stack ; cur_file--) + for (; cur_file != (file_stack-1) ; cur_file--) { - if (*cur_file != stdin && *cur_file) - my_fclose(*cur_file,MYF(0)); - char* p= file_name_stack[cur_file_name--]= 0; - if (p) - free(p); + DBUG_PRINT("info", ("file_name: %s", cur_file->file_name)); + if (cur_file->file && cur_file->file != stdin) + my_fclose(cur_file->file, MYF(0)); + my_free((gptr)cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR)); + cur_file->file_name= 0; } DBUG_VOID_RETURN; } @@ -561,17 +566,17 @@ static void free_used_memory() DBUG_VOID_RETURN; } -static void die(const char* fmt, ...) +static void die(const char *fmt, ...) { va_list args; DBUG_ENTER("die"); va_start(args, fmt); if (fmt) { - fprintf(stderr, "%s: ", my_progname); - if (*cur_file && cur_file > (file_stack + 1) ) + fprintf(stderr, "mysqltest: "); + if (cur_file && cur_file != file_stack) fprintf(stderr, "In included file \"%s\": ", - file_name_stack[cur_file_name]); + cur_file->file_name); fprintf(stderr, "At line %u: ", start_lineno); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); @@ -596,7 +601,7 @@ static void abort_not_supported_test() exit(62); } -static void verbose_msg(const char* fmt, ...) +static void verbose_msg(const char *fmt, ...) { va_list args; DBUG_ENTER("verbose_msg"); @@ -605,7 +610,7 @@ static void verbose_msg(const char* fmt, ...) va_start(args, fmt); - fprintf(stderr, "%s: At line %u: ", my_progname, start_lineno); + fprintf(stderr, "mysqltest: At line %u: ", start_lineno); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); va_end(args); @@ -615,12 +620,12 @@ static void verbose_msg(const char* fmt, ...) void init_parser() { - parser.current_line = parser.read_lines = 0; - memset(&var_reg,0, sizeof(var_reg)); + parser.current_line= parser.read_lines= 0; + memset(&var_reg, 0, sizeof(var_reg)); } -int dyn_string_cmp(DYNAMIC_STRING* ds, const char* fname) +int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) { MY_STAT stat_info; char *tmp, *res_ptr; @@ -686,7 +691,7 @@ err: DBUG_RETURN(res); } -static int check_result(DYNAMIC_STRING* ds, const char* fname, +static int check_result(DYNAMIC_STRING* ds, const char *fname, my_bool require_option) { int error = 0; @@ -714,7 +719,7 @@ static int check_result(DYNAMIC_STRING* ds, const char* fname, } -VAR* var_get(const char* var_name, const char** var_name_end, my_bool raw, +VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw, my_bool ignore_not_existing) { int digit; @@ -727,7 +732,7 @@ VAR* var_get(const char* var_name, const char** var_name_end, my_bool raw, digit = *++var_name - '0'; if (digit < 0 || digit >= 10) { - const char* save_var_name = var_name, *end; + const char *save_var_name = var_name, *end; uint length; end = (var_name_end) ? *var_name_end : 0; while (my_isvar(charset_info,*var_name) && var_name != end) @@ -769,7 +774,7 @@ err: DBUG_RETURN(0); } -static VAR *var_obtain(const char* name, int len) +static VAR *var_obtain(const char *name, int len) { VAR* v; if ((v = (VAR*)hash_search(&var_hash, name, len))) @@ -806,8 +811,10 @@ int var_set(const char *var_name, const char *var_name_end, } -int open_file(const char* name) +int open_file(const char *name) { + DBUG_ENTER("open_file"); + DBUG_PRINT("enter", ("name: %s", name)); char buff[FN_REFLEN]; if (!test_if_hard_path(name)) { @@ -816,13 +823,17 @@ int open_file(const char* name) } fn_format(buff,name,"","",4); - if (*cur_file && cur_file == file_stack_end) + if (cur_file == file_stack_end) die("Source directives are nesting too deep"); - if (!(*++cur_file = my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0)))) + cur_file++; + if (!(cur_file->file = my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0)))) + { + cur_file--; die("Could not open file %s", buff); + } + cur_file->file_name= my_strdup(buff, MYF(MY_FAE)); *++lineno=1; - file_name_stack[++cur_file_name]= strdup(buff); - return 0; + DBUG_RETURN(0); } @@ -833,14 +844,15 @@ int open_file(const char* name) int check_eol_junk(const char *eol) { - char *p= (char*)eol; + DBUG_ENTER("check_eol_junk"); + DBUG_PRINT("enter", ("eol: %s", eol)); + const char *p= eol; /* Remove all spacing chars except new line */ - while (*p && my_isspace(charset_info,*p) && (*p != '\n')) + while (*p && my_isspace(charset_info, *p) && (*p != '\n')) p++; /* Check for extra delimiter */ - size_t l= strlen(delimiter); - if (*p && strlen(p) >= l && !strncmp(p, delimiter, l) ) + if (*p && !strncmp(p, delimiter, delimiter_length)) die("Extra delimiter \"%s\" found", delimiter); /* Allow trailing # comment */ @@ -850,12 +862,12 @@ int check_eol_junk(const char *eol) die("Missing delimiter"); die("End of line junk detected: \"%s\"", p); } - return 0; + DBUG_RETURN(0); } /* ugly long name, but we are following the convention */ -int do_wait_for_slave_to_stop(struct st_query* q __attribute__((unused))) +int do_wait_for_slave_to_stop(struct st_query *q __attribute__((unused))) { MYSQL* mysql = &cur_con->mysql; for (;;) @@ -880,57 +892,56 @@ int do_wait_for_slave_to_stop(struct st_query* q __attribute__((unused))) break; my_sleep(SLAVE_POLL_INTERVAL); } - return check_eol_junk(q->first_argument); + return 0; } -int do_require_manager(struct st_query* q) +int do_require_manager(struct st_query *query __attribute__((unused)) ) { if (!manager) abort_not_supported_test(); - return check_eol_junk(q->first_argument); + return 0; } #ifndef EMBEDDED_LIBRARY -int do_server_start(struct st_query* q) +int do_server_start(struct st_query *q) { - check_eol_junk(q->first_argument); - return do_server_op(q,"start"); + return do_server_op(q, "start"); } -int do_server_stop(struct st_query* q) +int do_server_stop(struct st_query *q) { - check_eol_junk(q->first_argument); - return do_server_op(q,"stop"); + return do_server_op(q, "stop"); } -int do_server_op(struct st_query* q,const char* op) +int do_server_op(struct st_query *q, const char *op) { - char* p=q->first_argument; - char com_buf[256],*com_p; + char *p= q->first_argument; + char com_buf[256], *com_p; if (!manager) { die("Manager is not initialized, manager commands are not possible"); } - com_p=strmov(com_buf,op); - com_p=strmov(com_p,"_exec "); + com_p= strmov(com_buf,op); + com_p= strmov(com_p,"_exec "); if (!*p) - die("Missing server name in server_%s",op); - while (*p && !my_isspace(charset_info,*p)) + die("Missing server name in server_%s", op); + while (*p && !my_isspace(charset_info, *p)) *com_p++= *p++; - *com_p++=' '; - com_p=int10_to_str(manager_wait_timeout,com_p,10); - *com_p++ = '\n'; - *com_p=0; - if (mysql_manager_command(manager,com_buf,(int)(com_p-com_buf))) - die("Error in command: %s(%d)",manager->last_error,manager->last_errno); + *com_p++= ' '; + com_p= int10_to_str(manager_wait_timeout, com_p, 10); + *com_p++= '\n'; + *com_p= 0; + if (mysql_manager_command(manager, com_buf, (int)(com_p-com_buf))) + die("Error in command: %s(%d)", manager->last_error, manager->last_errno); while (!manager->eof) { - if (mysql_manager_fetch_line(manager,com_buf,sizeof(com_buf))) + if (mysql_manager_fetch_line(manager, com_buf, sizeof(com_buf))) die("Error fetching result line: %s(%d)", manager->last_error, manager->last_errno); } - return check_eol_junk(p); + q->last_argument= p; + return 0; } #endif @@ -940,7 +951,7 @@ int do_server_op(struct st_query* q,const char* op) SYNOPSIS do_source() - q called command + query called command DESCRIPTION source @@ -949,26 +960,24 @@ int do_server_op(struct st_query* q,const char* op) */ -int do_source(struct st_query* q) +int do_source(struct st_query *query) { - char* p=q->first_argument, *name; + char *p= query->first_argument, *name; if (!*p) die("Missing file name in source"); - name = p; + name= p; while (*p && !my_isspace(charset_info,*p)) p++; if (*p) - { *p++= 0; - check_eol_junk(p); - } - /* If this file has already been sourced, dont source it again. - It's already available in the q_lines cache */ + query->last_argument= p; + /* + If this file has already been sourced, dont source it again. + It's already available in the q_lines cache + */ if (parser.current_line < (parser.read_lines - 1)) return 0; return open_file(name); - - } @@ -977,7 +986,7 @@ int do_source(struct st_query* q) SYNOPSIS do_exec() - q called command + query called command DESCRIPTION exec @@ -989,24 +998,25 @@ int do_source(struct st_query* q) */ -static void do_exec(struct st_query* q) +static void do_exec(struct st_query *query) { int error; DYNAMIC_STRING *ds= NULL; DYNAMIC_STRING ds_tmp; char buf[1024]; FILE *res_file; - char *cmd= q->first_argument; + char *cmd= query->first_argument; DBUG_ENTER("do_exec"); while (*cmd && my_isspace(charset_info, *cmd)) cmd++; if (!*cmd) die("Missing argument in exec"); + query->last_argument= query->end; DBUG_PRINT("info", ("Executing '%s'", cmd)); - if (!(res_file= popen(cmd, "r")) && q->abort_on_error) + if (!(res_file= popen(cmd, "r")) && query->abort_on_error) die("popen(\"%s\", \"r\") failed", cmd); if (disable_result_log) @@ -1019,7 +1029,7 @@ static void do_exec(struct st_query* q) } else { - if (q->record_file[0]) + if (query->record_file[0]) { init_dynamic_string(&ds_tmp, "", 16384, 65536); ds= &ds_tmp; @@ -1033,20 +1043,20 @@ static void do_exec(struct st_query* q) error= pclose(res_file); if (error != 0) { - uint i, status= WEXITSTATUS(error); + uint status= WEXITSTATUS(error), i; my_bool ok= 0; - if (q->abort_on_error) + if (query->abort_on_error) die("command \"%s\" failed", cmd); DBUG_PRINT("info", ("error: %d, status: %d", error, status)); - for (i=0 ; i < q->expected_errors ; i++) + for (i= 0; i < query->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)) + query->expected_errno[i].code.errnum)); + if ((query->expected_errno[i].type == ERR_ERRNO) && + (query->expected_errno[i].code.errnum == status)) { ok= 1; verbose_msg("command \"%s\" failed with expected error: %d", @@ -1057,12 +1067,12 @@ static void do_exec(struct st_query* q) die("command \"%s\" failed with wrong error: %d", cmd, status); } - else if (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0) + else if (query->expected_errno[0].type == ERR_ERRNO && + query->expected_errno[0].code.errnum != 0) { /* Error code we wanted was != 0, i.e. not an expected success */ die("command \"%s\" succeeded - should have failed with errno %d...", - cmd, q->expected_errno[0].code.errnum); + cmd, query->expected_errno[0].code.errnum); } if (!disable_result_log) @@ -1072,14 +1082,14 @@ static void do_exec(struct st_query* q) if (record) { - if (!q->record_file[0] && !result_file) + if (!query->record_file[0] && !result_file) die("Missing result file"); if (!result_file) - str_to_file(q->record_file, ds->str, ds->length); + str_to_file(query->record_file, ds->str, ds->length); } - else if (q->record_file[0]) + else if (query->record_file[0]) { - error= check_result(ds, q->record_file, q->require_file); + error= check_result(ds, query->record_file, query->require_file); } if (ds == &ds_tmp) dynstr_free(&ds_tmp); @@ -1087,7 +1097,7 @@ static void do_exec(struct st_query* q) } -int var_query_set(VAR* v, const char* p, const char** p_end) +int var_query_set(VAR* v, const char *p, const char** p_end) { char* end = (char*)((p_end && *p_end) ? *p_end : p + strlen(p)); MYSQL_RES *res; @@ -1150,7 +1160,7 @@ void var_copy(VAR* dest, VAR* src) memcpy(dest->str_val,src->str_val,src->str_val_len+1); } -int eval_expr(VAR* v, const char* p, const char** p_end) +int eval_expr(VAR* v, const char *p, const char** p_end) { VAR* vp; if (*p == '$') @@ -1192,69 +1202,57 @@ int eval_expr(VAR* v, const char* p, const char** p_end) } +enum enum_operator +{ + DO_DEC, + DO_INC +}; + /* - Increase the value of a variable + Decrease or increase the value of a variable SYNOPSIS - do_inc() - q called command + do_modify_var() + query called command + name human readable name of operator + operator operation to perform on the var DESCRIPTION + dec $var_name inc $var_name */ -int do_inc(struct st_query* q) +int do_modify_var(struct st_query *query, const char *name, + enum enum_operator operator) { - char* p=q->first_argument; + char *p= query->first_argument; VAR* v; if (!*p) - die("Missing arguments to inc"); + die("Missing arguments to %s", name); if (*p != '$') - die("First argument to inc must be a variable (start with $)"); - v = var_get(p, 0, 1, 0); - v->int_val++; - v->int_dirty = 1; - while (*p && !my_isspace(charset_info,*p)) - p++; - check_eol_junk(p); + die("First argument to %s must be a variable (start with $)", name); + v= var_get(p, &p, 1, 0); + switch (operator){ + case DO_DEC: + v->int_val--; + break; + case DO_INC: + v->int_val++; + break; + default: + die("Invalid operator to do_operator"); + break; + } + v->int_dirty= 1; + query->last_argument= ++p; return 0; } -/* - Decrease the value of a variable - - SYNOPSIS - do_dec() - q called command - - DESCRIPTION - dec $var_name - -*/ - -int do_dec(struct st_query* q) +int do_system(struct st_query *q) { - char* p=q->first_argument; - VAR* v; - if (!*p) - die("Missing arguments to dec"); - if (*p != '$') - die("First argument to dec must be a variable (start with $)"); - v = var_get(p, 0, 1, 0); - v->int_val--; - v->int_dirty = 1; - while (*p && !my_isspace(charset_info,*p)) - p++; - check_eol_junk(p); - return 0; -} - - -int do_system(struct st_query* q) -{ - char* p=q->first_argument; + char *p=q->first_argument; VAR v; var_init(&v, 0, 0, 0, 0); eval_expr(&v, p, 0); /* NULL terminated */ @@ -1277,6 +1275,7 @@ int do_system(struct st_query* q) else die("Missing arguments to system, nothing to do!"); var_free(&v); + q->last_argument= q->end; return 0; } @@ -1300,10 +1299,10 @@ int do_system(struct st_query* q) */ -int do_echo(struct st_query* q) +int do_echo(struct st_query *q) { - char* p=q->first_argument; - DYNAMIC_STRING *ds= NULL; + char *p= q->first_argument; + DYNAMIC_STRING *ds; DYNAMIC_STRING ds_tmp; VAR v; var_init(&v,0,0,0,0); @@ -1311,7 +1310,7 @@ int do_echo(struct st_query* q) if (q->record_file[0]) { init_dynamic_string(&ds_tmp, "", 256, 512); - ds = &ds_tmp; + ds= &ds_tmp; } else ds= &ds_res; @@ -1323,40 +1322,27 @@ int do_echo(struct st_query* q) var_free(&v); if (ds == &ds_tmp) dynstr_free(&ds_tmp); + q->last_argument= q->end; return 0; } -int do_sync_with_master2(const char* p) +int do_sync_with_master2(long offset) { MYSQL_RES* res; MYSQL_ROW row; - MYSQL* mysql = &cur_con->mysql; + MYSQL* mysql= &cur_con->mysql; char query_buf[FN_REFLEN+128]; - int offset= 0, tries= 0; + int tries= 0; int rpl_parse; if (!master_pos.file[0]) { die("Line %u: Calling 'sync_with_master' without calling 'save_master_pos'", start_lineno); } - rpl_parse = mysql_rpl_parse_enabled(mysql); + rpl_parse= mysql_rpl_parse_enabled(mysql); mysql_disable_rpl_parse(mysql); - const char* offset_str= p; - /* Step until end of integer arg and check it */ - while (*p && !my_isspace(charset_info, *p)) - { - if (!my_isdigit(charset_info, *p)) - die("Invalid integer argument \"%s\"", offset_str); - p++; - } - check_eol_junk(p); - - if (*offset_str) - offset = atoi(offset_str); - - sprintf(query_buf, "select master_pos_wait('%s', %ld)", master_pos.file, master_pos.pos + offset); @@ -1366,10 +1352,10 @@ wait_for_position: die("line %u: failed in %s: %d: %s", start_lineno, query_buf, mysql_errno(mysql), mysql_error(mysql)); - if (!(last_result = res = mysql_store_result(mysql))) + if (!(last_result= res= mysql_store_result(mysql))) die("line %u: mysql_store_result() returned NULL for '%s'", start_lineno, query_buf); - if (!(row = mysql_fetch_row(res))) + if (!(row= mysql_fetch_row(res))) die("line %u: empty result in %s", start_lineno, query_buf); if (!row[0]) { @@ -1394,9 +1380,23 @@ wait_for_position: return 0; } -int do_sync_with_master(struct st_query* q) +int do_sync_with_master(struct st_query *query) { - return do_sync_with_master2(q->first_argument); + long offset= 0; + char *p= query->first_argument; + const char *offset_start= p; + const char *offset_end= query->end; + int error; + if (*offset_start) + { + for (; my_isdigit(charset_info, *p); p++) + offset = offset * 10 + *p - '0'; + + if(*p && !my_isspace(charset_info, *p)) + die("Invalid integer argument \"%s\"", offset_start); + query->last_argument= p; + } + return do_sync_with_master2(offset); } int do_save_master_pos() @@ -1435,7 +1435,7 @@ int do_save_master_pos() SYNOPSIS do_let() - q called command + query called command DESCRIPTION let $= @@ -1449,34 +1449,32 @@ int do_save_master_pos() Program will die if error detected */ -int do_let(struct st_query* q) +int do_let(struct st_query *query) { - char* p=q->first_argument; + char *p= query->first_argument; char *var_name, *var_name_end, *var_val_start; /* Find */ if (!*p) die("Missing arguments to let"); - var_name = p; - while (*p && *p != '=' && !my_isspace(charset_info,*p)) + var_name= p; + while (*p && (*p != '=') && !my_isspace(charset_info,*p)) p++; - var_name_end = p; - if (var_name+1==var_name_end) + var_name_end= p; + if (var_name+1 == var_name_end) die("Missing variable name in let"); - while (*p && (*p != '=' || my_isspace(charset_info,*p))) + while (my_isspace(charset_info,*p)) p++; - if (*p == '=') - p++; - else + if (*p++ != '=') die("Missing assignment operator in let"); /* Find start of */ while (*p && my_isspace(charset_info,*p)) p++; - var_val_start = p; - + var_val_start= p; + query->last_argument= query->end; /* Assign var_val to var_name */ - return var_set(var_name, var_name_end, var_val_start, q->end); + return var_set(var_name, var_name_end, var_val_start, query->end); } @@ -1495,28 +1493,25 @@ int var_set_errno(int sql_errno) } -int do_rpl_probe(struct st_query* q) +int do_rpl_probe(struct st_query *query __attribute__((unused))) { DBUG_ENTER("do_rpl_probe"); if (mysql_rpl_probe(&cur_con->mysql)) die("Failed in mysql_rpl_probe(): '%s'", mysql_error(&cur_con->mysql)); - check_eol_junk(q->first_argument); DBUG_RETURN(0); } -int do_enable_rpl_parse(struct st_query* q) +int do_enable_rpl_parse(struct st_query *query __attribute__((unused))) { mysql_enable_rpl_parse(&cur_con->mysql); - check_eol_junk(q->first_argument); return 0; } -int do_disable_rpl_parse(struct st_query* q) +int do_disable_rpl_parse(struct st_query *query __attribute__((unused))) { mysql_disable_rpl_parse(&cur_con->mysql); - check_eol_junk(q->first_argument); return 0; } @@ -1535,57 +1530,52 @@ int do_disable_rpl_parse(struct st_query* q) */ -int do_sleep(struct st_query* q, my_bool real_sleep) +int do_sleep(struct st_query *query, my_bool real_sleep) { - char *p=q->first_argument; - while (*p && my_isspace(charset_info,*p)) + int error= 0; + char *p= query->first_argument; + char *sleep_start, *sleep_end= query->end; + double sleep_val; + + while (my_isspace(charset_info, *p)) p++; if (!*p) die("Missing argument to sleep"); + sleep_start= p; + /* Check that arg starts with a digit, not handled by my_strtod */ + if (!my_isdigit(charset_info, *sleep_start)) + die("Invalid argument to sleep \"%s\"", query->first_argument); + sleep_val= my_strtod(sleep_start, &sleep_end, &error); + if (error) + die("Invalid argument to sleep \"%s\"", query->first_argument); + + /* Fixed sleep time selected by --sleep option */ if (opt_sleep && !real_sleep) - my_sleep(opt_sleep * 1000000L); - else - { - int err= 0; - double val=1; - const char* val_str= p; - while (*p && !my_isspace(charset_info,*p)) - { - if (!my_isdigit(charset_info, *p) && !my_ispunct(charset_info, *p)) - err= 1; - p++; - } - if (!err) - val= my_strtod(val_str, &p, &err); - if (err) - die("Invalid argument to sleep \"%s\"", q->first_argument); - my_sleep((ulong) (val * 1000000L)); - } - return check_eol_junk(p++); + sleep_val= opt_sleep; + + my_sleep((ulong) (sleep_val * 1000000L)); + query->last_argument= sleep_end; + return 0; } -static void get_file_name(char *filename, struct st_query* q) +static void get_file_name(char *filename, struct st_query *q) { - - - char* p=q->first_argument, *name; + char *p= q->first_argument, *name; if (!*p) die("Missing file name argument"); - name = p; + name= p; while (*p && !my_isspace(charset_info,*p)) p++; if (*p) - { *p++= 0; - check_eol_junk(p); - } + q->last_argument= p; strmake(filename, name, FN_REFLEN); } -static void set_charset(struct st_query* q) +static void set_charset(struct st_query *q) { - char* charset_name= q->first_argument; - char* p; + char *charset_name= q->first_argument; + char *p; if (!charset_name || !*charset_name) die("Missing charset name in 'character_set'"); @@ -1594,19 +1584,16 @@ static void set_charset(struct st_query* q) while (*p && !my_isspace(charset_info,*p)) p++; if(*p) - { *p++= 0; - check_eol_junk(p); - } - + q->last_argument= p; charset_info= get_charset_by_csname(charset_name,MY_CS_PRIMARY,MYF(MY_WME)); if (!charset_info) abort_not_supported_test(); } -static uint get_errcodes(match_err *to,struct st_query* q) +static uint get_errcodes(match_err *to,struct st_query *q) { - char* p= q->first_argument; + char *p= q->first_argument; uint count= 0; DBUG_ENTER("get_errcodes"); @@ -1636,7 +1623,7 @@ static uint get_errcodes(match_err *to,struct st_query* q) } count++; } while (*(p++) == ','); - + q->last_argument= (p - 1); to[count].type= ERR_EMPTY; /* End of data */ DBUG_RETURN(count); } @@ -1650,7 +1637,7 @@ static uint get_errcodes(match_err *to,struct st_query* q) static char *get_string(char **to_ptr, char **from_ptr, - struct st_query* q) + struct st_query *q) { reg1 char c,sep; char *to= *to_ptr, *from= *from_ptr, *start=to; @@ -1733,7 +1720,7 @@ static char *get_string(char **to_ptr, char **from_ptr, static void get_replace(struct st_query *q) { uint i; - char *from=q->first_argument; + char *from= q->first_argument; char *buff,*start; char word_end_chars[256],*pos; POINTER_ARRAY to_array,from_array; @@ -1751,7 +1738,7 @@ static void get_replace(struct st_query *q) char *to=buff; to=get_string(&buff, &from, q); if (!*from) - die("Wrong number of arguments to replace in %s", q->query); + die("Wrong number of arguments to replace_result in '%s'", q->query); insert_pointer_name(&from_array,to); to=get_string(&buff, &from, q); insert_pointer_name(&to_array,to); @@ -1765,10 +1752,11 @@ static void get_replace(struct st_query *q) (uint) from_array.typelib.count, word_end_chars)) || initialize_replace_buffer()) - die("Can't initialize replace from %s", q->query); + die("Can't initialize replace from '%s'", q->query); free_pointer_array(&from_array); free_pointer_array(&to_array); my_free(start, MYF(0)); + q->last_argument= q->end; DBUG_VOID_RETURN; } @@ -1784,30 +1772,18 @@ void free_replace() DBUG_VOID_RETURN; } -int select_connection(char *p) + +int select_connection_name(const char *name) { - char* name; struct connection *con; - DBUG_ENTER("select_connection"); - DBUG_PRINT("enter",("name: '%s'",p)); + DBUG_ENTER("select_connection2"); + DBUG_PRINT("enter",("name: '%s'", name)); - if (!*p) - die("Missing connection name in connect"); - name = p; - while (*p && !my_isspace(charset_info,*p)) - p++; - - if (*p) - { - *p++= 0; - check_eol_junk(p); - } - - for (con = cons; con < next_con; con++) + for (con= cons; con < next_con; con++) { if (!strcmp(con->name, name)) { - cur_con = con; + cur_con= con; DBUG_RETURN(0); } } @@ -1815,26 +1791,42 @@ int select_connection(char *p) DBUG_RETURN(1); /* Never reached */ } -int close_connection(struct st_query* q) + +int select_connection(struct st_query *query) { - char* p=q->first_argument, *name; + char *name; + char *p= query->first_argument; + DBUG_ENTER("select_connection"); + + if (!*p) + die("Missing connection name in connect"); + name= p; + while (*p && !my_isspace(charset_info,*p)) + p++; + if (*p) + *p++= 0; + query->last_argument= p; + return select_connection_name(name); +} + + +int close_connection(struct st_query *q) +{ + char *p= q->first_argument, *name; struct connection *con; DBUG_ENTER("close_connection"); DBUG_PRINT("enter",("name: '%s'",p)); if (!*p) die("Missing connection name in connect"); - name = p; + name= p; while (*p && !my_isspace(charset_info,*p)) p++; if (*p) - { *p++= 0; - check_eol_junk(p); - } - - for (con = cons; con < next_con; con++) + q->last_argument= p; + for (con= cons; con < next_con; con++) { if (!strcmp(con->name, name)) { @@ -1864,21 +1856,21 @@ int close_connection(struct st_query* q) ) are delimiters/terminators */ -char* safe_get_param(char* str, char** arg, const char* msg) +char* safe_get_param(char *str, char** arg, const char *msg) { DBUG_ENTER("safe_get_param"); while (*str && my_isspace(charset_info,*str)) str++; - *arg = str; + *arg= str; for (; *str && *str != ',' && *str != ')' ; str++) { if (my_isspace(charset_info,*str)) - *str = 0; + *str= 0; } if (!*str) die(msg); - *str++ = 0; + *str++= 0; DBUG_RETURN(str); } @@ -1895,9 +1887,9 @@ void init_manager() } #endif -int safe_connect(MYSQL* con, const char* host, const char* user, - const char* pass, - const char* db, int port, const char* sock) +int safe_connect(MYSQL* con, const char *host, const char *user, + const char *pass, + const char *db, int port, const char *sock) { int con_error = 1; int i; @@ -1915,14 +1907,14 @@ int safe_connect(MYSQL* con, const char* host, const char* user, } -int do_connect(struct st_query* q) +int do_connect(struct st_query *q) { - char* con_name, *con_user,*con_pass, *con_host, *con_port_str, + char *con_name, *con_user,*con_pass, *con_host, *con_port_str, *con_db, *con_sock; - char* p=q->first_argument; + char *p= q->first_argument; char buff[FN_REFLEN]; int con_port; - int free_con_sock = 0; + int free_con_sock= 0; DBUG_ENTER("do_connect"); DBUG_PRINT("enter",("connect: %s",p)); @@ -1930,41 +1922,41 @@ int do_connect(struct st_query* q) if (*p != '(') die("Syntax error in connect - expected '(' found '%c'", *p); p++; - p = safe_get_param(p, &con_name, "missing connection name"); - p = safe_get_param(p, &con_host, "missing connection host"); - p = safe_get_param(p, &con_user, "missing connection user"); - p = safe_get_param(p, &con_pass, "missing connection password"); - p = safe_get_param(p, &con_db, "missing connection db"); + p= safe_get_param(p, &con_name, "missing connection name"); + p= safe_get_param(p, &con_host, "missing connection host"); + p= safe_get_param(p, &con_user, "missing connection user"); + p= safe_get_param(p, &con_pass, "missing connection password"); + p= safe_get_param(p, &con_db, "missing connection db"); if (!*p || *p == ';') /* Default port and sock */ { - con_port=port; - con_sock=(char*) unix_sock; + con_port= port; + con_sock= (char*) unix_sock; } else { VAR* var_port, *var_sock; - p = safe_get_param(p, &con_port_str, "missing connection port"); + p= safe_get_param(p, &con_port_str, "missing connection port"); if (*con_port_str == '$') { - if (!(var_port = var_get(con_port_str, 0, 0, 0))) + if (!(var_port= var_get(con_port_str, 0, 0, 0))) die("Unknown variable '%s'", con_port_str+1); - con_port = var_port->int_val; + con_port= var_port->int_val; } else - con_port=atoi(con_port_str); - p = safe_get_param(p, &con_sock, "missing connection socket"); + con_port= atoi(con_port_str); + p= safe_get_param(p, &con_sock, "missing connection socket"); if (*con_sock == '$') { - if (!(var_sock = var_get(con_sock, 0, 0, 0))) + if (!(var_sock= var_get(con_sock, 0, 0, 0))) die("Unknown variable '%s'", con_sock+1); - if (!(con_sock = (char*)my_malloc(var_sock->str_val_len+1, MYF(0)))) + if (!(con_sock= (char*)my_malloc(var_sock->str_val_len+1, MYF(0)))) die("Out of memory"); - free_con_sock = 1; + free_con_sock= 1; memcpy(con_sock, var_sock->str_val, var_sock->str_val_len); - con_sock[var_sock->str_val_len] = 0; + con_sock[var_sock->str_val_len]= 0; } } - check_eol_junk(p); + q->last_argument= p; if (next_con == cons_end) die("Connection limit exhausted - increase MAX_CONS in mysqltest.c"); @@ -1984,33 +1976,34 @@ int do_connect(struct st_query* q) if (con_sock && !free_con_sock && *con_sock && *con_sock != FN_LIBCHAR) con_sock=fn_format(buff, con_sock, TMPDIR, "",0); if (!con_db[0]) - con_db=db; + con_db= db; /* Special database to allow one to connect without a database name */ if (con_db && !strcmp(con_db,"*NO-ONE*")) - con_db=0; + con_db= 0; if ((safe_connect(&next_con->mysql, con_host, con_user, con_pass, con_db, con_port, con_sock ? con_sock: 0))) die("Could not open connection '%s': %s", con_name, mysql_error(&next_con->mysql)); - if (!(next_con->name = my_strdup(con_name, MYF(MY_WME)))) + if (!(next_con->name= my_strdup(con_name, MYF(MY_WME)))) die(NullS); - cur_con = next_con++; + cur_con= next_con++; if (free_con_sock) my_free(con_sock, MYF(MY_WME)); DBUG_RETURN(0); } -int do_done(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) + { + if (*q->query != '}') + die("Stray 'end' command - end of block before beginning"); die("Stray '}' - end of block before beginning"); + } /* Test if inner block has been executed */ if (cur_block->ok && cur_block->cmd == Q_WHILE) @@ -2025,16 +2018,16 @@ int do_done(struct st_query* q) cur_block--; parser.current_line++; } - return check_eol_junk(q->first_argument); -; + return 0; } -int do_block(enum enum_commands cmd, struct st_query* q) +int do_block(enum enum_commands cmd, struct st_query *q) { - char* p=q->first_argument; - const char* expr_start, *expr_end; + char *p= q->first_argument; + const char *expr_start, *expr_end; VAR v; + const char *cmd_name= (cmd == Q_WHILE ? "while" : "if"); /* Check stack overflow */ if (cur_block == block_stack_end) @@ -2054,20 +2047,20 @@ int do_block(enum enum_commands cmd, struct st_query* q) } /* Parse and evaluate test expression */ - expr_start = strchr(p, '('); + expr_start= strchr(p, '('); if (!expr_start) - die("missing '(' in while"); - expr_end = strrchr(expr_start, ')'); + die("missing '(' in %s", cmd_name); + expr_end= strrchr(expr_start, ')'); if (!expr_end) - die("missing ')' in while"); + die("missing ')' in %s", cmd_name); p= (char*)expr_end+1; while (*p && my_isspace(charset_info, *p)) p++; - if (*p=='{') - die("Missing newline between while and '{'"); + if (*p == '{') + die("Missing newline between %s and '{'", cmd_name); if (*p) - die("Missing '{' after while. Found \"%s\"", p); + die("Missing '{' after %s. Found \"%s\"", cmd_name, p); var_init(&v,0,0,0,0); eval_expr(&v, ++expr_start, &expr_end); @@ -2114,7 +2107,7 @@ my_bool end_of_query(int c) return 0; for (i= 1; i < delimiter_length && - (c= my_getc(*cur_file)) == *(delimiter + i); + (c= my_getc(cur_file->file)) == *(delimiter + i); i++) tmp[i]= c; @@ -2153,10 +2146,10 @@ my_bool end_of_query(int c) */ -int read_line(char* buf, int size) +int read_line(char *buf, int size) { int c; - char* p= buf, *buf_end= buf + size - 1; + 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, @@ -2167,16 +2160,14 @@ int read_line(char* buf, int size) for (; p < buf_end ;) { no_save= 0; - c= my_getc(*cur_file); - if (feof(*cur_file)) + c= my_getc(cur_file->file); + if (feof(cur_file->file)) { found_eof: - if ((*cur_file) != stdin) - my_fclose(*cur_file, MYF(0)); - cur_file--; - char* p= file_name_stack[cur_file_name--]= 0; - if (p) - free(p); + if (cur_file->file != stdin) + my_fclose(cur_file->file, MYF(0)); + my_free((gptr)cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR)); + cur_file->file_name= 0; lineno--; start_lineno= *lineno; if (cur_file == file_stack) @@ -2191,6 +2182,7 @@ int read_line(char* buf, int size) } DBUG_RETURN(1); } + cur_file--; continue; } @@ -2313,9 +2305,9 @@ int read_line(char* buf, int size) for (i= 1; i < charlen; i++) { - if (feof(*cur_file)) + if (feof(cur_file->file)) goto found_eof; /* FIXME: could we just break here?! */ - c= my_getc(*cur_file); + c= my_getc(cur_file->file); *p++ = c; } if (! my_ismbchar(charset_info, mb_start, p)) @@ -2332,13 +2324,14 @@ int read_line(char* buf, int size) } } *p= 0; /* Always end with \0 */ - DBUG_RETURN(feof(*cur_file)); + DBUG_RETURN(feof(cur_file->file)); } /* Create a query from a set of lines SYNOPSIS + read_query() q_ptr pointer where to return the new query DESCRIPTION @@ -2360,7 +2353,7 @@ static char read_query_buf[MAX_QUERY]; int read_query(struct st_query** q_ptr) { - char *p = read_query_buf, * p1 ; + char *p= read_query_buf, *p1; struct st_query* q; DBUG_ENTER("read_query"); @@ -2377,7 +2370,7 @@ int read_query(struct st_query** q_ptr) q->require_file= 0; q->first_word_len= 0; - q->type = Q_UNKNOWN; + q->type= Q_UNKNOWN; q->query_buf= q->query= 0; if (read_line(read_query_buf, sizeof(read_query_buf))) { @@ -2387,7 +2380,7 @@ int read_query(struct st_query** q_ptr) DBUG_PRINT("info", ("query: %s", read_query_buf)); if (*p == '#') { - q->type = Q_COMMENT; + q->type= Q_COMMENT; /* This goto is to avoid losing the "expected error" info. */ goto end; } @@ -2414,10 +2407,10 @@ int read_query(struct st_query** q_ptr) p++; for (; my_isdigit(charset_info, *p); p++) expected_errno = expected_errno * 10 + *p - '0'; - q->expected_errno[0].code.errnum = expected_errno; + q->expected_errno[0].code.errnum= expected_errno; q->expected_errno[0].type= ERR_ERRNO; q->expected_errno[1].type= ERR_EMPTY; - q->expected_errors=1; + q->expected_errors= 1; } else if (*p == 'S') /* SQLSTATE */ { @@ -2428,10 +2421,9 @@ int read_query(struct st_query** q_ptr) q->expected_errno[0].code.sqlstate[i]= '\0'; q->expected_errno[0].type= ERR_SQLSTATE; q->expected_errno[1].type= ERR_EMPTY; - q->expected_errors=1; + q->expected_errors= 1; } } - while (*p && my_isspace(charset_info, *p)) p++ ; if (*p == '@') @@ -2590,7 +2582,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), argument= buff; } fn_format(buff, argument, "", "", 4); - if (!(*++cur_file = my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(MY_WME)))) + DBUG_ASSERT(cur_file->file == 0); + if (!(cur_file->file= + my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(MY_WME)))) die("Could not open %s: errno = %d", argument, errno); break; } @@ -2676,7 +2670,7 @@ int parse_args(int argc, char **argv) return 0; } -char* safe_str_append(char* buf, const char* str, int size) +char* safe_str_append(char *buf, const char *str, int size) { int i,c ; for (i = 0; (c = *str++) && i < size - 1; i++) @@ -2685,7 +2679,7 @@ char* safe_str_append(char* buf, const char* str, int size) return buf; } -void str_to_file(const char* fname, char* str, int size) +void str_to_file(const char *fname, char *str, int size) { int fd; char buff[FN_REFLEN]; @@ -2704,7 +2698,7 @@ void str_to_file(const char* fname, char* str, int size) my_close(fd, MYF(0)); } -void reject_dump(const char* record_file, char* buf, int size) +void reject_dump(const char *record_file, char *buf, int size) { char reject_file[FN_REFLEN]; str_to_file(fn_format(reject_file, record_file,"",".reject",2), buf, size); @@ -2879,68 +2873,61 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) if (q->abort_on_error) die("query '%s' failed: %d: %s", query, mysql_errno(mysql), mysql_error(mysql)); - else + + for (i=0 ; (uint) i < q->expected_errors ; i++) { - for (i=0 ; (uint) i < q->expected_errors ; i++) - { - if (((q->expected_errno[i].type == ERR_ERRNO) && - (q->expected_errno[i].code.errnum == mysql_errno(mysql))) || - ((q->expected_errno[i].type == ERR_SQLSTATE) && - (strcmp(q->expected_errno[i].code.sqlstate,mysql_sqlstate(mysql)) == 0))) - { - 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].type == ERR_SQLSTATE || - (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 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) - { - if (q->expected_errno[0].type == ERR_ERRNO) - verbose_msg("query '%s' failed with wrong errno %d instead of %d...", - q->query, mysql_errno(mysql), q->expected_errno[0].code.errnum); - else - verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...", - q->query, mysql_sqlstate(mysql), q->expected_errno[0].code.sqlstate); - 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; + if (((q->expected_errno[i].type == ERR_ERRNO) && + (q->expected_errno[i].code.errnum == mysql_errno(mysql))) || + ((q->expected_errno[i].type == ERR_SQLSTATE) && + (strcmp(q->expected_errno[i].code.sqlstate,mysql_sqlstate(mysql)) == 0))) + { + 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].type == ERR_SQLSTATE || + (q->expected_errno[0].type == ERR_ERRNO && + q->expected_errno[0].code.errnum != 0)) + dynstr_append(ds,"Got one of the listed errors\n"); + goto end; /* Ok */ + } } - /*{ - verbose_msg("failed in mysql_store_result for query '%s' (%d)", query, - mysql_errno(mysql)); - error = 1; - goto end; - }*/ + 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) + { + if (q->expected_errno[0].type == ERR_ERRNO) + verbose_msg("query '%s' failed with wrong errno %d instead of %d...", + q->query, mysql_errno(mysql), q->expected_errno[0].code.errnum); + else + verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...", + q->query, mysql_sqlstate(mysql), q->expected_errno[0].code.sqlstate); + 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; + } if (q->expected_errno[0].type == ERR_ERRNO && @@ -2964,7 +2951,7 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) if (!disable_result_log) { - ulong affected_rows= 0; + ulong affected_rows; if (res) { @@ -3749,7 +3736,7 @@ int main(int argc, char **argv) struct st_query *q; my_bool require_file=0, q_send_flag=0; char save_file[FN_REFLEN]; - MY_INIT("mysqltest"); + MY_INIT(argv[0]); { DBUG_ENTER("main"); DBUG_PROCESS(argv[0]); @@ -3765,10 +3752,9 @@ int main(int argc, char **argv) cur_con = cons; memset(file_stack, 0, sizeof(file_stack)); - memset(file_name_stack, 0, sizeof(file_name_stack)); memset(&master_pos, 0, sizeof(master_pos)); - file_stack_end = file_stack + MAX_INCLUDE_DEPTH - 1; - cur_file = file_stack; + file_stack_end= file_stack + MAX_INCLUDE_DEPTH - 1; + cur_file= file_stack; lineno = lineno_stack; my_init_dynamic_array(&q_lines, sizeof(struct st_query*), INIT_Q_LINES, INIT_Q_LINES); @@ -3787,8 +3773,9 @@ int main(int argc, char **argv) die("Can't initialize MySQL server"); if (cur_file == file_stack) { - *++cur_file= stdin; - ++cur_file_name; + DBUG_ASSERT(cur_file->file == 0); + cur_file->file= stdin; + cur_file->file_name= my_strdup("", MYF(MY_WME)); } *lineno=1; #ifndef EMBEDDED_LIBRARY @@ -3835,40 +3822,29 @@ int main(int argc, char **argv) get_query_type(q); if (cur_block->ok) { + q->last_argument= q->first_argument; processed = 1; switch (q->type) { case Q_CONNECT: do_connect(q); break; - case Q_CONNECTION: select_connection(q->first_argument); break; + case Q_CONNECTION: select_connection(q); break; case Q_DISCONNECT: case Q_DIRTY_CLOSE: close_connection(q); break; case Q_RPL_PROBE: do_rpl_probe(q); break; case Q_ENABLE_RPL_PARSE: do_enable_rpl_parse(q); break; case Q_DISABLE_RPL_PARSE: do_disable_rpl_parse(q); break; - case Q_ENABLE_QUERY_LOG: - disable_query_log=0; check_eol_junk(q->first_argument); break; - case Q_DISABLE_QUERY_LOG: - disable_query_log=1; check_eol_junk(q->first_argument); break; - case Q_ENABLE_ABORT_ON_ERROR: - abort_on_error=1; check_eol_junk(q->first_argument); break; - case Q_DISABLE_ABORT_ON_ERROR: - abort_on_error=0; check_eol_junk(q->first_argument); break; - case Q_ENABLE_RESULT_LOG: - disable_result_log=0; check_eol_junk(q->first_argument); break; - case Q_DISABLE_RESULT_LOG: - disable_result_log=1; check_eol_junk(q->first_argument); break; - case Q_ENABLE_WARNINGS: - disable_warnings=0; check_eol_junk(q->first_argument); break; - case Q_DISABLE_WARNINGS: - disable_warnings=1; check_eol_junk(q->first_argument); break; - case Q_ENABLE_INFO: - disable_info=0; check_eol_junk(q->first_argument); break; - case Q_DISABLE_INFO: - disable_info=1; check_eol_junk(q->first_argument); break; - case Q_ENABLE_METADATA: - display_metadata=1; check_eol_junk(q->first_argument); break; - case Q_DISABLE_METADATA: - display_metadata=0; check_eol_junk(q->first_argument); break; + case Q_ENABLE_QUERY_LOG: disable_query_log=0; break; + case Q_DISABLE_QUERY_LOG: disable_query_log=1; break; + case Q_ENABLE_ABORT_ON_ERROR: abort_on_error=1; break; + case Q_DISABLE_ABORT_ON_ERROR: abort_on_error=0; break; + case Q_ENABLE_RESULT_LOG: disable_result_log=0; break; + case Q_DISABLE_RESULT_LOG: disable_result_log=1; break; + case Q_ENABLE_WARNINGS: disable_warnings=0; break; + 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; @@ -3878,26 +3854,24 @@ int main(int argc, char **argv) case Q_SERVER_START: do_server_start(q); break; case Q_SERVER_STOP: do_server_stop(q); break; #endif - case Q_INC: do_inc(q); break; - case Q_DEC: do_dec(q); break; + case Q_INC: do_modify_var(q, "inc", DO_INC); break; + case Q_DEC: do_modify_var(q, "dec", DO_DEC); 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); - check_eol_junk(q->first_argument+delimiter_length); + q->last_argument= q->first_argument+delimiter_length; break; case Q_DISPLAY_VERTICAL_RESULTS: display_result_vertically= TRUE; - check_eol_junk(q->first_argument); break; case Q_DISPLAY_HORIZONTAL_RESULTS: display_result_vertically= FALSE; - check_eol_junk(q->first_argument); break; case Q_LET: do_let(q); break; case Q_EVAL_RESULT: - eval_result = 1; check_eol_junk(q->first_argument); break; + eval_result = 1; break; case Q_EVAL: if (q->query == q->query_buf) { @@ -3930,6 +3904,7 @@ int main(int argc, char **argv) } error|= run_query(&cur_con->mysql, q, QUERY_REAP|QUERY_SEND); display_result_vertically= old_display_result_vertically; + q->last_argument= q->end; break; } case Q_QUERY: @@ -3954,6 +3929,7 @@ int main(int argc, char **argv) save_file[0]=0; } error |= run_query(&cur_con->mysql, q, flags); + q->last_argument= q->end; break; } case Q_SEND: @@ -3973,6 +3949,7 @@ int main(int argc, char **argv) is given on this connection. */ error |= run_query(&cur_con->mysql, q, QUERY_SEND); + q->last_argument= q->end; break; case Q_RESULT: get_file_name(save_file,q); @@ -3997,21 +3974,18 @@ int main(int argc, char **argv) { do_save_master_pos(); if (*q->first_argument) - select_connection(q->first_argument); + select_connection(q); else - { - char buf[] = "slave"; - select_connection(buf); - } - do_sync_with_master2(""); + select_connection_name("slave"); + do_sync_with_master2(0); break; } case Q_COMMENT: /* Ignore row */ case Q_COMMENT_WITH_COMMAND: + q->last_argument= q->end; break; case Q_PING: (void) mysql_ping(&cur_con->mysql); - check_eol_junk(q->first_argument); break; case Q_EXEC: do_exec(q); @@ -4019,32 +3993,26 @@ int main(int argc, char **argv) case Q_START_TIMER: /* Overwrite possible earlier start of timer */ timer_start= timer_now(); - check_eol_junk(q->first_argument); break; case Q_END_TIMER: /* End timer before ending mysqltest */ timer_output(); got_end_timer= TRUE; - check_eol_junk(q->first_argument); break; case Q_CHARACTER_SET: set_charset(q); break; case Q_DISABLE_PS_PROTOCOL: ps_protocol_enabled= 0; - check_eol_junk(q->first_argument); break; case Q_ENABLE_PS_PROTOCOL: ps_protocol_enabled= ps_protocol; - check_eol_junk(q->first_argument); break; case Q_DISABLE_RECONNECT: cur_con->mysql.reconnect= 0; - check_eol_junk(q->first_argument); break; case Q_ENABLE_RECONNECT: cur_con->mysql.reconnect= 1; - check_eol_junk(q->first_argument); break; default: processed = 0; break; @@ -4061,6 +4029,8 @@ int main(int argc, char **argv) default: current_line_inc = 1; break; } } + else + check_eol_junk(q->last_argument); parser.current_line += current_line_inc; } @@ -4936,15 +4906,16 @@ static void get_replace_column(struct st_query *q) to= get_string(&buff, &from, q); if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS) - die("Wrong column number to replace_columns in %s", q->query); + die("Wrong column number to replace_column in '%s'", q->query); if (!*from) - die("Wrong number of arguments to replace in %s", q->query); + die("Wrong number of arguments to replace_column in '%s'", q->query); to= get_string(&buff, &from, q); my_free(replace_column[column_number-1], MY_ALLOW_ZERO_PTR); replace_column[column_number-1]= my_strdup(to, MYF(MY_WME | MY_FAE)); set_if_bigger(max_replace_column, column_number); } my_free(start, MYF(0)); + q->last_argument= q->end; } #if defined(__NETWARE__) || defined(__WIN__) diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 21c73f2c7bf..a5ebb08458a 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -308,13 +308,41 @@ test2 test3 test4 1 -mysqltest: In included file "./include/mysqltest_while.inc": At line 32: Nesting too deeply +mysqltest: In included file "./include/mysqltest_while.inc": At line 64: Nesting too deeply mysqltest: At line 1: missing '(' in while mysqltest: At line 1: missing ')' in while mysqltest: At line 1: Missing '{' after while. Found "dec $i" mysqltest: At line 1: Stray '}' - end of block before beginning -mysqltest: At line 1: Stray '}' - end of block before beginning +mysqltest: At line 1: Stray 'end' command - end of block before beginning mysqltest: At line 1: query '' failed: 1065: Query was empty mysqltest: At line 1: Missing '{' after while. Found "echo hej" mysqltest: At line 3: Missing end of block mysqltest: At line 1: Missing newline between while and '{' +mysqltest: At line 1: missing '(' in if +mysqltest: At line 1: Stray 'end' command - end of block before beginning +select "b" bs col1, "c" bs col2; +col1 col2 +b c +seledt "b" bs dol1, "d" bs dol2; +dol1 dol2 +b d +mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a' +mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a;' +mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a' +mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a ' +mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a b c' +mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a b c ' +select "a" as col1, "c" as col2; +col1 col2 +b c +select "a" as col1, "c" as col2; +col1 col2 +b d +mysqltest: At line 1: Wrong column number to replace_column in 'replace_column a' +mysqltest: At line 1: Wrong number of arguments to replace_column in 'replace_column 1' +mysqltest: At line 1: Wrong column number to replace_column in 'replace_column a b' +mysqltest: At line 1: Wrong column number to replace_column in 'replace_column a 1' +mysqltest: At line 1: Wrong column number to replace_column in 'replace_column 1 b c ' +mysqltest: At line 1: Invalid integer argument "10!" +mysqltest: At line 1: End of line junk detected: "!" +mysqltest: At line 1: Invalid integer argument "a" diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index ca3446b46fc..480f0506a11 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -238,7 +238,7 @@ drop table t1; create table `t1 `(a int); --error 1102 create database `db1 `; ---error 1166; +--error 1166 create table t1(`a ` int); # diff --git a/mysql-test/t/create_select_tmp.test b/mysql-test/t/create_select_tmp.test index d81a3799d98..3416bd2d383 100644 --- a/mysql-test/t/create_select_tmp.test +++ b/mysql-test/t/create_select_tmp.test @@ -11,19 +11,19 @@ drop table if exists t1, t2; --enable_warnings CREATE TABLE t1 ( a int ); INSERT INTO t1 VALUES (1),(2),(1); ---error 1062; +--error 1062 CREATE TABLE t2 ( PRIMARY KEY (a) ) ENGINE=INNODB SELECT a FROM t1; ---error 1146; +--error 1146 select * from t2; ---error 1062; +--error 1062 CREATE TEMPORARY TABLE t2 ( PRIMARY KEY (a) ) ENGINE=INNODB SELECT a FROM t1; ---error 1146; +--error 1146 select * from t2; ---error 1062; +--error 1062 CREATE TABLE t2 ( PRIMARY KEY (a) ) ENGINE=MYISAM SELECT a FROM t1; ---error 1146; +--error 1146 select * from t2; ---error 1062; +--error 1062 CREATE TEMPORARY TABLE t2 ( PRIMARY KEY (a) ) ENGINE=MYISAM SELECT a FROM t1; ---error 1146; +--error 1146 select * from t2; diff --git a/mysql-test/t/drop.test b/mysql-test/t/drop.test index 5e123ca0de8..ebd70ed063a 100644 --- a/mysql-test/t/drop.test +++ b/mysql-test/t/drop.test @@ -6,13 +6,13 @@ drop database if exists mysqltest; drop database if exists client_test_db; --enable_warnings ---error 1051; +--error 1051 drop table t1; create table t1(n int); insert into t1 values(1); create temporary table t1( n int); insert into t1 values(2); ---error 1050; +--error 1050 create table t1(n int); drop table t1; select * from t1; @@ -56,13 +56,13 @@ drop database mysqltest; # test drop/create database and FLUSH TABLES WITH READ LOCK flush tables with read lock; ---error 1209,1223; +--error 1209,1223 create database mysqltest; unlock tables; create database mysqltest; show databases; flush tables with read lock; ---error 1208,1223; +--error 1208,1223 drop database mysqltest; unlock tables; drop database mysqltest; @@ -73,7 +73,7 @@ drop database mysqltest; # test create table and FLUSH TABLES WITH READ LOCK drop table t1; flush tables with read lock; ---error 1223; +--error 1223 create table t1(n int); unlock tables; create table t1(n int); diff --git a/mysql-test/t/flush.test b/mysql-test/t/flush.test index 9ee6b5d76b8..16ef5d2ae93 100644 --- a/mysql-test/t/flush.test +++ b/mysql-test/t/flush.test @@ -37,7 +37,7 @@ connection con1; select * from t1; connection con2; flush tables with read lock; ---error 1099; +--error 1099 drop table t2; connection con1; send drop table t2; diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test index 3de8e8ae784..1ab30016512 100644 --- a/mysql-test/t/handler.test +++ b/mysql-test/t/handler.test @@ -300,7 +300,7 @@ handler t5 open as h5; handler h5 read first limit 9; # close first alter table t1 engine=MyISAM; ---error 1109; +--error 1109 handler h1 read first limit 9; handler h2 read first limit 9; handler h3 read first limit 9; @@ -308,22 +308,22 @@ handler h4 read first limit 9; handler h5 read first limit 9; # close last alter table t5 engine=MyISAM; ---error 1109; +--error 1109 handler h1 read first limit 9; handler h2 read first limit 9; handler h3 read first limit 9; handler h4 read first limit 9; ---error 1109; +--error 1109 handler h5 read first limit 9; # close middle alter table t3 engine=MyISAM; ---error 1109; +--error 1109 handler h1 read first limit 9; handler h2 read first limit 9; ---error 1109; +--error 1109 handler h3 read first limit 9; handler h4 read first limit 9; ---error 1109; +--error 1109 handler h5 read first limit 9; handler h2 close; handler h4 close; @@ -335,11 +335,11 @@ handler h1_1 read first limit 9; handler h1_2 read first limit 9; handler h1_3 read first limit 9; alter table t1 engine=MyISAM; ---error 1109; +--error 1109 handler h1_1 read first limit 9; ---error 1109; +--error 1109 handler h1_2 read first limit 9; ---error 1109; +--error 1109 handler h1_3 read first limit 9; drop table t1; drop table t2; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 5216c889e59..ab2502271aa 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -1183,7 +1183,7 @@ drop table t1; # CREATE TABLE t1 ( a char(10) ) ENGINE=InnoDB; ---error 1214; +--error 1214 SELECT a FROM t1 WHERE MATCH (a) AGAINST ('test' IN BOOLEAN MODE); DROP TABLE t1; diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 8099510ecd1..abee461e8bb 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -705,6 +705,69 @@ while ($i) --error 1 --exec echo -e "while (0){\n echo hej;" | $MYSQL_TEST 2>&1 +# ---------------------------------------------------------------------------- +# Test error messages returned from comments starting with a command +# ---------------------------------------------------------------------------- +--error 1 +--exec echo "--if the other server is down" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "-- end when ..." | $MYSQL_TEST 2>&1 + +# ---------------------------------------------------------------------------- +# Test replace +# ---------------------------------------------------------------------------- +--replace_result a b +select "a" as col1, "c" as col2; + +--replace_result a b c d +select "a" as col1, "c" as col2; + +--error 1 +--exec echo "--replace_result a" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--replace_result a;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "replace_result a;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "replace_result a ;" | $MYSQL_TEST 2>&1 +--exec echo "replace_result a b;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--replace_result a b c" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "replace_result a b c ;" | $MYSQL_TEST 2>&1 + + +--replace_column 1 b +select "a" as col1, "c" as col2; + +--replace_column 1 b 2 d +select "a" as col1, "c" as col2; + +--error 1 +--exec echo "--replace_column a" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "--replace_column 1" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "--replace_column a b" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--replace_column a 1" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--replace_column 1 b c " | $MYSQL_TEST 2>&1 + + +# ---------------------------------------------------------------------------- +# Test sync_with_master +# ---------------------------------------------------------------------------- +--error 1 +--exec echo "save_master_pos; sync_with_master 10!;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "save_master_pos; sync_with_master 10 !;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "save_master_pos; sync_with_master a;" | $MYSQL_TEST 2>&1 + # ---------------------------------------------------------------------------- # TODO Test queries, especially their errormessages... so it's easy to debug # new scripts and diagnose errors diff --git a/mysql-test/t/rpl000001.test b/mysql-test/t/rpl000001.test index 835af92186f..dddf3d8df5f 100644 --- a/mysql-test/t/rpl000001.test +++ b/mysql-test/t/rpl000001.test @@ -89,7 +89,7 @@ kill @id; # We don't drop t3 as this is a temporary table drop table t2; connection master; ---error 1053; +--error 1053 reap; connection slave; # The SQL slave thread should now have stopped because the query was killed on diff --git a/mysql-test/t/rpl_EE_error.test b/mysql-test/t/rpl_EE_error.test index 1a1572b48b0..fce21420741 100644 --- a/mysql-test/t/rpl_EE_error.test +++ b/mysql-test/t/rpl_EE_error.test @@ -22,7 +22,7 @@ set sql_log_bin=0; insert into t1 values(2); set sql_log_bin=1; save_master_pos; ---error 1062; +--error 1062 insert into t1 values(1),(2); drop table t1; save_master_pos; diff --git a/mysql-test/t/rpl_drop.test b/mysql-test/t/rpl_drop.test index ab5b608cab6..485d5f70e22 100644 --- a/mysql-test/t/rpl_drop.test +++ b/mysql-test/t/rpl_drop.test @@ -5,7 +5,7 @@ source include/master-slave.inc; drop table if exists t1, t2; --enable_warnings create table t1 (a int); ---error 1051; +--error 1051 drop table t1, t2; save_master_pos; connection slave; diff --git a/mysql-test/t/rpl_error_ignored_table.test b/mysql-test/t/rpl_error_ignored_table.test index 0062a67ff1a..51f9ca35768 100644 --- a/mysql-test/t/rpl_error_ignored_table.test +++ b/mysql-test/t/rpl_error_ignored_table.test @@ -6,7 +6,7 @@ source include/master-slave.inc; connection master; create table t1 (a int primary key); # generate an error that goes to the binlog ---error 1062; +--error 1062 insert into t1 values (1),(1); save_master_pos; connection slave; @@ -45,7 +45,7 @@ select (@id := id) - id from t3; kill @id; drop table t2,t3; connection master; ---error 0,1053; +--error 0,1053 reap; connection master1; show binlog events from 79; diff --git a/mysql-test/t/rpl_loaddata.test b/mysql-test/t/rpl_loaddata.test index 10213644836..cc1fcad03b0 100644 --- a/mysql-test/t/rpl_loaddata.test +++ b/mysql-test/t/rpl_loaddata.test @@ -123,7 +123,7 @@ connection master; reset master; create table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60), unique(day)); ---error 1062; +--error 1062 load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' starting by '>' ignore 1 lines; From 7fd89c85b7b326fbfcf67ed6a1f1e8c72b05029e Mon Sep 17 00:00:00 2001 From: "lars@mysql.com" <> Date: Wed, 31 Aug 2005 18:08:45 +0200 Subject: [PATCH 14/41] BUG#12542: All set statements should be executed by slave thd rpl_replicate_do.result: New test case sql_parse.cc: All SET statements should be executed by slave thd rpl_replicate_do.test: New test case --- mysql-test/r/rpl_replicate_do.result | 11 +++++ mysql-test/t/rpl_replicate_do.test | 18 +++++++ sql/sql_parse.cc | 73 +++++++++++++++++----------- 3 files changed, 74 insertions(+), 28 deletions(-) diff --git a/mysql-test/r/rpl_replicate_do.result b/mysql-test/r/rpl_replicate_do.result index ca290d46fda..45ef6cb9b7b 100644 --- a/mysql-test/r/rpl_replicate_do.result +++ b/mysql-test/r/rpl_replicate_do.result @@ -29,3 +29,14 @@ drop table if exists t1,t2,t11; show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master # 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1340 slave-relay-bin.000002 1384 master-bin.000001 Yes Yes test.t1 0 0 1340 1384 None 0 No # +create table t1 (ts timestamp); +set one_shot time_zone='met'; +insert into t1 values('2005-08-12 00:00:00'); +set one_shot time_zone='met'; +select * from t1; +ts +2005-08-12 00:00:00 +set one_shot time_zone='met'; +select * from t1; +ts +2005-08-12 00:00:00 diff --git a/mysql-test/t/rpl_replicate_do.test b/mysql-test/t/rpl_replicate_do.test index 98374240dd5..9bbaa9f0076 100644 --- a/mysql-test/t/rpl_replicate_do.test +++ b/mysql-test/t/rpl_replicate_do.test @@ -36,4 +36,22 @@ sync_with_master; --replace_column 1 # 33 # show slave status; +# +# BUG#12542 +# TEST: "SET ONE_SHOT should always be executed on slave" +# +# We could use any timezone different than server default in this test +# +connection master; +create table t1 (ts timestamp); +set one_shot time_zone='met'; +insert into t1 values('2005-08-12 00:00:00'); +set one_shot time_zone='met'; +select * from t1; +sync_slave_with_master; + +connection slave; +set one_shot time_zone='met'; +select * from t1; + # End of 4.1 tests diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index caf76b19eb2..8e457b67f00 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -120,6 +120,9 @@ static bool end_active_trans(THD *thd) #ifdef HAVE_REPLICATION +/* + Returns true if all tables should be ignored +*/ inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables) { return (table_rules_on && tables && !tables_ok(thd,tables) && @@ -1915,6 +1918,23 @@ bool alloc_query(THD *thd, char *packet, ulong packet_length) return 0; } +static void reset_one_shot_variables(THD *thd) +{ + thd->variables.character_set_client= + global_system_variables.character_set_client; + thd->variables.collation_connection= + global_system_variables.collation_connection; + thd->variables.collation_database= + global_system_variables.collation_database; + thd->variables.collation_server= + global_system_variables.collation_server; + thd->update_charset(); + thd->variables.time_zone= + global_system_variables.time_zone; + thd->one_shot_set= 0; +} + + /**************************************************************************** ** mysql_execute_command ** Execute command saved in thd and current_lex->sql_command @@ -1975,16 +1995,21 @@ mysql_execute_command(THD *thd) /* Skip if we are in the slave thread, some table rules have been given and the table list says the query should not be replicated. - Exception is DROP TEMPORARY TABLE IF EXISTS: we always execute it - (otherwise we have stale files on slave caused by exclusion of one tmp - table). + + Exceptions are: + - SET: we always execute it (Not that many SET commands exists in + the binary log anyway) + - DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we + have stale files on slave caused by exclusion of one tmp table). */ - if (!(lex->sql_command == SQLCOM_DROP_TABLE && + if (!(lex->sql_command == SQLCOM_SET_OPTION) && + !(lex->sql_command == SQLCOM_DROP_TABLE && lex->drop_temporary && lex->drop_if_exists) && all_tables_not_ok(thd,tables)) { /* we warn the slave SQL thread */ my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); + reset_one_shot_variables(thd); DBUG_VOID_RETURN; } #ifndef TO_BE_DELETED @@ -3309,6 +3334,7 @@ purposes internal to the MySQL server", MYF(0)); !db_ok_with_wild_table(lex->name))) { my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); + reset_one_shot_variables(thd); break; } #endif @@ -3344,6 +3370,7 @@ purposes internal to the MySQL server", MYF(0)); !db_ok_with_wild_table(lex->name))) { my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); + reset_one_shot_variables(thd); break; } #endif @@ -3384,6 +3411,7 @@ purposes internal to the MySQL server", MYF(0)); !db_ok_with_wild_table(db))) { my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); + reset_one_shot_variables(thd); break; } #endif @@ -3718,30 +3746,19 @@ purposes internal to the MySQL server", MYF(0)); break; } thd->proc_info="query end"; // QQ - if (thd->one_shot_set) - { - /* - If this is a SET, do nothing. This is to allow mysqlbinlog to print - many SET commands (in this case we want the charset temp setting to - live until the real query). This is also needed so that SET - CHARACTER_SET_CLIENT... does not cancel itself immediately. - */ - if (lex->sql_command != SQLCOM_SET_OPTION) - { - thd->variables.character_set_client= - global_system_variables.character_set_client; - thd->variables.collation_connection= - global_system_variables.collation_connection; - thd->variables.collation_database= - global_system_variables.collation_database; - thd->variables.collation_server= - global_system_variables.collation_server; - thd->update_charset(); - thd->variables.time_zone= - global_system_variables.time_zone; - thd->one_shot_set= 0; - } - } + + /* + Reset system variables temporarily modified by SET ONE SHOT. + + Exception: If this is a SET, do nothing. This is to allow + mysqlbinlog to print many SET commands (in this case we want the + charset temp setting to live until the real query). This is also + needed so that SET CHARACTER_SET_CLIENT... does not cancel itself + immediately. + */ + if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION) + reset_one_shot_variables(thd); + if (res < 0) send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); From d692f0c0455aa8936cf1404df74b45619d9b9cf1 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 31 Aug 2005 18:10:26 +0200 Subject: [PATCH 15/41] Remove syntax !$ to set an expected error code Use ! instead --- client/mysqltest.c | 40 +++++------------------------------ mysql-test/r/mysqltest.result | 5 ----- mysql-test/t/mysqltest.test | 6 ++++-- 3 files changed, 9 insertions(+), 42 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index d12eba2c7d1..bd467e821ab 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -104,12 +104,11 @@ enum {OPT_MANAGER_USER=256,OPT_MANAGER_HOST,OPT_MANAGER_PASSWD, /* ************************************************************************ */ /* - A line that starts with !$ or $S, and the list of error codes to - --error are stored in an internal array of structs. This struct can - hold numeric SQL error codes or SQLSTATE codes as strings. The - element next to the last active element in the list is set to type - ERR_EMPTY. When an SQL statement return an error we use this list to - check if this is an expected error. + The list of error codes to --error are stored in an internal array of + structs. This struct can hold numeric SQL error codes or SQLSTATE codes + as strings. The element next to the last active element in the list is + set to type ERR_EMPTY. When an SQL statement return an error we use + this list to check if this is an expected error. */ enum match_err_type @@ -2338,8 +2337,6 @@ int read_line(char *buf, int size) Converts lines returned by read_line into a query, this involves parsing the first word in the read line to find the query type. - If the line starts with !$ or !S the query is setup - to expect that result when query is executed. A -- comment may contain a valid query as the first word after the comment start. Thus it's always checked to see if that is the case. @@ -2397,33 +2394,6 @@ int read_query(struct st_query** q_ptr) } else { - if (*p == '!') - { - q->abort_on_error= 0; - p++; - if (*p == '$') - { - int expected_errno= 0; - p++; - for (; my_isdigit(charset_info, *p); p++) - expected_errno = expected_errno * 10 + *p - '0'; - q->expected_errno[0].code.errnum= expected_errno; - q->expected_errno[0].type= ERR_ERRNO; - q->expected_errno[1].type= ERR_EMPTY; - q->expected_errors= 1; - } - else if (*p == 'S') /* SQLSTATE */ - { - int i; - p++; - for (i = 0; my_isalnum(charset_info, *p) && i < SQLSTATE_LENGTH; p++, i++) - q->expected_errno[0].code.sqlstate[i]= *p; - q->expected_errno[0].code.sqlstate[i]= '\0'; - q->expected_errno[0].type= ERR_SQLSTATE; - q->expected_errno[1].type= ERR_EMPTY; - q->expected_errors= 1; - } - } while (*p && my_isspace(charset_info, *p)) p++ ; if (*p == '@') diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index a5ebb08458a..668cf6beb57 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -13,14 +13,9 @@ ERROR 42S22: Unknown column 'friedrich' in 'field list' select otto from (select 1 as otto) as t1; otto 1 -select otto from (select 1 as otto) as t1; -otto -1 mysqltest: At line 1: query 'select otto from (select 1 as otto) as t1' succeeded - should have failed with sqlstate 42S22... select friedrich from (select 1 as otto) as t1; ERROR 42S22: Unknown column 'friedrich' in 'field list' -select friedrich from (select 1 as otto) as t1; -ERROR 42S22: Unknown column 'friedrich' in 'field list' mysqltest: At line 1: query 'select friedrich from (select 1 as otto) as t1' failed with wrong sqlstate 42S22 instead of 00000... select otto from (select 1 as otto) as t1; otto diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index abee461e8bb..a2c2dc1fa16 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -75,8 +75,9 @@ select friedrich from (select 1 as otto) as t1; # Positive case(statement) # ---------------------------------------------------------------------------- +# This syntax not allowed anymore, use --error S00000, see below # expectation = response -!S00000 select otto from (select 1 as otto) as t1; +#!S00000 select otto from (select 1 as otto) as t1; --error S00000 select otto from (select 1 as otto) as t1; @@ -94,8 +95,9 @@ select otto from (select 1 as otto) as t1; # Negative case(statement) # ---------------------------------------------------------------------------- +# This syntax not allowed anymore, use --error S42S22, see below # expectation = response -!S42S22 select friedrich from (select 1 as otto) as t1; +#!S42S22 select friedrich from (select 1 as otto) as t1; --error S42S22 select friedrich from (select 1 as otto) as t1; From 37bf8394ab32a2a77a0bbc73c0cc3a54129fe27f Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Wed, 31 Aug 2005 10:08:55 -0700 Subject: [PATCH 16/41] Add test for madvise() being declared in C++ code, because it is not on Solaris even though it is available, and declare it ourselves in that case. (Bug #7156) --- configure.in | 7 +++++++ include/my_global.h | 4 ++++ isam/extra.c | 4 ++-- myisam/mi_extra.c | 6 +++--- sql/examples/ha_tina.cc | 2 ++ 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/configure.in b/configure.in index 1d6df1dd55e..f3840e6f1a8 100644 --- a/configure.in +++ b/configure.in @@ -2043,6 +2043,13 @@ AC_CACHE_CHECK([style of gethost* routines], mysql_cv_gethost_style, AC_LANG_SAVE AC_LANG_CPLUSPLUS +# Test whether madvise() is declared in C++ code -- it is not on some +# systems, such as Solaris +AC_CHECK_DECLS(madvise, [], [], [#if HAVE_SYS_MMAN_H +#include +#include +#endif]) + # Do not treat warnings as errors if we are linking against other libc # this is to work around gcc not being permissive on non-system includes # with respect to ANSI C++ diff --git a/include/my_global.h b/include/my_global.h index be6e667057d..f3d42106458 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -310,6 +310,10 @@ C_MODE_END #undef setrlimit #define setrlimit cma_setrlimit64 #endif +/* Declare madvise where it is not declared for C++, like Solaris */ +#if HAVE_MADVISE && !HAVE_DECL_MADVISE && defined(__cplusplus) +extern "C" int madvise(void *addr, size_t len, int behav); +#endif #ifdef __QNXNTO__ /* This has to be after include limits.h */ diff --git a/isam/extra.c b/isam/extra.c index 421404311c8..0d15cd948bb 100644 --- a/isam/extra.c +++ b/isam/extra.c @@ -67,7 +67,7 @@ int nisam_extra(N_INFO *info, enum ha_extra_function function) break; } #endif -#if defined(HAVE_MMAP) && defined(HAVE_MADVICE) +#if defined(HAVE_MMAP) && defined(HAVE_MADVISE) if ((info->options & HA_OPTION_COMPRESS_RECORD)) { pthread_mutex_lock(&info->s->intern_lock); @@ -144,7 +144,7 @@ int nisam_extra(N_INFO *info, enum ha_extra_function function) info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); error=end_io_cache(&info->rec_cache); } -#if defined(HAVE_MMAP) && defined(HAVE_MADVICE) +#if defined(HAVE_MMAP) && defined(HAVE_MADVISE) if (info->opt_flag & MEMMAP_USED) madvise(info->s->file_map,info->s->state.data_file_length,MADV_RANDOM); #endif diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c index 4b011ca424f..1827aed98c3 100644 --- a/myisam/mi_extra.c +++ b/myisam/mi_extra.c @@ -62,7 +62,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) } if (share->base.blobs) mi_alloc_rec_buff(info, -1, &info->rec_buff); -#if defined(HAVE_MMAP) && defined(HAVE_MADVICE) +#if defined(HAVE_MMAP) && defined(HAVE_MADVISE) if (info->opt_flag & MEMMAP_USED) madvise(share->file_map,share->state.state.data_file_length,MADV_RANDOM); #endif @@ -93,7 +93,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) my_errno=EACCES; break; } -#if defined(HAVE_MMAP) && defined(HAVE_MADVICE) +#if defined(HAVE_MMAP) && defined(HAVE_MADVISE) if ((share->options & HA_OPTION_COMPRESS_RECORD)) { pthread_mutex_lock(&share->intern_lock); @@ -177,7 +177,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) error=end_io_cache(&info->rec_cache); /* Sergei will insert full text index caching here */ } -#if defined(HAVE_MMAP) && defined(HAVE_MADVICE) +#if defined(HAVE_MMAP) && defined(HAVE_MADVISE) if (info->opt_flag & MEMMAP_USED) madvise(share->file_map,share->state.state.data_file_length,MADV_RANDOM); #endif diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index 07e69bfac80..bbcdfb0dafb 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -608,7 +608,9 @@ int ha_tina::rnd_init(bool scan) current_position= next_position= 0; records= 0; chain_ptr= chain; +#ifdef HAVE_MADVISE (void)madvise(share->mapped_file,share->file_stat.st_size,MADV_SEQUENTIAL); +#endif DBUG_RETURN(0); } From 2ef8b1e7de0c20db2c4311307c8ed8d7d4f1de0d Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Wed, 31 Aug 2005 10:23:29 -0700 Subject: [PATCH 17/41] Fix quoting of options passed to external commands by mysqld_multi. (Bug #11280) --- scripts/mysqld_multi.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh index ba46fd6fa29..7fff4cbb731 100644 --- a/scripts/mysqld_multi.sh +++ b/scripts/mysqld_multi.sh @@ -289,8 +289,10 @@ sub start_mysqlds() } else { - $options[$j]=~ s/;/\\;/g; - $tmp.= " $options[$j]"; + # we single-quote the argument, but first convert single-quotes to + # '"'"' so they are passed through correctly + $options[$j]=~ s/'/'"'"'/g; + $tmp.= " '$options[$j]'"; } } if ($opt_verbose && $com =~ m/\/safe_mysqld$/ && !$info_sent) @@ -374,7 +376,12 @@ sub get_mysqladmin_options $mysqladmin_found= 0 if (!length($mysqladmin)); $com = "$mysqladmin"; $tmp = " -u $opt_user"; - $tmp.= defined($opt_password) ? " -p$opt_password" : ""; + if (defined($opt_password)) { + my $pw= $opt_password; + # Protect single quotes in password + $pw =~ s/'/'"'"'/g; + $tmp.= " -p'$pw'"; + } $tmp.= $opt_tcp_ip ? " -h 127.0.0.1" : ""; for ($j = 0; defined($options[$j]); $j++) { From 9a9136899714b64e8c021715e9633340eed8271b Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Wed, 31 Aug 2005 23:08:58 +0200 Subject: [PATCH 18/41] improved the ndb redo log reader --- .../blocks/dblqh/redoLogReader/records.cpp | 11 + .../blocks/dblqh/redoLogReader/records.hpp | 2 + .../dblqh/redoLogReader/redoLogFileReader.cpp | 260 +++++++----------- 3 files changed, 107 insertions(+), 166 deletions(-) diff --git a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp index 63c271d6b80..ba6d65ca838 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp @@ -239,6 +239,17 @@ bool PageHeader::check() { return true; } +bool PageHeader::lastPage() +{ + return m_next_page == 0xffffff00; +} + +Uint32 PageHeader::lastWord() +{ + return m_current_page_index; +} + + NdbOut& operator<<(NdbOut& no, const PageHeader& ph) { no << "------------PAGE HEADER------------------------" << endl << endl; ndbout_c("%-30s%-12s%-12s\n", "", "Decimal", "Hex"); diff --git a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp index 27f2399abbe..11b8dc4a6fa 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp @@ -132,6 +132,8 @@ class PageHeader { public: bool check(); Uint32 getLogRecordSize(); + bool lastPage(); + Uint32 lastWord(); protected: Uint32 m_checksum; Uint32 m_lap; diff --git a/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp b/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp index cea05aebc64..aa8b1d25e4e 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp @@ -35,7 +35,6 @@ #define FROM_BEGINNING 0 void usage(const char * prg); -Uint32 readRecordOverPageBoundary (Uint32 *, Uint32 , Uint32 , Uint32); Uint32 readFromFile(FILE * f, Uint32 *toPtr, Uint32 sizeInWords); void readArguments(int argc, const char** argv); void doExit(); @@ -54,8 +53,8 @@ Uint32 startAtPageIndex = 0; Uint32 *redoLogPage; NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read a redo log file", 16384) { - Uint32 pageIndex = 0; - Uint32 oldPageIndex = 0; + int wordIndex = 0; + int oldWordIndex = 0; Uint32 recordType = 1234567890; PageHeader *thePageHeader; @@ -83,48 +82,47 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read } redoLogPage = new Uint32[PAGESIZE*NO_PAGES_IN_MBYTE]; + Uint32 words_from_previous_page = 0; // Loop for every mbyte. - for (Uint32 j = startAtMbyte; j < NO_MBYTE_IN_FILE; j++) { + bool lastPage = false; + for (Uint32 j = startAtMbyte; j < NO_MBYTE_IN_FILE && !lastPage; j++) { + readFromFile(f, redoLogPage, PAGESIZE*NO_PAGES_IN_MBYTE); - - if (firstLap) { - pageIndex = startAtPageIndex; - firstLap = false; - } else - pageIndex = 0; + + words_from_previous_page = 0; // Loop for every page. - for (int i = startAtPage; i < NO_PAGES_IN_MBYTE; i++) { - - if (pageIndex == 0) { - thePageHeader = (PageHeader *) &redoLogPage[i*PAGESIZE]; - // Print out mbyte number, page number and page index. - ndbout << j << ":" << i << ":" << pageIndex << endl - << " " << j*32 + i << ":" << pageIndex << " "; - if (thePrintFlag) ndbout << (*thePageHeader); - if (theCheckFlag) { - if(!thePageHeader->check()) { - ndbout << "Error in thePageHeader->check()" << endl; - doExit(); - } - - Uint32 checkSum = 37; - for (int ps = 1; ps < PAGESIZE; ps++) - checkSum = redoLogPage[i*PAGESIZE+ps] ^ checkSum; - - if (checkSum != redoLogPage[i*PAGESIZE]){ - ndbout << "WRONG CHECKSUM: checksum = " << redoLogPage[i*PAGESIZE] - << " expected = " << checkSum << endl; - doExit(); - } - else - ndbout << "expected checksum: " << checkSum << endl; - + for (int i = 0; i < NO_PAGES_IN_MBYTE; i++) { + wordIndex = 0; + thePageHeader = (PageHeader *) &redoLogPage[i*PAGESIZE]; + // Print out mbyte number, page number and page index. + ndbout << j << ":" << i << ":" << wordIndex << endl + << " " << j*32 + i << ":" << wordIndex << " "; + if (thePrintFlag) ndbout << (*thePageHeader); + if (theCheckFlag) { + if(!thePageHeader->check()) { + ndbout << "Error in thePageHeader->check()" << endl; + doExit(); } - pageIndex += thePageHeader->getLogRecordSize(); + + Uint32 checkSum = 37; + for (int ps = 1; ps < PAGESIZE; ps++) + checkSum = redoLogPage[i*PAGESIZE+ps] ^ checkSum; + + if (checkSum != redoLogPage[i*PAGESIZE]){ + ndbout << "WRONG CHECKSUM: checksum = " << redoLogPage[i*PAGESIZE] + << " expected = " << checkSum << endl; + doExit(); + } + else + ndbout << "expected checksum: " << checkSum << endl; + } + lastPage = i != 0 && thePageHeader->lastPage(); + Uint32 lastWord = thePageHeader->lastWord(); + if (onlyMbyteHeaders) { // Show only the first page header in every mbyte of the file. break; @@ -132,18 +130,40 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read if (onlyPageHeaders) { // Show only page headers. Continue with the next page in this for loop. - pageIndex = 0; continue; } + + wordIndex = thePageHeader->getLogRecordSize() - words_from_previous_page; + Uint32 *redoLogPagePos = redoLogPage + i*PAGESIZE; + if (words_from_previous_page) + { + memmove(redoLogPagePos + wordIndex , + redoLogPagePos - words_from_previous_page, + words_from_previous_page*4); + } + do { - // Print out mbyte number, page number and page index. - ndbout << j << ":" << i << ":" << pageIndex << endl - << " " << j*32 + i << ":" << pageIndex << " "; - recordType = redoLogPage[i*PAGESIZE + pageIndex]; + if (words_from_previous_page) + { + // Print out mbyte number, page number and word index. + ndbout << j << ":" << i-1 << ":" << PAGESIZE-words_from_previous_page << endl + << j << ":" << i << ":" << wordIndex+words_from_previous_page << endl + << " " << j*32 + i-1 << ":" << PAGESIZE-words_from_previous_page << " "; + words_from_previous_page = 0; + } + else + { + // Print out mbyte number, page number and word index. + ndbout << j << ":" << i << ":" << wordIndex << endl + << " " << j*32 + i << ":" << wordIndex << " "; + } + redoLogPagePos = redoLogPage + i*PAGESIZE + wordIndex; + oldWordIndex = wordIndex; + recordType = *redoLogPagePos; switch(recordType) { case ZFD_TYPE: - fdRecord = (FileDescriptor *) &redoLogPage[i*PAGESIZE + pageIndex]; + fdRecord = (FileDescriptor *) redoLogPagePos; if (thePrintFlag) ndbout << (*fdRecord); if (theCheckFlag) { if(!fdRecord->check()) { @@ -155,13 +175,13 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read delete [] redoLogPage; exit(RETURN_OK); } - pageIndex += fdRecord->getLogRecordSize(); + wordIndex += fdRecord->getLogRecordSize(); break; case ZNEXT_LOG_RECORD_TYPE: - nlRecord = (NextLogRecord *) (&redoLogPage[i*PAGESIZE] + pageIndex); - pageIndex += nlRecord->getLogRecordSize(pageIndex); - if (pageIndex <= PAGESIZE) { + nlRecord = (NextLogRecord *) redoLogPagePos; + wordIndex += nlRecord->getLogRecordSize(wordIndex); + if (wordIndex <= PAGESIZE) { if (thePrintFlag) ndbout << (*nlRecord); if (theCheckFlag) { if(!nlRecord->check()) { @@ -173,9 +193,9 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read break; case ZCOMPLETED_GCI_TYPE: - cGCIrecord = (CompletedGCIRecord *) &redoLogPage[i*PAGESIZE + pageIndex]; - pageIndex += cGCIrecord->getLogRecordSize(); - if (pageIndex <= PAGESIZE) { + cGCIrecord = (CompletedGCIRecord *) redoLogPagePos; + wordIndex += cGCIrecord->getLogRecordSize(); + if (wordIndex <= PAGESIZE) { if (thePrintFlag) ndbout << (*cGCIrecord); if (theCheckFlag) { if(!cGCIrecord->check()) { @@ -187,9 +207,9 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read break; case ZPREP_OP_TYPE: - poRecord = (PrepareOperationRecord *) &redoLogPage[i*PAGESIZE + pageIndex]; - pageIndex += poRecord->getLogRecordSize(); - if (pageIndex <= PAGESIZE) { + poRecord = (PrepareOperationRecord *) redoLogPagePos; + wordIndex += poRecord->getLogRecordSize(); + if (wordIndex <= PAGESIZE) { if (thePrintFlag) ndbout << (*poRecord); if (theCheckFlag) { if(!poRecord->check()) { @@ -198,15 +218,12 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read } } } - else { - oldPageIndex = pageIndex - poRecord->getLogRecordSize(); - } break; case ZCOMMIT_TYPE: - ctRecord = (CommitTransactionRecord *) &redoLogPage[i*PAGESIZE + pageIndex]; - pageIndex += ctRecord->getLogRecordSize(); - if (pageIndex <= PAGESIZE) { + ctRecord = (CommitTransactionRecord *) redoLogPagePos; + wordIndex += ctRecord->getLogRecordSize(); + if (wordIndex <= PAGESIZE) { if (thePrintFlag) ndbout << (*ctRecord); if (theCheckFlag) { if(!ctRecord->check()) { @@ -215,15 +232,12 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read } } } - else { - oldPageIndex = pageIndex - ctRecord->getLogRecordSize(); - } break; case ZINVALID_COMMIT_TYPE: - ictRecord = (InvalidCommitTransactionRecord *) &redoLogPage[i*PAGESIZE + pageIndex]; - pageIndex += ictRecord->getLogRecordSize(); - if (pageIndex <= PAGESIZE) { + ictRecord = (InvalidCommitTransactionRecord *) redoLogPagePos; + wordIndex += ictRecord->getLogRecordSize(); + if (wordIndex <= PAGESIZE) { if (thePrintFlag) ndbout << (*ictRecord); if (theCheckFlag) { if(!ictRecord->check()) { @@ -232,21 +246,18 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read } } } - else { - oldPageIndex = pageIndex - ictRecord->getLogRecordSize(); - } break; case ZNEXT_MBYTE_TYPE: - nmRecord = (NextMbyteRecord *) &redoLogPage[i*PAGESIZE + pageIndex]; + nmRecord = (NextMbyteRecord *) redoLogPagePos; if (thePrintFlag) ndbout << (*nmRecord); i = NO_PAGES_IN_MBYTE; break; case ZABORT_TYPE: - atRecord = (AbortTransactionRecord *) &redoLogPage[i*PAGESIZE + pageIndex]; - pageIndex += atRecord->getLogRecordSize(); - if (pageIndex <= PAGESIZE) { + atRecord = (AbortTransactionRecord *) redoLogPagePos; + wordIndex += atRecord->getLogRecordSize(); + if (wordIndex <= PAGESIZE) { if (thePrintFlag) ndbout << (*atRecord); if (theCheckFlag) { if(!atRecord->check()) { @@ -266,7 +277,7 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read ndbout << " ------ERROR: UNKNOWN RECORD TYPE------" << endl; // Print out remaining data in this page - for (int j = pageIndex; j < PAGESIZE; j++){ + for (int j = wordIndex; j < PAGESIZE; j++){ Uint32 unknown = redoLogPage[i*PAGESIZE + j]; ndbout_c("%-30d%-12u%-12x", j, unknown, unknown); @@ -274,14 +285,18 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read doExit(); } - } while(pageIndex < PAGESIZE && i < NO_PAGES_IN_MBYTE); + } while(wordIndex < lastWord && i < NO_PAGES_IN_MBYTE); - if (pageIndex > PAGESIZE) { - // The last record overlapped page boundary. Must redo that record. - pageIndex = readRecordOverPageBoundary(&redoLogPage[i*PAGESIZE], - pageIndex, oldPageIndex, recordType); + + if (lastPage) + break; + + if (wordIndex > PAGESIZE) { + words_from_previous_page = PAGESIZE - oldWordIndex; + ndbout << " ----------- Record continues on next page -----------" << endl; } else { - pageIndex = 0; + wordIndex = 0; + words_from_previous_page = 0; } ndbout << endl; }//for @@ -310,93 +325,6 @@ Uint32 readFromFile(FILE * f, Uint32 *toPtr, Uint32 sizeInWords) { } -//---------------------------------------------------------------- -// -//---------------------------------------------------------------- - -Uint32 readRecordOverPageBoundary(Uint32 *pagePtr, Uint32 pageIndex, Uint32 oldPageIndex, Uint32 recordType) { - Uint32 pageHeader[PAGEHEADERSIZE]; - Uint32 tmpPages[PAGESIZE*10]; - PageHeader *thePageHeader; - Uint32 recordSize = 0; - - PrepareOperationRecord *poRecord; - CommitTransactionRecord *ctRecord; - InvalidCommitTransactionRecord *ictRecord; - - memcpy(pageHeader, pagePtr + PAGESIZE, PAGEHEADERSIZE*sizeof(Uint32)); - memcpy(tmpPages, pagePtr + oldPageIndex, (PAGESIZE - oldPageIndex)*sizeof(Uint32)); - memcpy(tmpPages + PAGESIZE - oldPageIndex , - (pagePtr + PAGESIZE + PAGEHEADERSIZE), - (PAGESIZE - PAGEHEADERSIZE)*sizeof(Uint32)); - - switch(recordType) { - case ZPREP_OP_TYPE: - poRecord = (PrepareOperationRecord *) tmpPages; - recordSize = poRecord->getLogRecordSize(); - if (recordSize < (PAGESIZE - PAGEHEADERSIZE)) { - if (theCheckFlag) { - if(!poRecord->check()) { - ndbout << "Error in poRecord->check() (readRecordOverPageBoundary)" << endl; - doExit(); - } - } - if (thePrintFlag) ndbout << (*poRecord); - } else { - ndbout << "Error: Record greater than a Page" << endl; - } - break; - - case ZCOMMIT_TYPE: - ctRecord = (CommitTransactionRecord *) tmpPages; - recordSize = ctRecord->getLogRecordSize(); - if (recordSize < (PAGESIZE - PAGEHEADERSIZE)) { - if (theCheckFlag) { - if(!ctRecord->check()) { - ndbout << "Error in ctRecord->check() (readRecordOverPageBoundary)" << endl; - doExit(); - } - } - if (thePrintFlag) ndbout << (*ctRecord); - } else { - ndbout << endl << "Error: Record greater than a Page" << endl; - } - break; - - case ZINVALID_COMMIT_TYPE: - ictRecord = (InvalidCommitTransactionRecord *) tmpPages; - recordSize = ictRecord->getLogRecordSize(); - if (recordSize < (PAGESIZE - PAGEHEADERSIZE)) { - if (theCheckFlag) { - if(!ictRecord->check()) { - ndbout << "Error in ictRecord->check() (readRecordOverPageBoundary)" << endl; - doExit(); - } - } - if (thePrintFlag) ndbout << (*ictRecord); - } else { - ndbout << endl << "Error: Record greater than a Page" << endl; - } - break; - - case ZNEW_PREP_OP_TYPE: - case ZABORT_TYPE: - case ZFRAG_SPLIT_TYPE: - case ZNEXT_MBYTE_TYPE: - ndbout << endl << "Record type = " << recordType << " not implemented." << endl; - return 0; - - default: - ndbout << endl << "Error: Unknown record type. Record type = " << recordType << endl; - return 0; - } - - thePageHeader = (PageHeader *) (pagePtr + PAGESIZE); - if (thePrintFlag) ndbout << (*thePageHeader); - - return PAGEHEADERSIZE - PAGESIZE + oldPageIndex + recordSize; -} - //---------------------------------------------------------------- // //---------------------------------------------------------------- From ce91c0f1c8938af9c1174def4c7d86789737f34f Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Wed, 31 Aug 2005 23:24:50 +0200 Subject: [PATCH 19/41] added make of ndb sys file printer --- ndb/src/kernel/blocks/dbdih/Makefile.am | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ndb/src/kernel/blocks/dbdih/Makefile.am b/ndb/src/kernel/blocks/dbdih/Makefile.am index d6ad380b806..3b5ae716a63 100644 --- a/ndb/src/kernel/blocks/dbdih/Makefile.am +++ b/ndb/src/kernel/blocks/dbdih/Makefile.am @@ -1,10 +1,16 @@ noinst_LIBRARIES = libdbdih.a +EXTRA_PROGRAMS = ndbd_sysfile_reader libdbdih_a_SOURCES = DbdihInit.cpp DbdihMain.cpp +ndbd_sysfile_reader_SOURCES = printSysfile/printSysfile.cpp include $(top_srcdir)/ndb/config/common.mk.am include $(top_srcdir)/ndb/config/type_kernel.mk.am +LDADD += \ + $(top_builddir)/ndb/src/common/util/libgeneral.la \ + $(top_builddir)/ndb/src/common/portlib/libportlib.la + # Don't update the files from bitkeeper %::SCCS/s.% From 29dc269678b4e55b48dd67a2d1eeb7ab94ab077e Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Wed, 31 Aug 2005 23:56:02 +0200 Subject: [PATCH 20/41] Bug#12833 corrected parsing of CLUSTERLOG command in ndb_mgm --- ndb/src/mgmclient/CommandInterpreter.cpp | 83 +++++++++++++----------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/ndb/src/mgmclient/CommandInterpreter.cpp b/ndb/src/mgmclient/CommandInterpreter.cpp index e1619917de5..124c5c18748 100644 --- a/ndb/src/mgmclient/CommandInterpreter.cpp +++ b/ndb/src/mgmclient/CommandInterpreter.cpp @@ -1909,47 +1909,54 @@ CommandInterpreter::executeEventReporting(int processId, return; } BaseString tmp(parameters); - Vector spec; - tmp.split(spec, "="); - if(spec.size() != 2){ - ndbout << "Invalid loglevel specification: " << parameters << endl; - return; - } + Vector specs; + tmp.split(specs, " "); - spec[0].trim().ndb_toupper(); - int category = ndb_mgm_match_event_category(spec[0].c_str()); - if(category == NDB_MGM_ILLEGAL_EVENT_CATEGORY){ - if(!convert(spec[0].c_str(), category) || - category < NDB_MGM_MIN_EVENT_CATEGORY || - category > NDB_MGM_MAX_EVENT_CATEGORY){ - ndbout << "Unknown category: \"" << spec[0].c_str() << "\"" << endl; - return; + for (int i=0; i < specs.size(); i++) + { + Vector spec; + specs[i].split(spec, "="); + if(spec.size() != 2){ + ndbout << "Invalid loglevel specification: " << specs[i] << endl; + continue; + } + + spec[0].trim().ndb_toupper(); + int category = ndb_mgm_match_event_category(spec[0].c_str()); + if(category == NDB_MGM_ILLEGAL_EVENT_CATEGORY){ + if(!convert(spec[0].c_str(), category) || + category < NDB_MGM_MIN_EVENT_CATEGORY || + category > NDB_MGM_MAX_EVENT_CATEGORY){ + ndbout << "Unknown category: \"" << spec[0].c_str() << "\"" << endl; + continue; + } + } + + int level; + if (!convert(spec[1].c_str(),level)) + { + ndbout << "Invalid level: " << spec[1].c_str() << endl; + continue; + } + + ndbout << "Executing CLUSTERLOG " << spec[0] << "=" << spec[1] + << " on node " << processId << flush; + + struct ndb_mgm_reply reply; + int result; + result = ndb_mgm_set_loglevel_clusterlog(m_mgmsrv, + processId, + (ndb_mgm_event_category)category, + level, + &reply); + + if (result != 0) { + ndbout_c(" failed."); + printError(); + } else { + ndbout_c(" OK!"); } } - - int level; - if (!convert(spec[1].c_str(),level)) - { - ndbout << "Invalid level: " << spec[1].c_str() << endl; - return; - } - - ndbout << "Executing CLUSTERLOG on node " << processId << flush; - - struct ndb_mgm_reply reply; - int result; - result = ndb_mgm_set_loglevel_clusterlog(m_mgmsrv, - processId, - (ndb_mgm_event_category)category, - level, - &reply); - - if (result != 0) { - ndbout_c(" failed."); - printError(); - } else { - ndbout_c(" OK!"); - } } /***************************************************************************** From e0f3c5c0fb936fd0ebeee54c07ae16265e9537b9 Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Thu, 1 Sep 2005 00:13:01 +0200 Subject: [PATCH 21/41] Bug #12043, do not core on misconfig unless debug compiled --- ndb/src/mgmsrv/ConfigInfo.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/ndb/src/mgmsrv/ConfigInfo.cpp b/ndb/src/mgmsrv/ConfigInfo.cpp index bc078b711dc..cface035174 100644 --- a/ndb/src/mgmsrv/ConfigInfo.cpp +++ b/ndb/src/mgmsrv/ConfigInfo.cpp @@ -2136,7 +2136,17 @@ const int ConfigInfo::m_NoOfParams = sizeof(m_ParamInfo) / sizeof(ParamInfo); /**************************************************************************** * Ctor ****************************************************************************/ -static void require(bool v) { if(!v) abort();} +static void require(bool v) +{ + if(!v) + { +#ifndef DBUG_OFF + abort(); +#else + exit(-1); +#endif + } +} ConfigInfo::ConfigInfo() : m_info(true), m_systemDefaults(true) @@ -2277,7 +2287,7 @@ ConfigInfo::ConfigInfo() ****************************************************************************/ inline void warning(const char * src, const char * arg){ ndbout << "Illegal call to ConfigInfo::" << src << "() - " << arg << endl; - abort(); + require(false); } const Properties * @@ -3394,7 +3404,7 @@ fixDepricated(InitConfigFileParser::Context & ctx, const char * data){ } case PropertiesType_Properties: default: - abort(); + ::require(false); } } return true; @@ -3406,7 +3416,7 @@ static bool saveInConfigValues(InitConfigFileParser::Context & ctx, const char * data){ const Properties * sec; if(!ctx.m_currentInfo->get(ctx.fname, &sec)){ - abort(); + require(false); return false; } @@ -3477,7 +3487,7 @@ saveInConfigValues(InitConfigFileParser::Context & ctx, const char * data){ break; } default: - abort(); + require(false); } require(ok); } From 00b17c1c171e65df99d793de0653490a37291099 Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Wed, 31 Aug 2005 18:32:15 -0700 Subject: [PATCH 22/41] Fix handling of filenames that start the same as reserved filenames on Windows. (Bug #12325) --- mysql-test/include/windows.inc | 4 ++++ mysql-test/r/lowercase_table.result | 6 ------ mysql-test/r/windows.result | 8 ++++++++ mysql-test/t/lowercase_table.test | 10 ---------- mysql-test/t/windows.test | 20 ++++++++++++++++++++ mysys/my_access.c | 2 +- 6 files changed, 33 insertions(+), 17 deletions(-) create mode 100644 mysql-test/include/windows.inc create mode 100644 mysql-test/r/windows.result create mode 100644 mysql-test/t/windows.test diff --git a/mysql-test/include/windows.inc b/mysql-test/include/windows.inc new file mode 100644 index 00000000000..05ec7b0e021 --- /dev/null +++ b/mysql-test/include/windows.inc @@ -0,0 +1,4 @@ +--require r/true.require +disable_query_log; +select convert(@@version_compile_os using latin1) IN ("Win32","Win64","Windows") as "TRUE"; +enable_query_log; diff --git a/mysql-test/r/lowercase_table.result b/mysql-test/r/lowercase_table.result index 499f46a237e..ef379cebaa9 100644 --- a/mysql-test/r/lowercase_table.result +++ b/mysql-test/r/lowercase_table.result @@ -83,9 +83,3 @@ create table t2 like T1; drop table t1, t2; show tables; Tables_in_test -use lpt1; -ERROR 42000: Unknown database 'lpt1' -use com1; -ERROR 42000: Unknown database 'com1' -use prn; -ERROR 42000: Unknown database 'prn' diff --git a/mysql-test/r/windows.result b/mysql-test/r/windows.result new file mode 100644 index 00000000000..039c5b1476e --- /dev/null +++ b/mysql-test/r/windows.result @@ -0,0 +1,8 @@ +use lpt1; +ERROR 42000: Unknown database 'lpt1' +use com1; +ERROR 42000: Unknown database 'com1' +use prn; +ERROR 42000: Unknown database 'prn' +create table nu (a int); +drop table nu; diff --git a/mysql-test/t/lowercase_table.test b/mysql-test/t/lowercase_table.test index 4d33c8c1c48..709743ce687 100644 --- a/mysql-test/t/lowercase_table.test +++ b/mysql-test/t/lowercase_table.test @@ -83,14 +83,4 @@ drop table t1, t2; show tables; -# -#Bug 9148: Denial of service -# ---error 1049 -use lpt1; ---error 1049 -use com1; ---error 1049 -use prn; - # End of 4.1 tests diff --git a/mysql-test/t/windows.test b/mysql-test/t/windows.test new file mode 100644 index 00000000000..d6bcfeb8cb3 --- /dev/null +++ b/mysql-test/t/windows.test @@ -0,0 +1,20 @@ +# Windows-specific tests +--source include/windows.inc + +# +# Bug 9148: Denial of service +# +--error 1049 +use lpt1; +--error 1049 +use com1; +--error 1049 +use prn; + +# +# Bug #12325: Can't create table named 'nu' +# +create table nu (a int); +drop table nu; + +# End of 4.1 tests diff --git a/mysys/my_access.c b/mysys/my_access.c index 8fc83a020cf..237312b5c9b 100644 --- a/mysys/my_access.c +++ b/mysys/my_access.c @@ -105,7 +105,7 @@ int check_if_legal_filename(const char *path) { if (*reserved != my_toupper(&my_charset_latin1, *name)) break; - if (++name == end) + if (++name == end && !reserved[1]) DBUG_RETURN(1); /* Found wrong path */ } while (*++reserved); } From 906f7c4481fbd209f61809989b2b1f8d92869037 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 1 Sep 2005 09:34:40 +0200 Subject: [PATCH 23/41] Bug #12471 mysqltest, --error within loop affects wrong statement - Move clearing of expected errors --- client/mysqltest.c | 12 ++++++++++-- mysql-test/r/mysqltest.result | 7 +++++++ mysql-test/t/mysqltest.test | 13 +++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index bd467e821ab..3b13084081e 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2385,8 +2385,6 @@ int read_query(struct st_query** q_ptr) sizeof(global_expected_errno)); q->expected_errors= global_expected_errors; q->abort_on_error= (global_expected_errors == 0 && abort_on_error); - bzero((gptr) global_expected_errno, sizeof(global_expected_errno)); - global_expected_errors=0; if (p[0] == '-' && p[1] == '-') { q->type= Q_COMMENT_WITH_COMMAND; @@ -4002,6 +4000,16 @@ int main(int argc, char **argv) else check_eol_junk(q->last_argument); + if (q->type != Q_ERROR) + { + /* + As soon as any non "error" command has been executed, + the array with expected errors should be cleared + */ + global_expected_errors= 0; + bzero((gptr) global_expected_errno, sizeof(global_expected_errno)); + } + parser.current_line += current_line_inc; } diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 668cf6beb57..36dc09b9e24 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -341,3 +341,10 @@ mysqltest: At line 1: Wrong column number to replace_column in 'replace_column 1 mysqltest: At line 1: Invalid integer argument "10!" mysqltest: At line 1: End of line junk detected: "!" mysqltest: At line 1: Invalid integer argument "a" +failing_statement; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'failing_statement' at line 1 +failing_statement; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'failing_statement' at line 1 +SELECT 1 as a; +a +1 diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index a2c2dc1fa16..c1ebbb7fb3b 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -775,4 +775,17 @@ select "a" as col1, "c" as col2; # new scripts and diagnose errors # ---------------------------------------------------------------------------- +# ---------------------------------------------------------------------------- +# Test bug#12386 +# ---------------------------------------------------------------------------- +let $num= 2; +while ($num) +{ + --error 1064 + failing_statement; + + dec $num; +} + +SELECT 1 as a; From ced32517c78cc0c5e723caccceaaf1ff534baf3e Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 1 Sep 2005 10:53:33 +0200 Subject: [PATCH 24/41] Bug #3131 mysqltest fails on $2=$1 assignment in test --- client/mysqltest.c | 22 +++++++++++++++------- mysql-test/r/mysqltest.result | 7 +++++++ mysql-test/t/mysqltest.test | 20 ++++++++++++++++++++ 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 3b13084081e..6c7d51c393d 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1147,16 +1147,24 @@ int var_query_set(VAR* v, const char *p, const char** p_end) return 0; } -void var_copy(VAR* dest, VAR* src) +void var_copy(VAR *dest, VAR *src) { - dest->int_val=src->int_val; - dest->int_dirty=src->int_dirty; + dest->int_val= src->int_val; + dest->int_dirty= src->int_dirty; + + /* Alloc/realloc data for str_val in dest */ if (dest->alloced_len < src->alloced_len && - !(dest->str_val=my_realloc(dest->str_val,src->alloced_len+1, - MYF(MY_WME)))) + !(dest->str_val= dest->str_val + ? my_realloc(dest->str_val, src->alloced_len, MYF(MY_WME)) + : my_malloc(src->alloced_len, MYF(MY_WME)))) die("Out of memory"); - dest->str_val_len=src->str_val_len; - memcpy(dest->str_val,src->str_val,src->str_val_len+1); + else + dest->alloced_len= src->alloced_len; + + /* Copy str_val data to dest */ + dest->str_val_len= src->str_val_len; + if (src->str_val_len) + memcpy(dest->str_val, src->str_val, src->str_val_len); } int eval_expr(VAR* v, const char *p, const char** p_end) diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 36dc09b9e24..80c54f589da 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -206,6 +206,13 @@ source database hej hej hej +1 + + +a long variable content +a long variable content +a long $where variable content + mysqltest: At line 1: Missing arguments to let mysqltest: At line 1: Missing variable name in let mysqltest: At line 1: Variable name in hi=hi does not start with '$' diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index c1ebbb7fb3b..e58f07d7a4a 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -473,6 +473,26 @@ echo $1; let $1 = hej; echo $1; +let $1=1; +let $2=$1; +echo $2; +let $5=$6; +echo $5; +echo $6; + +let $where=a long variable content; +echo $where; + +let $where2= $where; +echo $where2; + +let $where3=a long $where variable content; +echo $where3; + +let $novar1= $novar2; +echo $novar1; + + # Test illegal uses of let From 72b08b7e57f4010c3349093ed614c22864044629 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 1 Sep 2005 11:11:10 +0200 Subject: [PATCH 25/41] Fix compiler warnings for mysqltest.c --- client/mysqltest.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 6c7d51c393d..d49a3b8b85b 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1233,7 +1233,7 @@ enum enum_operator int do_modify_var(struct st_query *query, const char *name, enum enum_operator operator) { - char *p= query->first_argument; + const char *p= query->first_argument; VAR* v; if (!*p) die("Missing arguments to %s", name); @@ -1252,7 +1252,7 @@ int do_modify_var(struct st_query *query, const char *name, break; } v->int_dirty= 1; - query->last_argument= ++p; + query->last_argument= (char*)++p; return 0; } @@ -1392,8 +1392,6 @@ int do_sync_with_master(struct st_query *query) long offset= 0; char *p= query->first_argument; const char *offset_start= p; - const char *offset_end= query->end; - int error; if (*offset_start) { for (; my_isdigit(charset_info, *p); p++) From 1a5f346bf9ef2d4b12cfbd26989650045b1339fa Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Thu, 1 Sep 2005 14:32:42 +0200 Subject: [PATCH 26/41] mtr_process.pl: Make sure mtr_kill_processes() is called with an array ref Corrected error string for STDERR redirect --- mysql-test/lib/mtr_process.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index a7587ce691f..bae66353825 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -183,7 +183,7 @@ sub spawn_impl ($$$$$$$$) { { if ( ! open(STDERR,$log_file_open_mode,$error) ) { - mtr_error("can't redirect STDERR to \"$output\": $!"); + mtr_error("can't redirect STDERR to \"$error\": $!"); } } } @@ -560,8 +560,8 @@ sub mtr_stop_mysqld_servers ($) { start_reap_all(); # Avoid zombies - SIGNAL: - mtr_kill_processes(\keys (%mysqld_pids)); + my @mysqld_pids= keys %mysqld_pids; + mtr_kill_processes(\@mysqld_pids); stop_reap_all(); # Get into control again From da2af0bb6ddbd20adf517dbcd4008029fe0c77e0 Mon Sep 17 00:00:00 2001 From: "dlenev@mysql.com" <> Date: Thu, 1 Sep 2005 16:52:59 +0400 Subject: [PATCH 27/41] Fix for bug #12423 "Deadlock when doing FLUSH PRIVILEGES and GRANT in multi-threaded environment". To avoid deadlocks between several simultaneously run account management commands (particularly between FLUSH PRIVILEGES/SET PASSWORD and GRANT commands) we should always take table and internal locks during their execution in the same order. In other words we should first open and lock privilege tables and only then obtain acl_cache::lock/LOCK_grant locks. --- mysql-test/r/grant2.result | 9 + mysql-test/t/grant2.test | 43 ++++ sql/mysqld.cc | 4 +- sql/sql_acl.cc | 402 ++++++++++++++++++++++--------------- sql/sql_acl.h | 8 +- sql/sql_parse.cc | 25 ++- 6 files changed, 320 insertions(+), 171 deletions(-) diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result index ada205f6f23..df88da960d9 100644 --- a/mysql-test/r/grant2.result +++ b/mysql-test/r/grant2.result @@ -96,3 +96,12 @@ i REVOKE ALL ON mysqltest_1.t1 FROM mysqltest_1@'127.0.0.0/255.0.0.0'; drop table mysqltest_1.t1; drop database mysqltest_1; +lock table mysql.user write; + flush privileges; + grant all on *.* to 'mysqltest_1'@'localhost'; +unlock tables; +lock table mysql.user write; + set password for 'mysqltest_1'@'localhost' = password(''); + revoke all on *.* from 'mysqltest_1'@'localhost'; +unlock tables; +drop user 'mysqltest_1'@'localhost'; diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test index f347869d9ec..ad62903194c 100644 --- a/mysql-test/t/grant2.test +++ b/mysql-test/t/grant2.test @@ -125,4 +125,47 @@ REVOKE ALL ON mysqltest_1.t1 FROM mysqltest_1@'127.0.0.0/255.0.0.0'; drop table mysqltest_1.t1; drop database mysqltest_1; + +# Bug #12423 "Deadlock when doing FLUSH PRIVILEGES and GRANT in +# multi-threaded environment". We should be able to execute FLUSH +# PRIVILEGES and SET PASSWORD simultaneously with other account +# management commands (such as GRANT and REVOKE) without causing +# deadlocks. To achieve this we should ensure that all account +# management commands take table and internal locks in the same order. +connect (con2root,localhost,root,,); +connect (con3root,localhost,root,,); +# Check that we can execute FLUSH PRIVILEGES and GRANT simultaneously +# This will check that locks are taken in proper order during both +# user/db-level and table/column-level privileges reloading. +connection default; +lock table mysql.user write; +connection con2root; +send flush privileges; +connection con3root; +send grant all on *.* to 'mysqltest_1'@'localhost'; +connection default; +unlock tables; +connection con2root; +reap; +connection con3root; +reap; +# Check for simultaneous SET PASSWORD and REVOKE. +connection default; +lock table mysql.user write; +connection con2root; +send set password for 'mysqltest_1'@'localhost' = password(''); +connection con3root; +send revoke all on *.* from 'mysqltest_1'@'localhost'; +connection default; +unlock tables; +connection con2root; +reap; +connection con3root; +reap; +connection default; +# Clean-up +drop user 'mysqltest_1'@'localhost'; +disconnect con2root; +disconnect con3root; + # End of 4.1 tests diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 2e38ec98c08..87a99457918 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3079,7 +3079,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); */ error_handler_hook = my_message_sql; start_signal_handler(); // Creates pidfile - if (acl_init((THD *)0, opt_noacl) || + if (acl_init(opt_noacl) || my_tz_init((THD *)0, default_tz_name, opt_bootstrap)) { abort_loop=1; @@ -3096,7 +3096,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); exit(1); } if (!opt_noacl) - (void) grant_init((THD *)0); + (void) grant_init(); #ifdef HAVE_DLOPEN if (!opt_noacl) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index d191da32189..857489311fa 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -62,17 +62,20 @@ static HASH acl_check_hosts, column_priv_hash; static DYNAMIC_ARRAY acl_wild_hosts; static hash_filo *acl_cache; static uint grant_version=0; -static uint priv_version=0; /* Version of priv tables. incremented by acl_init */ +static uint priv_version=0; /* Version of priv tables. incremented by acl_load */ static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0); static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b); static ulong get_sort(uint count,...); static void init_check_host(void); static ACL_USER *find_acl_user(const char *host, const char *user); -static bool update_user_table(THD *thd, const char *host, const char *user, +static bool update_user_table(THD *thd, TABLE *table, + const char *host, const char *user, const char *new_password, uint new_password_len); static void update_hostname(acl_host_and_ip *host, const char *hostname); static bool compare_hostname(const acl_host_and_ip *host,const char *hostname, const char *ip); +static my_bool acl_load(THD *thd, TABLE_LIST *tables); +static my_bool grant_load(TABLE_LIST *tables); /* Convert scrambled password to binary form, according to scramble type, @@ -117,79 +120,84 @@ static void restrict_update_of_old_passwords_var(THD *thd, /* - Read grant privileges from the privilege tables in the 'mysql' database. + Initialize structures responsible for user/db-level privilege checking and + load privilege information for them from tables in the 'mysql' database. SYNOPSIS acl_init() - thd Thread handler - dont_read_acl_tables Set to 1 if run with --skip-grant + dont_read_acl_tables TRUE if we want to skip loading data from + privilege tables and disable privilege checking. + + NOTES + This function is mostly responsible for preparatory steps, main work + on initialization and grants loading is done in acl_reload(). RETURN VALUES 0 ok 1 Could not initialize grant's */ - -my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) +my_bool acl_init(bool dont_read_acl_tables) { THD *thd; - TABLE_LIST tables[3]; - TABLE *table; - READ_RECORD read_record_info; - MYSQL_LOCK *lock; - my_bool return_val=1; - bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; - char tmp_name[NAME_LEN+1]; - + my_bool return_val; DBUG_ENTER("acl_init"); - if (!acl_cache) - acl_cache=new hash_filo(ACL_CACHE_SIZE,0,0, - (hash_get_key) acl_entry_get_key, - (hash_free_key) free, system_charset_info); + acl_cache= new hash_filo(ACL_CACHE_SIZE, 0, 0, + (hash_get_key) acl_entry_get_key, + (hash_free_key) free, system_charset_info); if (dont_read_acl_tables) { DBUG_RETURN(0); /* purecov: tested */ } - priv_version++; /* Privileges updated */ - /* To be able to run this from boot, we allocate a temporary THD */ if (!(thd=new THD)) DBUG_RETURN(1); /* purecov: inspected */ thd->store_globals(); + /* + It is safe to call acl_reload() since acl_* arrays and hashes which + will be freed there are global static objects and thus are initialized + by zeros at startup. + */ + return_val= acl_reload(thd); + delete thd; + /* Remember that we don't have a THD */ + my_pthread_setspecific_ptr(THR_THD, 0); + DBUG_RETURN(return_val); +} + + +/* + Initialize structures responsible for user/db-level privilege checking + and load information about grants from open privilege tables. + + SYNOPSIS + acl_load() + thd Current thread + tables List containing open "mysql.host", "mysql.user" and + "mysql.db" tables. + + RETURN VALUES + FALSE Success + TRUE Error +*/ + +static my_bool acl_load(THD *thd, TABLE_LIST *tables) +{ + TABLE *table; + READ_RECORD read_record_info; + my_bool return_val= 1; + bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; + char tmp_name[NAME_LEN+1]; + DBUG_ENTER("acl_load"); + + priv_version++; /* Privileges updated */ acl_cache->clear(1); // Clear locked hostname cache - thd->db= my_strdup("mysql",MYF(0)); - thd->db_length=5; // Safety - bzero((char*) &tables,sizeof(tables)); - tables[0].alias=tables[0].real_name=(char*) "host"; - tables[1].alias=tables[1].real_name=(char*) "user"; - tables[2].alias=tables[2].real_name=(char*) "db"; - tables[0].next=tables+1; - tables[1].next=tables+2; - tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ; - tables[0].db=tables[1].db=tables[2].db=thd->db; - uint counter; - if (open_tables(thd, tables, &counter)) - { - sql_print_error("Fatal error: Can't open privilege tables: %s", - thd->net.last_error); - goto end; - } - TABLE *ptr[3]; // Lock tables for quick update - ptr[0]= tables[0].table; - ptr[1]= tables[1].table; - ptr[2]= tables[2].table; - if (! (lock= mysql_lock_tables(thd, ptr, 3, 0))) - { - sql_print_error("Fatal error: Can't lock privilege tables: %s", - thd->net.last_error); - goto end; - } init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0); init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0); VOID(my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50)); @@ -431,21 +439,10 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) freeze_size(&acl_dbs); init_check_host(); - mysql_unlock_tables(thd, lock); initialized=1; - thd->version--; // Force close to free memory return_val=0; end: - close_thread_tables(thd); - delete thd; - if (org_thd) - org_thd->store_globals(); /* purecov: inspected */ - else - { - /* Remember that we don't have a THD */ - my_pthread_setspecific_ptr(THR_THD, 0); - } DBUG_RETURN(return_val); } @@ -469,26 +466,60 @@ void acl_free(bool end) /* - Forget current privileges and read new privileges from the privilege tables + Forget current user/db-level privileges and read new privileges + from the privilege tables. SYNOPSIS acl_reload() - thd Thread handle (can be NULL) + thd Current thread + + NOTE + All tables of calling thread which were open and locked by LOCK TABLES + statement will be unlocked and closed. + This function is also used for initialization of structures responsible + for user/db-level privilege checking. + + RETURN VALUE + FALSE Success + TRUE Failure */ -void acl_reload(THD *thd) +my_bool acl_reload(THD *thd) { + TABLE_LIST tables[3]; DYNAMIC_ARRAY old_acl_hosts,old_acl_users,old_acl_dbs; MEM_ROOT old_mem; bool old_initialized; + my_bool return_val= 1; DBUG_ENTER("acl_reload"); - if (thd && thd->locked_tables) + if (thd->locked_tables) { // Can't have locked tables here thd->lock=thd->locked_tables; thd->locked_tables=0; close_thread_tables(thd); } + + /* + To avoid deadlocks we should obtain table locks before + obtaining acl_cache->lock mutex. + */ + bzero((char*) tables, sizeof(tables)); + tables[0].alias=tables[0].real_name=(char*) "host"; + tables[1].alias=tables[1].real_name=(char*) "user"; + tables[2].alias=tables[2].real_name=(char*) "db"; + tables[0].db=tables[1].db=tables[2].db= (char*) "mysql"; + tables[0].next= tables+1; + tables[1].next= tables+2; + tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ; + + if (simple_open_n_lock_tables(thd, tables)) + { + sql_print_error("Fatal error: Can't open and lock privilege tables: %s", + thd->net.last_error); + goto end; + } + if ((old_initialized=initialized)) VOID(pthread_mutex_lock(&acl_cache->lock)); @@ -499,7 +530,7 @@ void acl_reload(THD *thd) delete_dynamic(&acl_wild_hosts); hash_free(&acl_check_hosts); - if (acl_init(thd, 0)) + if ((return_val= acl_load(thd, tables))) { // Error. Revert to old list DBUG_PRINT("error",("Reverting to old privileges")); acl_free(); /* purecov: inspected */ @@ -518,7 +549,9 @@ void acl_reload(THD *thd) } if (old_initialized) VOID(pthread_mutex_unlock(&acl_cache->lock)); - DBUG_VOID_RETURN; +end: + close_thread_tables(thd); + DBUG_RETURN(return_val); } @@ -1229,7 +1262,13 @@ bool check_change_password(THD *thd, const char *host, const char *user, bool change_password(THD *thd, const char *host, const char *user, char *new_password) { + TABLE_LIST tables; + TABLE *table; + /* Buffer should be extended when password length is extended. */ + char buff[512]; + ulong query_length; uint new_password_len= strlen(new_password); + bool result= 1; DBUG_ENTER("change_password"); DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'", host,user,new_password)); @@ -1238,42 +1277,71 @@ bool change_password(THD *thd, const char *host, const char *user, if (check_change_password(thd, host, user, new_password, new_password_len)) DBUG_RETURN(1); + bzero((char*) &tables, sizeof(tables)); + tables.alias=tables.real_name= (char*) "user"; + tables.db= (char*) "mysql"; + +#ifdef HAVE_REPLICATION + /* + GRANT and REVOKE are applied the slave in/exclusion rules as they are + some kind of updates to the mysql.% tables. + */ + if (thd->slave_thread && table_rules_on) + { + /* + The tables must be marked "updating" so that tables_ok() takes them into + account in tests. It's ok to leave 'updating' set after tables_ok. + */ + tables.updating= 1; + /* Thanks to bzero, tables.next==0 */ + if (!tables_ok(0, &tables)) + DBUG_RETURN(0); + } +#endif + + if (!(table= open_ltable(thd, &tables, TL_WRITE))) + DBUG_RETURN(1); + VOID(pthread_mutex_lock(&acl_cache->lock)); ACL_USER *acl_user; if (!(acl_user= find_acl_user(host, user))) { VOID(pthread_mutex_unlock(&acl_cache->lock)); send_error(thd, ER_PASSWORD_NO_MATCH); - DBUG_RETURN(1); + goto end; } /* update loaded acl entry: */ set_user_salt(acl_user, new_password, new_password_len); - if (update_user_table(thd, + if (update_user_table(thd, table, acl_user->host.hostname ? acl_user->host.hostname : "", acl_user->user ? acl_user->user : "", new_password, new_password_len)) { VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */ send_error(thd,0); /* purecov: deadcode */ - DBUG_RETURN(1); /* purecov: deadcode */ + goto end; } acl_cache->clear(1); // Clear locked hostname cache VOID(pthread_mutex_unlock(&acl_cache->lock)); - - char buff[512]; /* Extend with extended password length*/ - ulong query_length= + result= 0; + query_length= my_sprintf(buff, (buff,"SET PASSWORD FOR \"%-.120s\"@\"%-.120s\"=\"%-.120s\"", acl_user->user ? acl_user->user : "", acl_user->host.hostname ? acl_user->host.hostname : "", new_password)); - thd->clear_error(); mysql_update_log.write(thd, buff, query_length); - Query_log_event qinfo(thd, buff, query_length, 0, FALSE); - mysql_bin_log.write(&qinfo); - DBUG_RETURN(0); + if (mysql_bin_log.is_open()) + { + thd->clear_error(); + Query_log_event qinfo(thd, buff, query_length, 0, FALSE); + mysql_bin_log.write(&qinfo); + } +end: + close_thread_tables(thd); + DBUG_RETURN(result); } @@ -1385,43 +1453,28 @@ bool hostname_requires_resolving(const char *hostname) return FALSE; } + /* - Update grants in the user and database privilege tables + Update record for user in mysql.user privilege table with new password. + + SYNOPSIS + update_user_table() + thd Thread handle + table Pointer to TABLE object for open mysql.user table + host/user Hostname/username pair identifying user for which + new password should be set + new_password New password + new_password_len Length of new password */ -static bool update_user_table(THD *thd, const char *host, const char *user, +static bool update_user_table(THD *thd, TABLE *table, + const char *host, const char *user, const char *new_password, uint new_password_len) { - TABLE_LIST tables; - TABLE *table; - bool error=1; + int error; DBUG_ENTER("update_user_table"); DBUG_PRINT("enter",("user: %s host: %s",user,host)); - bzero((char*) &tables,sizeof(tables)); - tables.alias=tables.real_name=(char*) "user"; - tables.db=(char*) "mysql"; - -#ifdef HAVE_REPLICATION - /* - GRANT and REVOKE are applied the slave in/exclusion rules as they are - some kind of updates to the mysql.% tables. - */ - if (thd->slave_thread && table_rules_on) - { - /* - The tables must be marked "updating" so that tables_ok() takes them into - account in tests. It's ok to leave 'updating' set after tables_ok. - */ - tables.updating= 1; - /* Thanks to bzero, tables.next==0 */ - if (!tables_ok(0, &tables)) - DBUG_RETURN(0); - } -#endif - - if (!(table=open_ltable(thd,&tables,TL_WRITE))) - DBUG_RETURN(1); /* purecov: deadcode */ table->field[0]->store(host,(uint) strlen(host), &my_charset_latin1); table->field[1]->store(user,(uint) strlen(user), &my_charset_latin1); @@ -1439,13 +1492,9 @@ static bool update_user_table(THD *thd, const char *host, const char *user, if ((error=table->file->update_row(table->record[1],table->record[0]))) { table->file->print_error(error,MYF(0)); /* purecov: deadcode */ - goto end; /* purecov: deadcode */ + DBUG_RETURN(1); } - error=0; // Record updated - -end: - close_thread_tables(thd); - DBUG_RETURN(error); + DBUG_RETURN(0); } @@ -2617,18 +2666,59 @@ void grant_free(void) } -/* Init grant array if possible */ +/* + Initialize structures responsible for table/column-level privilege checking + and load information for them from tables in the 'mysql' database. -my_bool grant_init(THD *org_thd) + SYNOPSIS + grant_init() + + RETURN VALUES + 0 ok + 1 Could not initialize grant's +*/ + +my_bool grant_init() { THD *thd; - TABLE_LIST tables[2]; - MYSQL_LOCK *lock; + my_bool return_val; + DBUG_ENTER("grant_init"); + + if (!(thd= new THD)) + DBUG_RETURN(1); /* purecov: deadcode */ + thd->store_globals(); + return_val= grant_reload(thd); + delete thd; + /* Remember that we don't have a THD */ + my_pthread_setspecific_ptr(THR_THD, 0); + DBUG_RETURN(return_val); +} + + +/* + Initialize structures responsible for table/column-level privilege + checking and load information about grants from open privilege tables. + + SYNOPSIS + grant_load() + thd Current thread + tables List containing open "mysql.tables_priv" and + "mysql.columns_priv" tables. + + RETURN VALUES + FALSE - success + TRUE - error +*/ + +static my_bool grant_load(TABLE_LIST *tables) +{ MEM_ROOT *memex_ptr; my_bool return_val= 1; TABLE *t_table, *c_table; bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; - DBUG_ENTER("grant_init"); + MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, + THR_MALLOC); + DBUG_ENTER("grant_load"); grant_option = FALSE; (void) hash_init(&column_priv_hash,&my_charset_latin1, @@ -2636,32 +2726,6 @@ my_bool grant_init(THD *org_thd) (hash_free_key) free_grant_table,0); init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0); - /* Don't do anything if running with --skip-grant */ - if (!initialized) - DBUG_RETURN(0); /* purecov: tested */ - - if (!(thd=new THD)) - DBUG_RETURN(1); /* purecov: deadcode */ - thd->store_globals(); - thd->db= my_strdup("mysql",MYF(0)); - thd->db_length=5; // Safety - bzero((char*) &tables, sizeof(tables)); - tables[0].alias=tables[0].real_name= (char*) "tables_priv"; - tables[1].alias=tables[1].real_name= (char*) "columns_priv"; - tables[0].next=tables+1; - tables[0].lock_type=tables[1].lock_type=TL_READ; - tables[0].db=tables[1].db=thd->db; - - uint counter; - if (open_tables(thd, tables, &counter)) - goto end; - - TABLE *ptr[2]; // Lock tables for quick update - ptr[0]= tables[0].table; - ptr[1]= tables[1].table; - if (! (lock= mysql_lock_tables(thd, ptr, 2, 0))) - goto end; - t_table = tables[0].table; c_table = tables[1].table; t_table->file->ha_index_init(0); if (t_table->file->index_first(t_table->record[0])) @@ -2671,7 +2735,6 @@ my_bool grant_init(THD *org_thd) } grant_option= TRUE; - /* Will be restored by org_thd->store_globals() */ memex_ptr= &memex; my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr); do @@ -2708,48 +2771,63 @@ my_bool grant_init(THD *org_thd) end_unlock: t_table->file->ha_index_end(); - mysql_unlock_tables(thd, lock); - thd->version--; // Force close to free memory - -end: - close_thread_tables(thd); - delete thd; - if (org_thd) - org_thd->store_globals(); - else - { - /* Remember that we don't have a THD */ - my_pthread_setspecific_ptr(THR_THD, 0); - } + my_pthread_setspecific_ptr(THR_MALLOC, save_mem_root_ptr); DBUG_RETURN(return_val); } /* - Reload grant array (table and column privileges) if possible + Reload information about table and column level privileges if possible. SYNOPSIS grant_reload() - thd Thread handler (can be NULL) + thd Current thread NOTES - Locked tables are checked by acl_init and doesn't have to be checked here + Locked tables are checked by acl_reload() and doesn't have to be checked + in this call. + This function is also used for initialization of structures responsible + for table/column-level privilege checking. + + RETURN VALUE + FALSE Success + TRUE Error */ -void grant_reload(THD *thd) +my_bool grant_reload(THD *thd) { + TABLE_LIST tables[2]; HASH old_column_priv_hash; bool old_grant_option; MEM_ROOT old_mem; + my_bool return_val= 1; DBUG_ENTER("grant_reload"); + /* Don't do anything if running with --skip-grant-tables */ + if (!initialized) + DBUG_RETURN(0); + + bzero((char*) tables, sizeof(tables)); + tables[0].alias=tables[0].real_name= (char*) "tables_priv"; + tables[1].alias=tables[1].real_name= (char*) "columns_priv"; + tables[0].db=tables[1].db= (char *) "mysql"; + tables[0].next=tables+1; + tables[0].lock_type=tables[1].lock_type=TL_READ; + + /* + To avoid deadlocks we should obtain table locks before + obtaining LOCK_grant rwlock. + */ + if (simple_open_n_lock_tables(thd, tables)) + goto end; + rw_wrlock(&LOCK_grant); grant_version++; old_column_priv_hash= column_priv_hash; old_grant_option= grant_option; old_mem= memex; - if (grant_init(thd)) + if ((return_val= grant_load(tables))) { // Error. Revert to old hash DBUG_PRINT("error",("Reverting to old privileges")); grant_free(); /* purecov: deadcode */ @@ -2763,7 +2841,9 @@ void grant_reload(THD *thd) free_root(&old_mem,MYF(0)); } rw_unlock(&LOCK_grant); - DBUG_VOID_RETURN; +end: + close_thread_tables(thd); + DBUG_RETURN(return_val); } diff --git a/sql/sql_acl.h b/sql/sql_acl.h index dc1b04c063a..256101ec7d8 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -134,8 +134,8 @@ public: /* prototypes */ bool hostname_requires_resolving(const char *hostname); -my_bool acl_init(THD *thd, bool dont_read_acl_tables); -void acl_reload(THD *thd); +my_bool acl_init(bool dont_read_acl_tables); +my_bool acl_reload(THD *thd); void acl_free(bool end=0); ulong acl_get(const char *host, const char *ip, const char *user, const char *db, my_bool db_is_pattern); @@ -151,9 +151,9 @@ int mysql_grant(THD *thd, const char *db, List &user_list, int mysql_table_grant(THD *thd, TABLE_LIST *table, List &user_list, List &column_list, ulong rights, bool revoke); -my_bool grant_init(THD *thd); +my_bool grant_init(); void grant_free(void); -void grant_reload(THD *thd); +my_bool grant_reload(THD *thd); bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, uint show_command, uint number, bool dont_print_error); bool check_grant_column (THD *thd,TABLE *table, const char *name, uint length, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index cd87b097038..dc788abc019 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4971,10 +4971,27 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, #ifndef NO_EMBEDDED_ACCESS_CHECKS if (options & REFRESH_GRANT) { - acl_reload(thd); - grant_reload(thd); - if (mqh_used) - reset_mqh(thd,(LEX_USER *) NULL,TRUE); + THD *tmp_thd= 0; + /* + If reload_acl_and_cache() is called from SIGHUP handler we have to + allocate temporary THD for execution of acl_reload()/grant_reload(). + */ + if (!thd && (thd= (tmp_thd= new THD))) + thd->store_globals(); + if (thd) + { + (void)acl_reload(thd); + (void)grant_reload(thd); + if (mqh_used) + reset_mqh(thd, (LEX_USER *) NULL, TRUE); + } + if (tmp_thd) + { + delete tmp_thd; + /* Remember that we don't have a THD */ + my_pthread_setspecific_ptr(THR_THD, 0); + thd= 0; + } } #endif if (options & REFRESH_LOG) From 9dd14fc38132022fa527076a75512d8a4b38ca39 Mon Sep 17 00:00:00 2001 From: "lars@mysql.com" <> Date: Thu, 1 Sep 2005 17:58:00 +0200 Subject: [PATCH 28/41] BUG#12542: Added comments --- sql/log_event.cc | 20 ++++++++++++++++++++ sql/sql_parse.cc | 3 ++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 66c732e8cb0..b08439a20b8 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1008,6 +1008,16 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) #endif clear_all_errors(thd, rli); + /* + Note: We do not need to execute reset_one_shot_variables() if this + db_ok() test fails. + Reason: The db stored in binlog events is the same for SET and for + its companion query. If the SET is ignored because of + db_ok(), the companion query will also be ignored, and if + the companion query is ignored in the db_ok() test of + ::exec_event(), then the companion SET also have so we + don't need to reset_one_shot_variables(). + */ if (db_ok(thd->db, replicate_do_db, replicate_ignore_db)) { thd->set_time((time_t)when); @@ -1762,6 +1772,16 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, Create_file_log_event::exec_event() and then discarding Append_block and al. Another way is do the filtering in the I/O thread (more efficient: no disk writes at all). + + + Note: We do not need to execute reset_one_shot_variables() if this + db_ok() test fails. + Reason: The db stored in binlog events is the same for SET and for + its companion query. If the SET is ignored because of + db_ok(), the companion query will also be ignored, and if + the companion query is ignored in the db_ok() test of + ::exec_event(), then the companion SET also have so we + don't need to reset_one_shot_variables(). */ if (db_ok(thd->db, replicate_do_db, replicate_ignore_db)) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8e457b67f00..94064d5ddfa 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1998,7 +1998,8 @@ mysql_execute_command(THD *thd) Exceptions are: - SET: we always execute it (Not that many SET commands exists in - the binary log anyway) + the binary log anyway -- only 4.1 masters write SET statements, + in 5.0 there are no SET statements in the binary log) - DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we have stale files on slave caused by exclusion of one tmp table). */ From 0a2e013c9d9c2aebbdadbd88d2b37cf54dd93c80 Mon Sep 17 00:00:00 2001 From: "joerg@mysql.com" <> Date: Thu, 1 Sep 2005 20:01:21 +0200 Subject: [PATCH 29/41] Add "MYSQL_BASE_VERSION" to the list of substituted variables in the "scripts" subdirectory. --- scripts/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/Makefile.am b/scripts/Makefile.am index a5e6b094bf6..3dd3e4fbbac 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -119,6 +119,7 @@ SUFFIXES = .sh -e 's!@''innodb_system_libs''@!@innodb_system_libs@!' \ -e 's!@''openssl_libs''@!@openssl_libs@!' \ -e 's!@''VERSION''@!@VERSION@!' \ + -e 's!@''MYSQL_BASE_VERSION''@!@MYSQL_BASE_VERSION@!' \ -e 's!@''MYSQL_SERVER_SUFFIX''@!@MYSQL_SERVER_SUFFIX@!' \ -e 's!@''COMPILATION_COMMENT''@!@COMPILATION_COMMENT@!' \ -e 's!@''MACHINE_TYPE''@!@MACHINE_TYPE@!' \ From f1f45919c9d4f73729d323f141645648951c68f8 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 1 Sep 2005 20:49:06 +0200 Subject: [PATCH 30/41] Fix missing command terminator --- mysql-test/t/rpl_slave_status.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/rpl_slave_status.test b/mysql-test/t/rpl_slave_status.test index 7e16097edd0..2c5bd2bffb0 100644 --- a/mysql-test/t/rpl_slave_status.test +++ b/mysql-test/t/rpl_slave_status.test @@ -1,5 +1,5 @@ # Test case for BUG #10780 -source include/master-slave.inc +--source include/master-slave.inc connection master; grant replication slave on *.* to rpl@127.0.0.1 identified by 'rpl'; connection slave; From 78f32604ac9e7342beef1287d67af92e3a34c41b Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Fri, 2 Sep 2005 11:14:47 +0200 Subject: [PATCH 31/41] mysqltest.test: Remove output from shells in result file --- mysql-test/r/mysqltest.result | 7 ++----- mysql-test/t/mysqltest.test | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 80c54f589da..9175bdc7250 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -179,9 +179,7 @@ source database echo message echo message mysqltest: At line 1: Empty variable -sh: -c: line 0: syntax error near unexpected token `;' -sh: -c: line 0: `;' -mysqltest: At line 1: command ";" failed +mysqltest: At line 1: command "';' 2> /dev/null" failed mysqltest: At line 1: Missing argument in exec MySQL "MySQL" @@ -303,8 +301,7 @@ mysqltest: At line 1: First argument to dec must be a variable (start with $) mysqltest: At line 1: End of line junk detected: "1000" mysqltest: At line 1: Missing arguments to system, nothing to do! mysqltest: At line 1: Missing arguments to system, nothing to do! -sh: NonExistsinfComamdn: command not found -mysqltest: At line 1: system command 'NonExistsinfComamdn' failed +mysqltest: At line 1: system command 'NonExistsinfComamdn 2> /dev/null' failed test test2 test3 diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index ee2104d19b0..bfb1919e75c 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -424,7 +424,7 @@ echo ; # Illegal use of exec --error 1 ---exec echo "--exec ;" | $MYSQL_TEST 2>&1 +--exec echo "--exec ';' 2> /dev/null" | $MYSQL_TEST 2>&1 --error 1 --exec echo "--exec " | $MYSQL_TEST 2>&1 @@ -672,7 +672,7 @@ system echo "hej" > /dev/null; --error 1 --exec echo "system $NONEXISTSINFVAREABLI;" | $MYSQL_TEST 2>&1 --error 1 ---exec echo "system NonExistsinfComamdn;" | $MYSQL_TEST 2>&1 +--exec echo "system NonExistsinfComamdn 2> /dev/null;" | $MYSQL_TEST 2>&1 --disable_abort_on_error system NonExistsinfComamdn; From 3a555b999ca97b0541a63c4c76186267720a0197 Mon Sep 17 00:00:00 2001 From: "jonas@eel.(none)" <> Date: Fri, 2 Sep 2005 11:47:24 +0200 Subject: [PATCH 32/41] ndb - bug #10987 make sure not to cut log to early (specificly not use LCP with maxGciStarted that has not yet completed) --- ndb/include/kernel/signaldata/SignalData.hpp | 1 + .../kernel/signaldata/StartFragReq.hpp | 2 ++ .../debugger/signaldata/SignalDataPrint.cpp | 1 + .../common/debugger/signaldata/StartRec.cpp | 25 +++++++++++++++++++ ndb/src/kernel/blocks/dbdih/DbdihMain.cpp | 12 ++++++--- 5 files changed, 38 insertions(+), 3 deletions(-) diff --git a/ndb/include/kernel/signaldata/SignalData.hpp b/ndb/include/kernel/signaldata/SignalData.hpp index f9d3a6faa64..b0cfbc1540c 100644 --- a/ndb/include/kernel/signaldata/SignalData.hpp +++ b/ndb/include/kernel/signaldata/SignalData.hpp @@ -215,5 +215,6 @@ GSN_PRINT_SIGNATURE(printSCAN_FRAGREQ); GSN_PRINT_SIGNATURE(printCONTINUEB_NDBFS); GSN_PRINT_SIGNATURE(printCONTINUEB_DBDIH); +GSN_PRINT_SIGNATURE(printSTART_FRAG_REQ); #endif diff --git a/ndb/include/kernel/signaldata/StartFragReq.hpp b/ndb/include/kernel/signaldata/StartFragReq.hpp index ec05c1ee366..ab17a147195 100644 --- a/ndb/include/kernel/signaldata/StartFragReq.hpp +++ b/ndb/include/kernel/signaldata/StartFragReq.hpp @@ -32,6 +32,8 @@ class StartFragReq { public: STATIC_CONST( SignalLength = 19 ); + friend bool printSTART_FRAG_REQ(FILE *, const Uint32 *, Uint32, Uint16); + private: Uint32 userPtr; Uint32 userRef; diff --git a/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp b/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp index a4cee38e06f..bd1dff074f9 100644 --- a/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp +++ b/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp @@ -195,6 +195,7 @@ SignalDataPrintFunctions[] = { ,{ GSN_ACC_LOCKREQ, printACC_LOCKREQ } ,{ GSN_LQH_TRANSCONF, printLQH_TRANSCONF } ,{ GSN_SCAN_FRAGREQ, printSCAN_FRAGREQ } + ,{ GSN_START_FRAGREQ, printSTART_FRAG_REQ } ,{ 0, 0 } }; diff --git a/ndb/src/common/debugger/signaldata/StartRec.cpp b/ndb/src/common/debugger/signaldata/StartRec.cpp index 482e3cb0728..54830e533c5 100644 --- a/ndb/src/common/debugger/signaldata/StartRec.cpp +++ b/ndb/src/common/debugger/signaldata/StartRec.cpp @@ -17,6 +17,7 @@ #include #include +#include bool printSTART_REC_REQ(FILE * output, @@ -50,3 +51,27 @@ printSTART_REC_CONF(FILE * output, return true; } + +bool +printSTART_FRAG_REQ(FILE * output, + const Uint32 * theData, + Uint32 len, + Uint16 recBlockNo) +{ + StartFragReq* sig = (StartFragReq*)theData; + + fprintf(output, " table: %d frag: %d lcpId: %d lcpNo: %d #nodes: %d \n", + sig->tableId, sig->fragId, sig->lcpId, sig->lcpNo, + sig->noOfLogNodes); + + for(Uint32 i = 0; inoOfLogNodes; i++) + { + fprintf(output, " (node: %d startGci: %d lastGci: %d)", + sig->lqhLogNode[i], + sig->startGci[i], + sig->lastGci[i]); + } + + fprintf(output, "\n"); + return true; +} diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index 669be2b48f0..ca066b588e7 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -9640,6 +9640,9 @@ void Dbdih::execLCP_FRAG_REP(Signal* signal) } bool tableDone = reportLcpCompletion(lcpReport); + + Uint32 started = lcpReport->maxGciStarted; + Uint32 completed = lcpReport->maxGciCompleted; if(tableDone){ jam(); @@ -9673,7 +9676,9 @@ void Dbdih::execLCP_FRAG_REP(Signal* signal) signal->theData[1] = nodeId; signal->theData[2] = tableId; signal->theData[3] = fragId; - sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 4, JBB); + signal->theData[4] = started; + signal->theData[5] = completed; + sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 6, JBB); #endif bool ok = false; @@ -10790,7 +10795,9 @@ void Dbdih::findMinGci(ReplicaRecordPtr fmgReplicaPtr, lcpNo = fmgReplicaPtr.p->nextLcp; do { ndbrequire(lcpNo < MAX_LCP_STORED); - if (fmgReplicaPtr.p->lcpStatus[lcpNo] == ZVALID) { + if (fmgReplicaPtr.p->lcpStatus[lcpNo] == ZVALID && + fmgReplicaPtr.p->maxGciStarted[lcpNo] <= coldgcp) + { jam(); keepGci = fmgReplicaPtr.p->maxGciCompleted[lcpNo]; oldestRestorableGci = fmgReplicaPtr.p->maxGciStarted[lcpNo]; @@ -10798,7 +10805,6 @@ void Dbdih::findMinGci(ReplicaRecordPtr fmgReplicaPtr, return; } else { jam(); - ndbrequire(fmgReplicaPtr.p->lcpStatus[lcpNo] == ZINVALID); if (fmgReplicaPtr.p->createGci[0] == fmgReplicaPtr.p->initialGci) { jam(); /*------------------------------------------------------------------- From b267176708e0bb94c537b211b67e950640abeed2 Mon Sep 17 00:00:00 2001 From: "jonas@eel.(none)" <> Date: Fri, 2 Sep 2005 11:50:50 +0200 Subject: [PATCH 33/41] ndb - bug#12608 Always abort if node failure occured between startTransaction and commit (can later be improved by wl#2610) --- ndb/src/kernel/blocks/dbtc/DbtcMain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index 93b122b9a99..f0861d1f0cc 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -4404,7 +4404,7 @@ Dbtc::DIVER_node_fail_handling(Signal* signal, UintR Tgci) *------------------------------------------------------------------------*/ tabortInd = ZFALSE; setupFailData(signal); - if (tabortInd == ZFALSE) { + if (false && tabortInd == ZFALSE) { jam(); commitGciHandling(signal, Tgci); toCommitHandlingLab(signal); From 4b80ed1bde9622490b5a6e75ad9c2c3a54dbd3d2 Mon Sep 17 00:00:00 2001 From: "jonas@eel.(none)" <> Date: Fri, 2 Sep 2005 11:55:41 +0200 Subject: [PATCH 34/41] ndb - fix printout related to bug#10987 --- ndb/src/common/debugger/EventLogger.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ndb/src/common/debugger/EventLogger.cpp b/ndb/src/common/debugger/EventLogger.cpp index 97945394690..f7cef644c64 100644 --- a/ndb/src/common/debugger/EventLogger.cpp +++ b/ndb/src/common/debugger/EventLogger.cpp @@ -585,11 +585,13 @@ EventLogger::getText(char * m_text, size_t m_text_len, BaseString::snprintf(m_text, m_text_len, "%sTable ID = %u, fragment ID = %u has completed LCP " - "on Node %u", + "on Node %u maxGciStarted: %d maxGciCompleted: %d", theNodeId, theData[2], theData[3], - theData[1]); + theData[1], + theData[4], + theData[5]); break; case EventReport::TransReportCounters: // ------------------------------------------------------------------- From ed093d581a5bd979dc86fcfa5b7ccf5c3da84cb5 Mon Sep 17 00:00:00 2001 From: "joerg@mysql.com" <> Date: Fri, 2 Sep 2005 20:07:08 +0200 Subject: [PATCH 35/41] Compile error fix. --- client/mysqltest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 33702e9d1d2..92735c97fea 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -812,9 +812,9 @@ int var_set(const char *var_name, const char *var_name_end, int open_file(const char *name) { + char buff[FN_REFLEN]; DBUG_ENTER("open_file"); DBUG_PRINT("enter", ("name: %s", name)); - char buff[FN_REFLEN]; if (!test_if_hard_path(name)) { strxmov(buff, opt_basedir, name, NullS); @@ -843,9 +843,9 @@ int open_file(const char *name) int check_eol_junk(const char *eol) { + const char *p= eol; DBUG_ENTER("check_eol_junk"); DBUG_PRINT("enter", ("eol: %s", eol)); - const char *p= eol; /* Remove all spacing chars except new line */ while (*p && my_isspace(charset_info, *p) && (*p != '\n')) p++; From 3c6ec2a98e760d16acc32173053bbe75ae75b890 Mon Sep 17 00:00:00 2001 From: "tulin@dl145b.mysql.com" <> Date: Mon, 5 Sep 2005 09:13:28 +0200 Subject: [PATCH 36/41] fixed small bug in ndb redolog printer + added option to dumpe rest of page after exnd of data --- .../blocks/dblqh/redoLogReader/records.cpp | 4 ++- .../blocks/dblqh/redoLogReader/records.hpp | 2 +- .../dblqh/redoLogReader/redoLogFileReader.cpp | 25 ++++++++++++++----- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp index ba6d65ca838..b7e2ab072b5 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp @@ -134,7 +134,9 @@ bool PrepareOperationRecord::check() { return true; } -Uint32 PrepareOperationRecord::getLogRecordSize() { +Uint32 PrepareOperationRecord::getLogRecordSize(Uint32 wordsRead) { + if (wordsRead < 2) + return 2; // make sure we read more return m_logRecordSize; } diff --git a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp index 11b8dc4a6fa..b2da7427f4e 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp @@ -83,7 +83,7 @@ class PrepareOperationRecord { friend NdbOut& operator<<(NdbOut&, const PrepareOperationRecord&); public: bool check(); - Uint32 getLogRecordSize(); + Uint32 getLogRecordSize(Uint32 wordsRead); protected: Uint32 m_recordType; diff --git a/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp b/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp index aa8b1d25e4e..751d27db74e 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp @@ -41,6 +41,7 @@ void doExit(); FILE * f= 0; char fileName[256]; +bool theDumpFlag = false; bool thePrintFlag = true; bool theCheckFlag = true; bool onlyPageHeaders = false; @@ -208,7 +209,7 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read case ZPREP_OP_TYPE: poRecord = (PrepareOperationRecord *) redoLogPagePos; - wordIndex += poRecord->getLogRecordSize(); + wordIndex += poRecord->getLogRecordSize(PAGESIZE-wordIndex); if (wordIndex <= PAGESIZE) { if (thePrintFlag) ndbout << (*poRecord); if (theCheckFlag) { @@ -277,10 +278,9 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read ndbout << " ------ERROR: UNKNOWN RECORD TYPE------" << endl; // Print out remaining data in this page - for (int j = wordIndex; j < PAGESIZE; j++){ - Uint32 unknown = redoLogPage[i*PAGESIZE + j]; - - ndbout_c("%-30d%-12u%-12x", j, unknown, unknown); + for (int k = wordIndex; k < PAGESIZE; k++){ + Uint32 unknown = redoLogPage[i*PAGESIZE + k]; + ndbout_c("%-30d%-12u%-12x", k, unknown, unknown); } doExit(); @@ -289,8 +289,19 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read if (lastPage) + { + if (theDumpFlag) + { + ndbout << " ------PAGE END: DUMPING REST OF PAGE------" << endl; + for (int k = wordIndex > PAGESIZE ? oldWordIndex : wordIndex; + k < PAGESIZE; k++) + { + Uint32 word = redoLogPage[i*PAGESIZE + k]; + ndbout_c("%-30d%-12u%-12x", k, word, word); + } + } break; - + } if (wordIndex > PAGESIZE) { words_from_previous_page = PAGESIZE - oldWordIndex; ndbout << " ----------- Record continues on next page -----------" << endl; @@ -353,6 +364,8 @@ void readArguments(int argc, const char** argv) { if (strcmp(argv[i], "-noprint") == 0) { thePrintFlag = false; + } else if (strcmp(argv[i], "-dump") == 0) { + theDumpFlag = true; } else if (strcmp(argv[i], "-nocheck") == 0) { theCheckFlag = false; } else if (strcmp(argv[i], "-mbyteheaders") == 0) { From c83eedc829914de214aa928b4919f8384c75190a Mon Sep 17 00:00:00 2001 From: "tulin@dl145b.mysql.com" <> Date: Mon, 5 Sep 2005 09:29:28 +0200 Subject: [PATCH 37/41] added timestamp to shutdown messages in ndbd --- ndb/src/kernel/main.cpp | 2 +- ndb/src/kernel/vm/Emulator.cpp | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/ndb/src/kernel/main.cpp b/ndb/src/kernel/main.cpp index 1e5cd5270e4..1cab3c96d19 100644 --- a/ndb/src/kernel/main.cpp +++ b/ndb/src/kernel/main.cpp @@ -57,7 +57,7 @@ int main(int argc, char** argv) NDB_INIT(argv[0]); // Print to stdout/console g_eventLogger.createConsoleHandler(); - g_eventLogger.setCategory("NDB"); + g_eventLogger.setCategory("ndbd"); g_eventLogger.enable(Logger::LL_ON, Logger::LL_CRITICAL); g_eventLogger.enable(Logger::LL_ON, Logger::LL_ERROR); g_eventLogger.enable(Logger::LL_ON, Logger::LL_WARNING); diff --git a/ndb/src/kernel/vm/Emulator.cpp b/ndb/src/kernel/vm/Emulator.cpp index d6ed6c0dafd..f52233fc276 100644 --- a/ndb/src/kernel/vm/Emulator.cpp +++ b/ndb/src/kernel/vm/Emulator.cpp @@ -30,13 +30,15 @@ #include #include -#include #include #include +#include + extern "C" { extern void (* ndb_new_handler)(); } +extern EventLogger g_eventLogger; /** * Declare the global variables @@ -141,23 +143,23 @@ NdbShutdown(NdbShutdownType type, switch(type){ case NST_Normal: - ndbout << "Shutdown initiated" << endl; + g_eventLogger.info("Shutdown initiated"); break; case NST_Watchdog: - ndbout << "Watchdog " << shutting << " system" << endl; + g_eventLogger.info("Watchdog %s system", shutting); break; case NST_ErrorHandler: - ndbout << "Error handler " << shutting << " system" << endl; + g_eventLogger.info("Error handler %s system", shutting); break; case NST_ErrorHandlerSignal: - ndbout << "Error handler signal " << shutting << " system" << endl; + g_eventLogger.info("Error handler signal %s system", shutting); break; case NST_Restart: - ndbout << "Restarting system" << endl; + g_eventLogger.info("Restarting system"); break; default: - ndbout << "Error handler " << shutting << " system" - << " (unknown type: " << (unsigned)type << ")" << endl; + g_eventLogger.info("Error handler %s system (unknown type: %u)", + shutting, (unsigned)type); type = NST_ErrorHandler; break; } @@ -173,7 +175,7 @@ NdbShutdown(NdbShutdownType type, /** * Very serious, don't attempt to free, just die!! */ - ndbout << "Watchdog shutdown completed - " << exitAbort << endl; + g_eventLogger.info("Watchdog shutdown completed - %s", exitAbort); #if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) signal(6, SIG_DFL); abort(); @@ -227,7 +229,7 @@ NdbShutdown(NdbShutdownType type, } if(type != NST_Normal && type != NST_Restart){ - ndbout << "Error handler shutdown completed - " << exitAbort << endl; + g_eventLogger.info("Error handler shutdown completed - %s", exitAbort); #if ( defined VM_TRACE || defined ERROR_INSERT ) && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) signal(6, SIG_DFL); abort(); @@ -243,7 +245,7 @@ NdbShutdown(NdbShutdownType type, exit(restartType); } - ndbout << "Shutdown completed - exiting" << endl; + g_eventLogger.info("Shutdown completed - exiting"); } else { /** * Shutdown is already in progress @@ -253,7 +255,7 @@ NdbShutdown(NdbShutdownType type, * If this is the watchdog, kill system the hard way */ if (type== NST_Watchdog){ - ndbout << "Watchdog is killing system the hard way" << endl; + g_eventLogger.info("Watchdog is killing system the hard way"); #if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) signal(6, SIG_DFL); abort(); From 1fb4441782580fb45d5bea9376e7f43c6ee816e6 Mon Sep 17 00:00:00 2001 From: "ramil@mysql.com" <> Date: Mon, 5 Sep 2005 16:31:42 +0500 Subject: [PATCH 38/41] a fix (bug #4214: Table corruption with myisampack and large BLOB objects). --- myisam/mi_check.c | 6 ++- myisam/mi_packrec.c | 113 +++++++++++++++++++++----------------------- myisam/mi_static.c | 2 +- myisam/myisamdef.h | 5 +- myisam/myisampack.c | 25 +++------- 5 files changed, 69 insertions(+), 82 deletions(-) diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 60a2b664c70..711331518a7 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -3189,9 +3189,11 @@ int sort_write_record(MI_SORT_PARAM *sort_param) break; case COMPRESSED_RECORD: reclength=info->packed_length; - length=save_pack_length(block_buff,reclength); + length= save_pack_length((uint) share->pack.version, block_buff, + reclength); if (info->s->base.blobs) - length+=save_pack_length(block_buff+length,info->blob_length); + length+= save_pack_length((uint) share->pack.version, + block_buff + length, info->blob_length); if (my_b_write(&info->rec_cache,block_buff,length) || my_b_write(&info->rec_cache,(byte*) sort_param->rec_buff,reclength)) { diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c index 1a71d43a7f1..322420b71db 100644 --- a/myisam/mi_packrec.c +++ b/myisam/mi_packrec.c @@ -149,11 +149,12 @@ my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys) my_errno=HA_ERR_END_OF_FILE; goto err0; } - if (memcmp((byte*) header,(byte*) myisam_pack_file_magic,4)) + if (memcmp((byte*) header, (byte*) myisam_pack_file_magic, 3)) { my_errno=HA_ERR_WRONG_IN_RECORD; goto err0; } + share->pack.version= header[3]; share->pack.header_length= uint4korr(header+4); share->min_pack_length=(uint) uint4korr(header+8); share->max_pack_length=(uint) uint4korr(header+12); @@ -1040,38 +1041,12 @@ uint _mi_pack_get_block_info(MI_INFO *myisam, MI_BLOCK_INFO *info, File file, return BLOCK_FATAL_ERROR; DBUG_DUMP("header",(byte*) header,ref_length); } - if (header[0] < 254) - { - info->rec_len=header[0]; - head_length=1; - } - else if (header[0] == 254) - { - info->rec_len=uint2korr(header+1); - head_length=3; - } - else - { - info->rec_len=uint3korr(header+1); - head_length=4; - } + head_length= read_pack_length((uint) myisam->s->pack.version, header, + &info->rec_len); if (myisam->s->base.blobs) { - if (header[head_length] < 254) - { - info->blob_len=header[head_length]; - head_length++; - } - else if (header[head_length] == 254) - { - info->blob_len=uint2korr(header+head_length+1); - head_length+=3; - } - else - { - info->blob_len=uint3korr(header+head_length+1); - head_length+=4; - } + head_length+= read_pack_length((uint) myisam->s->pack.version, + header + head_length, &info->blob_len); if (!(mi_alloc_rec_buff(myisam,info->rec_len + info->blob_len, &myisam->rec_buff))) return BLOCK_FATAL_ERROR; /* not enough memory */ @@ -1220,34 +1195,12 @@ void _mi_unmap_file(MI_INFO *info) static uchar *_mi_mempack_get_block_info(MI_INFO *myisam,MI_BLOCK_INFO *info, uchar *header) { - if (header[0] < 254) - info->rec_len= *header++; - else if (header[0] == 254) - { - info->rec_len=uint2korr(header+1); - header+=3; - } - else - { - info->rec_len=uint3korr(header+1); - header+=4; - } + header+= read_pack_length((uint) myisam->s->pack.version, header, + &info->rec_len); if (myisam->s->base.blobs) { - if (header[0] < 254) - { - info->blob_len= *header++; - } - else if (header[0] == 254) - { - info->blob_len=uint2korr(header+1); - header+=3; - } - else - { - info->blob_len=uint3korr(header+1); - header+=4; - } + header+= read_pack_length((uint) myisam->s->pack.version, header, + &info->blob_len); /* mi_alloc_rec_buff sets my_errno on error */ if (!(mi_alloc_rec_buff(myisam, info->blob_len, &myisam->rec_buff))) @@ -1319,7 +1272,7 @@ static int _mi_read_rnd_mempack_record(MI_INFO *info, byte *buf, /* Save length of row */ -uint save_pack_length(byte *block_buff,ulong length) +uint save_pack_length(uint version, byte *block_buff, ulong length) { if (length < 254) { @@ -1333,6 +1286,46 @@ uint save_pack_length(byte *block_buff,ulong length) return 3; } *(uchar*) block_buff=255; - int3store(block_buff+1,(ulong) length); - return 4; + if (version == 1) /* old format */ + { + DBUG_ASSERT(length <= 0xFFFFFF); + int3store(block_buff + 1, (ulong) length); + return 4; + } + else + { + int4store(block_buff + 1, (ulong) length); + return 5; + } +} + + +uint read_pack_length(uint version, const uchar *buf, ulong *length) +{ + if (buf[0] < 254) + { + *length= buf[0]; + return 1; + } + else if (buf[0] == 254) + { + *length= uint2korr(buf + 1); + return 3; + } + if (version == 1) /* old format */ + { + *length= uint3korr(buf + 1); + return 4; + } + else + { + *length= uint4korr(buf + 1); + return 5; + } +} + + +uint calc_pack_length(uint version, ulong length) +{ + return (length < 254) ? 1 : (length < 65536) ? 3 : (version == 1) ? 4 : 5; } diff --git a/myisam/mi_static.c b/myisam/mi_static.c index f41aeff8453..9725c120f44 100644 --- a/myisam/mi_static.c +++ b/myisam/mi_static.c @@ -27,7 +27,7 @@ LIST *myisam_open_list=0; uchar NEAR myisam_file_magic[]= { (uchar) 254, (uchar) 254,'\007', '\001', }; uchar NEAR myisam_pack_file_magic[]= -{ (uchar) 254, (uchar) 254,'\010', '\001', }; +{ (uchar) 254, (uchar) 254,'\010', '\002', }; my_string myisam_log_filename=(char*) "myisam.log"; File myisam_log_file= -1; uint myisam_quick_table_bits=9; diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index a41bcf5449b..15b310e907e 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -149,6 +149,7 @@ typedef struct st_mi_blob /* Info of record */ typedef struct st_mi_isam_pack { ulong header_length; uint ref_length; + uchar version; } MI_PACK; @@ -669,7 +670,9 @@ extern void _myisam_log_record(enum myisam_log_commands command,MI_INFO *info, int result); extern my_bool _mi_memmap_file(MI_INFO *info); extern void _mi_unmap_file(MI_INFO *info); -extern uint save_pack_length(byte *block_buff,ulong length); +extern uint save_pack_length(uint version, byte *block_buff, ulong length); +extern uint read_pack_length(uint version, const uchar *buf, ulong *length); +extern uint calc_pack_length(uint version, ulong length); uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite); char *mi_state_info_read(char *ptr, MI_STATE_INFO *state); diff --git a/myisam/myisampack.c b/myisam/myisampack.c index 405c69544e7..60522c6f364 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -1666,6 +1666,7 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) HUFF_COUNTS *count,*end_count; HUFF_TREE *tree; MI_INFO *isam_file=mrg->file[0]; + uint pack_version= (uint) isam_file->s->pack.version; DBUG_ENTER("compress_isam_file"); if (!(record=(byte*) my_alloca(isam_file->s->base.reclength))) @@ -1693,23 +1694,10 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) huff_counts[i].tree->height+huff_counts[i].length_bits; } max_calc_length/=8; - if (max_calc_length < 254) - pack_ref_length=1; - else if (max_calc_length <= 65535) - pack_ref_length=3; - else - pack_ref_length=4; + pack_ref_length= calc_pack_length(pack_version, max_calc_length); record_count=0; - pack_blob_length=0; - if (isam_file->s->base.blobs) - { - if (mrg->max_blob_length < 254) - pack_blob_length=1; - else if (mrg->max_blob_length <= 65535) - pack_blob_length=3; - else - pack_blob_length=4; - } + pack_blob_length= isam_file->s->base.blobs ? + calc_pack_length(pack_version, mrg->max_blob_length) : 0; max_pack_length=pack_ref_length+pack_blob_length; mrg_reset(mrg); @@ -1865,9 +1853,10 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) } flush_bits(); length=(ulong) (file_buffer.pos-record_pos)-max_pack_length; - pack_length=save_pack_length(record_pos,length); + pack_length= save_pack_length(pack_version, record_pos, length); if (pack_blob_length) - pack_length+=save_pack_length(record_pos+pack_length,tot_blob_length); + pack_length+= save_pack_length(pack_version, record_pos + pack_length, + tot_blob_length); /* Correct file buffer if the header was smaller */ if (pack_length != max_pack_length) From 7573d04323232958c7e15d93e53f44da435be4d0 Mon Sep 17 00:00:00 2001 From: "tulin@dl145b.mysql.com" <> Date: Mon, 5 Sep 2005 15:14:44 +0200 Subject: [PATCH 39/41] Bug #12992 Cluster StopOnError = Y restarts ndbd indefinitly --- ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp | 8 ++++ ndb/src/kernel/error/ErrorReporter.cpp | 14 ++++++- ndb/src/kernel/error/ErrorReporter.hpp | 2 + ndb/src/kernel/main.cpp | 37 +++++++++++++++++++ ndb/src/kernel/vm/Emulator.cpp | 6 +++ ndb/src/kernel/vm/Emulator.hpp | 3 +- 6 files changed, 67 insertions(+), 3 deletions(-) diff --git a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp index 2e2c834ad9c..071a85c96da 100644 --- a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp +++ b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp @@ -2493,6 +2493,14 @@ void Ndbcntr::Missra::sendNextSTTOR(Signal* signal){ const Uint32 start = currentBlockIndex; + if (currentStartPhase == ZSTART_PHASE_6) + { + // Ndbd has passed the critical startphases. + // Change error handler from "startup" state + // to normal state. + ErrorReporter::setErrorHandlerShutdownType(); + } + for(; currentBlockIndex < ALL_BLOCKS_SZ; currentBlockIndex++){ jam(); if(ALL_BLOCKS[currentBlockIndex].NextSP == currentStartPhase){ diff --git a/ndb/src/kernel/error/ErrorReporter.cpp b/ndb/src/kernel/error/ErrorReporter.cpp index e4ead4ce34d..25409db48a8 100644 --- a/ndb/src/kernel/error/ErrorReporter.cpp +++ b/ndb/src/kernel/error/ErrorReporter.cpp @@ -152,6 +152,14 @@ ErrorReporter::formatMessage(ErrorCategory type, return; } +NdbShutdownType ErrorReporter::s_errorHandlerShutdownType = NST_ErrorHandler; + +void +ErrorReporter::setErrorHandlerShutdownType(NdbShutdownType nst) +{ + s_errorHandlerShutdownType = nst; +} + void ErrorReporter::handleAssert(const char* message, const char* file, int line) { @@ -170,7 +178,7 @@ ErrorReporter::handleAssert(const char* message, const char* file, int line) WriteMessage(assert, ERR_ERROR_PRGERR, message, refMessage, theEmulatedJamIndex, theEmulatedJam); - NdbShutdown(NST_ErrorHandler); + NdbShutdown(s_errorHandlerShutdownType); } void @@ -182,7 +190,7 @@ ErrorReporter::handleThreadAssert(const char* message, BaseString::snprintf(refMessage, 100, "file: %s lineNo: %d - %s", file, line, message); - NdbShutdown(NST_ErrorHandler); + NdbShutdown(s_errorHandlerShutdownType); }//ErrorReporter::handleThreadAssert() @@ -201,6 +209,8 @@ ErrorReporter::handleError(ErrorCategory type, int messageID, if(messageID == ERR_ERROR_INSERT){ NdbShutdown(NST_ErrorInsert); } else { + if (nst == NST_ErrorHandler) + nst = s_errorHandlerShutdownType; NdbShutdown(nst); } } diff --git a/ndb/src/kernel/error/ErrorReporter.hpp b/ndb/src/kernel/error/ErrorReporter.hpp index 2c79f242eea..c5533df46f4 100644 --- a/ndb/src/kernel/error/ErrorReporter.hpp +++ b/ndb/src/kernel/error/ErrorReporter.hpp @@ -26,6 +26,7 @@ class ErrorReporter { public: + static void setErrorHandlerShutdownType(NdbShutdownType nst = NST_ErrorHandler); static void handleAssert(const char* message, const char* file, int line); @@ -57,6 +58,7 @@ public: static const char* formatTimeStampString(); private: + static enum NdbShutdownType s_errorHandlerShutdownType; }; #endif diff --git a/ndb/src/kernel/main.cpp b/ndb/src/kernel/main.cpp index 1cab3c96d19..aa220b0ae05 100644 --- a/ndb/src/kernel/main.cpp +++ b/ndb/src/kernel/main.cpp @@ -45,8 +45,14 @@ extern NdbMutex * theShutdownMutex; void catchsigs(bool ignore); // for process signal handling +#define MAX_FAILED_STARTUPS 3 +// Flag set by child through SIGUSR1 to signal a failed startup +static bool failed_startup_flag = false; +// Counter for consecutive failed startups +static Uint32 failed_startups = 0; extern "C" void handler_shutdown(int signum); // for process signal handling extern "C" void handler_error(int signum); // for process signal handling +extern "C" void handler_sigusr1(int signum); // child signalling failed restart // Shows system information void systemInfo(const Configuration & conf, @@ -92,6 +98,8 @@ int main(int argc, char** argv) } #ifndef NDB_WIN32 + signal(SIGUSR1, handler_sigusr1); + for(pid_t child = fork(); child != 0; child = fork()){ /** * Parent @@ -137,6 +145,20 @@ int main(int argc, char** argv) */ exit(0); } + if (!failed_startup_flag) + { + // Reset the counter for consecutive failed startups + failed_startups = 0; + } + else if (failed_startups >= MAX_FAILED_STARTUPS && !theConfig->stopOnError()) + { + /** + * Error shutdown && stopOnError() + */ + g_eventLogger.alert("Ndbd has failed %u consecutive startups. Not restarting", failed_startups); + exit(0); + } + failed_startup_flag = false; g_eventLogger.info("Ndb has terminated (pid %d) restarting", child); theConfig->fetch_configuration(); } @@ -170,6 +192,9 @@ int main(int argc, char** argv) /** * Do startup */ + + ErrorReporter::setErrorHandlerShutdownType(NST_ErrorHandlerStartup); + switch(globalData.theRestartFlag){ case initial_state: globalEmulatorData.theThreadConfig->doStart(NodeState::SL_CMVMI); @@ -359,3 +384,15 @@ handler_error(int signum){ BaseString::snprintf(errorData, 40, "Signal %d received", signum); ERROR_SET_SIGNAL(fatal, 0, errorData, __FILE__); } + +extern "C" +void +handler_sigusr1(int signum) +{ + if (!failed_startup_flag) + { + failed_startups++; + failed_startup_flag = true; + } + g_eventLogger.info("Received signal %d. Ndbd failed startup (%u).", signum, failed_startups); +} diff --git a/ndb/src/kernel/vm/Emulator.cpp b/ndb/src/kernel/vm/Emulator.cpp index f52233fc276..76e1c3ab483 100644 --- a/ndb/src/kernel/vm/Emulator.cpp +++ b/ndb/src/kernel/vm/Emulator.cpp @@ -154,6 +154,9 @@ NdbShutdown(NdbShutdownType type, case NST_ErrorHandlerSignal: g_eventLogger.info("Error handler signal %s system", shutting); break; + case NST_ErrorHandlerStartup: + g_eventLogger.info("Error handler startup %s system", shutting); + break; case NST_Restart: g_eventLogger.info("Restarting system"); break; @@ -229,6 +232,9 @@ NdbShutdown(NdbShutdownType type, } if(type != NST_Normal && type != NST_Restart){ + // Signal parent that error occured during startup + if (type == NST_ErrorHandlerStartup) + kill(getppid(), SIGUSR1); g_eventLogger.info("Error handler shutdown completed - %s", exitAbort); #if ( defined VM_TRACE || defined ERROR_INSERT ) && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) signal(6, SIG_DFL); diff --git a/ndb/src/kernel/vm/Emulator.hpp b/ndb/src/kernel/vm/Emulator.hpp index dba8cb3ab9b..cd194202d85 100644 --- a/ndb/src/kernel/vm/Emulator.hpp +++ b/ndb/src/kernel/vm/Emulator.hpp @@ -83,7 +83,8 @@ enum NdbShutdownType { NST_ErrorHandler, NST_ErrorHandlerSignal, NST_Restart, - NST_ErrorInsert + NST_ErrorInsert, + NST_ErrorHandlerStartup }; enum NdbRestartType { From 7493f615d883fa6b97efb43372aa7c35a5eacee6 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Mon, 5 Sep 2005 17:58:29 +0400 Subject: [PATCH 40/41] func_gconcat.test, func_gconcat.result: Test case for bug #12859 group_concat in subquery cause incorrect not null. --- mysql-test/r/func_gconcat.result | 9 +++++++++ mysql-test/t/func_gconcat.test | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index a6c25fcd26c..12bc5ca2582 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -551,3 +551,12 @@ DROP TABLE t1,t2; select * from (select group_concat('c') from DUAL) t; group_concat('c') NULL +create table t1 ( a int not null default 0); +select * from (select group_concat(a) from t1) t2; +group_concat(a) +NULL +select group_concat('x') UNION ALL select 1; +group_concat('x') +NULL +1 +drop table t1; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 827a2813718..9e003d19ab9 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -348,4 +348,12 @@ DROP TABLE t1,t2; # select * from (select group_concat('c') from DUAL) t; +# +# Bug #12859 group_concat in subquery cause incorrect not null +# +create table t1 ( a int not null default 0); +select * from (select group_concat(a) from t1) t2; +select group_concat('x') UNION ALL select 1; +drop table t1; + # End of 4.1 tests From d5d360b180facaaab6f4ae10cfdae21890315c69 Mon Sep 17 00:00:00 2001 From: "tulin@dl145b.mysql.com" <> Date: Mon, 5 Sep 2005 16:33:40 +0200 Subject: [PATCH 41/41] added --core-file option to ndb executables added parseable printout in ndb_restore --- ndb/include/util/ndb_opts.h | 12 ++++++- ndb/src/kernel/vm/Emulator.cpp | 40 ++++++++++++--------- ndb/src/mgmsrv/ConfigInfo.cpp | 16 ++++----- ndb/src/mgmsrv/MgmtSrvr.cpp | 34 ++++++++++++------ ndb/src/mgmsrv/Services.cpp | 2 -- ndb/tools/Makefile.am | 2 +- ndb/tools/ndb_config.cpp | 1 + ndb/tools/restore/consumer_restore.cpp | 29 ++++++++++------ ndb/tools/restore/restore_main.cpp | 48 ++++++++++++++++---------- 9 files changed, 114 insertions(+), 70 deletions(-) diff --git a/ndb/include/util/ndb_opts.h b/ndb/include/util/ndb_opts.h index ca4ca5eac83..462d9996582 100644 --- a/ndb/include/util/ndb_opts.h +++ b/ndb/include/util/ndb_opts.h @@ -30,8 +30,14 @@ my_bool opt_ndb_optimized_node_selection bool opt_endinfo= 0; my_bool opt_ndb_shm; +my_bool opt_core; #define OPT_NDB_CONNECTSTRING 'c' +#if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) +#define OPT_WANT_CORE_DEFAULT 1 +#else +#define OPT_WANT_CORE_DEFAULT 0 +#endif #define NDB_STD_OPTS_COMMON \ { "usage", '?', "Display this help and exit.", \ @@ -57,7 +63,10 @@ my_bool opt_ndb_shm; GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},\ { "connect-string", OPT_NDB_CONNECTSTRING, "same as --ndb-connectstring",\ (gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0,\ - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 } + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },\ + { "core-file", OPT_WANT_CORE, "Write core on errors.",\ + (gptr*) &opt_core, (gptr*) &opt_core, 0,\ + GET_BOOL, NO_ARG, OPT_WANT_CORE_DEFAULT, 0, 0, 0, 0, 0} #ifndef DBUG_OFF #define NDB_STD_OPTS(prog_name) \ @@ -80,6 +89,7 @@ enum ndb_std_options { OPT_NDB_SHM= 256, OPT_NDB_SHM_SIGNUM, OPT_NDB_OPTIMIZED_NODE_SELECTION, + OPT_WANT_CORE, NDB_STD_OPTIONS_LAST /* should always be last in this enum */ }; diff --git a/ndb/src/kernel/vm/Emulator.cpp b/ndb/src/kernel/vm/Emulator.cpp index 76e1c3ab483..058829e05e2 100644 --- a/ndb/src/kernel/vm/Emulator.cpp +++ b/ndb/src/kernel/vm/Emulator.cpp @@ -39,6 +39,7 @@ extern "C" { extern void (* ndb_new_handler)(); } extern EventLogger g_eventLogger; +extern my_bool opt_core; /** * Declare the global variables @@ -168,23 +169,25 @@ NdbShutdown(NdbShutdownType type, } const char * exitAbort = 0; -#if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) - exitAbort = "aborting"; -#else - exitAbort = "exiting"; -#endif + if (opt_core) + exitAbort = "aborting"; + else + exitAbort = "exiting"; if(type == NST_Watchdog){ /** * Very serious, don't attempt to free, just die!! */ g_eventLogger.info("Watchdog shutdown completed - %s", exitAbort); -#if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) - signal(6, SIG_DFL); - abort(); -#else - exit(-1); -#endif + if (opt_core) + { + signal(6, SIG_DFL); + abort(); + } + else + { + exit(-1); + } } #ifndef NDB_WIN32 @@ -236,12 +239,15 @@ NdbShutdown(NdbShutdownType type, if (type == NST_ErrorHandlerStartup) kill(getppid(), SIGUSR1); g_eventLogger.info("Error handler shutdown completed - %s", exitAbort); -#if ( defined VM_TRACE || defined ERROR_INSERT ) && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) - signal(6, SIG_DFL); - abort(); -#else - exit(-1); -#endif + if (opt_core) + { + signal(6, SIG_DFL); + abort(); + } + else + { + exit(-1); + } } /** diff --git a/ndb/src/mgmsrv/ConfigInfo.cpp b/ndb/src/mgmsrv/ConfigInfo.cpp index cface035174..36a72dcb975 100644 --- a/ndb/src/mgmsrv/ConfigInfo.cpp +++ b/ndb/src/mgmsrv/ConfigInfo.cpp @@ -25,6 +25,7 @@ #include extern my_bool opt_ndb_shm; +extern my_bool opt_core; #define MAX_LINE_LENGTH 255 #define KEY_INTERNAL 0 @@ -2140,11 +2141,10 @@ static void require(bool v) { if(!v) { -#ifndef DBUG_OFF - abort(); -#else - exit(-1); -#endif + if (opt_core) + abort(); + else + exit(-1); } } @@ -2214,7 +2214,7 @@ ConfigInfo::ConfigInfo() ndbout << "Error: Parameter " << param._fname << " defined twice in section " << param._section << "." << endl; - exit(-1); + require(false); } // Add new pinfo to section @@ -2264,7 +2264,7 @@ ConfigInfo::ConfigInfo() ndbout << "Check that each entry has a section failed." << endl; ndbout << "Parameter \"" << m_ParamInfo[i]._fname << endl; ndbout << "Edit file " << __FILE__ << "." << endl; - exit(-1); + require(false); } if(m_ParamInfo[i]._type == ConfigInfo::CI_SECTION) @@ -2277,7 +2277,7 @@ ConfigInfo::ConfigInfo() << "\" does not exist in section \"" << m_ParamInfo[i]._section << "\"." << endl; ndbout << "Edit file " << __FILE__ << "." << endl; - exit(-1); + require(false); } } } diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp index 452dabc50e0..acab2ef9eac 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -65,6 +65,18 @@ extern int global_flag_send_heartbeat_now; extern int g_no_nodeid_checks; +extern my_bool opt_core; + +static void require(bool v) +{ + if(!v) + { + if (opt_core) + abort(); + else + exit(-1); + } +} void * MgmtSrvr::logLevelThread_C(void* m) @@ -436,14 +448,14 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, if (tmp_nodeid == 0) { ndbout_c(m_config_retriever->getErrorString()); - exit(-1); + require(false); } // read config from other managent server _config= fetchConfig(); if (_config == 0) { ndbout << m_config_retriever->getErrorString() << endl; - exit(-1); + require(false); } _ownNodeId= tmp_nodeid; } @@ -454,7 +466,7 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, _config= readConfig(); if (_config == 0) { ndbout << "Unable to read config file" << endl; - exit(-1); + require(false); } } @@ -511,7 +523,7 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, if ((m_node_id_mutex = NdbMutex_Create()) == 0) { ndbout << "mutex creation failed line = " << __LINE__ << endl; - exit(-1); + require(false); } if (_ownNodeId == 0) // we did not get node id from other server @@ -522,7 +534,7 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, 0, 0, error_string)){ ndbout << "Unable to obtain requested nodeid: " << error_string.c_str() << endl; - exit(-1); + require(false); } _ownNodeId = tmp; } @@ -533,7 +545,7 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, _ownNodeId)) { ndbout << m_config_retriever->getErrorString() << endl; - exit(-1); + require(false); } } @@ -2203,18 +2215,18 @@ MgmtSrvr::alloc_node_id(NodeId * nodeId, iter(*(ndb_mgm_configuration *)_config->m_configValues, CFG_SECTION_NODE); for(iter.first(); iter.valid(); iter.next()) { unsigned tmp= 0; - if(iter.get(CFG_NODE_ID, &tmp)) abort(); + if(iter.get(CFG_NODE_ID, &tmp)) require(false); if (*nodeId && *nodeId != tmp) continue; found_matching_id= true; - if(iter.get(CFG_TYPE_OF_SECTION, &type_c)) abort(); + if(iter.get(CFG_TYPE_OF_SECTION, &type_c)) require(false); if(type_c != (unsigned)type) continue; found_matching_type= true; if (connected_nodes.get(tmp)) continue; found_free_node= true; - if(iter.get(CFG_NODE_HOST, &config_hostname)) abort(); + if(iter.get(CFG_NODE_HOST, &config_hostname)) require(false); if (config_hostname && config_hostname[0] == 0) config_hostname= 0; else if (client_addr) { @@ -2561,7 +2573,7 @@ MgmtSrvr::backupCallback(BackupEvent & event) int MgmtSrvr::repCommand(Uint32* repReqId, Uint32 request, bool waitCompleted) { - abort(); + require(false); return 0; } @@ -2715,7 +2727,7 @@ MgmtSrvr::setDbParameter(int node, int param, const char * value, ndbout_c("Updating node %d param: %d to %s", node, param, val_char); break; default: - abort(); + require(false); } assert(res); } while(node == 0 && iter.next() == 0); diff --git a/ndb/src/mgmsrv/Services.cpp b/ndb/src/mgmsrv/Services.cpp index 00cf6390c73..46bfb531b61 100644 --- a/ndb/src/mgmsrv/Services.cpp +++ b/ndb/src/mgmsrv/Services.cpp @@ -343,8 +343,6 @@ MgmApiSession::getConfig_old(Parser_t::Context &ctx) { } #endif /* MGM_GET_CONFIG_BACKWARDS_COMPAT */ -inline void require(bool b){ if(!b) abort(); } - void MgmApiSession::getConfig(Parser_t::Context &ctx, const class Properties &args) { diff --git a/ndb/tools/Makefile.am b/ndb/tools/Makefile.am index 89830129576..795441380a8 100644 --- a/ndb/tools/Makefile.am +++ b/ndb/tools/Makefile.am @@ -30,7 +30,7 @@ ndb_restore_SOURCES = restore/restore_main.cpp \ restore/consumer.cpp \ restore/consumer_restore.cpp \ restore/consumer_printer.cpp \ - restore/Restore.cpp + restore/Restore.cpp $(tools_common_sources) ndb_config_SOURCES = ndb_config.cpp \ ../src/mgmsrv/Config.cpp \ diff --git a/ndb/tools/ndb_config.cpp b/ndb/tools/ndb_config.cpp index d188aec1337..725249a5af5 100644 --- a/ndb/tools/ndb_config.cpp +++ b/ndb/tools/ndb_config.cpp @@ -42,6 +42,7 @@ static const char * g_field_delimiter=","; static const char * g_row_delimiter=" "; int g_print_full_config, opt_ndb_shm; +my_bool opt_core; typedef ndb_mgm_configuration_iterator Iter; diff --git a/ndb/tools/restore/consumer_restore.cpp b/ndb/tools/restore/consumer_restore.cpp index d782a561e6a..70ea7460d78 100644 --- a/ndb/tools/restore/consumer_restore.cpp +++ b/ndb/tools/restore/consumer_restore.cpp @@ -14,9 +14,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include "consumer_restore.hpp" #include +extern my_bool opt_core; + extern FilteredNdbOut err; extern FilteredNdbOut info; extern FilteredNdbOut debug; @@ -458,7 +461,11 @@ bool BackupRestore::errorHandler(restore_callback_t *cb) void BackupRestore::exitHandler() { release(); - exit(-1); + NDBT_ProgramExit(NDBT_FAILED); + if (opt_core) + abort(); + else + exit(NDBT_FAILED); } @@ -492,7 +499,7 @@ BackupRestore::logEntry(const LogEntry & tup) { // Deep shit, TODO: handle the error err << "Cannot start transaction" << endl; - exit(-1); + exitHandler(); } // if const NdbDictionary::Table * table = get_table(tup.m_table->m_dictTable); @@ -500,7 +507,7 @@ BackupRestore::logEntry(const LogEntry & tup) if (op == NULL) { err << "Cannot get operation: " << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if int check = 0; @@ -518,13 +525,13 @@ BackupRestore::logEntry(const LogEntry & tup) default: err << "Log entry has wrong operation type." << " Exiting..."; - exit(-1); + exitHandler(); } if (check != 0) { err << "Error defining op: " << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if Bitmask<4096> keys; @@ -553,7 +560,7 @@ BackupRestore::logEntry(const LogEntry & tup) if (check != 0) { err << "Error defining op: " << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if } @@ -582,7 +589,7 @@ BackupRestore::logEntry(const LogEntry & tup) if (!ok) { err << "execute failed: " << errobj << endl; - exit(-1); + exitHandler(); } } @@ -629,7 +636,7 @@ BackupRestore::tuple(const TupleS & tup) { // Deep shit, TODO: handle the error ndbout << "Cannot start transaction" << endl; - exit(-1); + exitHandler(); } // if const TableS * table = tup.getTable(); @@ -638,7 +645,7 @@ BackupRestore::tuple(const TupleS & tup) { ndbout << "Cannot get operation: "; ndbout << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if // TODO: check return value and handle error @@ -646,7 +653,7 @@ BackupRestore::tuple(const TupleS & tup) { ndbout << "writeTuple call failed: "; ndbout << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if for (int i = 0; i < tup.getNoOfAttributes(); i++) @@ -680,7 +687,7 @@ BackupRestore::tuple(const TupleS & tup) { ndbout << "execute failed: "; ndbout << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } m_ndb->closeTransaction(trans); if (ret == 0) diff --git a/ndb/tools/restore/restore_main.cpp b/ndb/tools/restore/restore_main.cpp index 0c4419bb072..d786dffe89e 100644 --- a/ndb/tools/restore/restore_main.cpp +++ b/ndb/tools/restore/restore_main.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "consumer_restore.hpp" #include "consumer_printer.hpp" @@ -116,14 +117,14 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), if (ga_nodeId == 0) { printf("Error in --nodeid,-n setting, see --help\n"); - exit(1); + exit(NDBT_ProgramExit(NDBT_WRONGARGS)); } break; case 'b': if (ga_backupId == 0) { printf("Error in --backupid,-b setting, see --help\n"); - exit(1); + exit(NDBT_ProgramExit(NDBT_WRONGARGS)); } break; } @@ -136,7 +137,7 @@ readArguments(int *pargc, char*** pargv) load_defaults("my",load_default_groups,pargc,pargv); if (handle_options(pargc, pargv, my_long_options, get_one_option)) { - exit(1); + exit(NDBT_ProgramExit(NDBT_WRONGARGS)); } BackupPrinter* printer = new BackupPrinter(); @@ -226,6 +227,15 @@ free_data_callback() g_consumers[i]->tuple_free(); } +static void exitHandler(int code) +{ + NDBT_ProgramExit(code); + if (opt_core) + abort(); + else + exit(code); +} + int main(int argc, char** argv) { @@ -233,7 +243,7 @@ main(int argc, char** argv) if (!readArguments(&argc, &argv)) { - return -1; + exitHandler(NDBT_FAILED); } Ndb::setConnectString(opt_connect_str); @@ -245,7 +255,7 @@ main(int argc, char** argv) if (!metaData.readHeader()) { ndbout << "Failed to read " << metaData.getFilename() << endl << endl; - return -1; + exitHandler(NDBT_FAILED); } const BackupFormat::FileHeader & tmp = metaData.getFileHeader(); @@ -263,20 +273,20 @@ main(int argc, char** argv) if (res == 0) { ndbout_c("Restore: Failed to load content"); - return -1; + exitHandler(NDBT_FAILED); } if (metaData.getNoOfTables() == 0) { ndbout_c("Restore: The backup contains no tables "); - return -1; + exitHandler(NDBT_FAILED); } if (!metaData.validateFooter()) { ndbout_c("Restore: Failed to validate footer."); - return -1; + exitHandler(NDBT_FAILED); } Uint32 i; @@ -285,7 +295,7 @@ main(int argc, char** argv) if (!g_consumers[i]->init()) { clearConsumers(); - return -11; + exitHandler(NDBT_FAILED); } } @@ -300,7 +310,7 @@ main(int argc, char** argv) ndbout_c("Restore: Failed to restore table: %s. " "Exiting...", metaData[i]->getTableName()); - return -11; + exitHandler(NDBT_FAILED); } } } @@ -309,7 +319,7 @@ main(int argc, char** argv) if (!g_consumers[i]->endOfTables()) { ndbout_c("Restore: Failed while closing tables"); - return -11; + exitHandler(NDBT_FAILED); } if (ga_restore || ga_print) @@ -322,7 +332,7 @@ main(int argc, char** argv) if (!dataIter.readHeader()) { ndbout << "Failed to read header of data file. Exiting..." ; - return -11; + exitHandler(NDBT_FAILED); } @@ -340,12 +350,12 @@ main(int argc, char** argv) { ndbout_c("Restore: An error occured while restoring data. " "Exiting..."); - return -1; + exitHandler(NDBT_FAILED); } if (!dataIter.validateFragmentFooter()) { ndbout_c("Restore: Error validating fragment footer. " "Exiting..."); - return -1; + exitHandler(NDBT_FAILED); } } // while (dataIter.readFragmentHeader(res)) @@ -353,7 +363,7 @@ main(int argc, char** argv) { err << "Restore: An error occured while restoring data. Exiting... " << "res=" << res << endl; - return -1; + exitHandler(NDBT_FAILED); } @@ -366,7 +376,7 @@ main(int argc, char** argv) if (!logIter.readHeader()) { err << "Failed to read header of data file. Exiting..." << endl; - return -1; + exitHandler(NDBT_FAILED); } const LogEntry * logEntry = 0; @@ -380,7 +390,7 @@ main(int argc, char** argv) { err << "Restore: An restoring the data log. Exiting... res=" << res << endl; - return -1; + exitHandler(NDBT_FAILED); } logIter.validateFooter(); //not implemented for (i= 0; i < g_consumers.size(); i++) @@ -395,14 +405,14 @@ main(int argc, char** argv) ndbout_c("Restore: Failed to finalize restore table: %s. " "Exiting...", metaData[i]->getTableName()); - return -11; + exitHandler(NDBT_FAILED); } } } } } clearConsumers(); - return 0; + return NDBT_ProgramExit(NDBT_OK); } // main template class Vector;