diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 8b79266d749..8de096e5ec1 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -59,7 +59,8 @@ static const char* default_dbug_option = "d:t:o,/tmp/mysqlbinlog.trace"; #endif static const char *load_default_groups[]= { "mysqlbinlog","client",0 }; -void sql_print_error(const char *format, ...); +static void error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2); +static void warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2); static bool one_database=0, to_last_remote_log= 0, disable_log_bin= 0; static bool opt_hexdump= 0; @@ -92,24 +93,33 @@ static ulonglong rec_count= 0; static short binlog_flags = 0; static MYSQL* mysql = NULL; static const char* dirname_for_local_load= 0; -static bool stop_passed= 0; -static my_bool file_not_closed_error= 0; -/* - check_header() will set the pointer below. - Why do we need here a pointer on an event instead of an event ? - This is because the event will be created (alloced) in read_log_event() - (which returns a pointer) in check_header(). +/** + Pointer to the Format_description_log_event of the currently active binlog. + + This will be changed each time a new Format_description_log_event is + found in the binlog. It is finally destroyed at program termination. */ -static Format_description_log_event* glob_description_event; +static Format_description_log_event* glob_description_event= NULL; -static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, - const char* logname); -static int dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info, - const char* logname); -static int dump_log_entries(const char* logname); -static void die(const char* fmt, ...) __attribute__ ((__noreturn__)); -static MYSQL* safe_connect(); +/** + Exit status for functions in this file. +*/ +enum Exit_status { + /** No error occurred and execution should continue. */ + OK_CONTINUE= 0, + /** An error occurred and execution should stop. */ + ERROR_STOP, + /** No error occurred but execution should stop. */ + OK_STOP +}; + +static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, + const char* logname); +static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info, + const char* logname); +static Exit_status dump_log_entries(const char* logname); +static Exit_status safe_connect(); class Load_log_processor @@ -132,22 +142,29 @@ class Load_log_processor char *fname; Create_file_log_event *event; }; + /* + @todo Should be a map (e.g., a hash map), not an array. With the + present implementation, the number of elements in this array is + about the number of files loaded since the server started, which + may be big after a few years. We should be able to use existing + library data structures for this. /Sven + */ DYNAMIC_ARRAY file_names; - /* - Looking for new uniquie filename that doesn't exist yet by - adding postfix -%x + /** + Looks for a non-existing filename by adding a numerical suffix to + the given base name, creates the generated file, and returns the + filename by modifying the filename argument. - SYNOPSIS - create_unique_file() - - filename buffer for filename - file_name_end tail of buffer that should be changed - should point to a memory enough to printf("-%x",..) + @param[in,out] filename Base filename - RETURN VALUES - values less than 0 - can't find new filename - values great or equal 0 - created file with found filename + @param[in,out] file_name_end Pointer to last character of + filename. The numerical suffix will be written to this position. + Note that there must be a least five bytes of allocated memory + after file_name_end. + + @retval -1 Error (can't find new filename). + @retval >=0 Found file. */ File create_unique_file(char *filename, char *file_name_end) { @@ -201,22 +218,20 @@ public: delete_dynamic(&file_names); } - /* - Obtain Create_file event for LOAD DATA statement by its file_id. + /** + Obtain Create_file event for LOAD DATA statement by its file_id + and remove it from this Load_log_processor's list of events. - SYNOPSIS - grab_event() - file_id - file_id identifiying LOAD DATA statement + Checks whether we have already seen a Create_file_log_event with + the given file_id. If yes, returns a pointer to the event and + removes the event from array describing active temporary files. + From this moment, the caller is responsible for freeing the memory + occupied by the event. - DESCRIPTION - Checks whenever we have already seen Create_file event for this file_id. - If yes then returns pointer to it and removes it from array describing - active temporary files. Since this moment caller is responsible for - freeing memory occupied by this event and associated file name. + @param[in] file_id File id identifying LOAD DATA statement. - RETURN VALUES - Pointer to Create_file event or 0 if there was no such event - with this file_id. + @return Pointer to Create_file_log_event, or NULL if we have not + seen any Create_file_log_event with this file_id. */ Create_file_log_event *grab_event(uint file_id) { @@ -231,23 +246,20 @@ public: return res; } - /* - Obtain file name of temporary file for LOAD DATA statement by its file_id. + /** + Obtain file name of temporary file for LOAD DATA statement by its + file_id and remove it from this Load_log_processor's list of events. - SYNOPSIS - grab_fname() - file_id - file_id identifiying LOAD DATA statement + @param[in] file_id Identifier for the LOAD DATA statement. - DESCRIPTION - Checks whenever we have already seen Begin_load_query event for this - file_id. If yes then returns file name of corresponding temporary file. - Removes record about this file from the array of active temporary files. - Since this moment caller is responsible for freeing memory occupied by - this name. + Checks whether we have already seen Begin_load_query event for + this file_id. If yes, returns the file name of the corresponding + temporary file and removes the filename from the array of active + temporary files. From this moment, the caller is responsible for + freeing the memory occupied by this name. - RETURN VALUES - String with name of temporary file or 0 if we have not seen Begin_load_query - event with this file_id. + @return String with the name of the temporary file, or NULL if we + have not seen any Begin_load_query_event with this file_id. */ char *grab_fname(uint file_id) { @@ -264,19 +276,29 @@ public: } return res; } - int process(Create_file_log_event *ce); - int process(Begin_load_query_log_event *ce); - int process(Append_block_log_event *ae); + Exit_status process(Create_file_log_event *ce); + Exit_status process(Begin_load_query_log_event *ce); + Exit_status process(Append_block_log_event *ae); File prepare_new_file_for_old_format(Load_log_event *le, char *filename); - int load_old_format_file(NET* net, const char *server_fname, - uint server_fname_len, File file); - int process_first_event(const char *bname, uint blen, const uchar *block, - uint block_len, uint file_id, - Create_file_log_event *ce); + Exit_status load_old_format_file(NET* net, const char *server_fname, + uint server_fname_len, File file); + Exit_status process_first_event(const char *bname, uint blen, + const uchar *block, + uint block_len, uint file_id, + Create_file_log_event *ce); }; +/** + Creates and opens a new temporary file in the directory specified by previous call to init_by_dir_name() or init_by_cur_dir(). + @param[in] le The basename of the created file will start with the + basename of the file pointed to by this Load_log_event. + + @param[out] filename Buffer to save the filename in. + + @return File handle >= 0 on success, -1 on error. +*/ File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le, char *filename) { @@ -284,13 +306,13 @@ File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le, char *tail; File file; - fn_format(filename, le->fname, target_dir_name, "", 1); + fn_format(filename, le->fname, target_dir_name, "", MY_REPLACE_DIR); len= strlen(filename); tail= filename + len; if ((file= create_unique_file(filename,tail)) < 0) { - sql_print_error("Could not construct local filename %s",filename); + error("Could not construct local filename %s.",filename); return -1; } @@ -300,16 +322,33 @@ File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le, } -int Load_log_processor::load_old_format_file(NET* net, const char*server_fname, - uint server_fname_len, File file) +/** + Reads a file from a server and saves it locally. + + @param[in,out] net The server to read from. + + @param[in] server_fname The name of the file that the server should + read. + + @param[in] server_fname_len The length of server_fname. + + @param[in,out] file The file to write to. + + @retval ERROR_STOP An error occurred - the program should terminate. + @retval OK_CONTINUE No error, the program should continue. +*/ +Exit_status Load_log_processor::load_old_format_file(NET* net, + const char*server_fname, + uint server_fname_len, + File file) { uchar buf[FN_REFLEN+1]; buf[0] = 0; memcpy(buf + 1, server_fname, server_fname_len + 1); if (my_net_write(net, buf, server_fname_len +2) || net_flush(net)) { - sql_print_error("Failed requesting the remote dump of %s", server_fname); - return -1; + error("Failed requesting the remote dump of %s.", server_fname); + return ERROR_STOP; } for (;;) @@ -319,8 +358,8 @@ int Load_log_processor::load_old_format_file(NET* net, const char*server_fname, { if (my_net_write(net, (uchar*) "", 0) || net_flush(net)) { - sql_print_error("Failed sending the ack packet"); - return -1; + error("Failed sending the ack packet."); + return ERROR_STOP; } /* we just need to send something, as the server will read but @@ -331,63 +370,63 @@ int Load_log_processor::load_old_format_file(NET* net, const char*server_fname, } else if (packet_len == packet_error) { - sql_print_error("Failed reading a packet during the dump of %s ", - server_fname); - return -1; + error("Failed reading a packet during the dump of %s.", server_fname); + return ERROR_STOP; } if (packet_len > UINT_MAX) { - sql_print_error("Illegal length of packet read from net"); - return -1; + error("Illegal length of packet read from net."); + return ERROR_STOP; } if (my_write(file, (uchar*) net->read_pos, (uint) packet_len, MYF(MY_WME|MY_NABP))) - return -1; + return ERROR_STOP; } - return 0; + return OK_CONTINUE; } -/* - Process first event in the sequence of events representing LOAD DATA - statement. +/** + Process the first event in the sequence of events representing a + LOAD DATA statement. - SYNOPSIS - process_first_event() - bname - base name for temporary file to be created - blen - base name length - block - first block of data to be loaded - block_len - first block length - file_id - identifies LOAD DATA statement - ce - pointer to Create_file event object if we are processing - this type of event. + Creates a temporary file to be used in LOAD DATA and writes first + block of data to it. Registers its file name (and optional + Create_file event) in the array of active temporary files. - DESCRIPTION - Creates temporary file to be used in LOAD DATA and writes first block of - data to it. Registers its file name (and optional Create_file event) - in the array of active temporary files. + @param bname Base name for temporary file to be created. + @param blen Base name length. + @param block First block of data to be loaded. + @param block_len First block length. + @param file_id Identifies the LOAD DATA statement. + @param ce Pointer to Create_file event object if we are processing + this type of event. - RETURN VALUES - 0 - success - non-0 - error + @retval ERROR_STOP An error occurred - the program should terminate. + @retval OK_CONTINUE No error, the program should continue. */ - -int Load_log_processor::process_first_event(const char *bname, uint blen, - const uchar *block, uint block_len, - uint file_id, - Create_file_log_event *ce) +Exit_status Load_log_processor::process_first_event(const char *bname, + uint blen, + const uchar *block, + uint block_len, + uint file_id, + Create_file_log_event *ce) { uint full_len= target_dir_name_len + blen + 9 + 9 + 1; - int error= 0; + Exit_status retval= OK_CONTINUE; char *fname, *ptr; File file; File_name_record rec; DBUG_ENTER("Load_log_processor::process_first_event"); if (!(fname= (char*) my_malloc(full_len,MYF(MY_WME)))) - DBUG_RETURN(-1); + { + error("Out of memory."); + delete ce; + DBUG_RETURN(ERROR_STOP); + } memcpy(fname, target_dir_name, target_dir_name_len); ptr= fname + target_dir_name_len; @@ -397,9 +436,10 @@ int Load_log_processor::process_first_event(const char *bname, uint blen, if ((file= create_unique_file(fname,ptr)) < 0) { - sql_print_error("Could not construct local filename %s%s", - target_dir_name,bname); - DBUG_RETURN(-1); + error("Could not construct local filename %s%s.", + target_dir_name,bname); + delete ce; + DBUG_RETURN(ERROR_STOP); } rec.fname= fname; @@ -407,23 +447,39 @@ int Load_log_processor::process_first_event(const char *bname, uint blen, if (set_dynamic(&file_names, (uchar*)&rec, file_id)) { - sql_print_error("Could not construct local filename %s%s", - target_dir_name, bname); - DBUG_RETURN(-1); + error("Out of memory."); + delete ce; + DBUG_RETURN(ERROR_STOP); } if (ce) ce->set_fname_outside_temp_buf(fname, strlen(fname)); if (my_write(file, (uchar*)block, block_len, MYF(MY_WME|MY_NABP))) - error= -1; + { + error("Failed writing to file."); + retval= ERROR_STOP; + } if (my_close(file, MYF(MY_WME))) - error= -1; - DBUG_RETURN(error); + { + error("Failed closing file."); + retval= ERROR_STOP; + } + DBUG_RETURN(retval); } -int Load_log_processor::process(Create_file_log_event *ce) +/** + Process the given Create_file_log_event. + + @see Load_log_processor::process_first_event(const char*,uint,const char*,uint,uint,Create_file_log_event*) + + @param ce Create_file_log_event to process. + + @retval ERROR_STOP An error occurred - the program should terminate. + @retval OK_CONTINUE No error, the program should continue. +*/ +Exit_status Load_log_processor::process(Create_file_log_event *ce) { const char *bname= ce->fname + dirname_length(ce->fname); uint blen= ce->fname_len - (bname-ce->fname); @@ -433,14 +489,46 @@ int Load_log_processor::process(Create_file_log_event *ce) } -int Load_log_processor::process(Begin_load_query_log_event *blqe) +/** + Process the given Begin_load_query_log_event. + + @see Load_log_processor::process_first_event(const char*,uint,const char*,uint,uint,Create_file_log_event*) + + @param ce Begin_load_query_log_event to process. + + @retval ERROR_STOP An error occurred - the program should terminate. + @retval OK_CONTINUE No error, the program should continue. +*/ +Exit_status Load_log_processor::process(Begin_load_query_log_event *blqe) { return process_first_event("SQL_LOAD_MB", 11, blqe->block, blqe->block_len, blqe->file_id, 0); } -int Load_log_processor::process(Append_block_log_event *ae) +/** + Process the given Append_block_log_event. + + Appends the chunk of the file contents specified by the event to the + file created by a previous Begin_load_query_log_event or + Create_file_log_event. + + If the file_id for the event does not correspond to any file + previously registered through a Begin_load_query_log_event or + Create_file_log_event, this member function will print a warning and + return OK_CONTINUE. It is safe to return OK_CONTINUE, because no + query will be written for this event. We should not print an error + and fail, since the missing file_id could be because a (valid) + --start-position has been specified after the Begin/Create event but + before this Append event. + + @param ae Append_block_log_event to process. + + @retval ERROR_STOP An error occurred - the program should terminate. + + @retval OK_CONTINUE No error, the program should continue. +*/ +Exit_status Load_log_processor::process(Append_block_log_event *ae) { DBUG_ENTER("Load_log_processor::process"); const char* fname= ((ae->file_id < file_names.elements) ? @@ -450,15 +538,24 @@ int Load_log_processor::process(Append_block_log_event *ae) if (fname) { File file; - int error= 0; + Exit_status retval= OK_CONTINUE; if (((file= my_open(fname, O_APPEND|O_BINARY|O_WRONLY,MYF(MY_WME))) < 0)) - DBUG_RETURN(-1); + { + error("Failed opening file %s", fname); + DBUG_RETURN(ERROR_STOP); + } if (my_write(file,(uchar*)ae->block,ae->block_len,MYF(MY_WME|MY_NABP))) - error= -1; + { + error("Failed writing to file %s", fname); + retval= ERROR_STOP; + } if (my_close(file,MYF(MY_WME))) - error= -1; - DBUG_RETURN(error); + { + error("Failed closing file %s", fname); + retval= ERROR_STOP; + } + DBUG_RETURN(retval); } /* @@ -466,16 +563,50 @@ int Load_log_processor::process(Append_block_log_event *ae) --start-position). Assuming it's a big --start-position, we just do nothing and print a warning. */ - fprintf(stderr,"Warning: ignoring Append_block as there is no \ -Create_file event for file_id: %u\n",ae->file_id); - DBUG_RETURN(-1); + warning("Ignoring Append_block as there is no " + "Create_file event for file_id: %u", ae->file_id); + DBUG_RETURN(OK_CONTINUE); } -Load_log_processor load_processor; +static Load_log_processor load_processor; -static bool check_database(const char *log_dbname) +/** + Replace windows-style backslashes by forward slashes so it can be + consumed by the mysql client, which requires Unix path. + + @todo This is only useful under windows, so may be ifdef'ed out on + other systems. /Sven + + @todo If a Create_file_log_event contains a filename with a + backslash (valid under unix), then we have problems under windows. + /Sven + + @param[in,out] fname Filename to modify. The filename is modified + in-place. +*/ +static void convert_path_to_forward_slashes(char *fname) +{ + while (*fname) + { + if (*fname == '\\') + *fname= '/'; + fname++; + } +} + + +/** + Indicates whether the given database should be filtered out, + according to the --database=X option. + + @param log_dbname Name of database. + + @return nonzero if the database with the given name should be + filtered out, 0 otherwise. +*/ +static bool shall_skip_database(const char *log_dbname) { return one_database && (log_dbname != NULL) && @@ -483,8 +614,23 @@ static bool check_database(const char *log_dbname) } +/** + Prints the given event in base64 format. -static int + The header is printed to the head cache and the body is printed to + the body cache of the print_event_info structure. This allows all + base64 events corresponding to the same statement to be joined into + one BINLOG statement. + + @param[in] ev Log_event to print. + @param[in,out] result_file FILE to which the output will be written. + @param[in,out] print_event_info Parameters and context state + determining how to print. + + @retval ERROR_STOP An error occurred - the program should terminate. + @retval OK_CONTINUE No error, the program should continue. +*/ +static Exit_status write_event_header_and_base64(Log_event *ev, FILE *result_file, PRINT_EVENT_INFO *print_event_info) { @@ -497,35 +643,44 @@ write_event_header_and_base64(Log_event *ev, FILE *result_file, ev->print_base64(body, print_event_info, FALSE); /* Read data from cache and write to result file */ - DBUG_RETURN(copy_event_cache_to_file_and_reinit(head, result_file) || - copy_event_cache_to_file_and_reinit(body, result_file)); + if (copy_event_cache_to_file_and_reinit(head, result_file) || + copy_event_cache_to_file_and_reinit(body, result_file)) + { + error("Error writing event to file."); + DBUG_RETURN(ERROR_STOP); + } + DBUG_RETURN(OK_CONTINUE); } -/* - Process an event +/** + Print the given event, and either delete it or delegate the deletion + to someone else. - SYNOPSIS - process_event() + The deletion may be delegated in two cases: (1) the event is a + Format_description_log_event, and is saved in + glob_description_event; (2) the event is a Create_file_log_event, + and is saved in load_processor. - RETURN - 0 ok and continue - 1 error and terminate - -1 ok and terminate - - TODO - This function returns 0 even in some error cases. This should be changed. + @param[in,out] print_event_info Parameters and context state + determining how to print. + @param[in] ev Log_event to process. + @param[in] pos Offset from beginning of binlog file. + @param[in] logname Name of input binlog. + + @retval ERROR_STOP An error occurred - the program should terminate. + @retval OK_CONTINUE No error, the program should continue. + @retval OK_STOP No error, but the end of the specified range of + events to process has been reached and the program should terminate. */ - - - -int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, - my_off_t pos) +Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, + my_off_t pos, const char *logname) { char ll_buff[21]; Log_event_type ev_type= ev->get_type_code(); DBUG_ENTER("process_event"); print_event_info->short_form= short_form; + Exit_status retval= OK_CONTINUE; /* Format events are not concerned by --offset and such, we always need to @@ -545,14 +700,15 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, start_datetime= 0; offset= 0; // print everything and protect against cycling rec_count } - if (server_id && (server_id != ev->server_id)) { - DBUG_RETURN(0); - } + if (server_id && (server_id != ev->server_id)) + /* skip just this event, continue processing the log. */ + goto end; if (((my_time_t)(ev->when) >= stop_datetime) || (pos >= stop_position_mot)) { - stop_passed= 1; // skip all next binlogs - DBUG_RETURN(-1); + /* end the program */ + retval= OK_STOP; + goto end; } if (!short_form) fprintf(result_file, "# at %s\n",llstr(pos,ll_buff)); @@ -568,10 +724,15 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, switch (ev_type) { case QUERY_EVENT: - if (check_database(((Query_log_event*)ev)->db)) + if (shall_skip_database(((Query_log_event*)ev)->db)) goto end; if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS) - write_event_header_and_base64(ev, result_file, print_event_info); + { + if ((retval= write_event_header_and_base64(ev, result_file, + print_event_info)) != + OK_CONTINUE) + goto end; + } else ev->print(result_file, print_event_info); break; @@ -585,7 +746,7 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, related Append_block and Exec_load. Note that Load event from 3.23 is not tested. */ - if (check_database(ce->db)) + if (shall_skip_database(ce->db)) goto end; // Next event /* We print the event, but with a leading '#': this is just to inform @@ -596,7 +757,10 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, */ if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS) { - write_event_header_and_base64(ce, result_file, print_event_info); + if ((retval= write_event_header_and_base64(ce, result_file, + print_event_info)) != + OK_CONTINUE) + goto end; } else ce->print(result_file, print_event_info, TRUE); @@ -604,17 +768,29 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, // If this binlog is not 3.23 ; why this test?? if (glob_description_event->binlog_version >= 3) { - if (load_processor.process(ce)) - break; // Error - ev= 0; + /* + transfer the responsibility for destroying the event to + load_processor + */ + ev= NULL; + if ((retval= load_processor.process(ce)) != OK_CONTINUE) + goto end; } break; } + case APPEND_BLOCK_EVENT: + /* + Append_block_log_events can safely print themselves even if + the subsequent call load_processor.process fails, because the + output of Append_block_log_event::print is only a comment. + */ ev->print(result_file, print_event_info); - if (load_processor.process((Append_block_log_event*) ev)) - break; // Error + if ((retval= load_processor.process((Append_block_log_event*) ev)) != + OK_CONTINUE) + goto end; break; + case EXEC_LOAD_EVENT: { ev->print(result_file, print_event_info); @@ -627,13 +803,18 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, */ if (ce) { + /* + We must not convert earlier, since the file is used by + my_open() in Load_log_processor::append(). + */ + convert_path_to_forward_slashes((char*) ce->fname); ce->print(result_file, print_event_info, TRUE); my_free((char*)ce->fname,MYF(MY_WME)); delete ce; } else - fprintf(stderr,"Warning: ignoring Exec_load as there is no \ -Create_file event for file_id: %u\n",exv->file_id); + warning("Ignoring Execute_load_log_event as there is no " + "Create_file event for file_id: %u", exv->file_id); break; } case FORMAT_DESCRIPTION_EVENT: @@ -653,41 +834,37 @@ Create_file event for file_id: %u\n",exv->file_id); if (!force_if_open_opt && (glob_description_event->flags & LOG_EVENT_BINLOG_IN_USE_F)) { - file_not_closed_error= 1; - DBUG_RETURN(1); + error("Attempting to dump binlog '%s', which was not closed properly. " + "Most probably, mysqld is still writing it, or it crashed. " + "Rerun with --force-if-open to ignore this problem.", logname); + DBUG_RETURN(ERROR_STOP); } break; case BEGIN_LOAD_QUERY_EVENT: ev->print(result_file, print_event_info); - load_processor.process((Begin_load_query_log_event*) ev); + if ((retval= load_processor.process((Begin_load_query_log_event*) ev)) != + OK_CONTINUE) + goto end; break; case EXECUTE_LOAD_QUERY_EVENT: { Execute_load_query_log_event *exlq= (Execute_load_query_log_event*)ev; char *fname= load_processor.grab_fname(exlq->file_id); - if (check_database(exlq->db)) + if (!shall_skip_database(exlq->db)) { if (fname) - my_free(fname, MYF(MY_WME)); - goto end; + { + convert_path_to_forward_slashes(fname); + exlq->print(result_file, print_event_info, fname); + } + else + warning("Ignoring Execute_load_query since there is no " + "Begin_load_query event for file_id: %u", exlq->file_id); } if (fname) - { - /* - Fix the path so it can be consumed by mysql client (requires Unix path). - */ - int stop= strlen(fname); - for (int i= 0; i < stop; i++) - if (fname[i] == '\\') - fname[i]= '/'; - exlq->print(result_file, print_event_info, fname); my_free(fname, MYF(MY_WME)); - } - else - fprintf(stderr,"Warning: ignoring Execute_load_query as there is no \ -Begin_load_query event for file_id: %u\n", exlq->file_id); break; } case TABLE_MAP_EVENT: @@ -706,20 +883,18 @@ Begin_load_query event for file_id: %u\n", exlq->file_id); */ if (!print_event_info->printed_fd_event && !short_form) { - /* - todo: a lot to clean up here - */ const char* type_str= ev->get_type_str(); - delete ev; if (opt_base64_output_mode == BASE64_OUTPUT_NEVER) - die("--base64-output=never specified, but binlog contains a " - "%s event which must be printed in base64.", - type_str); + error("--base64-output=never specified, but binlog contains a " + "%s event which must be printed in base64.", + type_str); else - die("malformed binlog: it does not contain any " - "Format_description_log_event. I now found a %s event, which is " - "not safe to process without a Format_description_log_event.", - type_str); + error("malformed binlog: it does not contain any " + "Format_description_log_event. I now found a %s event, which " + "is not safe to process without a " + "Format_description_log_event.", + type_str); + goto err; } /* FALL THROUGH */ default: @@ -727,6 +902,10 @@ Begin_load_query event for file_id: %u\n", exlq->file_id); } } + goto end; + +err: + retval= ERROR_STOP; end: rec_count++; /* @@ -739,7 +918,7 @@ end: ev->temp_buf= 0; delete ev; } - DBUG_RETURN(0); + DBUG_RETURN(retval); } @@ -894,16 +1073,71 @@ that may lead to an endless loop.", }; -void sql_print_error(const char *format,...) +/** + Auxiliary function used by error() and warning(). + + Prints the given text (normally "WARNING: " or "ERROR: "), followed + by the given vprintf-style string, followed by a newline. + + @param format Printf-style format string. + @param args List of arguments for the format string. + @param msg Text to print before the string. +*/ +static void error_or_warning(const char *format, va_list args, const char *msg) +{ + fprintf(stderr, "%s: ", msg); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); +} + +/** + Prints a message to stderr, prefixed with the text "ERROR: " and + suffixed with a newline. + + @param format Printf-style format string, followed by printf + varargs. +*/ +static void error(const char *format,...) { va_list args; va_start(args, format); - fprintf(stderr, "ERROR: "); - vfprintf(stderr, format, args); - fprintf(stderr, "\n"); + error_or_warning(format, args, "ERROR"); va_end(args); } + +/** + This function is used in log_event.cc to report errors. + + @param format Printf-style format string, followed by printf + varargs. +*/ +static void sql_print_error(const char *format,...) +{ + va_list args; + va_start(args, format); + error_or_warning(format, args, "ERROR"); + va_end(args); +} + +/** + Prints a message to stderr, prefixed with the text "WARNING: " and + suffixed with a newline. + + @param format Printf-style format string, followed by printf + varargs. +*/ +static void warning(const char *format,...) +{ + va_list args; + va_start(args, format); + error_or_warning(format, args, "WARNING"); + va_end(args); +} + +/** + Frees memory for global variables in this file. +*/ static void cleanup() { my_free(pass,MYF(MY_ALLOW_ZERO_PTR)); @@ -911,20 +1145,10 @@ static void cleanup() my_free((char*) host, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) user, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) dirname_for_local_load, MYF(MY_ALLOW_ZERO_PTR)); -} -static void die(const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - fprintf(stderr, "ERROR: "); - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); - va_end(args); - cleanup(); - /* We cannot free DBUG, it is used in global destructors after exit(). */ - my_end(my_end_arg | MY_DONT_FREE_DBUG); - exit(1); + delete glob_description_event; + if (mysql) + mysql_close(mysql); } #include @@ -962,7 +1186,7 @@ static my_time_t convert_str_to_timestamp(const char* str) if (str_to_datetime(str, strlen(str), &l_time, 0, &was_cut) != MYSQL_TIMESTAMP_DATETIME || was_cut) { - fprintf(stderr, "Incorrect date and time argument: %s\n", str); + error("Incorrect date and time argument: %s", str); exit(1); } /* @@ -1063,34 +1287,56 @@ static int parse_args(int *argc, char*** argv) return 0; } -static MYSQL* safe_connect() -{ - MYSQL *local_mysql= mysql_init(NULL); - if (!local_mysql) - die("Failed on mysql_init"); +/** + Create and initialize the global mysql object, and connect to the + server. + + @retval ERROR_STOP An error occurred - the program should terminate. + @retval OK_CONTINUE No error, the program should continue. +*/ +static Exit_status safe_connect() +{ + mysql= mysql_init(NULL); + + if (!mysql) + { + error("Failed on mysql_init."); + return ERROR_STOP; + } if (opt_protocol) - mysql_options(local_mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol); - if (!mysql_real_connect(local_mysql, host, user, pass, 0, port, sock, 0)) + mysql_options(mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol); + if (!mysql_real_connect(mysql, host, user, pass, 0, port, sock, 0)) { - char errmsg[256]; - strmake(errmsg, mysql_error(local_mysql), sizeof(errmsg)-1); - mysql_close(local_mysql); - die("failed on connect: %s", errmsg); + error("Failed on connect: %s", mysql_error(mysql)); + return ERROR_STOP; } - local_mysql->reconnect= 1; - return local_mysql; + mysql->reconnect= 1; + return OK_CONTINUE; } -static int dump_log_entries(const char* logname) +/** + High-level function for dumping a named binlog. + + This function calls dump_remote_log_entries() or + dump_local_log_entries() to do the job. + + @param[in] logname Name of input binlog. + + @retval ERROR_STOP An error occurred - the program should terminate. + @retval OK_CONTINUE No error, the program should continue. + @retval OK_STOP No error, but the end of the specified range of + events to process has been reached and the program should terminate. +*/ +static Exit_status dump_log_entries(const char* logname) { - int rc; + Exit_status rc; PRINT_EVENT_INFO print_event_info; if (!print_event_info.init_ok()) - return 1; + return ERROR_STOP; /* Set safe delimiter, to dump things like CREATE PROCEDURE safely @@ -1108,51 +1354,50 @@ static int dump_log_entries(const char* logname) } -/* - This is not as smart as check_header() (used for local log); it will not work - for a binlog which mixes format. TODO: fix this. +/** + When reading a remote binlog, this function is used to grab the + Format_description_log_event in the beginning of the stream. + + This is not as smart as check_header() (used for local log); it will + not work for a binlog which mixes format. TODO: fix this. + + @retval ERROR_STOP An error occurred - the program should terminate. + @retval OK_CONTINUE No error, the program should continue. */ -static int check_master_version(MYSQL *mysql_arg, - Format_description_log_event - **description_event) +static Exit_status check_master_version() { MYSQL_RES* res = 0; MYSQL_ROW row; const char* version; - if (mysql_query(mysql_arg, "SELECT VERSION()") || - !(res = mysql_store_result(mysql_arg))) + if (mysql_query(mysql, "SELECT VERSION()") || + !(res = mysql_store_result(mysql))) { - /* purecov: begin inspected */ - char errmsg[256]; - strmake(errmsg, mysql_error(mysql_arg), sizeof(errmsg)-1); - mysql_close(mysql_arg); - die("Error checking master version: %s", errmsg); - /* purecov: end */ + error("Could not find server version: " + "Query failed when checking master version: %s", mysql_error(mysql)); + return ERROR_STOP; } if (!(row = mysql_fetch_row(res))) { - /* purecov: begin inspected */ - mysql_free_result(res); - mysql_close(mysql); - die("Master returned no rows for SELECT VERSION()"); - /* purecov: end */ - } - if (!(version = row[0])) - { - /* purecov: begin inspected */ - mysql_free_result(res); - mysql_close(mysql_arg); - die("Master reported NULL for the version"); - /* purecov: end */ + error("Could not find server version: " + "Master returned no rows for SELECT VERSION()."); + goto err; } + if (!(version = row[0])) + { + error("Could not find server version: " + "Master reported NULL for the version."); + goto err; + } + + delete glob_description_event; switch (*version) { case '3': - *description_event= new Format_description_log_event(1); + glob_description_event= new Format_description_log_event(1); break; case '4': - *description_event= new Format_description_log_event(3); + glob_description_event= new Format_description_log_event(3); break; case '5': /* @@ -1161,31 +1406,53 @@ static int check_master_version(MYSQL *mysql_arg, So we first assume that this is 4.0 (which is enough to read the Format_desc event if one comes). */ - *description_event= new Format_description_log_event(3); + glob_description_event= new Format_description_log_event(3); break; default: - /* purecov: begin inspected */ - mysql_free_result(res); - mysql_close(mysql_arg); - die("Master reported unrecognized MySQL version '%s'", version); - /* purecov: end */ + glob_description_event= NULL; + error("Could not find server version: " + "Master reported unrecognized MySQL version '%s'.", version); + goto err; } + if (!glob_description_event || !glob_description_event->is_valid()) + { + error("Failed creating Format_description_log_event; out of memory?"); + goto err; + } + mysql_free_result(res); - return 0; + return OK_CONTINUE; + +err: + mysql_free_result(res); + return ERROR_STOP; } -static int dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info, - const char* logname) +/** + Requests binlog dump from a remote server and prints the events it + receives. + + @param[in,out] print_event_info Parameters and context state + determining how to print. + @param[in] logname Name of input binlog. + + @retval ERROR_STOP An error occurred - the program should terminate. + @retval OK_CONTINUE No error, the program should continue. + @retval OK_STOP No error, but the end of the specified range of + events to process has been reached and the program should terminate. +*/ +static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info, + const char* logname) { uchar buf[128]; ulong len; uint logname_len; NET* net; - int error= 0; my_off_t old_off= start_position_mot; char fname[FN_REFLEN+1]; + Exit_status retval= OK_CONTINUE; DBUG_ENTER("dump_remote_log_entries"); /* @@ -1193,20 +1460,12 @@ static int dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info, we cannot re-use the same connection as before, because it is now dead (COM_BINLOG_DUMP kills the thread when it finishes). */ - mysql= safe_connect(); + if ((retval= safe_connect()) != OK_CONTINUE) + DBUG_RETURN(retval); net= &mysql->net; - if (check_master_version(mysql, &glob_description_event)) - { - fprintf(stderr, "Could not find server version"); - DBUG_RETURN(1); - } - if (!glob_description_event || !glob_description_event->is_valid()) - { - fprintf(stderr, "Invalid Format_description log event; \ -could be out of memory"); - DBUG_RETURN(1); - } + if ((retval= check_master_version()) != OK_CONTINUE) + DBUG_RETURN(retval); /* COM_BINLOG_DUMP accepts only 4 bytes for the position, so we are forced to @@ -1218,18 +1477,16 @@ could be out of memory"); size_t tlen = strlen(logname); if (tlen > UINT_MAX) { - fprintf(stderr,"Log name too long\n"); - error= 1; - goto err; + error("Log name too long."); + DBUG_RETURN(ERROR_STOP); } logname_len = (uint) tlen; int4store(buf + 6, 0); memcpy(buf + 10, logname, logname_len); if (simple_command(mysql, COM_BINLOG_DUMP, buf, logname_len + 10, 1)) { - fprintf(stderr,"Got fatal error sending the log dump command\n"); - error= 1; - goto err; + error("Got fatal error sending the log dump command."); + DBUG_RETURN(ERROR_STOP); } for (;;) @@ -1240,10 +1497,8 @@ could be out of memory"); len= cli_safe_read(mysql); if (len == packet_error) { - fprintf(stderr, "Got error reading packet from server: %s\n", - mysql_error(mysql)); - error= 1; - goto err; + error("Got error reading packet from server: %s", mysql_error(mysql)); + DBUG_RETURN(ERROR_STOP); } if (len < 8 && net->read_pos[0] == 254) break; // end of data @@ -1253,9 +1508,8 @@ could be out of memory"); len - 1, &error_msg, glob_description_event))) { - fprintf(stderr, "Could not construct log event object\n"); - error= 1; - goto err; + error("Could not construct log event object: %s", error_msg); + DBUG_RETURN(ERROR_STOP); } /* If reading from a remote host, ensure the temp_buf for the @@ -1294,8 +1548,7 @@ could be out of memory"); if ((rev->ident_len != logname_len) || memcmp(rev->new_log_ident, logname, logname_len)) { - error= 0; - goto err; + DBUG_RETURN(OK_CONTINUE); } /* Otherwise, this is a fake Rotate for our log, at the very @@ -1320,11 +1573,9 @@ could be out of memory"); if (old_off != BIN_LOG_HEADER_SIZE) len= 1; // fake event, don't increment old_off } - if ((error= process_event(print_event_info, ev, old_off))) - { - error= ((error < 0) ? 0 : 1); - goto err; - } + Exit_status retval= process_event(print_event_info, ev, old_off, logname); + if (retval != OK_CONTINUE) + DBUG_RETURN(retval); } else { @@ -1332,26 +1583,21 @@ could be out of memory"); const char *old_fname= le->fname; uint old_len= le->fname_len; File file; + Exit_status retval; if ((file= load_processor.prepare_new_file_for_old_format(le,fname)) < 0) - { - error= 1; - goto err; - } + DBUG_RETURN(ERROR_STOP); - if ((error= process_event(print_event_info, ev, old_off))) + retval= process_event(print_event_info, ev, old_off, logname); + if (retval != OK_CONTINUE) { my_close(file,MYF(MY_WME)); - error= ((error < 0) ? 0 : 1); - goto err; + DBUG_RETURN(retval); } - error= load_processor.load_old_format_file(net,old_fname,old_len,file); + retval= load_processor.load_old_format_file(net,old_fname,old_len,file); my_close(file,MYF(MY_WME)); - if (error) - { - error= 1; - goto err; - } + if (retval != OK_CONTINUE) + DBUG_RETURN(retval); } /* Let's adjust offset for remote log as for local log to produce @@ -1360,15 +1606,13 @@ could be out of memory"); old_off+= len-1; } -err: - mysql_close(mysql); - DBUG_RETURN(error); + DBUG_RETURN(OK_CONTINUE); } /** - Reads the @c Format_description_log_event from the beginning of the - input file. + Reads the @c Format_description_log_event from the beginning of a + local input file. The @c Format_description_log_event is only read if it is outside the range specified with @c --start-position; otherwise, it will be @@ -1382,32 +1626,42 @@ err: @param file The file to which a @c Format_description_log_event will be printed. - @param description_event Pointer to the global @c - Format_description_log_event pointer. This will be updated if a new - Format_description_log_event is found. + @param[in,out] print_event_info Parameters and context state + determining how to print. - @param print_event_info Context state needed to print events. + @param[in] logname Name of input binlog. + + @retval ERROR_STOP An error occurred - the program should terminate. + @retval OK_CONTINUE No error, the program should continue. + @retval OK_STOP No error, but the end of the specified range of + events to process has been reached and the program should terminate. */ -static void check_header(IO_CACHE* file, - Format_description_log_event **description_event, - PRINT_EVENT_INFO *print_event_info) +static Exit_status check_header(IO_CACHE* file, + PRINT_EVENT_INFO *print_event_info, + const char* logname) { uchar header[BIN_LOG_HEADER_SIZE]; uchar buf[PROBE_HEADER_LEN]; my_off_t tmp_pos, pos; - *description_event= new Format_description_log_event(3); + delete glob_description_event; + if (!(glob_description_event= new Format_description_log_event(3))) + { + error("Failed creating Format_description_log_event; out of memory?"); + return ERROR_STOP; + } + pos= my_b_tell(file); my_b_seek(file, (my_off_t)0); if (my_b_read(file, header, sizeof(header))) { - delete *description_event; - die("Failed reading header; Probably an empty file"); + error("Failed reading header; probably an empty file."); + return ERROR_STOP; } if (memcmp(header, BINLOG_MAGIC, sizeof(header))) { - delete *description_event; - die("File is not a binary log file"); + error("File is not a binary log file."); + return ERROR_STOP; } /* @@ -1430,10 +1684,9 @@ static void check_header(IO_CACHE* file, { if (file->error) { - delete *description_event; - die("\ -Could not read entry at offset %lu : Error in log format or read error", - tmp_pos); + error("Could not read entry at offset %llu: " + "Error in log format or read error.", (ulonglong)tmp_pos); + return ERROR_STOP; } /* Otherwise this is just EOF : this log currently contains 0-2 @@ -1463,8 +1716,13 @@ Could not read entry at offset %lu : Error in log format or read error", (LOG_EVENT_MINIMAL_HEADER_LEN + START_V3_HEADER_LEN)) { /* This is 3.23 (format 1) */ - delete *description_event; - *description_event= new Format_description_log_event(1); + delete glob_description_event; + if (!(glob_description_event= new Format_description_log_event(1))) + { + error("Failed creating Format_description_log_event; " + "out of memory?"); + return ERROR_STOP; + } } break; } @@ -1476,26 +1734,32 @@ Could not read entry at offset %lu : Error in log format or read error", Format_description_log_event *new_description_event; my_b_seek(file, tmp_pos); /* seek back to event's start */ if (!(new_description_event= (Format_description_log_event*) - Log_event::read_log_event(file, *description_event))) + Log_event::read_log_event(file, glob_description_event))) /* EOF can't be hit here normally, so it's a real error */ { - delete *description_event; - die("Could not read a Format_description_log_event event \ -at offset %lu ; this could be a log format error or read error", - tmp_pos); + error("Could not read a Format_description_log_event event at " + "offset %llu; this could be a log format error or read error.", + (ulonglong)tmp_pos); + return ERROR_STOP; } if (opt_base64_output_mode == BASE64_OUTPUT_AUTO || opt_base64_output_mode == BASE64_OUTPUT_ALWAYS) + { /* process_event will delete *description_event and set it to the new one, so we should not do it ourselves in this case. */ - process_event(print_event_info, new_description_event, tmp_pos); + Exit_status retval= process_event(print_event_info, + new_description_event, tmp_pos, + logname); + if (retval != OK_CONTINUE) + return retval; + } else { - delete *description_event; - *description_event= new_description_event; + delete glob_description_event; + glob_description_event= new_description_event; } DBUG_PRINT("info",("Setting description_event")); } @@ -1503,12 +1767,13 @@ at offset %lu ; this could be a log format error or read error", { Log_event *ev; my_b_seek(file, tmp_pos); /* seek back to event's start */ - if (!(ev= Log_event::read_log_event(file, *description_event))) - /* EOF can't be hit here normally, so it's a real error */ + if (!(ev= Log_event::read_log_event(file, glob_description_event))) { - delete *description_event; - die("Could not read a Rotate_log_event event at offset %lu ;" - " this could be a log format error or read error", tmp_pos); + /* EOF can't be hit here normally, so it's a real error */ + error("Could not read a Rotate_log_event event at offset %llu;" + " this could be a log format error or read error.", + (ulonglong)tmp_pos); + return ERROR_STOP; } delete ev; } @@ -1517,31 +1782,48 @@ at offset %lu ; this could be a log format error or read error", } } my_b_seek(file, pos); + return OK_CONTINUE; } -static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, - const char* logname) +/** + Reads a local binlog and prints the events it sees. + + @param[in] logname Name of input binlog. + + @param[in,out] print_event_info Parameters and context state + determining how to print. + + @retval ERROR_STOP An error occurred - the program should terminate. + @retval OK_CONTINUE No error, the program should continue. + @retval OK_STOP No error, but the end of the specified range of + events to process has been reached and the program should terminate. +*/ +static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, + const char* logname) { File fd = -1; IO_CACHE cache,*file= &cache; uchar tmp_buff[BIN_LOG_HEADER_SIZE]; - int error= 0; + Exit_status retval= OK_CONTINUE; if (logname && strcmp(logname, "-") != 0) { + /* read from normal file */ if ((fd = my_open(logname, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0) - return 1; + return ERROR_STOP; if (init_io_cache(file, fd, 0, READ_CACHE, start_position_mot, 0, MYF(MY_WME | MY_NABP))) { my_close(fd, MYF(MY_WME)); - return 1; + return ERROR_STOP; } - check_header(file, &glob_description_event, print_event_info); + if ((retval= check_header(file, print_event_info, logname)) != OK_CONTINUE) + goto end; } - else // reading from stdin; + else { + /* read from stdin */ /* Windows opens stdin in text mode by default. Certain characters such as CTRL-Z are interpeted as events and the read() method @@ -1553,14 +1835,18 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, #if defined (__WIN__) || (_WIN64) if (_setmode(fileno(stdin), O_BINARY) == -1) { - fprintf(stderr, "Could not set binary mode on stdin.\n"); - return 1; + error("Could not set binary mode on stdin."); + return ERROR_STOP; } #endif if (init_io_cache(file, fileno(stdin), 0, READ_CACHE, (my_off_t) 0, 0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE))) - return 1; - check_header(file, &glob_description_event, print_event_info); + { + error("Failed to init IO cache."); + return ERROR_STOP; + } + if ((retval= check_header(file, print_event_info, logname)) != OK_CONTINUE) + goto end; if (start_position) { /* skip 'start_position' characters from stdin */ @@ -1571,8 +1857,8 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, tmp=min(length,sizeof(buff)); if (my_b_read(file, buff, (uint) tmp)) { - error= 1; - goto end; + error("Failed reading from file."); + goto err; } } } @@ -1580,14 +1866,14 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, if (!glob_description_event || !glob_description_event->is_valid()) { - delete glob_description_event; - die("Invalid Format_description log event; could be out of memory"); + error("Invalid Format_description log event; could be out of memory."); + goto err; } if (!start_position && my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE)) { - error= 1; - goto end; + error("Failed reading from file."); + goto err; } for (;;) { @@ -1605,36 +1891,36 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, file->error= 0; else if (file->error) { - fprintf(stderr, - "Could not read entry at offset %s:" - "Error in log format or read error\n", - llstr(old_off,llbuff)); - error= 1; + error("Could not read entry at offset %s: " + "Error in log format or read error.", + llstr(old_off,llbuff)); + goto err; } // file->error == 0 means EOF, that's OK, we break in this case - break; - } - if ((error= process_event(print_event_info, ev, old_off))) - { - if (error < 0) - error= 0; - break; + goto end; } + if ((retval= process_event(print_event_info, ev, old_off, logname)) != + OK_CONTINUE) + goto end; } + /* NOTREACHED */ + +err: + retval= ERROR_STOP; + end: if (fd >= 0) my_close(fd, MYF(MY_WME)); end_io_cache(file); - delete glob_description_event; - return error; + return retval; } int main(int argc, char** argv) { char **defaults_argv; - int exit_value= 0; + Exit_status retval= OK_CONTINUE; ulonglong save_stop_position; MY_INIT(argv[0]); DBUG_ENTER("main"); @@ -1696,15 +1982,13 @@ int main(int argc, char** argv) "\n/*!40101 SET NAMES %s */;\n", charset); for (save_stop_position= stop_position, stop_position= ~(my_off_t)0 ; - (--argc >= 0) && !stop_passed ; ) + (--argc >= 0) ; ) { if (argc == 0) // last log, --stop-position applies stop_position= save_stop_position; - if (dump_log_entries(*(argv++))) - { - exit_value=1; + if ((retval= dump_log_entries(*argv++)) != OK_CONTINUE) break; - } + // For next log, --start-position does not apply start_position= BIN_LOG_HEADER_SIZE; } @@ -1736,17 +2020,9 @@ int main(int argc, char** argv) /* We cannot free DBUG, it is used in global destructors after exit(). */ my_end(my_end_arg | MY_DONT_FREE_DBUG); - if (file_not_closed_error) - { - fprintf(stderr, -"\nError: attempting to dump binlog '%s' which was not closed properly.\n" -"Most probably mysqld is still writting it, or crashed.\n" -"Your current options specify --disable-force-if-open\n" -"which means to abort on this problem.\n" -"You can rerun using --force-if-open to ignore this problem.\n\n", argv[-1]); - } - exit(exit_value); - DBUG_RETURN(exit_value); // Keep compilers happy + exit(retval == ERROR_STOP ? 1 : 0); + /* Keep compilers happy. */ + DBUG_RETURN(retval == ERROR_STOP ? 1 : 0); } /* diff --git a/include/my_base.h b/include/my_base.h index 947f7695215..4f552fa5fe0 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -419,7 +419,9 @@ enum ha_base_keytype { statement */ #define HA_ERR_CORRUPT_EVENT 171 /* The event was corrupt, leading to illegal data being read */ -#define HA_ERR_LAST 171 /*Copy last error nr.*/ +#define HA_ERR_ROWS_EVENT_APPLY 172 /* The event could not be processed + no other hanlder error happened */ +#define HA_ERR_LAST 172 /*Copy last error nr.*/ /* Add error numbers before HA_ERR_LAST and change it accordingly. */ #define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1) diff --git a/mysql-test/extra/rpl_tests/rpl_stm_charset.test b/mysql-test/extra/rpl_tests/rpl_charset.test similarity index 86% rename from mysql-test/extra/rpl_tests/rpl_stm_charset.test rename to mysql-test/extra/rpl_tests/rpl_charset.test index 629ccdf69f7..8bcb60b0227 100644 --- a/mysql-test/extra/rpl_tests/rpl_stm_charset.test +++ b/mysql-test/extra/rpl_tests/rpl_charset.test @@ -1,9 +1,6 @@ # Replication of character sets. # This test will fail if the server/client does not support enough charsets. -# Requires statement logging --- source include/have_binlog_format_mixed_or_statement.inc - source include/master-slave.inc; --disable_warnings set timestamp=1000000000; @@ -52,14 +49,10 @@ insert into t1 (b) values(@@character_set_client); # collation_client does not exist insert into t1 (b) values(@@character_set_connection); insert into t1 (b) values(@@collation_connection); ---disable_query_log -select "--- --master--" as ""; ---enable_query_log +--echo --- --master-- select * from t1 order by a; sync_slave_with_master; ---disable_query_log -select "--- --slave--" as ""; ---enable_query_log +--echo --- --slave-- select * from mysqltest2.t1 order by a; connection master; @@ -70,14 +63,10 @@ insert into t1 (b) values(LEAST("M set collation_connection=latin1_german2_ci; insert into t1 (b) values(@@collation_connection); insert into t1 (b) values(LEAST("Müller","Muffler")); ---disable_query_log -select "--- --master--" as ""; ---enable_query_log +--echo --- --master-- select * from t1 order by a; sync_slave_with_master; ---disable_query_log -select "--- --slave--" as ""; ---enable_query_log +--echo --- --slave-- select * from mysqltest2.t1 order by a; # Presently charset info is not logged with LOAD DATA but it will @@ -96,20 +85,15 @@ connection master; set @a= _cp850 'Müller' collate cp850_general_ci; truncate table t1; insert into t1 (b) values(collation(@a)); ---disable_query_log -select "--- --master--" as ""; ---enable_query_log +--echo --- --master-- select * from t1 order by a; sync_slave_with_master; ---disable_query_log -select "--- --slave--" as ""; ---enable_query_log +--echo --- --slave-- select * from mysqltest2.t1 order by a; connection master; drop database mysqltest2; drop database mysqltest3; -source include/show_binlog_events.inc; sync_slave_with_master; # Check that we can change global.collation_server (since 5.0.3) @@ -153,10 +137,6 @@ sync_slave_with_master; select hex(c1), hex(c2) from t1; connection master; -# Let's have a look at generated SETs. -flush logs; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR ---exec $MYSQL_BINLOG --short-form $MYSQLTEST_VARDIR/log/master-bin.000001 drop table t1; sync_slave_with_master; diff --git a/mysql-test/extra/rpl_tests/rpl_ndb_apply_status.test b/mysql-test/extra/rpl_tests/rpl_ndb_apply_status.test index 926c4106d6d..4677f6da25d 100644 --- a/mysql-test/extra/rpl_tests/rpl_ndb_apply_status.test +++ b/mysql-test/extra/rpl_tests/rpl_ndb_apply_status.test @@ -50,17 +50,30 @@ insert into t1 values (1,2); --echo connection master; -# here is actually a bug, since there is no begin statement, the -# query is autocommitted, and end_pos shows end of the insert and not -# end of the commit +--echo # Now check that that is in the apply_status table is consistant +--echo # with what is in the binlog +--echo +--echo # since insert is done with transactional engine, expect a BEGIN +--echo # at +--echo --replace_result $start_pos --replace_column 5 # --eval show binlog events from $start_pos limit 1 + +--echo +--echo # Now the insert, one step after +--echo +--replace_result $start_pos +--replace_column 2 # 5 # +--eval show binlog events from $start_pos limit 1,1 + +--echo +--echo # and the COMMIT should be at --echo --replace_result $start_pos $end_pos --replace_column 2 # --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ ---eval show binlog events from $start_pos limit 1,1 +--eval show binlog events from $start_pos limit 2,1 --echo diff --git a/mysql-test/extra/rpl_tests/rpl_row_charset.test b/mysql-test/extra/rpl_tests/rpl_row_charset.test deleted file mode 100644 index c1eccff9bd5..00000000000 --- a/mysql-test/extra/rpl_tests/rpl_row_charset.test +++ /dev/null @@ -1,179 +0,0 @@ -# Replication of character sets. -# This test will fail if the server/client does not support enough charsets. - ---disable_warnings -set timestamp=1000000000; -drop database if exists mysqltest2; -drop database if exists mysqltest3; ---enable_warnings - -create database mysqltest2 character set latin2; -set @@character_set_server=latin5; -create database mysqltest3; ---disable_query_log -select "--- --master--" as ""; ---enable_query_log -show create database mysqltest2; -show create database mysqltest3; -sync_slave_with_master; ---disable_query_log -select "--- --slave--" as ""; ---enable_query_log -show create database mysqltest2; -show create database mysqltest3; - -connection master; -set @@collation_server=armscii8_bin; -drop database mysqltest3; -create database mysqltest3; ---disable_query_log -select "--- --master--" as ""; ---enable_query_log -show create database mysqltest3; -sync_slave_with_master; ---disable_query_log -select "--- --slave--" as ""; ---enable_query_log -show create database mysqltest3; - -connection master; -use mysqltest2; ---eval create table t1 (a int auto_increment primary key, b varchar(100))engine=$engine_type; -set character_set_client=cp850, collation_connection=latin2_croatian_ci; -insert into t1 (b) values(@@character_set_server); -insert into t1 (b) values(@@collation_server); -# character_set_database and collation_database are not tested as they -# needn't be replicated (Bar said in Jan 2005). -insert into t1 (b) values(@@character_set_client); -# collation_client does not exist -insert into t1 (b) values(@@character_set_connection); -insert into t1 (b) values(@@collation_connection); ---disable_query_log -select "--- --master--" as ""; ---enable_query_log -select * from t1 order by a; -sync_slave_with_master; ---disable_query_log -select "--- --slave--" as ""; ---enable_query_log -select * from mysqltest2.t1 order by a; - -select "--- --muller--" as ""; -connection master; -set character_set_client=latin1, collation_connection=latin1_german1_ci; -truncate table t1; -insert into t1 (b) values(@@collation_connection); -insert into t1 (b) values(LEAST("Müller","Muffler")); -set collation_connection=latin1_german2_ci; -insert into t1 (b) values(@@collation_connection); -insert into t1 (b) values(LEAST("Müller","Muffler")); ---disable_query_log -select "--- --master--" as ""; ---enable_query_log -select * from t1 order by a; -sync_slave_with_master; ---disable_query_log -select "--- --slave--" as ""; ---enable_query_log -select * from mysqltest2.t1 order by a; - -# Presently charset info is not logged with LOAD DATA but it will -# change in Jan 2005 when Dmitri pushes his new LOAD DATA, -# before 5.0.3 goes out. When done, LOAD DATA INFILE should be tested -# here. - -# See if user var is prefixed with collation in binlog and replicated well. -# Note: replication of user variables is broken as far as derivation is -# concerned. That's because when we store a user variable in the binlog, -# we lose its derivation. So later on the slave, it's impossible to -# know if the collation was explicit or not, so we use DERIVATION_NONE, -# which provokes error messages (like 'Illegal mix of collation') when -# we replay the master's INSERT/etc statements. - - -select "--- --INSERT--" as ""; -connection master; -set @a= _cp850 'Müller' collate cp850_general_ci; -truncate table t1; -insert into t1 (b) values(collation(@a)); ---disable_query_log -select "--- --master--" as ""; ---enable_query_log -select * from t1 order by a; -sync_slave_with_master; ---disable_query_log -select "--- --slave--" as ""; ---enable_query_log -select * from mysqltest2.t1 order by a; - -connection master; -drop database mysqltest2; -drop database mysqltest3; -source include/show_binlog_events.inc; -sync_slave_with_master; - -# Check that we can change global.collation_server (since 5.0.3) - -select "--- --global--" as ""; -set global character_set_server=latin2; -set global character_set_server=latin1; # back -connection master; -set global character_set_server=latin2; -set global character_set_server=latin1; # back - -# Check that SET ONE_SHOT is really one shot - -select "--- --oneshot--" as ""; -set one_shot @@character_set_server=latin5; -set @@max_join_size=1000; -select @@character_set_server; -select @@character_set_server; -set @@character_set_server=latin5; -select @@character_set_server; -select @@character_set_server; - -# ONE_SHOT on not charset/collation stuff is not allowed --- error 1382 -set one_shot max_join_size=10; - -# Test of wrong character set numbers; -error 1115; -set character_set_client=9999999; -error 1273; -set collation_server=9999998; - -# This one was contributed by Sergey Petrunia (BUG#3943) - -select "--- --3943--" as ""; -use test; ---eval CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255))ENGINE=$engine_type; -SET CHARACTER_SET_CLIENT=koi8r, - CHARACTER_SET_CONNECTION=cp1251, - CHARACTER_SET_RESULTS=koi8r; -INSERT INTO t1 (c1, c2) VALUES ('îĠ, ÚÁ ÒÙÂÁÌËĠ','îĠ, ÚÁ ÒÙÂÁÌËĠ'); -SET SQL_BIG_SELECTS=1; -select hex(c1), hex(c2) from t1; -sync_slave_with_master; -SET SQL_BIG_SELECTS=1; -select hex(c1), hex(c2) from t1; - -connection master; -# Let's have a look at generated SETs. ---replace_result $MYSQLTEST_VARDIR MYSQL_TEST_DIR/var -#--exec $MYSQL_BINLOG --short-form $MYSQLTEST_VARDIR/log/master-bin.000001 -drop table t1; -sync_slave_with_master; - -# -# BUG#6676: Derivation of variables must be correct on slave -# -select "--- --6676--" as ""; -connection master; -eval create table `t1` ( - `pk` varchar(10) not null default '', - primary key (`pk`) -) engine=$engine_type default charset=latin1; -set @p=_latin1 'test'; -update t1 set pk='test' where pk=@p; -drop table t1; -sync_slave_with_master; diff --git a/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test b/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test index b5795cf525d..0e391cb0f37 100644 --- a/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test +++ b/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test @@ -46,7 +46,7 @@ ALTER TABLE t1_bit ALTER TABLE t1_char ADD x CHAR(20) DEFAULT 'Just a test'; # ... and add one non-nullable INT column last in table 't1_text' # with no default, -ALTER TABLE t1_nodef ADD x INT NOT NULL; +ALTER TABLE t1_nodef ADD x INT NOT NULL, ADD y INT NOT NULL, ADD z INT NOT NULL; # ... and remove the last column in t2 ALTER TABLE t2 DROP b; # ... change the type of the single column in table 't4' @@ -222,8 +222,8 @@ sync_slave_with_master; --echo **** On Slave **** connection slave; -INSERT INTO t1_nodef VALUES (1,2,3); -INSERT INTO t1_nodef VALUES (2,4,6); +INSERT INTO t1_nodef VALUES (1,2,3,4,5); +INSERT INTO t1_nodef VALUES (2,4,6,8,10); --echo **** On Master **** connection master; diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index d9ba9466482..2ca2669eb7f 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -889,6 +889,7 @@ our @tags= ["include/have_ndb.inc", "ndb_test", 1], ["include/have_multi_ndb.inc", "ndb_test", 1], ["include/have_ndb_extra.inc", "ndb_extra", 1], + ["include/ndb_master-slave.inc", "ndb_test", 1], ["require_manager", "require_manager", 1], ); diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 42471f35ebe..53b02da448f 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -136,9 +136,12 @@ our $opt_suites; our $opt_suites_default= "main,binlog,rpl,rpl_ndb,ndb"; # Default suites to run our @extra_suites= ( - ["mysql-5.1-new-ndb", "ndb_team"], - ["mysql-5.1-telco-6.2", "ndb_team"], - ["mysql-5.1-telco-6.3", "ndb_team"], + ["mysql-5.1-new-ndb", "ndb_team"], + ["mysql-5.1-new-ndb-merge", "ndb_team"], + ["mysql-5.1-telco-6.2", "ndb_team"], + ["mysql-5.1-telco-6.2-merge", "ndb_team"], + ["mysql-5.1-telco-6.3", "ndb_team"], + ["mysql-6.0-ndb", "ndb_team"], ); @@ -413,13 +416,20 @@ sub main () { { # use default and add any extra_suites as defined $opt_suites= $opt_suites_default; - my $ddd= basename(dirname($glob_mysql_test_dir)); - foreach my $extra_suite (@extra_suites) + my $ccc= dirname($glob_mysql_test_dir); + my $found= 0; + while (!$found and !($ccc eq "/") and !($ccc eq "")) { - if ($extra_suite->[0] eq "$ddd") + my $ddd= basename($ccc); + foreach my $extra_suite (@extra_suites) { - $opt_suites= "$extra_suite->[1],$opt_suites"; + if ($extra_suite->[0] eq "$ddd") + { + $opt_suites= "$extra_suite->[1],$opt_suites"; + $found= 1; + } } + $ccc= dirname($ccc); } } diff --git a/mysql-test/r/events_scheduling.result b/mysql-test/r/events_scheduling.result index 033136ba354..b7d4578bede 100644 --- a/mysql-test/r/events_scheduling.result +++ b/mysql-test/r/events_scheduling.result @@ -78,11 +78,6 @@ FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA=DATABASE() AND EVENT_NAME='event_2'; IF(TIME_TO_SEC(TIMEDIFF(ENDS,STARTS))=6, 'OK', 'ERROR') OK -SELECT IF(LAST_EXECUTED-ENDS <= 0, 'OK', 'ERROR') -FROM INFORMATION_SCHEMA.EVENTS -WHERE EVENT_SCHEMA=DATABASE() AND EVENT_NAME='event_2'; -IF(LAST_EXECUTED-ENDS <= 0, 'OK', 'ERROR') -OK "Already dropped because ended. Therefore an error." DROP EVENT event_3; ERROR HY000: Unknown event 'event_3' diff --git a/mysql-test/suite/binlog/r/binlog_base64_flag.result b/mysql-test/suite/binlog/r/binlog_base64_flag.result index aa801346d9f..8e5d7def823 100644 --- a/mysql-test/suite/binlog/r/binlog_base64_flag.result +++ b/mysql-test/suite/binlog/r/binlog_base64_flag.result @@ -40,8 +40,13 @@ SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.uniq SET @@session.sql_mode=0/*!*/; /*!\C latin1 *//*!*/; SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/; -create table t1 (a int) engine= myisam/*!*/; +create table t1 (a int) engine= myisam +/*!*/; # at 203 +DELIMITER ; +# End of log file +ROLLBACK /* added by mysqlbinlog */; +/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; ==== Test non-matching FD event and Row event ==== BINLOG ' 4CdYRw8BAAAAYgAAAGYAAAAAAAQANS4xLjE1LW5kYi02LjEuMjQtZGVidWctbG9nAAAAAAAAAAAA diff --git a/mysql-test/suite/binlog/r/binlog_old_versions.result b/mysql-test/suite/binlog/r/binlog_old_versions.result index a514f9278a6..77289252b4c 100644 --- a/mysql-test/suite/binlog/r/binlog_old_versions.result +++ b/mysql-test/suite/binlog/r/binlog_old_versions.result @@ -29,6 +29,16 @@ SELECT COUNT(*) FROM t3; COUNT(*) 17920 DROP TABLE t1, t2, t3; +==== Read binlog from version 4.1 ==== +SELECT * FROM t1 ORDER BY a; +a b +0 last_insert_id +4 four +190243 random +SELECT COUNT(*) FROM t3; +COUNT(*) +17920 +DROP TABLE t1, t3; ==== Read binlog from alcatel tree (mysql-5.1-wl2325-5.0-drop6) ==== SELECT * FROM t1 ORDER BY a; a b diff --git a/mysql-test/suite/binlog/std_data/binlog_old_version_4_1.000001 b/mysql-test/suite/binlog/std_data/binlog_old_version_4_1.000001 new file mode 100644 index 00000000000..66db9668d46 Binary files /dev/null and b/mysql-test/suite/binlog/std_data/binlog_old_version_4_1.000001 differ diff --git a/mysql-test/suite/binlog/std_data/binlog-bug32407.000001 b/mysql-test/suite/binlog/std_data/bug32407.001 similarity index 100% rename from mysql-test/suite/binlog/std_data/binlog-bug32407.000001 rename to mysql-test/suite/binlog/std_data/bug32407.001 diff --git a/mysql-test/suite/binlog/std_data/binlog_old_version_5_1-telco.000001 b/mysql-test/suite/binlog/std_data/ver_5_1-telco.001 similarity index 100% rename from mysql-test/suite/binlog/std_data/binlog_old_version_5_1-telco.000001 rename to mysql-test/suite/binlog/std_data/ver_5_1-telco.001 diff --git a/mysql-test/suite/binlog/std_data/binlog_old_version_5_1-wl2325_row.000001 b/mysql-test/suite/binlog/std_data/ver_5_1-wl2325_r.001 similarity index 100% rename from mysql-test/suite/binlog/std_data/binlog_old_version_5_1-wl2325_row.000001 rename to mysql-test/suite/binlog/std_data/ver_5_1-wl2325_r.001 diff --git a/mysql-test/suite/binlog/std_data/binlog_old_version_5_1-wl2325_stm.000001 b/mysql-test/suite/binlog/std_data/ver_5_1-wl2325_s.001 similarity index 100% rename from mysql-test/suite/binlog/std_data/binlog_old_version_5_1-wl2325_stm.000001 rename to mysql-test/suite/binlog/std_data/ver_5_1-wl2325_s.001 diff --git a/mysql-test/suite/binlog/std_data/binlog_old_version_5_1_17.000001 b/mysql-test/suite/binlog/std_data/ver_5_1_17.001 similarity index 100% rename from mysql-test/suite/binlog/std_data/binlog_old_version_5_1_17.000001 rename to mysql-test/suite/binlog/std_data/ver_5_1_17.001 diff --git a/mysql-test/suite/binlog/std_data/binlog_old_version_5_1_23.000001 b/mysql-test/suite/binlog/std_data/ver_5_1_23.001 similarity index 100% rename from mysql-test/suite/binlog/std_data/binlog_old_version_5_1_23.000001 rename to mysql-test/suite/binlog/std_data/ver_5_1_23.001 diff --git a/mysql-test/suite/binlog/t/binlog_base64_flag.test b/mysql-test/suite/binlog/t/binlog_base64_flag.test index 32319460ab8..01f98b8a134 100644 --- a/mysql-test/suite/binlog/t/binlog_base64_flag.test +++ b/mysql-test/suite/binlog/t/binlog_base64_flag.test @@ -6,6 +6,10 @@ # See also BUG#32407. +# BINLOG statement does not work in embedded mode. +source include/not_embedded.inc; + + # Test to show BUG#32407. This reads a binlog created with the # mysql-5.1-telco-6.1 tree, specifically at the tag # mysql-5.1.15-ndb-6.1.23, and applies it to the database. The test @@ -15,7 +19,7 @@ # The binlog contains row events equivalent to: # CREATE TABLE t1 (a int) engine = myisam # INSERT INTO t1 VALUES (1), (1) -exec $MYSQL_BINLOG suite/binlog/std_data/binlog-bug32407.000001 | $MYSQL; +exec $MYSQL_BINLOG suite/binlog/std_data/bug32407.001 | $MYSQL; # The above line should succeed and t1 should contain two ones select * from t1; @@ -68,7 +72,7 @@ select * from t1; # mysqlbinlog should fail --replace_regex /#[0-9][0-9][0-9][0-9][0-9][0-9] .*/#/ error 1; -exec $MYSQL_BINLOG --base64-output=never suite/binlog/std_data/binlog-bug32407.000001; +exec $MYSQL_BINLOG --base64-output=never suite/binlog/std_data/bug32407.001; # the above line should output the query log event and then stop @@ -78,7 +82,7 @@ exec $MYSQL_BINLOG --base64-output=never suite/binlog/std_data/binlog-bug32407.0 --echo ==== Test non-matching FD event and Row event ==== # This is the Format_description_log_event from -# binlog-bug32407.000001, encoded in base64. It contains only the old +# bug32407.001, encoded in base64. It contains only the old # row events (number of event types is 22) BINLOG ' 4CdYRw8BAAAAYgAAAGYAAAAAAAQANS4xLjE1LW5kYi02LjEuMjQtZGVidWctbG9nAAAAAAAAAAAA diff --git a/mysql-test/suite/binlog/t/binlog_killed.test b/mysql-test/suite/binlog/t/binlog_killed.test index e5f7288b17c..ab8a8cd59bd 100644 --- a/mysql-test/suite/binlog/t/binlog_killed.test +++ b/mysql-test/suite/binlog/t/binlog_killed.test @@ -39,7 +39,7 @@ connection con2; reap; let $rows= `select count(*) from t2 /* must be 2 or 0 */`; ---exec $MYSQL_BINLOG --start-position=134 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog +--exec $MYSQL_BINLOG --force-if-open --start-position=134 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR eval select (@a:=load_file("$MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog")) @@ -250,7 +250,7 @@ source include/show_binlog_events.inc; # a proof the query is binlogged with an error ---exec $MYSQL_BINLOG --start-position=106 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--exec $MYSQL_BINLOG --force-if-open --start-position=106 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR eval select (@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) @@ -296,7 +296,7 @@ source include/show_binlog_events.inc; # a proof the query is binlogged with an error ---exec $MYSQL_BINLOG --start-position=106 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--exec $MYSQL_BINLOG --force-if-open --start-position=106 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR eval select (@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) diff --git a/mysql-test/suite/binlog/t/binlog_killed_simulate.test b/mysql-test/suite/binlog/t/binlog_killed_simulate.test index 2121a90dc8c..cb3b5a6e827 100644 --- a/mysql-test/suite/binlog/t/binlog_killed_simulate.test +++ b/mysql-test/suite/binlog/t/binlog_killed_simulate.test @@ -23,7 +23,7 @@ update t1 set a=2 /* will be "killed" after work has been done */; #todo: introduce a suite private macro that provides numeric values # for some constants like the offset of the first real event # that is different between severs versions. ---exec $MYSQL_BINLOG --start-position=106 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--exec $MYSQL_BINLOG --force-if-open --start-position=106 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR eval select (@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) @@ -51,7 +51,7 @@ load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "kil source include/show_binlog_events.inc; ---exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--exec $MYSQL_BINLOG --force-if-open --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR eval select (@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) diff --git a/mysql-test/suite/binlog/t/binlog_old_versions.test b/mysql-test/suite/binlog/t/binlog_old_versions.test index 2d56ebd588d..0ccea406a82 100644 --- a/mysql-test/suite/binlog/t/binlog_old_versions.test +++ b/mysql-test/suite/binlog/t/binlog_old_versions.test @@ -31,7 +31,7 @@ DROP TABLE IF EXISTS t1, t2, t3; --echo ==== Read modern binlog (version 5.1.23) ==== # Read binlog. ---exec $MYSQL_BINLOG --local-load=$MYSQLTEST_VARDIR/tmp/ suite/binlog/std_data/binlog_old_version_5_1_23.000001 | $MYSQL --local-infile=1 +--exec $MYSQL_BINLOG --local-load=$MYSQLTEST_VARDIR/tmp/ suite/binlog/std_data/ver_5_1_23.001 | $MYSQL --local-infile=1 # Show result. SELECT * FROM t1 ORDER BY a; SELECT * FROM t2 ORDER BY a; @@ -43,7 +43,7 @@ DROP TABLE t1, t2, t3; --echo ==== Read binlog from version 5.1.17 ==== # Read binlog. ---exec $MYSQL_BINLOG --local-load=$MYSQLTEST_VARDIR/tmp/ suite/binlog/std_data/binlog_old_version_5_1_17.000001 | $MYSQL --local-infile=1 +--exec $MYSQL_BINLOG --local-load=$MYSQLTEST_VARDIR/tmp/ suite/binlog/std_data/ver_5_1_17.001 | $MYSQL --local-infile=1 # Show result. SELECT * FROM t1 ORDER BY a; SELECT * FROM t2 ORDER BY a; @@ -52,6 +52,21 @@ SELECT COUNT(*) FROM t3; DROP TABLE t1, t2, t3; +--echo ==== Read binlog from version 4.1 ==== + +# In this version, neither row-based binlogging nor Xid events +# existed, so the binlog was generated without the "row-based tests" +# part and the "get xid event" part, and it does not create table t2. + +# Read binlog. +--exec $MYSQL_BINLOG --local-load=$MYSQLTEST_VARDIR/tmp/ suite/binlog/std_data/binlog_old_version_4_1.000001 | $MYSQL --local-infile=1 +# Show result. +SELECT * FROM t1 ORDER BY a; +SELECT COUNT(*) FROM t3; +# Reset. +DROP TABLE t1, t3; + + --echo ==== Read binlog from alcatel tree (mysql-5.1-wl2325-5.0-drop6) ==== # In this version, it was not possible to switch between row-based and @@ -60,9 +75,9 @@ DROP TABLE t1, t2, t3; # replication. # Read rbr binlog. ---exec $MYSQL_BINLOG --local-load=$MYSQLTEST_VARDIR/tmp/ suite/binlog/std_data/binlog_old_version_5_1-wl2325_row.000001 | $MYSQL --local-infile=1 +--exec $MYSQL_BINLOG --local-load=$MYSQLTEST_VARDIR/tmp/ suite/binlog/std_data/ver_5_1-wl2325_r.001 | $MYSQL --local-infile=1 # Read stm binlog. ---exec $MYSQL_BINLOG --local-load=$MYSQLTEST_VARDIR/tmp/ suite/binlog/std_data/binlog_old_version_5_1-wl2325_stm.000001 | $MYSQL --local-infile=1 +--exec $MYSQL_BINLOG --local-load=$MYSQLTEST_VARDIR/tmp/ suite/binlog/std_data/ver_5_1-wl2325_s.001 | $MYSQL --local-infile=1 # Show result. SELECT * FROM t1 ORDER BY a; SELECT * FROM t2 ORDER BY a; @@ -74,7 +89,7 @@ DROP TABLE t1, t2, t3; --echo ==== Read binlog from ndb tree (mysql-5.1-telco-6.1) ==== # Read binlog. ---exec $MYSQL_BINLOG --local-load=$MYSQLTEST_VARDIR/tmp/ suite/binlog/std_data/binlog_old_version_5_1-telco.000001 | $MYSQL --local-infile=1 +--exec $MYSQL_BINLOG --local-load=$MYSQLTEST_VARDIR/tmp/ suite/binlog/std_data/ver_5_1-telco.001 | $MYSQL --local-infile=1 # Show resulting tablea. SELECT * FROM t1 ORDER BY a; SELECT * FROM t2 ORDER BY a; diff --git a/mysql-test/suite/binlog/t/disabled.def b/mysql-test/suite/binlog/t/disabled.def index c93bc2a158e..a6e73fa31d8 100644 --- a/mysql-test/suite/binlog/t/disabled.def +++ b/mysql-test/suite/binlog/t/disabled.def @@ -10,4 +10,3 @@ # ############################################################################## binlog_multi_engine : Bug#32663 binlog_multi_engine.test fails randomly -binlog_base64_flag : BUG#33247 2007-12-14 Sven: mysqlbinlog does not clean up after itself on termination. When compiled in debug mode, this test generates lots of warnings for memory leaks. diff --git a/mysql-test/suite/bugs/data/rpl_bug12691.dat b/mysql-test/suite/bugs/data/rpl_bug12691.dat new file mode 100644 index 00000000000..de980441c3a --- /dev/null +++ b/mysql-test/suite/bugs/data/rpl_bug12691.dat @@ -0,0 +1,3 @@ +a +b +c diff --git a/mysql-test/suite/bugs/r/rpl_bug12691.result b/mysql-test/suite/bugs/r/rpl_bug12691.result new file mode 100644 index 00000000000..69d5e8009b0 --- /dev/null +++ b/mysql-test/suite/bugs/r/rpl_bug12691.result @@ -0,0 +1,34 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; + +**** On Master **** +CREATE TABLE t1 (b CHAR(10)); + +**** On Slave **** +STOP SLAVE; + +**** On Master **** +LOAD DATA INFILE FILENAME +SELECT COUNT(*) FROM t1; +COUNT(*) +3 +SHOW BINLOG EVENTS; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Format_desc 1 # Server ver: # +master-bin.000001 # Query 1 # use `test`; CREATE TABLE t1 (b CHAR(10)) +master-bin.000001 # Begin_load_query 1 # ;file_id=#;block_len=# +master-bin.000001 # Execute_load_query 1 # use `test`; LOAD DATA INFILE FILENAME ;file_id=# + +**** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +SELECT COUNT(*) FROM t1; +COUNT(*) +0 + +**** On Master **** +DROP TABLE t1; diff --git a/mysql-test/suite/bugs/t/rpl_bug12691.test b/mysql-test/suite/bugs/t/rpl_bug12691.test new file mode 100644 index 00000000000..b29c85584a5 --- /dev/null +++ b/mysql-test/suite/bugs/t/rpl_bug12691.test @@ -0,0 +1,53 @@ +# Bug#12691: Exec_master_log_pos corrupted with SQL_SLAVE_SKIP_COUNTER +# Date: 01/31/2008 +# Added: Serge Kozlov + +--source include/master-slave.inc +--connection master +--source include/have_binlog_format_mixed_or_statement.inc + +--echo +--echo **** On Master **** +CREATE TABLE t1 (b CHAR(10)); +--echo +--echo **** On Slave **** +--sync_slave_with_master +STOP SLAVE; +--source include/wait_for_slave_to_stop.inc + +--connection master + +--echo +--echo **** On Master **** +--exec cp $MYSQL_TEST_DIR/suite/bugs/data/rpl_bug12691.dat $MYSQLTEST_VARDIR/tmp/ +--echo LOAD DATA INFILE FILENAME +--disable_query_log +--eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/rpl_bug12691.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' +--enable_query_log +--remove_file $MYSQLTEST_VARDIR/tmp/rpl_bug12691.dat + +SELECT COUNT(*) FROM t1; + +--replace_column 2 # 5 # +--replace_regex /Server ver: .+/Server ver: #/ /table_id: [0-9]+/table_id: #/ /COMMIT.+xid=[0-9]+.+/#/ /file_id=[0-9]+/file_id=#/ /block_len=[0-9]+/block_len=#/ /'.+'/FILENAME/ +SHOW BINLOG EVENTS; + +--save_master_pos + +--connection slave +--echo +--echo **** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +--source include/wait_for_slave_to_start.inc +--sync_with_master + +SELECT COUNT(*) FROM t1; + +# Clean up +--connection master +--echo +--echo **** On Master **** +DROP TABLE t1; +--sync_slave_with_master + diff --git a/mysql-test/suite/ndb/r/ndb_auto_increment.result b/mysql-test/suite/ndb/r/ndb_auto_increment.result index 5740ed38242..78612b35113 100644 --- a/mysql-test/suite/ndb/r/ndb_auto_increment.result +++ b/mysql-test/suite/ndb/r/ndb_auto_increment.result @@ -421,10 +421,10 @@ select * from t1 order by a; a 1 20 -21 33 34 35 +65 insert into t1 values (100); insert into t1 values (NULL); insert into t1 values (NULL); @@ -432,11 +432,11 @@ select * from t1 order by a; a 1 20 -21 -22 33 34 35 +65 +66 100 101 set auto_increment_offset = @old_auto_increment_offset; diff --git a/mysql-test/suite/ndb/r/ndb_autoinc.result b/mysql-test/suite/ndb/r/ndb_autoinc.result new file mode 100644 index 00000000000..fe9d36393ad --- /dev/null +++ b/mysql-test/suite/ndb/r/ndb_autoinc.result @@ -0,0 +1,37 @@ +DROP TABLE IF EXISTS t1,t2,t3; +USE test; +CREATE TABLE t1 ( +id INT AUTO_INCREMENT, +PRIMARY KEY(id) +) ENGINE=NDBCLUSTER; +CREATE TABLE t2 ( +id INT AUTO_INCREMENT, +KEY(id) +) ENGINE=NDBCLUSTER; +ERROR HY000: Can't create table 'test.t2' (errno: 4335) +SHOW TABLES; +Tables_in_test +t1 +CREATE TABLE t3 ( +id INT AUTO_INCREMENT, +KEY(id) +) ENGINE=MYISAM; +ALTER TABLE t3 +ENGINE NDBCLUSTER; +SHOW CREATE TABLE t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + KEY `id` (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +ALTER TABLE t3 +ADD PRIMARY KEY (id); +SHOW CREATE TABLE t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`id`), + KEY `id` (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1, t3; +End of 5.1 tests diff --git a/mysql-test/suite/ndb/r/ndb_bug31477.result b/mysql-test/suite/ndb/r/ndb_bug31477.result new file mode 100644 index 00000000000..002a928b485 --- /dev/null +++ b/mysql-test/suite/ndb/r/ndb_bug31477.result @@ -0,0 +1,98 @@ +drop table if exists t1; +create table t1(a int primary key, b int, c int, unique(b)) engine = ndb; +insert into t1 values (2,2,2); +insert into t1 values (3,3,3); +insert into t1 values (4,4,4); +begin; +insert into t1 values (1,1,1); +begin; +update t1 set c = 2 where b = 1; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +rollback; +rollback; +drop table t1; +create table t1(a int primary key, b int, c int, key(b)) engine = ndb; +insert into t1 values (2,2,2); +insert into t1 values (3,3,3); +insert into t1 values (4,4,4); +begin; +insert into t1 values (1,1,1); +begin; +update t1 set c = 2 where b = 1; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +rollback; +rollback; +drop table t1; +--con1 +create table t1(a int primary key, b int, c int, key(b)) engine = ndb; +insert into t1 values (1,1,1); +insert into t1 values (2,2,2); +insert into t1 values (3,3,3); +insert into t1 values (4,4,4); +begin; +update t1 set c = 10 where a = 1; +update t1 set c = 20 where a = 1; +update t1 set c = 30 where a = 1; +--con1 c=30 +select * from t1 where b >= 1 order by b; +a b c +1 1 30 +2 2 2 +3 3 3 +4 4 4 +--con2 c=1 +select * from t1 where b >= 1 order by b; +a b c +1 1 1 +2 2 2 +3 3 3 +4 4 4 +--con1 +delete from t1 where a = 1; +--con1 c=none +select * from t1 where b >= 1 order by b; +a b c +2 2 2 +3 3 3 +4 4 4 +--con2 c=1 +select * from t1 where b >= 1 order by b; +a b c +1 1 1 +2 2 2 +3 3 3 +4 4 4 +--con1 +commit; +--con1 c=none +select * from t1 where b >= 1 order by b; +a b c +2 2 2 +3 3 3 +4 4 4 +--con2 c=none +select * from t1 where b >= 1 order by b; +a b c +2 2 2 +3 3 3 +4 4 4 +--con1 +begin; +insert into t1 values (1,1,1); +update t1 set c = 10 where a = 1; +update t1 set c = 20 where a = 1; +update t1 set c = 30 where a = 1; +--con1 c=30 +select * from t1 where b >= 1 order by b; +a b c +1 1 30 +2 2 2 +3 3 3 +4 4 4 +--con2 c=none +select * from t1 where b >= 1 order by b; +a b c +2 2 2 +3 3 3 +4 4 4 +drop table t1; diff --git a/mysql-test/suite/ndb/r/ndb_condition_pushdown.result b/mysql-test/suite/ndb/r/ndb_condition_pushdown.result index 1d61e2c59c2..4b6f5031fb2 100644 --- a/mysql-test/suite/ndb/r/ndb_condition_pushdown.result +++ b/mysql-test/suite/ndb/r/ndb_condition_pushdown.result @@ -1904,6 +1904,12 @@ a b d 10 1 4369 20 2 8738 50 5 21845 +-- big filter just below limit +a b d +10 1 4369 +20 2 8738 +50 5 21845 +-- big filter just above limit a b d 10 1 4369 20 2 8738 diff --git a/mysql-test/suite/ndb/r/ndb_dd_basic.result b/mysql-test/suite/ndb/r/ndb_dd_basic.result index f04905b8d13..41e3d10fe5b 100644 --- a/mysql-test/suite/ndb/r/ndb_dd_basic.result +++ b/mysql-test/suite/ndb/r/ndb_dd_basic.result @@ -406,6 +406,16 @@ a b c 1 7 7 2 2 2 3 3 3 +DELETE FROM t1; +INSERT INTO t1 VALUES (3,'1','1'); +BEGIN; +UPDATE t1 SET b = b + 2 WHERE A = 3; +DELETE FROM t1 WHERE A = 3; +INSERT INTO t1 VALUES (3,'0','0'); +COMMIT; +SELECT * from t1 ORDER BY 1; +a b c +3 0 0 DROP TABLE t1; CREATE TABLE t1 ( a INT NOT NULL PRIMARY KEY, @@ -501,6 +511,18 @@ f1 f2 111111 aaaaaa 222222 bbbbbb drop table test.t1; +CREATE TABLE t1 ( +id int unsigned NOT NULL, +c1 int unsigned NOT NULL, +c2 int DEFAULT NULL, +PRIMARY KEY using hash (id), +UNIQUE KEY c1 using hash (c1)) +TABLESPACE ts1 STORAGE DISK ENGINE=ndbcluster; +insert into t1 values(1, 1, 3); +insert into t1 values(2, 2, 3); +update t1 set c1 = 1 where id = 2; +ERROR 23000: Duplicate entry '1' for key 'c1' +drop table t1; ALTER TABLESPACE ts1 DROP DATAFILE 'datafile.dat' ENGINE = NDB; diff --git a/mysql-test/suite/ndb/r/ndb_partition_key.result b/mysql-test/suite/ndb/r/ndb_partition_key.result index 60e96ce03b6..d87b59d6c0e 100644 --- a/mysql-test/suite/ndb/r/ndb_partition_key.result +++ b/mysql-test/suite/ndb/r/ndb_partition_key.result @@ -38,6 +38,23 @@ a b c 1 10 3 1 11 3 1 12 3 +select max(b) from t1 where a = 1; +max(b) +12 +select b from t1 where a = 1 order by b desc; +b +12 +11 +10 +9 +8 +7 +6 +5 +4 +3 +2 +1 DROP TABLE t1; CREATE TABLE t1 (a INT, b CHAR(10) COLLATE latin1_bin, c INT, d INT, PRIMARY KEY (a,b,c) USING HASH) diff --git a/mysql-test/suite/ndb/r/ndb_partition_range.result b/mysql-test/suite/ndb/r/ndb_partition_range.result index 0c717ed55e9..198898879df 100644 --- a/mysql-test/suite/ndb/r/ndb_partition_range.result +++ b/mysql-test/suite/ndb/r/ndb_partition_range.result @@ -46,6 +46,14 @@ a b c 1 1 1 6 1 1 10 1 1 +INSERT into t1 values (1, 2, 2); +select max(b) from t1 where a = 1; +max(b) +2 +select b from t1 where a = 1 order by b desc; +b +2 +1 drop table t1; CREATE TABLE t1 ( a int not null, diff --git a/mysql-test/suite/ndb/r/ndb_restore.result b/mysql-test/suite/ndb/r/ndb_restore.result index aba6997d218..a33c5c5f31c 100644 --- a/mysql-test/suite/ndb/r/ndb_restore.result +++ b/mysql-test/suite/ndb/r/ndb_restore.result @@ -253,21 +253,41 @@ a 2000 3000 10000 -show table status like 't1_c'; -Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -X X X X X X X X X X 3001 X X X X X X X -show table status like 't2_c'; -Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -X X X X X X X X X X 501 X X X X X X X -show table status like 't4_c'; -Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -X X X X X X X X X X 290000001 X X X X X X X -show table status like 't7_c'; -Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -X X X X X X X X X X 29 X X X X X X X -show table status like 't10_c'; -Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -X X X X X X X X X X 10001 X X X X X X X +select max(capgoaledatta) from t1_c; +max(capgoaledatta) +3000 +select auto_increment from information_schema.tables +where table_name = 't1_c'; +auto_increment +3001 +select max(capgotod) from t2_c; +max(capgotod) +500 +select auto_increment from information_schema.tables +where table_name = 't2_c'; +auto_increment +501 +select max(capfa) from t4_c; +max(capfa) +290000000 +select auto_increment from information_schema.tables +where table_name = 't4_c'; +auto_increment +290000001 +select max(dardtestard) from t7_c; +max(dardtestard) +28 +select auto_increment from information_schema.tables +where table_name = 't7_c'; +auto_increment +29 +select max(a) from t10_c; +max(a) +10000 +select auto_increment from information_schema.tables +where table_name = 't10_c'; +auto_increment +10001 ALTER TABLE t7_c PARTITION BY LINEAR KEY (`dardtestard`); CREATE TEMPORARY TABLE IF NOT EXISTS test.backup_info (id INT, backup_id INT) ENGINE = HEAP; diff --git a/mysql-test/suite/ndb/t/ndb_autoinc.test b/mysql-test/suite/ndb/t/ndb_autoinc.test new file mode 100644 index 00000000000..a5ae52c88d7 --- /dev/null +++ b/mysql-test/suite/ndb/t/ndb_autoinc.test @@ -0,0 +1,45 @@ +-- source include/have_ndb.inc +-- source include/not_embedded.inc + +--disable_warnings +DROP TABLE IF EXISTS t1,t2,t3; +--enable_warnings + +USE test; + +CREATE TABLE t1 ( + id INT AUTO_INCREMENT, + PRIMARY KEY(id) +) ENGINE=NDBCLUSTER; + +# Test For bug#30417 +--error 1005 + +CREATE TABLE t2 ( + id INT AUTO_INCREMENT, + KEY(id) +) ENGINE=NDBCLUSTER; + +SHOW TABLES; + +CREATE TABLE t3 ( + id INT AUTO_INCREMENT, + KEY(id) +) ENGINE=MYISAM; + +--disable_result_log +--error 1005 +ALTER TABLE t3 +ENGINE NDBCLUSTER; +--enable_result_log + +SHOW CREATE TABLE t3; + +ALTER TABLE t3 +ADD PRIMARY KEY (id); + +SHOW CREATE TABLE t3; + +DROP TABLE t1, t3; + +--echo End of 5.1 tests diff --git a/mysql-test/suite/ndb/t/ndb_bug31477.test b/mysql-test/suite/ndb/t/ndb_bug31477.test new file mode 100644 index 00000000000..41c519e56fd --- /dev/null +++ b/mysql-test/suite/ndb/t/ndb_bug31477.test @@ -0,0 +1,109 @@ +--source include/have_ndb.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# setup + +connect (con1,localhost,root,,test); +connect (con2,localhost,root,,test); + +# unique index +connection con1; +create table t1(a int primary key, b int, c int, unique(b)) engine = ndb; +insert into t1 values (2,2,2); +insert into t1 values (3,3,3); +insert into t1 values (4,4,4); + +begin; +insert into t1 values (1,1,1); + +connection con2; +begin; +--error 1205 +update t1 set c = 2 where b = 1; +rollback; + +connection con1; +rollback; +drop table t1; +# ordered index + +connection con1; +create table t1(a int primary key, b int, c int, key(b)) engine = ndb; +insert into t1 values (2,2,2); +insert into t1 values (3,3,3); +insert into t1 values (4,4,4); + +begin; +insert into t1 values (1,1,1); + +connection con2; +begin; +--error 1205 +update t1 set c = 2 where b = 1; +rollback; + +connection con1; +rollback; +drop table t1; + +# multiple versions + +--echo --con1 +connection con1; +create table t1(a int primary key, b int, c int, key(b)) engine = ndb; +insert into t1 values (1,1,1); +insert into t1 values (2,2,2); +insert into t1 values (3,3,3); +insert into t1 values (4,4,4); + +begin; +update t1 set c = 10 where a = 1; +update t1 set c = 20 where a = 1; +update t1 set c = 30 where a = 1; + +--echo --con1 c=30 +select * from t1 where b >= 1 order by b; +--echo --con2 c=1 +connection con2; +select * from t1 where b >= 1 order by b; + +--echo --con1 +connection con1; +delete from t1 where a = 1; + +--echo --con1 c=none +select * from t1 where b >= 1 order by b; +--echo --con2 c=1 +connection con2; +select * from t1 where b >= 1 order by b; + +--echo --con1 +connection con1; +commit; + +--echo --con1 c=none +select * from t1 where b >= 1 order by b; +--echo --con2 c=none +connection con2; +select * from t1 where b >= 1 order by b; + +--echo --con1 +connection con1; +begin; +insert into t1 values (1,1,1); +update t1 set c = 10 where a = 1; +update t1 set c = 20 where a = 1; +update t1 set c = 30 where a = 1; + +--echo --con1 c=30 +select * from t1 where b >= 1 order by b; +--echo --con2 c=none +connection con2; +select * from t1 where b >= 1 order by b; + +# this fails with "no such table" via con2 ??? +connection con1; +drop table t1; diff --git a/mysql-test/suite/ndb/t/ndb_condition_pushdown.test b/mysql-test/suite/ndb/t/ndb_condition_pushdown.test index 9e6a5e90e40..a56c9dda01c 100644 --- a/mysql-test/suite/ndb/t/ndb_condition_pushdown.test +++ b/mysql-test/suite/ndb/t/ndb_condition_pushdown.test @@ -1753,6 +1753,7 @@ set engine_condition_pushdown = 1; SELECT fname, lname FROM t1 WHERE (fname like 'Y%') or (lname like 'F%'); # bug#29390 (scan filter is too large, discarded) +# bug#34107 (previous limit was too large for TUP) drop table t1; @@ -1771,9 +1772,11 @@ select a,b,d from t1 where b in (0,1,2,5) order by b; +--echo -- big filter just below limit --disable_query_log select a,b,d from t1 where b in ( +0,1,2,5,0,1,2,5,0,1, 0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, 0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, 0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, @@ -1904,745 +1907,15 @@ select a,b,d from t1 0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, 0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, 0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, -0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2) + order by b; +--enable_query_log + +--echo -- big filter just above limit +--disable_query_log +select a,b,d from t1 + where b in ( +0,1,2,5,0,1,2,5,0,1,2, 0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, 0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, 0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, diff --git a/mysql-test/suite/ndb/t/ndb_dd_basic.test b/mysql-test/suite/ndb/t/ndb_dd_basic.test index 8c83c2febe5..0fb793e2142 100644 --- a/mysql-test/suite/ndb/t/ndb_dd_basic.test +++ b/mysql-test/suite/ndb/t/ndb_dd_basic.test @@ -346,6 +346,16 @@ UPDATE t1 SET c = '6' WHERE b = '7'; SELECT * FROM t1 ORDER BY 1; UPDATE t1 SET c = '7' WHERE c = '6'; SELECT * FROM t1 ORDER BY 1; + +DELETE FROM t1; +INSERT INTO t1 VALUES (3,'1','1'); +BEGIN; +UPDATE t1 SET b = b + 2 WHERE A = 3; +DELETE FROM t1 WHERE A = 3; +INSERT INTO t1 VALUES (3,'0','0'); +COMMIT; +SELECT * from t1 ORDER BY 1; + DROP TABLE t1; ######################## @@ -439,6 +449,21 @@ select f2 from test.t1 order by f2; select f1,f2 from test.t1 order by f1; drop table test.t1; +# bug#34118 hash index trigger and do not update any disk attr +CREATE TABLE t1 ( +id int unsigned NOT NULL, +c1 int unsigned NOT NULL, +c2 int DEFAULT NULL, +PRIMARY KEY using hash (id), +UNIQUE KEY c1 using hash (c1)) +TABLESPACE ts1 STORAGE DISK ENGINE=ndbcluster; + +insert into t1 values(1, 1, 3); +insert into t1 values(2, 2, 3); +--error ER_DUP_ENTRY +update t1 set c1 = 1 where id = 2; +drop table t1; + ################### # Test Cleanup ################### diff --git a/mysql-test/suite/ndb/t/ndb_partition_key.test b/mysql-test/suite/ndb/t/ndb_partition_key.test index 78e2c9d15c2..df351ea42c7 100644 --- a/mysql-test/suite/ndb/t/ndb_partition_key.test +++ b/mysql-test/suite/ndb/t/ndb_partition_key.test @@ -38,6 +38,10 @@ insert into t1 values select * from t1 order by b; +# BUG#33061: ORDER BY DESC becomes ASC in NDB partition pruning to one partition +select max(b) from t1 where a = 1; +select b from t1 where a = 1 order by b desc; + DROP TABLE t1; # diff --git a/mysql-test/suite/ndb/t/ndb_partition_range.test b/mysql-test/suite/ndb/t/ndb_partition_range.test index 7952ba502d2..778e552c6d8 100644 --- a/mysql-test/suite/ndb/t/ndb_partition_range.test +++ b/mysql-test/suite/ndb/t/ndb_partition_range.test @@ -48,6 +48,11 @@ select * from t1 where a=21 order by a; select * from t1 where a in (1,6,10,21) order by a; select * from t1 where b=1 and a in (1,6,10,21) order by a; +# BUG#33061: ORDER BY DESC becomes ASC in NDB partition pruning to one partition +INSERT into t1 values (1, 2, 2); +select max(b) from t1 where a = 1; +select b from t1 where a = 1 order by b desc; + drop table t1; # diff --git a/mysql-test/suite/ndb/t/ndb_restore.test b/mysql-test/suite/ndb/t/ndb_restore.test index 18efa66ebe0..c8b07fd351a 100644 --- a/mysql-test/suite/ndb/t/ndb_restore.test +++ b/mysql-test/suite/ndb/t/ndb_restore.test @@ -246,16 +246,21 @@ select count(*) select * from t10_c order by a; # Bug #27775 cont'd # - auto inc info should be correct ---replace_column 1 X 2 X 3 X 4 X 5 X 6 X 7 X 8 X 9 X 10 X 12 X 13 X 14 X 15 X 16 X 17 X 18 X -show table status like 't1_c'; ---replace_column 1 X 2 X 3 X 4 X 5 X 6 X 7 X 8 X 9 X 10 X 12 X 13 X 14 X 15 X 16 X 17 X 18 X -show table status like 't2_c'; ---replace_column 1 X 2 X 3 X 4 X 5 X 6 X 7 X 8 X 9 X 10 X 12 X 13 X 14 X 15 X 16 X 17 X 18 X -show table status like 't4_c'; ---replace_column 1 X 2 X 3 X 4 X 5 X 6 X 7 X 8 X 9 X 10 X 12 X 13 X 14 X 15 X 16 X 17 X 18 X -show table status like 't7_c'; ---replace_column 1 X 2 X 3 X 4 X 5 X 6 X 7 X 8 X 9 X 10 X 12 X 13 X 14 X 15 X 16 X 17 X 18 X -show table status like 't10_c'; +select max(capgoaledatta) from t1_c; +select auto_increment from information_schema.tables +where table_name = 't1_c'; +select max(capgotod) from t2_c; +select auto_increment from information_schema.tables +where table_name = 't2_c'; +select max(capfa) from t4_c; +select auto_increment from information_schema.tables +where table_name = 't4_c'; +select max(dardtestard) from t7_c; +select auto_increment from information_schema.tables +where table_name = 't7_c'; +select max(a) from t10_c; +select auto_increment from information_schema.tables +where table_name = 't10_c'; # # Try Partitioned tables as well diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_dd_advance.result b/mysql-test/suite/ndb_team/r/rpl_ndb_dd_advance.result similarity index 100% rename from mysql-test/suite/rpl_ndb/r/rpl_ndb_dd_advance.result rename to mysql-test/suite/ndb_team/r/rpl_ndb_dd_advance.result diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraColMaster.result b/mysql-test/suite/ndb_team/r/rpl_ndb_extraColMaster.result similarity index 99% rename from mysql-test/suite/rpl_ndb/r/rpl_ndb_extraColMaster.result rename to mysql-test/suite/ndb_team/r/rpl_ndb_extraColMaster.result index 194e6a375f3..97300e7131b 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraColMaster.result +++ b/mysql-test/suite/ndb_team/r/rpl_ndb_extraColMaster.result @@ -440,23 +440,21 @@ f1 f2 f3 f4 select * from t4 order by f1; f1 f2 f3 f4 1 1 1 first -select * from t31 order by f1; +select * from t31 order by f3; f1 f2 f3 f4 -1 1 5 fifth -1 1 3 third 1 1 1 first -1 1 6 sixth 1 1 2 second +1 1 3 third 1 1 4 fourth +1 1 5 fifth +1 1 6 sixth ** Do updates master ** update t31 set f5=555555555555555 where f3=6; update t31 set f2=2 where f3=2; update t31 set f1=NULL where f3=1; -update t31 set f3=NULL, f27=NULL, f35='f35 new value' where f3=3; -Warnings: -Warning 1048 Column 'f3' cannot be null +update t31 set f3=0, f27=NULL, f35='f35 new value' where f3=3; ** Delete from Master ** @@ -563,7 +561,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 Skip_Counter 0 Exec_Master_Log_Pos # @@ -581,7 +579,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -638,7 +636,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 Skip_Counter 0 Exec_Master_Log_Pos # @@ -656,7 +654,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -1581,23 +1579,21 @@ f1 f2 f3 f4 select * from t4 order by f1; f1 f2 f3 f4 1 1 1 first -select * from t31 order by f1; +select * from t31 order by f3; f1 f2 f3 f4 -1 1 5 fifth -1 1 3 third 1 1 1 first -1 1 6 sixth 1 1 2 second +1 1 3 third 1 1 4 fourth +1 1 5 fifth +1 1 6 sixth ** Do updates master ** update t31 set f5=555555555555555 where f3=6; update t31 set f2=2 where f3=2; update t31 set f1=NULL where f3=1; -update t31 set f3=NULL, f27=NULL, f35='f35 new value' where f3=3; -Warnings: -Warning 1048 Column 'f3' cannot be null +update t31 set f3=0, f27=NULL, f35='f35 new value' where f3=3; ** Delete from Master ** @@ -1704,7 +1700,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 Skip_Counter 0 Exec_Master_Log_Pos # @@ -1722,7 +1718,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -1779,7 +1775,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1534 +Last_Errno 1535 Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 Skip_Counter 0 Exec_Master_Log_Pos # @@ -1797,7 +1793,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1534 +Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_mix_innodb.result b/mysql-test/suite/ndb_team/r/rpl_ndb_mix_innodb.result similarity index 87% rename from mysql-test/suite/rpl_ndb/r/rpl_ndb_mix_innodb.result rename to mysql-test/suite/ndb_team/r/rpl_ndb_mix_innodb.result index 625d06de44b..eba1222ea33 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_mix_innodb.result +++ b/mysql-test/suite/ndb_team/r/rpl_ndb_mix_innodb.result @@ -20,13 +20,27 @@ from mysql.ndb_apply_status; @log_name:=log_name @start_pos:=start_pos @end_pos:=end_pos +# Now check that that is in the apply_status table is consistant +# with what is in the binlog + +# since insert is done with transactional engine, expect a BEGIN +# at + show binlog events from limit 1; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 Query 1 # use `test`; insert into t1 values (1,2) +master-bin.000001 Query 1 # use `test`; BEGIN + +# Now the insert, one step after show binlog events from limit 1,1; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Xid 1 445 COMMIT /* XID */ +master-bin.000001 # Query 1 # use `test`; insert into t1 values (1,2) + +# and the COMMIT should be at + +show binlog events from limit 2,1; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Xid 1 COMMIT /* XID */ begin; insert into t1 values (2,3); diff --git a/mysql-test/suite/ndb_team/t/disabled.def b/mysql-test/suite/ndb_team/t/disabled.def index 8ff2d29147d..714f1014a10 100644 --- a/mysql-test/suite/ndb_team/t/disabled.def +++ b/mysql-test/suite/ndb_team/t/disabled.def @@ -15,3 +15,6 @@ ndb_autodiscover2 : BUG#18952 2006-02-16 jmiller Needs to be fixed w.r.t # the below testcase have been reworked to avoid the bug, test contains comment, keep bug open #ndb_autodiscover3 : bug#21806 #ndb_autodiscover3 : Bug#20872 2007-07-15 ingo master*.err: miscellaneous error messages +#rpl_ndb_extraColMaster : BUG#30854 : Tables name show as binary in slave err msg on vm-win2003-64-b and Solaris +#rpl_ndb_mix_innodb : Bug #32720 Test rpl_ndb_mix_innodb fails on SPARC and PowerPC +#rpl_ndb_dd_advance : Bug #30222 rpl_ndb_dd_advance.test fails diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_dd_advance.test b/mysql-test/suite/ndb_team/t/rpl_ndb_dd_advance.test similarity index 100% rename from mysql-test/suite/rpl_ndb/t/rpl_ndb_dd_advance.test rename to mysql-test/suite/ndb_team/t/rpl_ndb_dd_advance.test diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_extraColMaster.test b/mysql-test/suite/ndb_team/t/rpl_ndb_extraColMaster.test similarity index 100% rename from mysql-test/suite/rpl_ndb/t/rpl_ndb_extraColMaster.test rename to mysql-test/suite/ndb_team/t/rpl_ndb_extraColMaster.test diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_mix_innodb-master.opt b/mysql-test/suite/ndb_team/t/rpl_ndb_mix_innodb-master.opt similarity index 100% rename from mysql-test/suite/rpl_ndb/t/rpl_ndb_mix_innodb-master.opt rename to mysql-test/suite/ndb_team/t/rpl_ndb_mix_innodb-master.opt diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_mix_innodb.test b/mysql-test/suite/ndb_team/t/rpl_ndb_mix_innodb.test similarity index 100% rename from mysql-test/suite/rpl_ndb/t/rpl_ndb_mix_innodb.test rename to mysql-test/suite/ndb_team/t/rpl_ndb_mix_innodb.test diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_charset.result b/mysql-test/suite/rpl/r/rpl_charset.result similarity index 65% rename from mysql-test/suite/rpl_ndb/r/rpl_ndb_charset.result rename to mysql-test/suite/rpl/r/rpl_charset.result index 8b1f3093332..ae5cf3b0fd1 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_charset.result +++ b/mysql-test/suite/rpl/r/rpl_charset.result @@ -40,14 +40,13 @@ show create database mysqltest3; Database Create Database mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET armscii8 COLLATE armscii8_bin */ use mysqltest2; -create table t1 (a int auto_increment primary key, b varchar(100))engine=NDB;; +create table t1 (a int auto_increment primary key, b varchar(100)); set character_set_client=cp850, collation_connection=latin2_croatian_ci; insert into t1 (b) values(@@character_set_server); insert into t1 (b) values(@@collation_server); insert into t1 (b) values(@@character_set_client); insert into t1 (b) values(@@character_set_connection); insert into t1 (b) values(@@collation_connection); - --- --master-- select * from t1 order by a; a b @@ -56,7 +55,6 @@ a b 3 cp850 4 latin2 5 latin2_croatian_ci - --- --slave-- select * from mysqltest2.t1 order by a; a b @@ -65,9 +63,6 @@ a b 3 cp850 4 latin2 5 latin2_croatian_ci -select "--- --muller--" as ""; - ---- --muller-- set character_set_client=latin1, collation_connection=latin1_german1_ci; truncate table t1; insert into t1 (b) values(@@collation_connection); @@ -75,7 +70,6 @@ insert into t1 (b) values(LEAST("M set collation_connection=latin1_german2_ci; insert into t1 (b) values(@@collation_connection); insert into t1 (b) values(LEAST("Müller","Muffler")); - --- --master-- select * from t1 order by a; a b @@ -83,7 +77,6 @@ a b 2 Muffler 3 latin1_german2_ci 4 Müller - --- --slave-- select * from mysqltest2.t1 order by a; a b @@ -91,65 +84,23 @@ a b 2 Muffler 3 latin1_german2_ci 4 Müller -select "--- --INSERT--" as ""; - ---- --INSERT-- set @a= _cp850 'Müller' collate cp850_general_ci; truncate table t1; insert into t1 (b) values(collation(@a)); - --- --master-- select * from t1 order by a; a b 1 cp850_general_ci - --- --slave-- select * from mysqltest2.t1 order by a; a b 1 cp850_general_ci drop database mysqltest2; drop database mysqltest3; -show binlog events from ; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # drop database if exists mysqltest2 -master-bin.000001 # Query # # drop database if exists mysqltest3 -master-bin.000001 # Query # # create database mysqltest2 character set latin2 -master-bin.000001 # Query # # create database mysqltest3 -master-bin.000001 # Query # # drop database mysqltest3 -master-bin.000001 # Query # # create database mysqltest3 -master-bin.000001 # Query # # use `mysqltest2`; create table t1 (a int auto_increment primary key, b varchar(100))engine=NDB -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status) -master-bin.000001 # Write_rows # # table_id: # -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # COMMIT -master-bin.000001 # Query # # use `mysqltest2`; truncate table t1 -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status) -master-bin.000001 # Write_rows # # table_id: # -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # COMMIT -master-bin.000001 # Query # # use `mysqltest2`; truncate table t1 -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status) -master-bin.000001 # Write_rows # # table_id: # -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # COMMIT -master-bin.000001 # Query # # drop database mysqltest2 -master-bin.000001 # Query # # drop database mysqltest3 -select "--- --global--" as ""; - ---- --global-- set global character_set_server=latin2; set global character_set_server=latin1; set global character_set_server=latin2; set global character_set_server=latin1; -select "--- --oneshot--" as ""; - ---- --oneshot-- set one_shot @@character_set_server=latin5; set @@max_join_size=1000; select @@character_set_server; @@ -171,31 +122,23 @@ set character_set_client=9999999; ERROR 42000: Unknown character set: '9999999' set collation_server=9999998; ERROR HY000: Unknown collation: '9999998' -select "--- --3943--" as ""; - ---- --3943-- use test; -CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255))ENGINE=NDB;; +CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255)); SET CHARACTER_SET_CLIENT=koi8r, CHARACTER_SET_CONNECTION=cp1251, CHARACTER_SET_RESULTS=koi8r; INSERT INTO t1 (c1, c2) VALUES ('îĠ, ÚÁ ÒÙÂÁÌËĠ','îĠ, ÚÁ ÒÙÂÁÌËĠ'); -SET SQL_BIG_SELECTS=1; select hex(c1), hex(c2) from t1; hex(c1) hex(c2) CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 -SET SQL_BIG_SELECTS=1; select hex(c1), hex(c2) from t1; hex(c1) hex(c2) CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 drop table t1; -select "--- --6676--" as ""; - ---- --6676-- create table `t1` ( `pk` varchar(10) not null default '', primary key (`pk`) -) engine=NDB default charset=latin1; +) engine=myisam default charset=latin1; set @p=_latin1 'test'; update t1 set pk='test' where pk=@p; drop table t1; diff --git a/mysql-test/suite/rpl/r/rpl_events.result b/mysql-test/suite/rpl/r/rpl_events.result index 18fe72a9879..273004b0a43 100644 --- a/mysql-test/suite/rpl/r/rpl_events.result +++ b/mysql-test/suite/rpl/r/rpl_events.result @@ -195,9 +195,11 @@ test slave_terminate SLAVESIDE_DISABLED 2 DROP EVENT test.slave_terminate; "Cleanup" DROP TABLE t1; +CREATE TABLE t28953 (a INT); CREATE EVENT event1 ON SCHEDULE EVERY 1 YEAR DO BEGIN -select * from t1; +select * from t28953; END;| ALTER EVENT event1 RENAME TO event2; DROP EVENT event2; +DROP TABLE t28953; diff --git a/mysql-test/suite/rpl/r/rpl_loaddata_map.result b/mysql-test/suite/rpl/r/rpl_loaddata_map.result index e6ddc1ebedc..7078389c987 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddata_map.result +++ b/mysql-test/suite/rpl/r/rpl_loaddata_map.result @@ -12,13 +12,13 @@ load data infile 'MYSQLTEST_VARDIR/tmp/bug30435_5k.txt' into table t2; select count(*) from t2 /* 5 000 */; count(*) 5000 -show binlog events in 'master-bin.000002' from 106; +show binlog events in 'master-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000002 106 Query 1 # use `test`; create table t2 (id int not null primary key auto_increment) -master-bin.000002 229 Begin_load_query 1 # ;file_id=#;block_len=8192 -master-bin.000002 8444 Append_block 1 # ;file_id=#;block_len=8192 -master-bin.000002 16659 Append_block 1 # ;file_id=#;block_len=7509 -master-bin.000002 24191 Execute_load_query 1 # use `test`; load data infile 'MYSQLTEST_VARDIR/tmp/bug30435_5k.txt' into table t2 ;file_id=# +master-bin.000002 # Query # # use `test`; create table t2 (id int not null primary key auto_increment) +master-bin.000002 # Begin_load_query # # ;file_id=#;block_len=# +master-bin.000002 # Append_block # # ;file_id=#;block_len=# +master-bin.000002 # Append_block # # ;file_id=#;block_len=# +master-bin.000002 # Execute_load_query # # use `test`; load data infile 'MYSQLTEST_VARDIR/tmp/bug30435_5k.txt' into table t2 ;file_id=# select count(*) from t2 /* 5 000 */; count(*) 5000 diff --git a/mysql-test/suite/rpl/r/rpl_row_charset.result b/mysql-test/suite/rpl/r/rpl_row_charset.result deleted file mode 100644 index caaa9d8332b..00000000000 --- a/mysql-test/suite/rpl/r/rpl_row_charset.result +++ /dev/null @@ -1,203 +0,0 @@ -stop slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -reset master; -reset slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -start slave; -set timestamp=1000000000; -drop database if exists mysqltest2; -drop database if exists mysqltest3; -create database mysqltest2 character set latin2; -set @@character_set_server=latin5; -create database mysqltest3; - ---- --master-- -show create database mysqltest2; -Database Create Database -mysqltest2 CREATE DATABASE `mysqltest2` /*!40100 DEFAULT CHARACTER SET latin2 */ -show create database mysqltest3; -Database Create Database -mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET latin5 */ - ---- --slave-- -show create database mysqltest2; -Database Create Database -mysqltest2 CREATE DATABASE `mysqltest2` /*!40100 DEFAULT CHARACTER SET latin2 */ -show create database mysqltest3; -Database Create Database -mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET latin5 */ -set @@collation_server=armscii8_bin; -drop database mysqltest3; -create database mysqltest3; - ---- --master-- -show create database mysqltest3; -Database Create Database -mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET armscii8 COLLATE armscii8_bin */ - ---- --slave-- -show create database mysqltest3; -Database Create Database -mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET armscii8 COLLATE armscii8_bin */ -use mysqltest2; -create table t1 (a int auto_increment primary key, b varchar(100))engine=myisam;; -set character_set_client=cp850, collation_connection=latin2_croatian_ci; -insert into t1 (b) values(@@character_set_server); -insert into t1 (b) values(@@collation_server); -insert into t1 (b) values(@@character_set_client); -insert into t1 (b) values(@@character_set_connection); -insert into t1 (b) values(@@collation_connection); - ---- --master-- -select * from t1 order by a; -a b -1 armscii8 -2 armscii8_bin -3 cp850 -4 latin2 -5 latin2_croatian_ci - ---- --slave-- -select * from mysqltest2.t1 order by a; -a b -1 armscii8 -2 armscii8_bin -3 cp850 -4 latin2 -5 latin2_croatian_ci -select "--- --muller--" as ""; - ---- --muller-- -set character_set_client=latin1, collation_connection=latin1_german1_ci; -truncate table t1; -insert into t1 (b) values(@@collation_connection); -insert into t1 (b) values(LEAST("Müller","Muffler")); -set collation_connection=latin1_german2_ci; -insert into t1 (b) values(@@collation_connection); -insert into t1 (b) values(LEAST("Müller","Muffler")); - ---- --master-- -select * from t1 order by a; -a b -1 latin1_german1_ci -2 Muffler -3 latin1_german2_ci -4 Müller - ---- --slave-- -select * from mysqltest2.t1 order by a; -a b -1 latin1_german1_ci -2 Muffler -3 latin1_german2_ci -4 Müller -select "--- --INSERT--" as ""; - ---- --INSERT-- -set @a= _cp850 'Müller' collate cp850_general_ci; -truncate table t1; -insert into t1 (b) values(collation(@a)); - ---- --master-- -select * from t1 order by a; -a b -1 cp850_general_ci - ---- --slave-- -select * from mysqltest2.t1 order by a; -a b -1 cp850_general_ci -drop database mysqltest2; -drop database mysqltest3; -show binlog events from ; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # drop database if exists mysqltest2 -master-bin.000001 # Query # # drop database if exists mysqltest3 -master-bin.000001 # Query # # create database mysqltest2 character set latin2 -master-bin.000001 # Query # # create database mysqltest3 -master-bin.000001 # Query # # drop database mysqltest3 -master-bin.000001 # Query # # create database mysqltest3 -master-bin.000001 # Query # # use `mysqltest2`; create table t1 (a int auto_increment primary key, b varchar(100))engine=myisam -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # use `mysqltest2`; truncate table t1 -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # use `mysqltest2`; truncate table t1 -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # drop database mysqltest2 -master-bin.000001 # Query # # drop database mysqltest3 -select "--- --global--" as ""; - ---- --global-- -set global character_set_server=latin2; -set global character_set_server=latin1; -set global character_set_server=latin2; -set global character_set_server=latin1; -select "--- --oneshot--" as ""; - ---- --oneshot-- -set one_shot @@character_set_server=latin5; -set @@max_join_size=1000; -select @@character_set_server; -@@character_set_server -latin5 -select @@character_set_server; -@@character_set_server -latin1 -set @@character_set_server=latin5; -select @@character_set_server; -@@character_set_server -latin5 -select @@character_set_server; -@@character_set_server -latin5 -set one_shot max_join_size=10; -ERROR HY000: The 'SET ONE_SHOT' syntax is reserved for purposes internal to the MySQL server -set character_set_client=9999999; -ERROR 42000: Unknown character set: '9999999' -set collation_server=9999998; -ERROR HY000: Unknown collation: '9999998' -select "--- --3943--" as ""; - ---- --3943-- -use test; -CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255))ENGINE=myisam;; -SET CHARACTER_SET_CLIENT=koi8r, -CHARACTER_SET_CONNECTION=cp1251, -CHARACTER_SET_RESULTS=koi8r; -INSERT INTO t1 (c1, c2) VALUES ('îĠ, ÚÁ ÒÙÂÁÌËĠ','îĠ, ÚÁ ÒÙÂÁÌËĠ'); -SET SQL_BIG_SELECTS=1; -select hex(c1), hex(c2) from t1; -hex(c1) hex(c2) -CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 -SET SQL_BIG_SELECTS=1; -select hex(c1), hex(c2) from t1; -hex(c1) hex(c2) -CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 -drop table t1; -select "--- --6676--" as ""; - ---- --6676-- -create table `t1` ( -`pk` varchar(10) not null default '', -primary key (`pk`) -) engine=myisam default charset=latin1; -set @p=_latin1 'test'; -update t1 set pk='test' where pk=@p; -drop table t1; diff --git a/mysql-test/suite/rpl/r/rpl_row_charset_innodb.result b/mysql-test/suite/rpl/r/rpl_row_charset_innodb.result deleted file mode 100644 index 4edc224135e..00000000000 --- a/mysql-test/suite/rpl/r/rpl_row_charset_innodb.result +++ /dev/null @@ -1,227 +0,0 @@ -stop slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -reset master; -reset slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -start slave; -set timestamp=1000000000; -drop database if exists mysqltest2; -drop database if exists mysqltest3; -create database mysqltest2 character set latin2; -set @@character_set_server=latin5; -create database mysqltest3; - ---- --master-- -show create database mysqltest2; -Database Create Database -mysqltest2 CREATE DATABASE `mysqltest2` /*!40100 DEFAULT CHARACTER SET latin2 */ -show create database mysqltest3; -Database Create Database -mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET latin5 */ - ---- --slave-- -show create database mysqltest2; -Database Create Database -mysqltest2 CREATE DATABASE `mysqltest2` /*!40100 DEFAULT CHARACTER SET latin2 */ -show create database mysqltest3; -Database Create Database -mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET latin5 */ -set @@collation_server=armscii8_bin; -drop database mysqltest3; -create database mysqltest3; - ---- --master-- -show create database mysqltest3; -Database Create Database -mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET armscii8 COLLATE armscii8_bin */ - ---- --slave-- -show create database mysqltest3; -Database Create Database -mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET armscii8 COLLATE armscii8_bin */ -use mysqltest2; -create table t1 (a int auto_increment primary key, b varchar(100))engine=innodb;; -set character_set_client=cp850, collation_connection=latin2_croatian_ci; -insert into t1 (b) values(@@character_set_server); -insert into t1 (b) values(@@collation_server); -insert into t1 (b) values(@@character_set_client); -insert into t1 (b) values(@@character_set_connection); -insert into t1 (b) values(@@collation_connection); - ---- --master-- -select * from t1 order by a; -a b -1 armscii8 -2 armscii8_bin -3 cp850 -4 latin2 -5 latin2_croatian_ci - ---- --slave-- -select * from mysqltest2.t1 order by a; -a b -1 armscii8 -2 armscii8_bin -3 cp850 -4 latin2 -5 latin2_croatian_ci -select "--- --muller--" as ""; - ---- --muller-- -set character_set_client=latin1, collation_connection=latin1_german1_ci; -truncate table t1; -insert into t1 (b) values(@@collation_connection); -insert into t1 (b) values(LEAST("Müller","Muffler")); -set collation_connection=latin1_german2_ci; -insert into t1 (b) values(@@collation_connection); -insert into t1 (b) values(LEAST("Müller","Muffler")); - ---- --master-- -select * from t1 order by a; -a b -1 latin1_german1_ci -2 Muffler -3 latin1_german2_ci -4 Müller - ---- --slave-- -select * from mysqltest2.t1 order by a; -a b -1 latin1_german1_ci -2 Muffler -3 latin1_german2_ci -4 Müller -select "--- --INSERT--" as ""; - ---- --INSERT-- -set @a= _cp850 'Müller' collate cp850_general_ci; -truncate table t1; -insert into t1 (b) values(collation(@a)); - ---- --master-- -select * from t1 order by a; -a b -1 cp850_general_ci - ---- --slave-- -select * from mysqltest2.t1 order by a; -a b -1 cp850_general_ci -drop database mysqltest2; -drop database mysqltest3; -show binlog events from ; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # drop database if exists mysqltest2 -master-bin.000001 # Query # # drop database if exists mysqltest3 -master-bin.000001 # Query # # create database mysqltest2 character set latin2 -master-bin.000001 # Query # # create database mysqltest3 -master-bin.000001 # Query # # drop database mysqltest3 -master-bin.000001 # Query # # create database mysqltest3 -master-bin.000001 # Query # # use `mysqltest2`; create table t1 (a int auto_increment primary key, b varchar(100))engine=innodb -master-bin.000001 # Query # # use `mysqltest2`; BEGIN -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Query # # use `mysqltest2`; BEGIN -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Query # # use `mysqltest2`; BEGIN -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Query # # use `mysqltest2`; BEGIN -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Query # # use `mysqltest2`; BEGIN -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Query # # use `mysqltest2`; BEGIN -master-bin.000001 # Query # # use `mysqltest2`; truncate table t1 -master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Query # # use `mysqltest2`; BEGIN -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Query # # use `mysqltest2`; BEGIN -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Query # # use `mysqltest2`; BEGIN -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Query # # use `mysqltest2`; BEGIN -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Query # # use `mysqltest2`; BEGIN -master-bin.000001 # Query # # use `mysqltest2`; truncate table t1 -master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Query # # use `mysqltest2`; BEGIN -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Query # # drop database mysqltest2 -master-bin.000001 # Query # # drop database mysqltest3 -select "--- --global--" as ""; - ---- --global-- -set global character_set_server=latin2; -set global character_set_server=latin1; -set global character_set_server=latin2; -set global character_set_server=latin1; -select "--- --oneshot--" as ""; - ---- --oneshot-- -set one_shot @@character_set_server=latin5; -set @@max_join_size=1000; -select @@character_set_server; -@@character_set_server -latin5 -select @@character_set_server; -@@character_set_server -latin1 -set @@character_set_server=latin5; -select @@character_set_server; -@@character_set_server -latin5 -select @@character_set_server; -@@character_set_server -latin5 -set one_shot max_join_size=10; -ERROR HY000: The 'SET ONE_SHOT' syntax is reserved for purposes internal to the MySQL server -set character_set_client=9999999; -ERROR 42000: Unknown character set: '9999999' -set collation_server=9999998; -ERROR HY000: Unknown collation: '9999998' -select "--- --3943--" as ""; - ---- --3943-- -use test; -CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255))ENGINE=innodb;; -SET CHARACTER_SET_CLIENT=koi8r, -CHARACTER_SET_CONNECTION=cp1251, -CHARACTER_SET_RESULTS=koi8r; -INSERT INTO t1 (c1, c2) VALUES ('îĠ, ÚÁ ÒÙÂÁÌËĠ','îĠ, ÚÁ ÒÙÂÁÌËĠ'); -SET SQL_BIG_SELECTS=1; -select hex(c1), hex(c2) from t1; -hex(c1) hex(c2) -CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 -SET SQL_BIG_SELECTS=1; -select hex(c1), hex(c2) from t1; -hex(c1) hex(c2) -CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 -drop table t1; -select "--- --6676--" as ""; - ---- --6676-- -create table `t1` ( -`pk` varchar(10) not null default '', -primary key (`pk`) -) engine=innodb default charset=latin1; -set @p=_latin1 'test'; -update t1 set pk='test' where pk=@p; -drop table t1; diff --git a/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result b/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result index 6859a406b16..e81d4f7454e 100644 --- a/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result +++ b/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result @@ -26,7 +26,7 @@ ADD x BIT(3) DEFAULT b'011', ADD y BIT(5) DEFAULT b'10101', ADD z BIT(2) DEFAULT b'10'; ALTER TABLE t1_char ADD x CHAR(20) DEFAULT 'Just a test'; -ALTER TABLE t1_nodef ADD x INT NOT NULL; +ALTER TABLE t1_nodef ADD x INT NOT NULL, ADD y INT NOT NULL, ADD z INT NOT NULL; ALTER TABLE t2 DROP b; ALTER TABLE t4 MODIFY a FLOAT; ALTER TABLE t5 MODIFY b FLOAT; @@ -393,8 +393,8 @@ INSERT INTO t1_nodef VALUES (1,2); INSERT INTO t1_nodef VALUES (2,4); SET SQL_LOG_BIN=1; **** On Slave **** -INSERT INTO t1_nodef VALUES (1,2,3); -INSERT INTO t1_nodef VALUES (2,4,6); +INSERT INTO t1_nodef VALUES (1,2,3,4,5); +INSERT INTO t1_nodef VALUES (2,4,6,8,10); **** On Master **** UPDATE t1_nodef SET b=2*b WHERE a=1; SELECT * FROM t1_nodef ORDER BY a; @@ -403,9 +403,9 @@ a b 2 4 **** On Slave **** SELECT * FROM t1_nodef ORDER BY a; -a b x -1 4 3 -2 4 6 +a b x y z +1 4 3 4 5 +2 4 6 8 10 **** On Master **** DELETE FROM t1_nodef WHERE a=2; SELECT * FROM t1_nodef ORDER BY a; @@ -413,8 +413,8 @@ a b 1 4 **** On Slave **** SELECT * FROM t1_nodef ORDER BY a; -a b x -1 4 3 +a b x y z +1 4 3 4 5 **** Cleanup **** DROP TABLE IF EXISTS t1_int,t1_bit,t1_char,t1_nodef; DROP TABLE IF EXISTS t2,t3,t4,t5,t6,t7,t8,t9; diff --git a/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result b/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result index 17b2a2f7b52..a6834be5a86 100644 --- a/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result +++ b/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result @@ -26,7 +26,7 @@ ADD x BIT(3) DEFAULT b'011', ADD y BIT(5) DEFAULT b'10101', ADD z BIT(2) DEFAULT b'10'; ALTER TABLE t1_char ADD x CHAR(20) DEFAULT 'Just a test'; -ALTER TABLE t1_nodef ADD x INT NOT NULL; +ALTER TABLE t1_nodef ADD x INT NOT NULL, ADD y INT NOT NULL, ADD z INT NOT NULL; ALTER TABLE t2 DROP b; ALTER TABLE t4 MODIFY a FLOAT; ALTER TABLE t5 MODIFY b FLOAT; @@ -393,8 +393,8 @@ INSERT INTO t1_nodef VALUES (1,2); INSERT INTO t1_nodef VALUES (2,4); SET SQL_LOG_BIN=1; **** On Slave **** -INSERT INTO t1_nodef VALUES (1,2,3); -INSERT INTO t1_nodef VALUES (2,4,6); +INSERT INTO t1_nodef VALUES (1,2,3,4,5); +INSERT INTO t1_nodef VALUES (2,4,6,8,10); **** On Master **** UPDATE t1_nodef SET b=2*b WHERE a=1; SELECT * FROM t1_nodef ORDER BY a; @@ -403,9 +403,9 @@ a b 2 4 **** On Slave **** SELECT * FROM t1_nodef ORDER BY a; -a b x -1 4 3 -2 4 6 +a b x y z +1 4 3 4 5 +2 4 6 8 10 **** On Master **** DELETE FROM t1_nodef WHERE a=2; SELECT * FROM t1_nodef ORDER BY a; @@ -413,8 +413,8 @@ a b 1 4 **** On Slave **** SELECT * FROM t1_nodef ORDER BY a; -a b x -1 4 3 +a b x y z +1 4 3 4 5 **** Cleanup **** DROP TABLE IF EXISTS t1_int,t1_bit,t1_char,t1_nodef; DROP TABLE IF EXISTS t2,t3,t4,t5,t6,t7,t8,t9; diff --git a/mysql-test/suite/rpl/r/rpl_stm_charset.result b/mysql-test/suite/rpl/r/rpl_stm_charset.result deleted file mode 100644 index 1f21f226be8..00000000000 --- a/mysql-test/suite/rpl/r/rpl_stm_charset.result +++ /dev/null @@ -1,293 +0,0 @@ -stop slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -reset master; -reset slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -start slave; -set timestamp=1000000000; -drop database if exists mysqltest2; -drop database if exists mysqltest3; -create database mysqltest2 character set latin2; -set @@character_set_server=latin5; -create database mysqltest3; - ---- --master-- -show create database mysqltest2; -Database Create Database -mysqltest2 CREATE DATABASE `mysqltest2` /*!40100 DEFAULT CHARACTER SET latin2 */ -show create database mysqltest3; -Database Create Database -mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET latin5 */ - ---- --slave-- -show create database mysqltest2; -Database Create Database -mysqltest2 CREATE DATABASE `mysqltest2` /*!40100 DEFAULT CHARACTER SET latin2 */ -show create database mysqltest3; -Database Create Database -mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET latin5 */ -set @@collation_server=armscii8_bin; -drop database mysqltest3; -create database mysqltest3; - ---- --master-- -show create database mysqltest3; -Database Create Database -mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET armscii8 COLLATE armscii8_bin */ - ---- --slave-- -show create database mysqltest3; -Database Create Database -mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET armscii8 COLLATE armscii8_bin */ -use mysqltest2; -create table t1 (a int auto_increment primary key, b varchar(100)); -set character_set_client=cp850, collation_connection=latin2_croatian_ci; -insert into t1 (b) values(@@character_set_server); -insert into t1 (b) values(@@collation_server); -insert into t1 (b) values(@@character_set_client); -insert into t1 (b) values(@@character_set_connection); -insert into t1 (b) values(@@collation_connection); - ---- --master-- -select * from t1 order by a; -a b -1 armscii8 -2 armscii8_bin -3 cp850 -4 latin2 -5 latin2_croatian_ci - ---- --slave-- -select * from mysqltest2.t1 order by a; -a b -1 armscii8 -2 armscii8_bin -3 cp850 -4 latin2 -5 latin2_croatian_ci -set character_set_client=latin1, collation_connection=latin1_german1_ci; -truncate table t1; -insert into t1 (b) values(@@collation_connection); -insert into t1 (b) values(LEAST("Müller","Muffler")); -set collation_connection=latin1_german2_ci; -insert into t1 (b) values(@@collation_connection); -insert into t1 (b) values(LEAST("Müller","Muffler")); - ---- --master-- -select * from t1 order by a; -a b -1 latin1_german1_ci -2 Muffler -3 latin1_german2_ci -4 Müller - ---- --slave-- -select * from mysqltest2.t1 order by a; -a b -1 latin1_german1_ci -2 Muffler -3 latin1_german2_ci -4 Müller -set @a= _cp850 'Müller' collate cp850_general_ci; -truncate table t1; -insert into t1 (b) values(collation(@a)); - ---- --master-- -select * from t1 order by a; -a b -1 cp850_general_ci - ---- --slave-- -select * from mysqltest2.t1 order by a; -a b -1 cp850_general_ci -drop database mysqltest2; -drop database mysqltest3; -show binlog events from ; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # drop database if exists mysqltest2 -master-bin.000001 # Query # # drop database if exists mysqltest3 -master-bin.000001 # Query # # create database mysqltest2 character set latin2 -master-bin.000001 # Query # # create database mysqltest3 -master-bin.000001 # Query # # drop database mysqltest3 -master-bin.000001 # Query # # create database mysqltest3 -master-bin.000001 # Query # # use `mysqltest2`; create table t1 (a int auto_increment primary key, b varchar(100)) -master-bin.000001 # Intvar # # INSERT_ID=1 -master-bin.000001 # Query # # use `mysqltest2`; insert into t1 (b) values(@@character_set_server) -master-bin.000001 # Intvar # # INSERT_ID=2 -master-bin.000001 # Query # # use `mysqltest2`; insert into t1 (b) values(@@collation_server) -master-bin.000001 # Intvar # # INSERT_ID=3 -master-bin.000001 # Query # # use `mysqltest2`; insert into t1 (b) values(@@character_set_client) -master-bin.000001 # Intvar # # INSERT_ID=4 -master-bin.000001 # Query # # use `mysqltest2`; insert into t1 (b) values(@@character_set_connection) -master-bin.000001 # Intvar # # INSERT_ID=5 -master-bin.000001 # Query # # use `mysqltest2`; insert into t1 (b) values(@@collation_connection) -master-bin.000001 # Query # # use `mysqltest2`; truncate table t1 -master-bin.000001 # Intvar # # INSERT_ID=1 -master-bin.000001 # Query # # use `mysqltest2`; insert into t1 (b) values(@@collation_connection) -master-bin.000001 # Intvar # # INSERT_ID=2 -master-bin.000001 # Query # # use `mysqltest2`; insert into t1 (b) values(LEAST("Müller","Muffler")) -master-bin.000001 # Intvar # # INSERT_ID=3 -master-bin.000001 # Query # # use `mysqltest2`; insert into t1 (b) values(@@collation_connection) -master-bin.000001 # Intvar # # INSERT_ID=4 -master-bin.000001 # Query # # use `mysqltest2`; insert into t1 (b) values(LEAST("Müller","Muffler")) -master-bin.000001 # Query # # use `mysqltest2`; truncate table t1 -master-bin.000001 # Intvar # # INSERT_ID=1 -master-bin.000001 # User var # # @`a`=_cp850 0x4DFC6C6C6572 COLLATE cp850_general_ci -master-bin.000001 # Query # # use `mysqltest2`; insert into t1 (b) values(collation(@a)) -master-bin.000001 # Query # # drop database mysqltest2 -master-bin.000001 # Query # # drop database mysqltest3 -set global character_set_server=latin2; -set global character_set_server=latin1; -set global character_set_server=latin2; -set global character_set_server=latin1; -set one_shot @@character_set_server=latin5; -set @@max_join_size=1000; -select @@character_set_server; -@@character_set_server -latin5 -select @@character_set_server; -@@character_set_server -latin1 -set @@character_set_server=latin5; -select @@character_set_server; -@@character_set_server -latin5 -select @@character_set_server; -@@character_set_server -latin5 -set one_shot max_join_size=10; -ERROR HY000: The 'SET ONE_SHOT' syntax is reserved for purposes internal to the MySQL server -set character_set_client=9999999; -ERROR 42000: Unknown character set: '9999999' -set collation_server=9999998; -ERROR HY000: Unknown collation: '9999998' -use test; -CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255)); -SET CHARACTER_SET_CLIENT=koi8r, -CHARACTER_SET_CONNECTION=cp1251, -CHARACTER_SET_RESULTS=koi8r; -INSERT INTO t1 (c1, c2) VALUES ('îĠ, ÚÁ ÒÙÂÁÌËĠ','îĠ, ÚÁ ÒÙÂÁÌËĠ'); -select hex(c1), hex(c2) from t1; -hex(c1) hex(c2) -CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 -select hex(c1), hex(c2) from t1; -hex(c1) hex(c2) -CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 -flush logs; -/*!40019 SET @@session.max_insert_delayed_threads=0*/; -/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; -DELIMITER /*!*/; -ROLLBACK/*!*/; -SET TIMESTAMP=1000000000/*!*/; -SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1/*!*/; -SET @@session.sql_mode=0/*!*/; -/*!\C latin1 *//*!*/; -SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/; -drop database if exists mysqltest2 -/*!*/; -SET TIMESTAMP=1000000000/*!*/; -drop database if exists mysqltest3 -/*!*/; -SET TIMESTAMP=1000000000/*!*/; -create database mysqltest2 character set latin2 -/*!*/; -SET TIMESTAMP=1000000000/*!*/; -/*!\C latin1 *//*!*/; -SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=30/*!*/; -create database mysqltest3 -/*!*/; -SET TIMESTAMP=1000000000/*!*/; -/*!\C latin1 *//*!*/; -SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=64/*!*/; -drop database mysqltest3 -/*!*/; -SET TIMESTAMP=1000000000/*!*/; -create database mysqltest3 -/*!*/; -use mysqltest2/*!*/; -SET TIMESTAMP=1000000000/*!*/; -create table t1 (a int auto_increment primary key, b varchar(100)) -/*!*/; -SET INSERT_ID=1/*!*/; -SET TIMESTAMP=1000000000/*!*/; -/*!\C cp850 *//*!*/; -SET @@session.character_set_client=4,@@session.collation_connection=27,@@session.collation_server=64/*!*/; -insert into t1 (b) values(@@character_set_server) -/*!*/; -SET INSERT_ID=2/*!*/; -SET TIMESTAMP=1000000000/*!*/; -insert into t1 (b) values(@@collation_server) -/*!*/; -SET INSERT_ID=3/*!*/; -SET TIMESTAMP=1000000000/*!*/; -insert into t1 (b) values(@@character_set_client) -/*!*/; -SET INSERT_ID=4/*!*/; -SET TIMESTAMP=1000000000/*!*/; -insert into t1 (b) values(@@character_set_connection) -/*!*/; -SET INSERT_ID=5/*!*/; -SET TIMESTAMP=1000000000/*!*/; -insert into t1 (b) values(@@collation_connection) -/*!*/; -SET TIMESTAMP=1000000000/*!*/; -/*!\C latin1 *//*!*/; -SET @@session.character_set_client=8,@@session.collation_connection=5,@@session.collation_server=64/*!*/; -truncate table t1 -/*!*/; -SET INSERT_ID=1/*!*/; -SET TIMESTAMP=1000000000/*!*/; -insert into t1 (b) values(@@collation_connection) -/*!*/; -SET INSERT_ID=2/*!*/; -SET TIMESTAMP=1000000000/*!*/; -insert into t1 (b) values(LEAST("Müller","Muffler")) -/*!*/; -SET INSERT_ID=3/*!*/; -SET TIMESTAMP=1000000000/*!*/; -/*!\C latin1 *//*!*/; -SET @@session.character_set_client=8,@@session.collation_connection=31,@@session.collation_server=64/*!*/; -insert into t1 (b) values(@@collation_connection) -/*!*/; -SET INSERT_ID=4/*!*/; -SET TIMESTAMP=1000000000/*!*/; -insert into t1 (b) values(LEAST("Müller","Muffler")) -/*!*/; -SET TIMESTAMP=1000000000/*!*/; -truncate table t1 -/*!*/; -SET INSERT_ID=1/*!*/; -SET @`a`:=_cp850 0x4DFC6C6C6572 COLLATE `cp850_general_ci`/*!*/; -SET TIMESTAMP=1000000000/*!*/; -insert into t1 (b) values(collation(@a)) -/*!*/; -SET TIMESTAMP=1000000000/*!*/; -drop database mysqltest2 -/*!*/; -SET TIMESTAMP=1000000000/*!*/; -drop database mysqltest3 -/*!*/; -use test/*!*/; -SET TIMESTAMP=1000000000/*!*/; -/*!\C latin1 *//*!*/; -SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=30/*!*/; -CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255)) -/*!*/; -SET TIMESTAMP=1000000000/*!*/; -/*!\C koi8r *//*!*/; -SET @@session.character_set_client=7,@@session.collation_connection=51,@@session.collation_server=30/*!*/; -INSERT INTO t1 (c1, c2) VALUES ('îĠ, ÚÁ ÒÙÂÁÌËĠ','îĠ, ÚÁ ÒÙÂÁÌËĠ') -/*!*/; -DELIMITER ; -# End of log file -ROLLBACK /* added by mysqlbinlog */; -/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; -drop table t1; -create table `t1` ( -`pk` varchar(10) not null default '', -primary key (`pk`) -) engine=myisam default charset=latin1; -set @p=_latin1 'test'; -update t1 set pk='test' where pk=@p; -drop table t1; diff --git a/mysql-test/suite/rpl/t/rpl_charset.test b/mysql-test/suite/rpl/t/rpl_charset.test new file mode 100644 index 00000000000..ed0d835f22d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_charset.test @@ -0,0 +1,3 @@ +let $engine_type=myisam; +source extra/rpl_tests/rpl_charset.test; + diff --git a/mysql-test/suite/rpl/t/rpl_events.test b/mysql-test/suite/rpl/t/rpl_events.test index 62ffead7dcb..2a9cf86fe55 100644 --- a/mysql-test/suite/rpl/t/rpl_events.test +++ b/mysql-test/suite/rpl/t/rpl_events.test @@ -28,10 +28,12 @@ set binlog_format=statement; connection master; +CREATE TABLE t28953 (a INT); + DELIMITER |; CREATE EVENT event1 ON SCHEDULE EVERY 1 YEAR DO BEGIN - select * from t1; + select * from t28953; END;| DELIMITER ;| @@ -45,3 +47,9 @@ DROP EVENT event2; sync_slave_with_master; +# Doing cleanup of the table referred to in the event to guarantee +# that there is no bad timing cauing it to try to access the table. + +connection master; +DROP TABLE t28953; +sync_slave_with_master; diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_map.test b/mysql-test/suite/rpl/t/rpl_loaddata_map.test index 3d6f09844b6..6a8378c8fdc 100644 --- a/mysql-test/suite/rpl/t/rpl_loaddata_map.test +++ b/mysql-test/suite/rpl/t/rpl_loaddata_map.test @@ -7,6 +7,7 @@ # BUG#33413 show binlog events fails if binlog has event size of close # to max_allowed_packet +source include/have_binlog_format_mixed_or_statement.inc; source include/master-slave.inc; source include/have_innodb.inc; source include/have_binlog_format_mixed_or_statement.inc; @@ -35,9 +36,9 @@ select count(*) from t2 /* 5 000 */; # the binglog will show fragmented Append_block events --let $binlog_start=106 ---replace_column 5 # ---replace_regex /\/\* xid=.* \*\//\/* XID *\// /file_id=[0-9]+/file_id=#/ ---replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--replace_column 2 # 4 # 5 # +--replace_regex /\/\* xid=.* \*\//\/* XID *\// /file_id=[0-9]+/file_id=#/ /block_len=[0-9]+/block_len=#/ +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR $binlog_start --eval show binlog events in 'master-bin.000002' from $binlog_start diff --git a/mysql-test/suite/rpl/t/rpl_row_charset.test b/mysql-test/suite/rpl/t/rpl_row_charset.test deleted file mode 100644 index c83ccc586ba..00000000000 --- a/mysql-test/suite/rpl/t/rpl_row_charset.test +++ /dev/null @@ -1,9 +0,0 @@ -######################################################## -# By JBM 2005-02-15 Wrapped to allow reuse of test code# -# Added to skip if ndb is default # -######################################################## --- source include/not_ndb_default.inc --- source include/have_binlog_format_row.inc --- source include/master-slave.inc -let $engine_type=myisam; --- source extra/rpl_tests/rpl_row_charset.test diff --git a/mysql-test/suite/rpl/t/rpl_row_charset_innodb-master.opt b/mysql-test/suite/rpl/t/rpl_row_charset_innodb-master.opt deleted file mode 100644 index 627becdbfb5..00000000000 --- a/mysql-test/suite/rpl/t/rpl_row_charset_innodb-master.opt +++ /dev/null @@ -1 +0,0 @@ ---innodb diff --git a/mysql-test/suite/rpl/t/rpl_row_charset_innodb-slave.opt b/mysql-test/suite/rpl/t/rpl_row_charset_innodb-slave.opt deleted file mode 100644 index 627becdbfb5..00000000000 --- a/mysql-test/suite/rpl/t/rpl_row_charset_innodb-slave.opt +++ /dev/null @@ -1 +0,0 @@ ---innodb diff --git a/mysql-test/suite/rpl/t/rpl_row_charset_innodb.test b/mysql-test/suite/rpl/t/rpl_row_charset_innodb.test deleted file mode 100644 index 2d48af65581..00000000000 --- a/mysql-test/suite/rpl/t/rpl_row_charset_innodb.test +++ /dev/null @@ -1,10 +0,0 @@ -######################################################## -# By JBM 2005-02-15 Wrapped to allow reuse of test code# -# Added to skip if ndb is default # -######################################################## --- source include/not_ndb_default.inc --- source include/have_binlog_format_row.inc --- source include/have_innodb.inc --- source include/master-slave.inc -let $engine_type=innodb; --- source extra/rpl_tests/rpl_row_charset.test diff --git a/mysql-test/suite/rpl/t/rpl_stm_charset.test b/mysql-test/suite/rpl/t/rpl_stm_charset.test deleted file mode 100644 index b103a47d78c..00000000000 --- a/mysql-test/suite/rpl/t/rpl_stm_charset.test +++ /dev/null @@ -1,2 +0,0 @@ -let $engine_type=myisam; --- source extra/rpl_tests/rpl_stm_charset.test diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_2innodb.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_2innodb.result index f8ec4624062..c5e9ff2721b 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_2innodb.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_2innodb.result @@ -4,7 +4,14 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; -SET storage_engine=ndb; +set @@global.slave_exec_mode= 'IDEMPOTENT'; +CREATE TABLE mysql.ndb_apply_status +( server_id INT UNSIGNED NOT NULL, +epoch BIGINT UNSIGNED NOT NULL, +log_name VARCHAR(255) BINARY NOT NULL, +start_pos BIGINT UNSIGNED NOT NULL, +end_pos BIGINT UNSIGNED NOT NULL, +PRIMARY KEY USING HASH (server_id)) ENGINE=INNODB; --- Doing pre test cleanup --- DROP TABLE IF EXISTS t1; --- Start test 1 Basic testing --- @@ -27,7 +34,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 --- Show table on slave --- SHOW CREATE TABLE t1; Table Create Table @@ -100,7 +107,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`,`total`) -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 --- Make sure that our tables on slave are still same engine --- --- and that the alter statements replicated correctly --- SHOW CREATE TABLE t1; @@ -186,7 +193,7 @@ t1 CREATE TABLE `t1` ( `total` bigint(20) unsigned DEFAULT NULL, `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = ndbcluster, PARTITION p1 VALUES LESS THAN (1946) ENGINE = ndbcluster, PARTITION p2 VALUES LESS THAN (1966) ENGINE = ndbcluster, PARTITION p3 VALUES LESS THAN (1986) ENGINE = ndbcluster, PARTITION p4 VALUES LESS THAN (2005) ENGINE = ndbcluster, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = ndbcluster) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = ndbcluster, PARTITION p1 VALUES LESS THAN (1946) ENGINE = ndbcluster, PARTITION p2 VALUES LESS THAN (1966) ENGINE = ndbcluster, PARTITION p3 VALUES LESS THAN (1986) ENGINE = ndbcluster, PARTITION p4 VALUES LESS THAN (2005) ENGINE = ndbcluster, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = ndbcluster) */ --- Show table on slave -- SHOW CREATE TABLE t1; Table Create Table @@ -200,7 +207,7 @@ t1 CREATE TABLE `t1` ( `total` bigint(20) unsigned DEFAULT NULL, `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = InnoDB, PARTITION p1 VALUES LESS THAN (1946) ENGINE = InnoDB, PARTITION p2 VALUES LESS THAN (1966) ENGINE = InnoDB, PARTITION p3 VALUES LESS THAN (1986) ENGINE = InnoDB, PARTITION p4 VALUES LESS THAN (2005) ENGINE = InnoDB, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = InnoDB, PARTITION p1 VALUES LESS THAN (1946) ENGINE = InnoDB, PARTITION p2 VALUES LESS THAN (1966) ENGINE = InnoDB, PARTITION p3 VALUES LESS THAN (1986) ENGINE = InnoDB, PARTITION p4 VALUES LESS THAN (2005) ENGINE = InnoDB, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -258,7 +265,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date NOT NULL DEFAULT '0000-00-00', PRIMARY KEY (`t`,`id`) -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = ndbcluster, PARTITION p1 VALUES LESS THAN (1946) ENGINE = ndbcluster, PARTITION p2 VALUES LESS THAN (1966) ENGINE = ndbcluster, PARTITION p3 VALUES LESS THAN (1986) ENGINE = ndbcluster, PARTITION p4 VALUES LESS THAN (2005) ENGINE = ndbcluster, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = ndbcluster) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = ndbcluster, PARTITION p1 VALUES LESS THAN (1946) ENGINE = ndbcluster, PARTITION p2 VALUES LESS THAN (1966) ENGINE = ndbcluster, PARTITION p3 VALUES LESS THAN (1986) ENGINE = ndbcluster, PARTITION p4 VALUES LESS THAN (2005) ENGINE = ndbcluster, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = ndbcluster) */ --- Make sure that our tables on slave are still same engine --- --- and that the alter statements replicated correctly --- SHOW CREATE TABLE t1; @@ -274,7 +281,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date NOT NULL DEFAULT '0000-00-00', PRIMARY KEY (`t`,`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = InnoDB, PARTITION p1 VALUES LESS THAN (1946) ENGINE = InnoDB, PARTITION p2 VALUES LESS THAN (1966) ENGINE = InnoDB, PARTITION p3 VALUES LESS THAN (1986) ENGINE = InnoDB, PARTITION p4 VALUES LESS THAN (2005) ENGINE = InnoDB, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = InnoDB, PARTITION p1 VALUES LESS THAN (1946) ENGINE = InnoDB, PARTITION p2 VALUES LESS THAN (1966) ENGINE = InnoDB, PARTITION p3 VALUES LESS THAN (1986) ENGINE = InnoDB, PARTITION p4 VALUES LESS THAN (2005) ENGINE = InnoDB, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -299,11 +306,11 @@ UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412; --- Check the update on master --- SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412; id hex(b1) vc bc d f total y t -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 +412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 --- Check Update on slave --- SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412; id hex(b1) vc bc d f total y t -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 +412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 --- Remove a record from t1 on master --- DELETE FROM t1 WHERE id = 42; --- Show current count on master for t1 --- @@ -342,7 +349,7 @@ t1 CREATE TABLE `t1` ( `total` bigint(20) unsigned DEFAULT NULL, `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = ndbcluster, PARTITION p1 VALUES IN (42,142) ENGINE = ndbcluster, PARTITION p2 VALUES IN (412) ENGINE = ndbcluster) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = ndbcluster, PARTITION p1 VALUES IN (42,142) ENGINE = ndbcluster, PARTITION p2 VALUES IN (412) ENGINE = ndbcluster) */ --- Show table on slave --- SHOW CREATE TABLE t1; Table Create Table @@ -356,7 +363,7 @@ t1 CREATE TABLE `t1` ( `total` bigint(20) unsigned DEFAULT NULL, `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = InnoDB, PARTITION p1 VALUES IN (42,142) ENGINE = InnoDB, PARTITION p2 VALUES IN (412) ENGINE = InnoDB) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = InnoDB, PARTITION p1 VALUES IN (42,142) ENGINE = InnoDB, PARTITION p2 VALUES IN (412) ENGINE = InnoDB) */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -414,7 +421,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = ndbcluster, PARTITION p1 VALUES IN (42,142) ENGINE = ndbcluster, PARTITION p2 VALUES IN (412) ENGINE = ndbcluster) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = ndbcluster, PARTITION p1 VALUES IN (42,142) ENGINE = ndbcluster, PARTITION p2 VALUES IN (412) ENGINE = ndbcluster) */ --- Make sure that our tables on slave are still same engine --- --- and that the alter statements replicated correctly --- SHOW CREATE TABLE t1; @@ -430,7 +437,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = InnoDB, PARTITION p1 VALUES IN (42,142) ENGINE = InnoDB, PARTITION p2 VALUES IN (412) ENGINE = InnoDB) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = InnoDB, PARTITION p1 VALUES IN (42,142) ENGINE = InnoDB, PARTITION p2 VALUES IN (412) ENGINE = InnoDB) */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -495,7 +502,7 @@ t1 CREATE TABLE `t1` ( `total` bigint(20) unsigned DEFAULT NULL, `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4 +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4 */ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -508,7 +515,7 @@ t1 CREATE TABLE `t1` ( `total` bigint(20) unsigned DEFAULT NULL, `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4 +) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4 */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -533,11 +540,11 @@ UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412; --- Check the update on master --- SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412; id hex(b1) vc bc d f total y t -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 +412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 --- Check Update on slave --- SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412; id hex(b1) vc bc d f total y t -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 +412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 --- Remove a record from t1 on master --- DELETE FROM t1 WHERE id = 42; --- Show current count on master for t1 --- @@ -566,7 +573,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date NOT NULL DEFAULT '0000-00-00', PRIMARY KEY (`t`,`id`) -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4 +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4 */ --- Make sure that our tables on slave are still same engine --- --- and that the alter statements replicated correctly --- SHOW CREATE TABLE t1; @@ -582,7 +589,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date NOT NULL DEFAULT '0000-00-00', PRIMARY KEY (`t`,`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4 +) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4 */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -607,11 +614,11 @@ UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412; --- Check the update on master --- SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412; id hex(b1) vc bc d f total y t -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 +412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 --- Check Update on slave --- SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412; id hex(b1) vc bc d f total y t -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 +412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 --- Remove a record from t1 on master --- DELETE FROM t1 WHERE id = 42; --- Show current count on master for t1 --- @@ -648,7 +655,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4 +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY () PARTITIONS 4 */ --- Show that tables on slave --- SHOW CREATE TABLE t1; Table Create Table @@ -663,7 +670,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4 +) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY () PARTITIONS 4 */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -720,7 +727,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`,`total`) -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4 +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY () PARTITIONS 4 */ --- Make sure that our tables on slave are still right type --- --- and that the alter statements replicated correctly --- SHOW CREATE TABLE t1; @@ -736,7 +743,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`,`total`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4 +) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY () PARTITIONS 4 */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -793,7 +800,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`,`total`) -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4 +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY () PARTITIONS 4 */ --- Make sure that our tables on slave are still same engine --- --- and that the alter statements replicated correctly --- SHOW CREATE TABLE t1; @@ -809,7 +816,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`,`total`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4 +) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY () PARTITIONS 4 */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -853,3 +860,4 @@ DELETE FROM t1; --- End test 5 key partition testing --- --- Do Cleanup --- DROP TABLE IF EXISTS t1; +drop table mysql.ndb_apply_status; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_2myisam.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_2myisam.result index 8611d83f3f3..824df733fa9 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_2myisam.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_2myisam.result @@ -4,7 +4,14 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; -SET storage_engine=ndb; +set @@global.slave_exec_mode= 'IDEMPOTENT'; +CREATE TABLE mysql.ndb_apply_status +( server_id INT UNSIGNED NOT NULL, +epoch BIGINT UNSIGNED NOT NULL, +log_name VARCHAR(255) BINARY NOT NULL, +start_pos BIGINT UNSIGNED NOT NULL, +end_pos BIGINT UNSIGNED NOT NULL, +PRIMARY KEY USING HASH (server_id)) ENGINE=MYISAM; --- Doing pre test cleanup --- DROP TABLE IF EXISTS t1; --- Start test 1 Basic testing --- @@ -186,7 +193,7 @@ t1 CREATE TABLE `t1` ( `total` bigint(20) unsigned DEFAULT NULL, `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = ndbcluster, PARTITION p1 VALUES LESS THAN (1946) ENGINE = ndbcluster, PARTITION p2 VALUES LESS THAN (1966) ENGINE = ndbcluster, PARTITION p3 VALUES LESS THAN (1986) ENGINE = ndbcluster, PARTITION p4 VALUES LESS THAN (2005) ENGINE = ndbcluster, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = ndbcluster) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = ndbcluster, PARTITION p1 VALUES LESS THAN (1946) ENGINE = ndbcluster, PARTITION p2 VALUES LESS THAN (1966) ENGINE = ndbcluster, PARTITION p3 VALUES LESS THAN (1986) ENGINE = ndbcluster, PARTITION p4 VALUES LESS THAN (2005) ENGINE = ndbcluster, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = ndbcluster) */ --- Show table on slave -- SHOW CREATE TABLE t1; Table Create Table @@ -200,7 +207,7 @@ t1 CREATE TABLE `t1` ( `total` bigint(20) unsigned DEFAULT NULL, `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = MyISAM, PARTITION p1 VALUES LESS THAN (1946) ENGINE = MyISAM, PARTITION p2 VALUES LESS THAN (1966) ENGINE = MyISAM, PARTITION p3 VALUES LESS THAN (1986) ENGINE = MyISAM, PARTITION p4 VALUES LESS THAN (2005) ENGINE = MyISAM, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = MyISAM, PARTITION p1 VALUES LESS THAN (1946) ENGINE = MyISAM, PARTITION p2 VALUES LESS THAN (1966) ENGINE = MyISAM, PARTITION p3 VALUES LESS THAN (1986) ENGINE = MyISAM, PARTITION p4 VALUES LESS THAN (2005) ENGINE = MyISAM, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -258,7 +265,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date NOT NULL DEFAULT '0000-00-00', PRIMARY KEY (`t`,`id`) -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = ndbcluster, PARTITION p1 VALUES LESS THAN (1946) ENGINE = ndbcluster, PARTITION p2 VALUES LESS THAN (1966) ENGINE = ndbcluster, PARTITION p3 VALUES LESS THAN (1986) ENGINE = ndbcluster, PARTITION p4 VALUES LESS THAN (2005) ENGINE = ndbcluster, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = ndbcluster) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = ndbcluster, PARTITION p1 VALUES LESS THAN (1946) ENGINE = ndbcluster, PARTITION p2 VALUES LESS THAN (1966) ENGINE = ndbcluster, PARTITION p3 VALUES LESS THAN (1986) ENGINE = ndbcluster, PARTITION p4 VALUES LESS THAN (2005) ENGINE = ndbcluster, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = ndbcluster) */ --- Make sure that our tables on slave are still same engine --- --- and that the alter statements replicated correctly --- SHOW CREATE TABLE t1; @@ -274,7 +281,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date NOT NULL DEFAULT '0000-00-00', PRIMARY KEY (`t`,`id`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = MyISAM, PARTITION p1 VALUES LESS THAN (1946) ENGINE = MyISAM, PARTITION p2 VALUES LESS THAN (1966) ENGINE = MyISAM, PARTITION p3 VALUES LESS THAN (1986) ENGINE = MyISAM, PARTITION p4 VALUES LESS THAN (2005) ENGINE = MyISAM, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (YEAR(t)) (PARTITION p0 VALUES LESS THAN (1901) ENGINE = MyISAM, PARTITION p1 VALUES LESS THAN (1946) ENGINE = MyISAM, PARTITION p2 VALUES LESS THAN (1966) ENGINE = MyISAM, PARTITION p3 VALUES LESS THAN (1986) ENGINE = MyISAM, PARTITION p4 VALUES LESS THAN (2005) ENGINE = MyISAM, PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -299,11 +306,11 @@ UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412; --- Check the update on master --- SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412; id hex(b1) vc bc d f total y t -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 +412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 --- Check Update on slave --- SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412; id hex(b1) vc bc d f total y t -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 +412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 --- Remove a record from t1 on master --- DELETE FROM t1 WHERE id = 42; --- Show current count on master for t1 --- @@ -342,7 +349,7 @@ t1 CREATE TABLE `t1` ( `total` bigint(20) unsigned DEFAULT NULL, `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = ndbcluster, PARTITION p1 VALUES IN (42,142) ENGINE = ndbcluster, PARTITION p2 VALUES IN (412) ENGINE = ndbcluster) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = ndbcluster, PARTITION p1 VALUES IN (42,142) ENGINE = ndbcluster, PARTITION p2 VALUES IN (412) ENGINE = ndbcluster) */ --- Show table on slave --- SHOW CREATE TABLE t1; Table Create Table @@ -356,7 +363,7 @@ t1 CREATE TABLE `t1` ( `total` bigint(20) unsigned DEFAULT NULL, `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = MyISAM, PARTITION p1 VALUES IN (42,142) ENGINE = MyISAM, PARTITION p2 VALUES IN (412) ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = MyISAM, PARTITION p1 VALUES IN (42,142) ENGINE = MyISAM, PARTITION p2 VALUES IN (412) ENGINE = MyISAM) */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -414,7 +421,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = ndbcluster, PARTITION p1 VALUES IN (42,142) ENGINE = ndbcluster, PARTITION p2 VALUES IN (412) ENGINE = ndbcluster) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = ndbcluster, PARTITION p1 VALUES IN (42,142) ENGINE = ndbcluster, PARTITION p2 VALUES IN (412) ENGINE = ndbcluster) */ --- Make sure that our tables on slave are still same engine --- --- and that the alter statements replicated correctly --- SHOW CREATE TABLE t1; @@ -430,7 +437,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = MyISAM, PARTITION p1 VALUES IN (42,142) ENGINE = MyISAM, PARTITION p2 VALUES IN (412) ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY LIST (id) (PARTITION p0 VALUES IN (2,4) ENGINE = MyISAM, PARTITION p1 VALUES IN (42,142) ENGINE = MyISAM, PARTITION p2 VALUES IN (412) ENGINE = MyISAM) */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -495,7 +502,7 @@ t1 CREATE TABLE `t1` ( `total` bigint(20) unsigned DEFAULT NULL, `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4 +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4 */ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -508,7 +515,7 @@ t1 CREATE TABLE `t1` ( `total` bigint(20) unsigned DEFAULT NULL, `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4 +) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4 */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -533,11 +540,11 @@ UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412; --- Check the update on master --- SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412; id hex(b1) vc bc d f total y t -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 +412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 --- Check Update on slave --- SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412; id hex(b1) vc bc d f total y t -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 +412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 --- Remove a record from t1 on master --- DELETE FROM t1 WHERE id = 42; --- Show current count on master for t1 --- @@ -566,7 +573,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date NOT NULL DEFAULT '0000-00-00', PRIMARY KEY (`t`,`id`) -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4 +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4 */ --- Make sure that our tables on slave are still same engine --- --- and that the alter statements replicated correctly --- SHOW CREATE TABLE t1; @@ -582,7 +589,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date NOT NULL DEFAULT '0000-00-00', PRIMARY KEY (`t`,`id`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4 +) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY HASH ( YEAR(t)) PARTITIONS 4 */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -607,11 +614,11 @@ UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412; --- Check the update on master --- SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412; id hex(b1) vc bc d f total y t -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 +412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 --- Check Update on slave --- SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412; id hex(b1) vc bc d f total y t -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 +412 0 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2006-02-22 --- Remove a record from t1 on master --- DELETE FROM t1 WHERE id = 42; --- Show current count on master for t1 --- @@ -648,7 +655,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4 +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY () PARTITIONS 4 */ --- Show that tables on slave --- SHOW CREATE TABLE t1; Table Create Table @@ -663,7 +670,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4 +) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY () PARTITIONS 4 */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -720,7 +727,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`,`total`) -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4 +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY () PARTITIONS 4 */ --- Make sure that our tables on slave are still right type --- --- and that the alter statements replicated correctly --- SHOW CREATE TABLE t1; @@ -736,7 +743,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`,`total`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4 +) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY () PARTITIONS 4 */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -793,7 +800,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`,`total`) -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4 +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY () PARTITIONS 4 */ --- Make sure that our tables on slave are still same engine --- --- and that the alter statements replicated correctly --- SHOW CREATE TABLE t1; @@ -809,7 +816,7 @@ t1 CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL, `t` date DEFAULT NULL, PRIMARY KEY (`id`,`total`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY KEY () PARTITIONS 4 +) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY () PARTITIONS 4 */ --- Perform basic operation on master --- --- and ensure replicated correctly --- "--- Insert into t1 --" as ""; @@ -853,3 +860,4 @@ DELETE FROM t1; --- End test 5 key partition testing --- --- Do Cleanup --- DROP TABLE IF EXISTS t1; +drop table mysql.ndb_apply_status; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_2ndb.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_2ndb.result new file mode 100644 index 00000000000..12882b28254 --- /dev/null +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_2ndb.result @@ -0,0 +1,400 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +SET storage_engine=ndb; + +=== NDB -> NDB === + +--- Doing pre test cleanup --- +DROP TABLE IF EXISTS t1; +--- Create Table Section --- +CREATE TABLE t1 (id MEDIUMINT NOT NULL, +b1 INT, +vc VARCHAR(255), +bc CHAR(255), +d DECIMAL(10,4) DEFAULT 0, +f FLOAT DEFAULT 0, +total BIGINT UNSIGNED, +y YEAR, +t DATE, +PRIMARY KEY(id)); +--- Show table on master --- +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` mediumint(9) NOT NULL, + `b1` int(11) DEFAULT NULL, + `vc` varchar(255) DEFAULT NULL, + `bc` char(255) DEFAULT NULL, + `d` decimal(10,4) DEFAULT '0.0000', + `f` float DEFAULT '0', + `total` bigint(20) unsigned DEFAULT NULL, + `y` year(4) DEFAULT NULL, + `t` date DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +--- Show table on slave --- +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` mediumint(9) NOT NULL, + `b1` int(11) DEFAULT NULL, + `vc` varchar(255) DEFAULT NULL, + `bc` char(255) DEFAULT NULL, + `d` decimal(10,4) DEFAULT '0.0000', + `f` float DEFAULT '0', + `total` bigint(20) unsigned DEFAULT NULL, + `y` year(4) DEFAULT NULL, + `t` date DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +STOP SLAVE; +RESET SLAVE; +RESET MASTER; +START SLAVE; +--- Populate t1 with data --- +--- Select from t1 on master --- +select * +from t1 +order by id; +id b1 vc bc d f total y t +2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 +4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 +42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 +142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14 +412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14 +--- Select from t1 on slave --- +select * +from t1 +order by id; +id b1 vc bc d f total y t +2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 +4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 +42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 +142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14 +412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14 +--- Perform basic operation on master --- +--- and ensure replicated correctly --- +--- Update t1 on master -- +UPDATE t1 SET b1 = 0, bc='updated', t="2006-02-22" +WHERE id < 100 +ORDER BY id; +--- Check the update on master --- +SELECT * +FROM t1 +WHERE id < 100 +ORDER BY id; +id b1 vc bc d f total y t +2 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 +4 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 +42 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 +--- Check Update on slave --- +SELECT * +FROM t1 +WHERE id < 100 +ORDER BY id; +id b1 vc bc d f total y t +2 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 +4 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 +42 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 +--- Remove a record from t1 on master --- +DELETE FROM t1 WHERE id = 412; +--- Show current count on master for t1 --- +SELECT COUNT(*) FROM t1; +COUNT(*) +4 +--- Show current count on slave for t1 --- +SELECT COUNT(*) FROM t1; +COUNT(*) +4 +TRUNCATE TABLE t1; +--- Check that simple Alter statements are replicated correctly -- +ALTER TABLE t1 DROP PRIMARY KEY; +ALTER TABLE t1 MODIFY vc char(32); +--- Show the new improved table on the master --- +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` mediumint(9) NOT NULL, + `b1` int(11) DEFAULT NULL, + `vc` char(32) DEFAULT NULL, + `bc` char(255) DEFAULT NULL, + `d` decimal(10,4) DEFAULT '0.0000', + `f` float DEFAULT '0', + `total` bigint(20) unsigned DEFAULT NULL, + `y` year(4) DEFAULT NULL, + `t` date DEFAULT NULL +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +--- Make sure that our tables on slave are still same engine --- +--- and that the alter statements replicated correctly --- +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` mediumint(9) NOT NULL, + `b1` int(11) DEFAULT NULL, + `vc` char(32) DEFAULT NULL, + `bc` char(255) DEFAULT NULL, + `d` decimal(10,4) DEFAULT '0.0000', + `f` float DEFAULT '0', + `total` bigint(20) unsigned DEFAULT NULL, + `y` year(4) DEFAULT NULL, + `t` date DEFAULT NULL +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +STOP SLAVE; +RESET SLAVE; +RESET MASTER; +START SLAVE; +--- Populate t1 with data --- +--- Select from t1 on master --- +select * +from t1 +order by id; +id b1 vc bc d f total y t +2 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 +4 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 +42 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 +142 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14 +412 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14 +--- Select from t1 on slave --- +select * +from t1 +order by id; +id b1 vc bc d f total y t +2 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 +4 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 +42 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 +142 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14 +412 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14 +--- Perform basic operation on master --- +--- and ensure replicated correctly --- +--- Update t1 on master -- +UPDATE t1 SET b1 = 0, bc='updated', t="2006-02-22" +WHERE id < 100 +ORDER BY id; +--- Check the update on master --- +SELECT * +FROM t1 +WHERE id < 100 +ORDER BY id; +id b1 vc bc d f total y t +2 0 Testing MySQL databases is a coo updated 654321.4321 15.21 0 1965 2006-02-22 +4 0 Testing MySQL databases is a coo updated 654321.4321 15.21 0 1965 2006-02-22 +42 0 Testing MySQL databases is a coo updated 654321.4321 15.21 0 1965 2006-02-22 +--- Check Update on slave --- +SELECT * +FROM t1 +WHERE id < 100 +ORDER BY id; +id b1 vc bc d f total y t +2 0 Testing MySQL databases is a coo updated 654321.4321 15.21 0 1965 2006-02-22 +4 0 Testing MySQL databases is a coo updated 654321.4321 15.21 0 1965 2006-02-22 +42 0 Testing MySQL databases is a coo updated 654321.4321 15.21 0 1965 2006-02-22 +--- Remove a record from t1 on master --- +DELETE FROM t1 WHERE id = 412; +--- Show current count on master for t1 --- +SELECT COUNT(*) FROM t1; +COUNT(*) +4 +--- Show current count on slave for t1 --- +SELECT COUNT(*) FROM t1; +COUNT(*) +4 +TRUNCATE TABLE t1; +--- Check that replication works when slave has more columns than master +ALTER TABLE t1 ADD PRIMARY KEY(id,total); +ALTER TABLE t1 MODIFY vc TEXT; +INSERT INTO t1 VALUES(3,1,'Testing MySQL databases is a cool ', +'Must make it bug free for the customer', +654321.4321,15.21,0,1965,"1905-11-14"); +INSERT INTO t1 VALUES(20,1,'Testing MySQL databases is a cool ', +'Must make it bug free for the customer', +654321.4321,15.21,0,1965,"1965-11-14"); +INSERT INTO t1 VALUES(50,1,'Testing MySQL databases is a cool ', +'Must make it bug free for the customer', +654321.4321,15.21,0,1965,"1985-11-14"); +--- Add columns on slave --- +ALTER TABLE t1 ADD (u int, v char(16) default 'default'); +UPDATE t1 SET u=7 WHERE id < 50; +UPDATE t1 SET v='explicit' WHERE id >10; +--- Show changed table on slave --- +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` mediumint(9) NOT NULL, + `b1` int(11) DEFAULT NULL, + `vc` text, + `bc` char(255) DEFAULT NULL, + `d` decimal(10,4) DEFAULT '0.0000', + `f` float DEFAULT '0', + `total` bigint(20) unsigned NOT NULL DEFAULT '0', + `y` year(4) DEFAULT NULL, + `t` date DEFAULT NULL, + `u` int(11) DEFAULT NULL, + `v` char(16) DEFAULT 'default', + PRIMARY KEY (`id`,`total`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +SELECT * +FROM t1 +ORDER BY id; +id b1 vc bc d f total y t u v +3 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 7 default +20 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 7 explicit +50 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 NULL explicit +STOP SLAVE; +RESET SLAVE; +RESET MASTER; +START SLAVE; +--- Populate t1 with data --- +--- Select from t1 on master --- +select * +from t1 +order by id; +id b1 vc bc d f total y t +2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 +3 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 +4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 +20 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 +42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 +50 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 +142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14 +412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14 +--- Select from t1 on slave --- +select * +from t1 +order by id; +id b1 vc bc d f total y t u v +2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 NULL NULL +3 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 7 default +4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 NULL NULL +20 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 7 explicit +42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 NULL NULL +50 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 NULL explicit +142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14 NULL NULL +412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14 NULL NULL +--- Perform basic operation on master --- +--- and ensure replicated correctly --- +--- Update t1 on master -- +UPDATE t1 SET b1 = 0, bc='updated', t="2006-02-22" +WHERE id < 100 +ORDER BY id; +--- Check the update on master --- +SELECT * +FROM t1 +WHERE id < 100 +ORDER BY id; +id b1 vc bc d f total y t +2 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 +3 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 +4 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 +20 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 +42 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 +50 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 +--- Check Update on slave --- +SELECT * +FROM t1 +WHERE id < 100 +ORDER BY id; +id b1 vc bc d f total y t u v +2 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 NULL NULL +3 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 7 default +4 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 NULL NULL +20 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 7 explicit +42 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 NULL NULL +50 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 NULL explicit +--- Remove a record from t1 on master --- +DELETE FROM t1 WHERE id = 412; +--- Show current count on master for t1 --- +SELECT COUNT(*) FROM t1; +COUNT(*) +7 +--- Show current count on slave for t1 --- +SELECT COUNT(*) FROM t1; +COUNT(*) +7 +TRUNCATE TABLE t1; +TRUNCATE TABLE t1; +--- Check that replication works when master has more columns than slave +--- Remove columns on slave --- +ALTER TABLE t1 DROP COLUMN v; +ALTER TABLE t1 DROP COLUMN u; +ALTER TABLE t1 DROP COLUMN t; +ALTER TABLE t1 DROP COLUMN y; +--- Show changed table on slave --- +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` mediumint(9) NOT NULL, + `b1` int(11) DEFAULT NULL, + `vc` text, + `bc` char(255) DEFAULT NULL, + `d` decimal(10,4) DEFAULT '0.0000', + `f` float DEFAULT '0', + `total` bigint(20) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`id`,`total`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +STOP SLAVE; +RESET SLAVE; +RESET MASTER; +START SLAVE; +--- Populate t1 with data --- +--- Select from t1 on master --- +select * +from t1 +order by id; +id b1 vc bc d f total y t +2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 +4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 +42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 +142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14 +412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14 +--- Select from t1 on slave --- +select * +from t1 +order by id; +id b1 vc bc d f total +2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 +4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 +42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 +142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 +412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 +--- Perform basic operation on master --- +--- and ensure replicated correctly --- +--- Update t1 on master -- +UPDATE t1 SET b1 = 0, bc='updated', t="2006-02-22" +WHERE id < 100 +ORDER BY id; +--- Check the update on master --- +SELECT * +FROM t1 +WHERE id < 100 +ORDER BY id; +id b1 vc bc d f total y t +2 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 +4 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 +42 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 +--- Check Update on slave --- +SELECT * +FROM t1 +WHERE id < 100 +ORDER BY id; +id b1 vc bc d f total +2 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 +4 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 +42 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 +--- Remove a record from t1 on master --- +DELETE FROM t1 WHERE id = 412; +--- Show current count on master for t1 --- +SELECT COUNT(*) FROM t1; +COUNT(*) +4 +--- Show current count on slave for t1 --- +SELECT COUNT(*) FROM t1; +COUNT(*) +4 +TRUNCATE TABLE t1; +TRUNCATE TABLE t1; +--- Do Cleanup -- +DROP TABLE IF EXISTS t1; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_2other.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_2other.result index 56b997028e9..84b60b599d8 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_2other.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_2other.result @@ -8,6 +8,14 @@ SET storage_engine=ndb; === NDB -> MYISAM === +set @@global.slave_exec_mode= 'IDEMPOTENT'; +CREATE TABLE mysql.ndb_apply_status +( server_id INT UNSIGNED NOT NULL, +epoch BIGINT UNSIGNED NOT NULL, +log_name VARCHAR(255) BINARY NOT NULL, +start_pos BIGINT UNSIGNED NOT NULL, +end_pos BIGINT UNSIGNED NOT NULL, +PRIMARY KEY USING HASH (server_id)) ENGINE=MYISAM; SET storage_engine=myisam; --- Doing pre test cleanup --- DROP TABLE IF EXISTS t1; @@ -402,6 +410,7 @@ DROP TABLE IF EXISTS t1; === NDB -> INNODB === +alter table mysql.ndb_apply_status engine=innodb; SET storage_engine=innodb; --- Doing pre test cleanup --- DROP TABLE IF EXISTS t1; @@ -793,397 +802,4 @@ TRUNCATE TABLE t1; TRUNCATE TABLE t1; --- Do Cleanup -- DROP TABLE IF EXISTS t1; - -=== NDB -> NDB === - -SET storage_engine=ndb; ---- Doing pre test cleanup --- -DROP TABLE IF EXISTS t1; ---- Create Table Section --- -CREATE TABLE t1 (id MEDIUMINT NOT NULL, -b1 INT, -vc VARCHAR(255), -bc CHAR(255), -d DECIMAL(10,4) DEFAULT 0, -f FLOAT DEFAULT 0, -total BIGINT UNSIGNED, -y YEAR, -t DATE, -PRIMARY KEY(id)); ---- Show table on master --- -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `id` mediumint(9) NOT NULL, - `b1` int(11) DEFAULT NULL, - `vc` varchar(255) DEFAULT NULL, - `bc` char(255) DEFAULT NULL, - `d` decimal(10,4) DEFAULT '0.0000', - `f` float DEFAULT '0', - `total` bigint(20) unsigned DEFAULT NULL, - `y` year(4) DEFAULT NULL, - `t` date DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 ---- Show table on slave --- -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `id` mediumint(9) NOT NULL, - `b1` int(11) DEFAULT NULL, - `vc` varchar(255) DEFAULT NULL, - `bc` char(255) DEFAULT NULL, - `d` decimal(10,4) DEFAULT '0.0000', - `f` float DEFAULT '0', - `total` bigint(20) unsigned DEFAULT NULL, - `y` year(4) DEFAULT NULL, - `t` date DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -STOP SLAVE; -RESET SLAVE; -RESET MASTER; -START SLAVE; ---- Populate t1 with data --- ---- Select from t1 on master --- -select * -from t1 -order by id; -id b1 vc bc d f total y t -2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 -4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 -42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 -142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14 -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14 ---- Select from t1 on slave --- -select * -from t1 -order by id; -id b1 vc bc d f total y t -2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 -4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 -42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 -142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14 -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14 ---- Perform basic operation on master --- ---- and ensure replicated correctly --- ---- Update t1 on master -- -UPDATE t1 SET b1 = 0, bc='updated', t="2006-02-22" -WHERE id < 100 -ORDER BY id; ---- Check the update on master --- -SELECT * -FROM t1 -WHERE id < 100 -ORDER BY id; -id b1 vc bc d f total y t -2 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 -4 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 -42 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 ---- Check Update on slave --- -SELECT * -FROM t1 -WHERE id < 100 -ORDER BY id; -id b1 vc bc d f total y t -2 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 -4 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 -42 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 ---- Remove a record from t1 on master --- -DELETE FROM t1 WHERE id = 412; ---- Show current count on master for t1 --- -SELECT COUNT(*) FROM t1; -COUNT(*) -4 ---- Show current count on slave for t1 --- -SELECT COUNT(*) FROM t1; -COUNT(*) -4 -TRUNCATE TABLE t1; ---- Check that simple Alter statements are replicated correctly -- -ALTER TABLE t1 DROP PRIMARY KEY; -ALTER TABLE t1 MODIFY vc char(32); ---- Show the new improved table on the master --- -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `id` mediumint(9) NOT NULL, - `b1` int(11) DEFAULT NULL, - `vc` char(32) DEFAULT NULL, - `bc` char(255) DEFAULT NULL, - `d` decimal(10,4) DEFAULT '0.0000', - `f` float DEFAULT '0', - `total` bigint(20) unsigned DEFAULT NULL, - `y` year(4) DEFAULT NULL, - `t` date DEFAULT NULL -) ENGINE=ndbcluster DEFAULT CHARSET=latin1 ---- Make sure that our tables on slave are still same engine --- ---- and that the alter statements replicated correctly --- -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `id` mediumint(9) NOT NULL, - `b1` int(11) DEFAULT NULL, - `vc` char(32) DEFAULT NULL, - `bc` char(255) DEFAULT NULL, - `d` decimal(10,4) DEFAULT '0.0000', - `f` float DEFAULT '0', - `total` bigint(20) unsigned DEFAULT NULL, - `y` year(4) DEFAULT NULL, - `t` date DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -STOP SLAVE; -RESET SLAVE; -RESET MASTER; -START SLAVE; ---- Populate t1 with data --- ---- Select from t1 on master --- -select * -from t1 -order by id; -id b1 vc bc d f total y t -2 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 -4 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 -42 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 -142 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14 -412 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14 ---- Select from t1 on slave --- -select * -from t1 -order by id; -id b1 vc bc d f total y t -2 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 -4 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 -42 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 -142 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14 -412 1 Testing MySQL databases is a coo Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14 ---- Perform basic operation on master --- ---- and ensure replicated correctly --- ---- Update t1 on master -- -UPDATE t1 SET b1 = 0, bc='updated', t="2006-02-22" -WHERE id < 100 -ORDER BY id; ---- Check the update on master --- -SELECT * -FROM t1 -WHERE id < 100 -ORDER BY id; -id b1 vc bc d f total y t -2 0 Testing MySQL databases is a coo updated 654321.4321 15.21 0 1965 2006-02-22 -4 0 Testing MySQL databases is a coo updated 654321.4321 15.21 0 1965 2006-02-22 -42 0 Testing MySQL databases is a coo updated 654321.4321 15.21 0 1965 2006-02-22 ---- Check Update on slave --- -SELECT * -FROM t1 -WHERE id < 100 -ORDER BY id; -id b1 vc bc d f total y t -2 0 Testing MySQL databases is a coo updated 654321.4321 15.21 0 1965 2006-02-22 -4 0 Testing MySQL databases is a coo updated 654321.4321 15.21 0 1965 2006-02-22 -42 0 Testing MySQL databases is a coo updated 654321.4321 15.21 0 1965 2006-02-22 ---- Remove a record from t1 on master --- -DELETE FROM t1 WHERE id = 412; ---- Show current count on master for t1 --- -SELECT COUNT(*) FROM t1; -COUNT(*) -4 ---- Show current count on slave for t1 --- -SELECT COUNT(*) FROM t1; -COUNT(*) -4 -TRUNCATE TABLE t1; ---- Check that replication works when slave has more columns than master -ALTER TABLE t1 ADD PRIMARY KEY(id,total); -ALTER TABLE t1 MODIFY vc TEXT; -INSERT INTO t1 VALUES(3,1,'Testing MySQL databases is a cool ', -'Must make it bug free for the customer', -654321.4321,15.21,0,1965,"1905-11-14"); -INSERT INTO t1 VALUES(20,1,'Testing MySQL databases is a cool ', -'Must make it bug free for the customer', -654321.4321,15.21,0,1965,"1965-11-14"); -INSERT INTO t1 VALUES(50,1,'Testing MySQL databases is a cool ', -'Must make it bug free for the customer', -654321.4321,15.21,0,1965,"1985-11-14"); ---- Add columns on slave --- -ALTER TABLE t1 ADD (u int, v char(16) default 'default'); -UPDATE t1 SET u=7 WHERE id < 50; -UPDATE t1 SET v='explicit' WHERE id >10; ---- Show changed table on slave --- -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `id` mediumint(9) NOT NULL, - `b1` int(11) DEFAULT NULL, - `vc` text, - `bc` char(255) DEFAULT NULL, - `d` decimal(10,4) DEFAULT '0.0000', - `f` float DEFAULT '0', - `total` bigint(20) unsigned NOT NULL DEFAULT '0', - `y` year(4) DEFAULT NULL, - `t` date DEFAULT NULL, - `u` int(11) DEFAULT NULL, - `v` char(16) DEFAULT 'default', - PRIMARY KEY (`id`,`total`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -SELECT * -FROM t1 -ORDER BY id; -id b1 vc bc d f total y t u v -3 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 7 default -20 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 7 explicit -50 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 NULL explicit -STOP SLAVE; -RESET SLAVE; -RESET MASTER; -START SLAVE; ---- Populate t1 with data --- ---- Select from t1 on master --- -select * -from t1 -order by id; -id b1 vc bc d f total y t -2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 -3 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 -4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 -20 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 -42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 -50 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 -142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14 -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14 ---- Select from t1 on slave --- -select * -from t1 -order by id; -id b1 vc bc d f total y t u v -2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 NULL default -3 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 7 default -4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 NULL default -20 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 7 explicit -42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 NULL default -50 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 NULL explicit -142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14 NULL default -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14 NULL default ---- Perform basic operation on master --- ---- and ensure replicated correctly --- ---- Update t1 on master -- -UPDATE t1 SET b1 = 0, bc='updated', t="2006-02-22" -WHERE id < 100 -ORDER BY id; ---- Check the update on master --- -SELECT * -FROM t1 -WHERE id < 100 -ORDER BY id; -id b1 vc bc d f total y t -2 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 -3 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 -4 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 -20 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 -42 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 -50 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 ---- Check Update on slave --- -SELECT * -FROM t1 -WHERE id < 100 -ORDER BY id; -id b1 vc bc d f total y t u v -2 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 NULL default -3 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 7 default -4 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 NULL default -20 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 7 explicit -42 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 NULL default -50 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 NULL explicit ---- Remove a record from t1 on master --- -DELETE FROM t1 WHERE id = 412; ---- Show current count on master for t1 --- -SELECT COUNT(*) FROM t1; -COUNT(*) -7 ---- Show current count on slave for t1 --- -SELECT COUNT(*) FROM t1; -COUNT(*) -7 -TRUNCATE TABLE t1; -TRUNCATE TABLE t1; ---- Check that replication works when master has more columns than slave ---- Remove columns on slave --- -ALTER TABLE t1 DROP COLUMN v; -ALTER TABLE t1 DROP COLUMN u; -ALTER TABLE t1 DROP COLUMN t; -ALTER TABLE t1 DROP COLUMN y; ---- Show changed table on slave --- -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `id` mediumint(9) NOT NULL, - `b1` int(11) DEFAULT NULL, - `vc` text, - `bc` char(255) DEFAULT NULL, - `d` decimal(10,4) DEFAULT '0.0000', - `f` float DEFAULT '0', - `total` bigint(20) unsigned NOT NULL DEFAULT '0', - PRIMARY KEY (`id`,`total`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -STOP SLAVE; -RESET SLAVE; -RESET MASTER; -START SLAVE; ---- Populate t1 with data --- ---- Select from t1 on master --- -select * -from t1 -order by id; -id b1 vc bc d f total y t -2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1965-11-14 -4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1985-11-14 -42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1905-11-14 -142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 1995-11-14 -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 1965 2005-11-14 ---- Select from t1 on slave --- -select * -from t1 -order by id; -id b1 vc bc d f total -2 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 -4 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 -42 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 -142 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 -412 1 Testing MySQL databases is a cool Must make it bug free for the customer 654321.4321 15.21 0 ---- Perform basic operation on master --- ---- and ensure replicated correctly --- ---- Update t1 on master -- -UPDATE t1 SET b1 = 0, bc='updated', t="2006-02-22" -WHERE id < 100 -ORDER BY id; ---- Check the update on master --- -SELECT * -FROM t1 -WHERE id < 100 -ORDER BY id; -id b1 vc bc d f total y t -2 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 -4 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 -42 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 1965 2006-02-22 ---- Check Update on slave --- -SELECT * -FROM t1 -WHERE id < 100 -ORDER BY id; -id b1 vc bc d f total -2 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 -4 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 -42 0 Testing MySQL databases is a cool updated 654321.4321 15.21 0 ---- Remove a record from t1 on master --- -DELETE FROM t1 WHERE id = 412; ---- Show current count on master for t1 --- -SELECT COUNT(*) FROM t1; -COUNT(*) -4 ---- Show current count on slave for t1 --- -SELECT COUNT(*) FROM t1; -COUNT(*) -4 -TRUNCATE TABLE t1; -TRUNCATE TABLE t1; ---- Do Cleanup -- -DROP TABLE IF EXISTS t1; +drop table mysql.ndb_apply_status; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_apply_status.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_apply_status.result new file mode 100644 index 00000000000..0fcd361da21 --- /dev/null +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_apply_status.result @@ -0,0 +1,20 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +*** on slave there should be zero rows *** +select count(*) from mysql.ndb_apply_status; +count(*) +0 +create table t1 (a int key, b int) engine ndb; +insert into t1 values (1,1); +*** on master it should be empty *** +select * from mysql.ndb_apply_status; +server_id epoch log_name start_pos end_pos +*** on slave there should be one row *** +select count(*) from mysql.ndb_apply_status; +count(*) +1 +drop table t1; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_stm_innodb.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_stm_innodb.result index 7008dc60d96..db9920dd79f 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_stm_innodb.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_stm_innodb.result @@ -20,13 +20,27 @@ from mysql.ndb_apply_status; @log_name:=log_name @start_pos:=start_pos @end_pos:=end_pos +# Now check that that is in the apply_status table is consistant +# with what is in the binlog + +# since insert is done with transactional engine, expect a BEGIN +# at + show binlog events from limit 1; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 Query 1 # use `test`; BEGIN +# Now the insert, one step after + show binlog events from limit 1,1; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query 1 486 use `test`; insert into t1 values (1,2) +master-bin.000001 # Query 1 # use `test`; insert into t1 values (1,2) + +# and the COMMIT should be at + +show binlog events from limit 2,1; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Xid 1 COMMIT /* XID */ begin; insert into t1 values (2,3); diff --git a/mysql-test/suite/rpl_ndb/t/disabled.def b/mysql-test/suite/rpl_ndb/t/disabled.def index b6bce159c6e..9fd63d2e72e 100644 --- a/mysql-test/suite/rpl_ndb/t/disabled.def +++ b/mysql-test/suite/rpl_ndb/t/disabled.def @@ -11,17 +11,5 @@ ############################################################################## -rpl_ndb_2innodb : Bug #32648 Test failure between NDB Cluster and other engines -rpl_ndb_2myisam : Bug #32648 Test failure between NDB Cluster and other engines -rpl_ndb_2other : Bug #32648 Test failure between NDB Cluster and other engines -rpl_ndb_extraColMaster : BUG#30854 : Tables name show as binary in slave err msg on vm-win2003-64-b and Solaris -rpl_ndb_mix_innodb : Bug #32720 Test rpl_ndb_mix_innodb fails on SPARC and PowerPC # the below testcase have been reworked to avoid the bug, test contains comment, keep bug open - -#rpl_ndb_dd_advance : Bug#25913 rpl_ndb_dd_advance fails randomly - - -rpl_ndb_innodb_trans : Bug#34454: Some test cases from the 'rpl_ndb' suite fail -rpl_ndb_charset : Bug#34454: Some test cases from the 'rpl_ndb' suite fail -rpl_ndb_multi : Bug#34454: Some test cases from the 'rpl_ndb' suite fail diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2innodb-master.opt b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2innodb-master.opt index 701dddb075b..9a3f30e4bd0 100644 --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2innodb-master.opt +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2innodb-master.opt @@ -1 +1 @@ ---default-storage-engine=ndbcluster +--new --default-storage-engine=ndbcluster diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2innodb-slave.opt b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2innodb-slave.opt index d8857e54be2..0d3f1619f1e 100644 --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2innodb-slave.opt +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2innodb-slave.opt @@ -1 +1 @@ ---innodb --default-storage-engine=innodb +--innodb --default-storage-engine=innodb --ndbcluster=0 diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2innodb.test b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2innodb.test index 30e4e49eb7a..43ad901d746 100644 --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2innodb.test +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2innodb.test @@ -8,9 +8,20 @@ # test and to have control over the tests. ############################################################## -- source include/have_ndb.inc --- source include/ndb_master-slave.inc -connection slave; +-- source include/master-slave.inc + +-- connection slave -- source include/have_innodb.inc -connection master; -SET storage_engine=ndb; +set @@global.slave_exec_mode= 'IDEMPOTENT'; +CREATE TABLE mysql.ndb_apply_status + ( server_id INT UNSIGNED NOT NULL, + epoch BIGINT UNSIGNED NOT NULL, + log_name VARCHAR(255) BINARY NOT NULL, + start_pos BIGINT UNSIGNED NOT NULL, + end_pos BIGINT UNSIGNED NOT NULL, + PRIMARY KEY USING HASH (server_id)) ENGINE=INNODB; + --source extra/rpl_tests/rpl_ndb_2multi_eng.test + +--connection slave +drop table mysql.ndb_apply_status; diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2myisam-master.opt b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2myisam-master.opt index 701dddb075b..b63ef44e8fc 100644 --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2myisam-master.opt +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2myisam-master.opt @@ -1 +1 @@ ---default-storage-engine=ndbcluster +--new --default-storage-engine=ndbcluster diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2myisam-slave.opt b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2myisam-slave.opt index 6035ce27c46..9b5f524e131 100644 --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2myisam-slave.opt +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2myisam-slave.opt @@ -1 +1 @@ ---default-storage-engine=myisam +--default-storage-engine=myisam --ndbcluster=0 diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2myisam.test b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2myisam.test index 182d4c72d87..b19116ffd78 100644 --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2myisam.test +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2myisam.test @@ -8,6 +8,19 @@ # test and to have control over the tests. ############################################################## -- source include/have_ndb.inc --- source include/ndb_master-slave.inc -SET storage_engine=ndb; +-- source include/master-slave.inc + +-- connection slave +set @@global.slave_exec_mode= 'IDEMPOTENT'; +CREATE TABLE mysql.ndb_apply_status + ( server_id INT UNSIGNED NOT NULL, + epoch BIGINT UNSIGNED NOT NULL, + log_name VARCHAR(255) BINARY NOT NULL, + start_pos BIGINT UNSIGNED NOT NULL, + end_pos BIGINT UNSIGNED NOT NULL, + PRIMARY KEY USING HASH (server_id)) ENGINE=MYISAM; + --source extra/rpl_tests/rpl_ndb_2multi_eng.test + +--connection slave +drop table mysql.ndb_apply_status; diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2ndb-slave.opt b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2ndb-slave.opt new file mode 100644 index 00000000000..5304fd49b6b --- /dev/null +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2ndb-slave.opt @@ -0,0 +1 @@ +--default-storage-engine=ndbcluster --log-slave-updates=0 diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2ndb.test b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2ndb.test new file mode 100644 index 00000000000..1657a6902ba --- /dev/null +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2ndb.test @@ -0,0 +1,18 @@ +############################################################# +# Author: Rafal Somla +# Date: 2006-08-20 +# Purpose: Trying to test ability to replicate from cluster +# to other engines (innodb, myisam), see also rpl_ndb_2other.test +############################################################## +--source include/have_binlog_format_mixed_or_row.inc +--source include/ndb_master-slave.inc + +# On master use NDB as storage engine. +connection master; +SET storage_engine=ndb; + +--echo +--echo === NDB -> NDB === +--echo +connection slave; +--source extra/rpl_tests/rpl_ndb_2multi_basic.test diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2other-slave.opt b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2other-slave.opt index a6c65034e68..188b31efa8a 100644 --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2other-slave.opt +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2other-slave.opt @@ -1 +1 @@ ---innodb --log-slave-updates=0 +--innodb --ndbcluster=0 --log-slave-updates=0 diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2other.test b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2other.test index b7e393ca3cc..67e8f7cea42 100644 --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2other.test +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2other.test @@ -7,7 +7,7 @@ --source include/have_ndb.inc --source include/have_innodb.inc --source include/have_binlog_format_mixed_or_row.inc ---source include/ndb_master-slave.inc +--source include/master-slave.inc # On master use NDB as storage engine. connection master; @@ -17,6 +17,14 @@ SET storage_engine=ndb; --echo === NDB -> MYISAM === --echo connection slave; +set @@global.slave_exec_mode= 'IDEMPOTENT'; +CREATE TABLE mysql.ndb_apply_status + ( server_id INT UNSIGNED NOT NULL, + epoch BIGINT UNSIGNED NOT NULL, + log_name VARCHAR(255) BINARY NOT NULL, + start_pos BIGINT UNSIGNED NOT NULL, + end_pos BIGINT UNSIGNED NOT NULL, + PRIMARY KEY USING HASH (server_id)) ENGINE=MYISAM; SET storage_engine=myisam; --source extra/rpl_tests/rpl_ndb_2multi_basic.test @@ -24,12 +32,9 @@ SET storage_engine=myisam; --echo === NDB -> INNODB === --echo connection slave; +alter table mysql.ndb_apply_status engine=innodb; SET storage_engine=innodb; --source extra/rpl_tests/rpl_ndb_2multi_basic.test ---echo ---echo === NDB -> NDB === ---echo connection slave; -SET storage_engine=ndb; ---source extra/rpl_tests/rpl_ndb_2multi_basic.test +drop table mysql.ndb_apply_status; diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_apply_status-master.opt b/mysql-test/suite/rpl_ndb/t/rpl_ndb_apply_status-master.opt new file mode 100644 index 00000000000..3f4aff8a321 --- /dev/null +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_apply_status-master.opt @@ -0,0 +1 @@ +--replicate_ignore_db=mysql diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_apply_status.test b/mysql-test/suite/rpl_ndb/t/rpl_ndb_apply_status.test new file mode 100644 index 00000000000..cc74acc6490 --- /dev/null +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_apply_status.test @@ -0,0 +1,26 @@ +-- source include/have_ndb.inc +-- source include/have_binlog_format_row.inc +-- source include/ndb_master-slave.inc + +# +# Bug#28170 replicate-ignore-db=mysql should not ignore mysql.ndb_apply_status +# +# Slave is started with --replicate-ignore-db=mysql +# +sync_slave_with_master; +echo *** on slave there should be zero rows ***; +select count(*) from mysql.ndb_apply_status; + +connection master; +create table t1 (a int key, b int) engine ndb; +insert into t1 values (1,1); +echo *** on master it should be empty ***; +select * from mysql.ndb_apply_status; + +sync_slave_with_master; +echo *** on slave there should be one row ***; +select count(*) from mysql.ndb_apply_status; + +connection master; +drop table t1; +sync_slave_with_master; diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_charset.test b/mysql-test/suite/rpl_ndb/t/rpl_ndb_charset.test deleted file mode 100644 index f14229a52f9..00000000000 --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_charset.test +++ /dev/null @@ -1,8 +0,0 @@ -######################################################## -# By JBM 2005-02-15 Wrapped to allow reuse of test code# -######################################################## --- source include/have_ndb.inc --- source include/have_binlog_format_mixed_or_row.inc --- source include/ndb_master-slave.inc -let $engine_type=NDB; --- source extra/rpl_tests/rpl_row_charset.test diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_multi.test b/mysql-test/suite/rpl_ndb/t/rpl_ndb_multi.test index dacb1307a7b..1ee9aaf5372 100644 --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_multi.test +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_multi.test @@ -56,15 +56,12 @@ DELETE FROM t1 WHERE c3 = 2; SELECT * FROM t1 ORDER BY c3; -save_master_pos; - # insert another row, and check that we have it on the slave connection server2; INSERT INTO t1 VALUES ("row5","E",5); SELECT * FROM t1 ORDER BY c3; -#sync_slave_with_master; +sync_slave_with_master; connection slave; ---sleep 2 SELECT * FROM t1 ORDER BY c3; STOP SLAVE; diff --git a/mysql-test/suite/stress/t/ddl_ndb.test b/mysql-test/suite/stress/t/ddl_ndb.test index 7eb45da8739..1e0a3680f8a 100644 --- a/mysql-test/suite/stress/t/ddl_ndb.test +++ b/mysql-test/suite/stress/t/ddl_ndb.test @@ -10,6 +10,8 @@ # Storage engine to be used in CREATE TABLE --source include/have_ndb.inc +connection default; + let $engine_type= NDB; diff --git a/mysql-test/t/events_scheduling.test b/mysql-test/t/events_scheduling.test index 226cad0f3eb..a5133166495 100644 --- a/mysql-test/t/events_scheduling.test +++ b/mysql-test/t/events_scheduling.test @@ -76,21 +76,28 @@ let $wait_condition=select count(*) = 0 from information_schema.events where event_name='event_4' and status='enabled'; --source include/wait_condition.inc -# check the data +# Wait for the events to fire and check the data afterwards +let $wait_condition=SELECT SUM(a) >= 4 FROM table_1; +source include/wait_condition.inc; SELECT IF(SUM(a) >= 4, 'OK', 'ERROR') FROM table_1; + +let $wait_condition=SELECT SUM(a) >= 5 FROM table_2; +source include/wait_condition.inc; SELECT IF(SUM(a) >= 5, 'OK', 'ERROR') FROM table_2; + +let $wait_condition=SELECT SUM(a) >= 1 FROM table_3; +source include/wait_condition.inc; SELECT IF(SUM(a) >= 1, 'OK', 'ERROR') FROM table_3; + +let $wait_condition=SELECT SUM(a) >= 1 FROM table_4; +source include/wait_condition.inc; SELECT IF(SUM(a) >= 1, 'OK', 'ERROR') FROM table_4; SELECT IF(TIME_TO_SEC(TIMEDIFF(ENDS,STARTS))=6, 'OK', 'ERROR') FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA=DATABASE() AND EVENT_NAME='event_2'; -SELECT IF(LAST_EXECUTED-ENDS <= 0, 'OK', 'ERROR') -FROM INFORMATION_SCHEMA.EVENTS -WHERE EVENT_SCHEMA=DATABASE() AND EVENT_NAME='event_2'; - --echo "Already dropped because ended. Therefore an error." --error ER_EVENT_DOES_NOT_EXIST DROP EVENT event_3; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 441da21bf1c..fdee8f92331 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -316,6 +316,10 @@ int execute_no_commit_ie(ha_ndbcluster *h, NdbTransaction *trans, /* Place holder for ha_ndbcluster thread specific data */ +typedef struct st_thd_ndb_share { + const void *key; + struct Ndb_local_table_statistics stat; +} THD_NDB_SHARE; static uchar *thd_ndb_share_get_key(THD_NDB_SHARE *thd_ndb_share, size_t *length, my_bool not_used __attribute__((unused))) @@ -372,41 +376,6 @@ Thd_ndb::init_open_tables() my_hash_reset(&open_tables); } -THD_NDB_SHARE * -Thd_ndb::get_open_table(THD *thd, const void *key) -{ - DBUG_ENTER("Thd_ndb::get_open_table"); - HASH_SEARCH_STATE state; - THD_NDB_SHARE *thd_ndb_share= - (THD_NDB_SHARE*)hash_first(&open_tables, (uchar *)&key, sizeof(key), &state); - while (thd_ndb_share && thd_ndb_share->key != key) - thd_ndb_share= (THD_NDB_SHARE*)hash_next(&open_tables, (uchar *)&key, sizeof(key), &state); - if (thd_ndb_share == 0) - { - thd_ndb_share= (THD_NDB_SHARE *) alloc_root(&thd->transaction.mem_root, - sizeof(THD_NDB_SHARE)); - if (!thd_ndb_share) - { - mem_alloc_error(sizeof(THD_NDB_SHARE)); - DBUG_RETURN(NULL); - } - thd_ndb_share->key= key; - thd_ndb_share->stat.last_count= count; - thd_ndb_share->stat.no_uncommitted_rows_count= 0; - thd_ndb_share->stat.records= ~(ha_rows)0; - my_hash_insert(&open_tables, (uchar *)thd_ndb_share); - } - else if (thd_ndb_share->stat.last_count != count) - { - thd_ndb_share->stat.last_count= count; - thd_ndb_share->stat.no_uncommitted_rows_count= 0; - thd_ndb_share->stat.records= ~(ha_rows)0; - } - DBUG_PRINT("exit", ("thd_ndb_share: 0x%lx key: 0x%lx", - (long) thd_ndb_share, (long) key)); - DBUG_RETURN(thd_ndb_share); -} - inline Ndb *ha_ndbcluster::get_ndb() { @@ -2742,10 +2711,13 @@ ha_ndbcluster::set_auto_inc(Field *field) ("Trying to set next auto increment value to %s", llstr(next_val, buff))); #endif - Ndb_tuple_id_range_guard g(m_share); - if (ndb->setAutoIncrementValue(m_table, g.range, next_val, TRUE) - == -1) - ERR_RETURN(ndb->getNdbError()); + if (ndb->checkUpdateAutoIncrementValue(m_share->tuple_id_range, next_val)) + { + Ndb_tuple_id_range_guard g(m_share); + if (ndb->setAutoIncrementValue(m_table, g.range, next_val, TRUE) + == -1) + ERR_RETURN(ndb->getNdbError()); + } DBUG_RETURN(0); } @@ -4554,12 +4526,48 @@ int ha_ndbcluster::init_handler_for_statement(THD *thd, Thd_ndb *thd_ndb) thd_ndb->trans_options|= TNTO_INJECTED_APPLY_STATUS; } #endif - // TODO remove double pointers... - if (!(m_thd_ndb_share= thd_ndb->get_open_table(thd, m_table))) + + if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { - DBUG_RETURN(1); + const void *key= m_table; + HASH_SEARCH_STATE state; + THD_NDB_SHARE *thd_ndb_share= + (THD_NDB_SHARE*)hash_first(&thd_ndb->open_tables, (uchar *)&key, sizeof(key), &state); + while (thd_ndb_share && thd_ndb_share->key != key) + thd_ndb_share= (THD_NDB_SHARE*)hash_next(&thd_ndb->open_tables, (uchar *)&key, sizeof(key), &state); + if (thd_ndb_share == 0) + { + thd_ndb_share= (THD_NDB_SHARE *) alloc_root(&thd->transaction.mem_root, + sizeof(THD_NDB_SHARE)); + if (!thd_ndb_share) + { + mem_alloc_error(sizeof(THD_NDB_SHARE)); + DBUG_RETURN(1); + } + thd_ndb_share->key= key; + thd_ndb_share->stat.last_count= thd_ndb->count; + thd_ndb_share->stat.no_uncommitted_rows_count= 0; + thd_ndb_share->stat.records= ~(ha_rows)0; + my_hash_insert(&thd_ndb->open_tables, (uchar *)thd_ndb_share); + } + else if (thd_ndb_share->stat.last_count != thd_ndb->count) + { + thd_ndb_share->stat.last_count= thd_ndb->count; + thd_ndb_share->stat.no_uncommitted_rows_count= 0; + thd_ndb_share->stat.records= ~(ha_rows)0; + } + DBUG_PRINT("exit", ("thd_ndb_share: 0x%lx key: 0x%lx", + (long) thd_ndb_share, (long) key)); + m_table_info= &thd_ndb_share->stat; + } + else + { + struct Ndb_local_table_statistics &stat= m_table_info_instance; + stat.last_count= thd_ndb->count; + stat.no_uncommitted_rows_count= 0; + stat.records= ~(ha_rows)0; + m_table_info= &stat; } - m_table_info= &m_thd_ndb_share->stat; DBUG_RETURN(0); } diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index cc79402fe92..a17323d3fd6 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -195,11 +195,6 @@ struct Ndb_local_table_statistics { ha_rows records; }; -typedef struct st_thd_ndb_share { - const void *key; - struct Ndb_local_table_statistics stat; -} THD_NDB_SHARE; - class Thd_ndb { public: @@ -207,7 +202,6 @@ class Thd_ndb ~Thd_ndb(); void init_open_tables(); - THD_NDB_SHARE *get_open_table(THD *thd, const void *key); Ndb *ndb; ulong count; @@ -514,6 +508,7 @@ private: NdbScanOperation *m_active_cursor; const NdbDictionary::Table *m_table; struct Ndb_local_table_statistics *m_table_info; + struct Ndb_local_table_statistics m_table_info_instance; char m_dbname[FN_HEADLEN]; //char m_schemaname[FN_HEADLEN]; char m_tabname[FN_HEADLEN]; @@ -522,7 +517,6 @@ private: bool m_lock_tuple; NDB_SHARE *m_share; NDB_INDEX_DATA m_index[MAX_KEY]; - THD_NDB_SHARE *m_thd_ndb_share; // NdbRecAttr has no reference to blob NdbValue m_value[NDB_MAX_ATTRIBUTES_IN_TABLE]; uchar m_ref[NDB_HIDDEN_PRIMARY_KEY_LENGTH]; diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 6dae841157c..fc1568a5ea6 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -683,6 +683,18 @@ static void ndbcluster_reset_slave(THD *thd) /* Initialize the binlog part of the ndb handlerton */ + +/** + Upon the sql command flush logs, we need to ensure that all outstanding + ndb data to be logged has made it to the binary log to get a deterministic + behavior on the rotation of the log. + */ +static bool ndbcluster_flush_logs(handlerton *hton) +{ + ndbcluster_binlog_wait(current_thd); + return FALSE; +} + static int ndbcluster_binlog_func(handlerton *hton, THD *thd, enum_binlog_func fn, void *arg) @@ -711,6 +723,7 @@ static int ndbcluster_binlog_func(handlerton *hton, THD *thd, void ndbcluster_binlog_init_handlerton() { handlerton *h= ndbcluster_hton; + h->flush_logs= ndbcluster_flush_logs; h->binlog_func= ndbcluster_binlog_func; h->binlog_log_query= ndbcluster_binlog_log_query; } diff --git a/sql/log_event.cc b/sql/log_event.cc index a4b32a84b42..0d2f3e7e708 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -99,27 +99,51 @@ static const char *HA_ERR(int i) case HA_ERR_RECORD_IS_THE_SAME: return "HA_ERR_RECORD_IS_THE_SAME"; case HA_ERR_LOGGING_IMPOSSIBLE: return "HA_ERR_LOGGING_IMPOSSIBLE"; case HA_ERR_CORRUPT_EVENT: return "HA_ERR_CORRUPT_EVENT"; + case HA_ERR_ROWS_EVENT_APPLY : return "HA_ERR_ROWS_EVENT_APPLY"; } return 0; } /** - macro to call from different branches of Rows_log_event::do_apply_event + Error reporting facility for Rows_log_event::do_apply_event + + @param level error, warning or info + @param ha_error HA_ERR_ code + @param rli pointer to the active Relay_log_info instance + @param thd pointer to the slave thread's thd + @param table pointer to the event's table object + @param type the type of the event + @param log_name the master binlog file name + @param pos the master binlog file pos (the next after the event) + */ static void inline slave_rows_error_report(enum loglevel level, int ha_error, Relay_log_info const *rli, THD *thd, TABLE *table, const char * type, const char *log_name, ulong pos) { - const char *handler_error= HA_ERR(ha_error); + const char *handler_error= HA_ERR(ha_error); + char buff[MAX_SLAVE_ERRMSG], *slider; + const char *buff_end= buff + sizeof(buff); + uint len; + List_iterator_fast it(thd->warn_list); + MYSQL_ERROR *err; + buff[0]= 0; + + for (err= it++, slider= buff; err && slider < buff_end - 1; + slider += len, err= it++) + { + len= my_snprintf(slider, buff_end - slider, + " %s, Error_code: %d;", err->msg, err->code); + } + rli->report(level, thd->net.client_last_errno, "Could not execute %s event on table %s.%s;" - "%s%s handler error %s; " + "%s handler error %s; " "the event's master log %s, end_log_pos %lu", type, table->s->db.str, table->s->table_name.str, - thd->net.client_last_error[0] != 0 ? thd->net.client_last_error : "", - thd->net.client_last_error[0] != 0 ? ";" : "", + buff, handler_error == NULL? "" : handler_error, log_name, pos); } @@ -212,9 +236,9 @@ uint debug_not_change_ts_if_art_event= 1; // bug#29309 simulation */ #ifdef MYSQL_CLIENT -static void pretty_print_str(IO_CACHE* cache, char* str, int len) +static void pretty_print_str(IO_CACHE* cache, const char* str, int len) { - char* end = str + len; + const char* end = str + len; my_b_printf(cache, "\'"); while (str < end) { @@ -277,9 +301,9 @@ inline int ignored_error_code(int err_code) */ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -static char *pretty_print_str(char *packet, char *str, int len) +static char *pretty_print_str(char *packet, const char *str, int len) { - char *end= str + len; + const char *end= str + len; char *pos= packet; *pos++= '\''; while (str < end) @@ -385,7 +409,7 @@ static void cleanup_load_tmpdir() write_str() */ -static bool write_str(IO_CACHE *file, char *str, uint length) +static bool write_str(IO_CACHE *file, const char *str, uint length) { uchar tmp[1]; tmp[0]= (uchar) length; @@ -2957,18 +2981,63 @@ Format_description_log_event(const char* buf, If post_header_len is null, it means malloc failed, and is_valid will fail, so there is no need to do anything. - The trees which have wrong event id's are: - mysql-5.1-wl2325-5.0-drop6p13-alpha, mysql-5.1-wl2325-5.0-drop6, - mysql-5.1-wl2325-5.0, mysql-5.1-wl2325-no-dd (`grep -C2 - BEGIN_LOAD_QUERY_EVENT /home/bk/ * /sql/log_event.h`). The - corresponding version (`grep mysql, configure.in` in those trees) - strings are 5.2.2-a_drop6p13-alpha, 5.2.2-a_drop6p13c, - 5.1.5-a_drop5p20, 5.1.2-a_drop5p5. + The trees in which events have wrong id's are: + + mysql-5.1-wl1012.old mysql-5.1-wl2325-5.0-drop6p13-alpha + mysql-5.1-wl2325-5.0-drop6 mysql-5.1-wl2325-5.0 + mysql-5.1-wl2325-no-dd + + (this was found by grepping for two lines in sequence where the + first matches "FORMAT_DESCRIPTION_EVENT," and the second matches + "TABLE_MAP_EVENT," in log_event.h in all trees) + + In these trees, the following server_versions existed since + TABLE_MAP_EVENT was introduced: + + 5.1.1-a_drop5p3 5.1.1-a_drop5p4 5.1.1-alpha + 5.1.2-a_drop5p10 5.1.2-a_drop5p11 5.1.2-a_drop5p12 + 5.1.2-a_drop5p13 5.1.2-a_drop5p14 5.1.2-a_drop5p15 + 5.1.2-a_drop5p16 5.1.2-a_drop5p16b 5.1.2-a_drop5p16c + 5.1.2-a_drop5p17 5.1.2-a_drop5p4 5.1.2-a_drop5p5 + 5.1.2-a_drop5p6 5.1.2-a_drop5p7 5.1.2-a_drop5p8 + 5.1.2-a_drop5p9 5.1.3-a_drop5p17 5.1.3-a_drop5p17b + 5.1.3-a_drop5p17c 5.1.4-a_drop5p18 5.1.4-a_drop5p19 + 5.1.4-a_drop5p20 5.1.4-a_drop6p0 5.1.4-a_drop6p1 + 5.1.4-a_drop6p2 5.1.5-a_drop5p20 5.2.0-a_drop6p3 + 5.2.0-a_drop6p4 5.2.0-a_drop6p5 5.2.0-a_drop6p6 + 5.2.1-a_drop6p10 5.2.1-a_drop6p11 5.2.1-a_drop6p12 + 5.2.1-a_drop6p6 5.2.1-a_drop6p7 5.2.1-a_drop6p8 + 5.2.2-a_drop6p13 5.2.2-a_drop6p13-alpha 5.2.2-a_drop6p13b + 5.2.2-a_drop6p13c + + (this was found by grepping for "mysql," in all historical + versions of configure.in in the trees listed above). + + There are 5.1.1-alpha versions that use the new event id's, so we + do not test that version string. So replication from 5.1.1-alpha + with the other event id's to a new version does not work. + Moreover, we can safely ignore the part after drop[56]. This + allows us to simplify the big list above to the following regexes: + + 5\.1\.[1-5]-a_drop5.* + 5\.1\.4-a_drop6.* + 5\.2\.[0-2]-a_drop6.* + + This is what we test for in the 'if' below. */ if (post_header_len && - (strncmp(server_version, "5.1.2-a_drop5", 13) == 0 || - strncmp(server_version, "5.1.5-a_drop5", 13) == 0 || - strncmp(server_version, "5.2.2-a_drop6", 13) == 0)) + server_version[0] == '5' && server_version[1] == '.' && + server_version[3] == '.' && + strncmp(server_version + 5, "-a_drop", 7) == 0 && + ((server_version[2] == '1' && + server_version[4] >= '1' && server_version[4] <= '5' && + server_version[12] == '5') || + (server_version[2] == '1' && + server_version[4] == '4' && + server_version[12] == '6') || + (server_version[2] == '2' && + server_version[4] >= '0' && server_version[4] <= '2' && + server_version[12] == '6'))) { if (number_of_event_types != 22) { @@ -6026,7 +6095,8 @@ bool sql_ex_info::write_data(IO_CACHE* file) sql_ex_info::init() */ -char *sql_ex_info::init(char *buf, char *buf_end, bool use_new_format) +const char *sql_ex_info::init(const char *buf, const char *buf_end, + bool use_new_format) { cached_new_format = use_new_format; if (use_new_format) @@ -6039,12 +6109,11 @@ char *sql_ex_info::init(char *buf, char *buf_end, bool use_new_format) the case when we have old format because we will be reusing net buffer to read the actual file before we write out the Create_file event. */ - const char *ptr= buf; - if (read_str(&ptr, buf_end, (const char **) &field_term, &field_term_len) || - read_str(&ptr, buf_end, (const char **) &enclosed, &enclosed_len) || - read_str(&ptr, buf_end, (const char **) &line_term, &line_term_len) || - read_str(&ptr, buf_end, (const char **) &line_start, &line_start_len) || - read_str(&ptr, buf_end, (const char **) &escaped, &escaped_len)) + if (read_str(&buf, buf_end, &field_term, &field_term_len) || + read_str(&buf, buf_end, &enclosed, &enclosed_len) || + read_str(&buf, buf_end, &line_term, &line_term_len) || + read_str(&buf, buf_end, &line_start, &line_start_len) || + read_str(&buf, buf_end, &escaped, &escaped_len)) return 0; opt_flags = *buf++; } @@ -7646,7 +7715,7 @@ Rows_log_event::write_row(const Relay_log_info *const rli, /* fill table->record[0] with default values */ - if ((error= prepare_record(rli, table, m_width, + if ((error= prepare_record(table, m_width, TRUE /* check if columns have def. values */))) DBUG_RETURN(error); @@ -7964,13 +8033,17 @@ int Rows_log_event::find_row(const Relay_log_info *rli) DBUG_ASSERT(m_table && m_table->in_use != NULL); TABLE *table= m_table; - int error; + int error= 0; - /* unpack row - missing fields get default values */ - - // TODO: shall we check and report errors here? - prepare_record(NULL,table,m_width,FALSE /* don't check errors */); - error= unpack_current_row(rli); + /* + rpl_row_tabledefs.test specifies that + if the extra field on the slave does not have a default value + and this is okay with Delete or Update events. + Todo: fix wl3228 hld that requires defauls for all types of events + */ + + prepare_record(table, m_width, FALSE); + error= unpack_current_row(rli); #ifndef DBUG_OFF DBUG_PRINT("info",("looking for the following record")); @@ -8191,7 +8264,6 @@ int Rows_log_event::find_row(const Relay_log_info *rli) DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == HA_ERR_RECORD_DELETED || error == 0); goto err; } - ok: table->default_column_bitmaps(); DBUG_RETURN(0); diff --git a/sql/log_event.h b/sql/log_event.h index efb8675780e..4e151d6cde9 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -152,11 +152,11 @@ struct old_sql_ex struct sql_ex_info { sql_ex_info() {} /* Remove gcc warning */ - char* field_term; - char* enclosed; - char* line_term; - char* line_start; - char* escaped; + const char* field_term; + const char* enclosed; + const char* line_term; + const char* line_start; + const char* escaped; int cached_new_format; uint8 field_term_len,enclosed_len,line_term_len,line_start_len, escaped_len; char opt_flags; @@ -171,7 +171,7 @@ struct sql_ex_info line_start_len + escaped_len + 6 : 7); } bool write_data(IO_CACHE* file); - char* init(char* buf,char* buf_end,bool use_new_format); + const char* init(const char* buf, const char* buf_end, bool use_new_format); bool new_format() { return ((cached_new_format != -1) ? cached_new_format : @@ -667,34 +667,35 @@ typedef struct st_print_event_info @section Log_event_binary_format Binary Format - Any Log_event saved on disk consists of the following three + Any @c Log_event saved on disk consists of the following three components. - @li Common-Header - @li Post-Header - @li Body + * Common-Header + * Post-Header + * Body - The Common-Header, documented below, always has the same form and - length within one version of MySQL. Each event type specifies a - form and length of the Post-Header common to all events of the type. - The Body may be of different form and length even for different - events of the same type. The binary formats of Post-Header and Body - are documented separately in each subclass. The binary format of - Common-Header is as follows. + The Common-Header, documented in the table @ref Table_common_header + "below", always has the same form and length within one version of + MySQL. Each event type specifies a form and length of the + Post-Header common to all events of the type. The Body may be of + different form and length even for different events of the same + type. The binary formats of Post-Header and Body are documented + separately in each subclass. The binary format of Common-Header is + as follows. - + - @@ -705,14 +706,14 @@ typedef struct st_print_event_info - - + + - + @@ -720,9 +721,12 @@ typedef struct st_print_event_info - + @@ -736,13 +740,55 @@ typedef struct st_print_event_info Summing up the numbers above, we see that the total size of the common header is 19 bytes. - @subsection Log_event_endianness_and_string_formats Endianness and String Formats + @subsection Log_event_format_of_atomic_primitives Format of Atomic Primitives - All numbers, whether they are 16-, 32-, or 64-bit, are stored in - little endian, i.e., the least significant byte first. + - All numbers, whether they are 16-, 24-, 32-, or 64-bit numbers, + are stored in little endian, i.e., the least significant byte first, + unless otherwise specified. - Strings are stored in various formats. The format of each string is - documented separately. + @anchor packed_integer + - Some events use a special format for efficient representation of + unsigned integers, called Packed Integer. A Packed Integer has the + capacity of storing up to 8-byte integers, while small integers + still can use 1, 3, or 4 bytes. The first byte indicates how many + bytes are used by the integer, according to the following table: + +
Common-Header
NameFormat
Format Description
timestamp 4 byte unsigned integerThe number of seconds since 1970. + The time when the query started, in seconds since 1970.
master_id4 byte integerserver_id4 byte unsigned integer Server ID of the server that created the event.
total_size4 byte integer4 byte unsigned integer The total size of this event, in bytes. In other words, this is the sum of the sizes of Common-Header, Post-Header, and Body.
master_position4 byte integer4 byte unsigned integer The position of the next event in the master binary log, in - bytes from the beginning of the file. + bytes from the beginning of the file. In a binlog that is not a + relay log, this is just the position of the next event, in bytes + from the beginning of the file. In a relay log, this is + the position of the next event in the master's binlog.
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Format of Packed Integer
First byteFormat
0-250The first byte is the number (in range 0-250), and no more + bytes are used.
252Two more bytes are used. The number is in the range + 251-0xffff.
253Three more bytes are used. The number is in the range + 0xffff-0xffffff.
254Eight more bytes are used. The number is in the range + 0xffffff-0xffffffffffffffff.
+ + - Strings are stored in various formats. The format of each string + is documented separately. */ class Log_event { @@ -1123,7 +1169,8 @@ protected: /** @class Query_log_event - Logs SQL queries. + A @c Query_log_event is created for each query that modifies the + database, unless the query is logged row-based. @section Query_log_event_binary_format Binary format @@ -1134,60 +1181,49 @@ protected: Name - Size
+ Format Description slave_proxy_id 4 byte unsigned integer - An integer identifying the client thread, which is unique on - the server. (Note, however, that two threads on different servers - may have the same slave_proxy_id.) This is used when a client - thread creates a temporary table. Temporary tables are local to - the client, and the slave_proxy_id is used to distinguish - temporary tables belonging to different clients. + An integer identifying the client thread that issued the + query. The id is unique per server. (Note, however, that two + threads on different servers may have the same slave_proxy_id.) + This is used when a client thread creates a temporary table local + to the client. The slave_proxy_id is used to distinguish + temporary tables that belong to different clients. exec_time - 4 byte integer - ???TODO + 4 byte unsigned integer + The time from when the query started to when it was logged in + the binlog, in seconds. db_len 1 byte integer - The length of the name of the currently selected - database. - + The length of the name of the currently selected database. error_code - 2 byte integer + 2 byte unsigned integer Error code generated by the master. If the master fails, the slave will fail with the same error code, except for the error - codes ER_DB_CREATE_EXISTS==1007 and ER_DB_DROP_EXISTS==1008. + codes ER_DB_CREATE_EXISTS == 1007 and ER_DB_DROP_EXISTS == 1008. status_vars_len - 2 byte integer + 2 byte unsigned integer The length of the status_vars block of the Body, in bytes. See - below. - - - - - Post-Header-For-Derived - 0 bytes - This field is only written by the subclass - Execute_load_query_log_event. In this base class, it takes 0 - bytes. See separate documentation for - Execute_load_query_log_event. + @ref query_log_event_status_vars "below". @@ -1199,19 +1235,19 @@ protected: Name - Size
+ Format Description - status_vars - variable length + @anchor query_log_event_status_vars status_vars + status_vars_len bytes Zero or more status variables. Each status variable consists of one byte identifying the variable stored, followed by the value of the variable. The possible variables are listed separately in - the table below. MySQL always writes events in the order defined - below; however, it is capable of reading them in any order. - + the table @ref Table_query_log_event_status_vars "below". MySQL + always writes events in the order defined below; however, it is + capable of reading them in any order. @@ -1237,13 +1273,14 @@ protected: The following table lists the status variables that may appear in the status_vars field. + @anchor Table_query_log_event_status_vars - - + + @@ -1251,13 +1288,13 @@ protected: - - - + @@ -1327,7 +1364,7 @@ protected: @@ -1351,14 +1388,14 @@ protected: - + @@ -1409,14 +1446,14 @@ protected: - + @@ -1717,26 +1755,27 @@ private: - + - - + @@ -1773,7 +1812,7 @@ private: - + @@ -1813,7 +1852,7 @@ private:
  • In the old format, we know that each string has length 0 or 1. Therefore, only the first byte of each string is stored. The order of the strings is the same as in the new format. These five - bytes are followed by the same 1-byte bitfield as in the new + bytes are followed by the same 1 byte bitfield as in the new format. Finally, a 1 byte bitfield called empty_flags is stored. The low 5 bits of empty_flags indicate which of the five strings have length 0. For each of the following flags that is set, the @@ -1831,7 +1870,7 @@ private:
  • - + @@ -1992,11 +2031,13 @@ extern char server_version[SERVER_VERSION_LENGTH]; Start_log_event_v3 is the Start_log_event of binlog format 3 (MySQL 3.23 and 4.x). - Format_description_log_event derives from Start_log_event_v3; it is the - Start_log_event of binlog format 4 (MySQL 5.0), that is, the event that - describes the other events' header/postheader lengths. This event is sent by - MySQL 5.0 whenever it starts sending a new binlog if the requested position - is >4 (otherwise if ==4 the event will be sent naturally). + + Format_description_log_event derives from Start_log_event_v3; it is + the Start_log_event of binlog format 4 (MySQL 5.0), that is, the + event that describes the other events' Common-Header/Post-Header + lengths. This event is sent by MySQL 5.0 whenever it starts sending + a new binlog if the requested position is >4 (otherwise if ==4 the + event will be sent naturally). @section Start_log_event_v3_binary_format Binary Format */ @@ -2150,7 +2191,9 @@ protected: /** @class Intvar_log_event - Logs special variables related to auto_increment values. + An Intvar_log_event will be created just before a Query_log_event, + if the query uses one of the variables LAST_INSERT_ID or INSERT_ID. + Each Intvar_log_event holds the value of one of these variables. @section Intvar_log_event_binary_format Binary Format @@ -2161,12 +2204,12 @@ protected: - + - +
    Status variables for Query_log_event
    Status variable1-byte identifierSize
    1 byte identifierFormat Description
    flags2 Q_FLAGS2_CODE == 0 4 byte bitfieldThe flags in thd->options, binary AND-ed with - OPTIONS_WRITTEN_TO_BIN_LOG. The thd->options bitfield contains - options for SELECT. OPTIONS_WRITTEN identifies those options that - need to be written to the binlog (not all do). Specifically, - OPTIONS_WRITTEN_TO_BIN_LOG equals (OPTION_AUTO_IS_NULL | - OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_RELAXED_UNIQUE_CHECKS | - OPTION_NOT_AUTOCOMMIT), or 0x0c084000 in hex. + The flags in @c thd->options, binary AND-ed with @c + OPTIONS_WRITTEN_TO_BIN_LOG. The @c thd->options bitfield contains + options for "SELECT". @c OPTIONS_WRITTEN identifies those options + that need to be written to the binlog (not all do). Specifically, + @c OPTIONS_WRITTEN_TO_BIN_LOG equals (@c OPTION_AUTO_IS_NULL | @c + OPTION_NO_FOREIGN_KEY_CHECKS | @c OPTION_RELAXED_UNIQUE_CHECKS | + @c OPTION_NOT_AUTOCOMMIT), or 0x0c084000 in hex. These flags correspond to the SQL variables SQL_AUTO_IS_NULL, FOREIGN_KEY_CHECKS, UNIQUE_CHECKS, and AUTOCOMMIT, documented in @@ -1271,8 +1308,8 @@ protected:
    sql_mode Q_SQL_MODE_CODE == 18 byte integerThe sql_mode variable. See the section "SQL Modes" in the + 8 byte bitfieldThe @c sql_mode variable. See the section "SQL Modes" in the MySQL manual, and see mysql_priv.h for a list of the possible flags. Currently (2007-10-04), the following flags are available:
    @@ -1310,10 +1347,10 @@ protected:
         MODE_PAD_CHAR_TO_FULL_LENGTH==0x80000000
         
    All these flags are replicated from the server. However, all - flags except MODE_NO_DIR_IN_CREATE are honored by the slave; the - slave always preserves its old value of MODE_NO_DIR_IN_CREATE. - For a rationale, see comment in Query_log_event::do_apply_event in - log_event.cc. + flags except @c MODE_NO_DIR_IN_CREATE are honored by the slave; + the slave always preserves its old value of @c + MODE_NO_DIR_IN_CREATE. For a rationale, see comment in + @c Query_log_event::do_apply_event in @c log_event.cc. This field is always written to the binlog.
    Stores the client's current catalog. Every database belongs to a catalog, the same way that every table belongs to a - database. Currently, there is only one catalog, 'std'. + database. Currently, there is only one catalog, "std". This field is written if the length of the catalog is > 0; otherwise it is not written. @@ -1343,7 +1380,7 @@ protected: auto_increment_offset, in that order. For more information, see "System variables" in the MySQL manual. - This field is written if auto_increment>1; otherwise it is not + This field is written if auto_increment > 1. Otherwise, it is not written.
    charset Q_CHARSET_CODE == 4three 2-byte unsigned integers (i.e., 6 bytes)three 2 byte unsigned integers, totally 2+2+2=6 bytes The three variables character_set_client, collation_connection, and collation_server, in that order. - `character_set_client' is a code identifying the character set and + character_set_client is a code identifying the character set and collation used by the client to encode the query. - `collation_connection' identifies the character set and collation + collation_connection identifies the character set and collation that the master converts the query to when it receives it; this is - useful when comparing literal strings. `collation_server' is the + useful when comparing literal strings. collation_server is the default character set and collation used when a new database is created. @@ -1396,9 +1433,9 @@ protected: Q_LC_TIME_NAMES_CODE == 7 2 byte integer A code identifying a table of month and day names. The - mapping from codes to languages is defined in sql_locale.cc. + mapping from codes to languages is defined in @c sql_locale.cc. - This field is written if it is != 0, i.e., if the locale is not + This field is written if it is not 0, i.e., if the locale is not en_US.
    2 byte integer The value of the collation_database system variable (in the - source code stored in thd->variables.collation_database), which + source code stored in @c thd->variables.collation_database), which holds the code for a (character set, collation) pair as described above (see Q_CHARSET_CODE). - `collation_database' was used in old versions (???WHEN). Its - value was loaded when issuing a "use db" command and could be - changed by issuing a "SET collation_database=xxx" command. It - used to affect the "LOAD DATA INFILE" and "CREATE TABLE" commands. + collation_database was used in old versions (???WHEN). Its value + was loaded when issuing a "use db" query and could be changed by + issuing a "SET collation_database=xxx" query. It used to affect + the "LOAD DATA INFILE" and "CREATE TABLE" commands. In newer versions, "CREATE TABLE" has been changed to take the character set from the database of the created table, rather than @@ -1433,17 +1470,17 @@ protected: @subsection Query_log_event_notes_on_previous_versions Notes on Previous Versions - @li Status vars were introduced in version 5.0. To read earlier + * Status vars were introduced in version 5.0. To read earlier versions correctly, check the length of the Post-Header. - @li The status variable Q_CATALOG_CODE == 2 existed in MySQL 5.0.x, + * The status variable Q_CATALOG_CODE == 2 existed in MySQL 5.0.x, where 0<=x<=3. It was identical to Q_CATALOG_CODE, except that the string had a trailing '\0'. The '\0' was removed in 5.0.4 since it was redundant (the string length is stored before the string). The Q_CATALOG_CODE will never be written by a new master, but can still be understood by a new slave. - @li See Q_CHARSET_DATABASE_NUMBER in the table above. + * See Q_CHARSET_DATABASE_NUMBER in the table above. */ class Query_log_event: public Log_event @@ -1576,7 +1613,8 @@ public: /* !!! Public in this patch to allow old usage */ /** @class Muted_query_log_event - Pretends to log SQL queries, but doesn't actually do so. + Pretends to log SQL queries, but doesn't actually do so. This is + used internally only and never written to any binlog. @section Muted_query_log_event_binary_format Binary Format @@ -1603,7 +1641,7 @@ public: @class Slave_log_event Note that this class is currently not used at all; no code writes a - Slave_log_event (though some code in repl_failsafe.cc reads + @c Slave_log_event (though some code in @c repl_failsafe.cc reads @c Slave_log_event). So it's not a problem if this code is not maintained. @@ -1617,7 +1655,7 @@ public:
    NameSize
    Format Description
    NameSize
    Format Description
    slave_proxy_id 4 byte unsigned integerAn integer identifying the client thread, which is unique on - the server. (Note, however, that the same slave_proxy_id may - appear on different servers.) This is used when a client thread - creates a temporary table. Temporary tables are local to the - client, and the slave_proxy_id is used to distinguish temporary - tables belonging to different clients. + An integer identifying the client thread that issued the + query. The id is unique per server. (Note, however, that two + threads on different servers may have the same slave_proxy_id.) + This is used when a client thread creates a temporary table local + to the client. The slave_proxy_id is used to distinguish + temporary tables that belong to different clients.
    exec_time 4 byte unsigned integer???TODOThe time from when the query started to when it was logged in + the binlog, in seconds.
    NameSize
    Format Description
    field_lensnum_fields 1-byte unsigned integersnum_fields 1 byte unsigned integers An array of num_fields integers representing the length of each field in the query. (num_fields is from the Post-Header).
    NameSize
    Format Description
    Typetype 1 byte enumeration One byte identifying the type of variable stored. Currently, two identifiers are supported: LAST_INSERT_ID_EVENT==1 and @@ -2182,7 +2225,6 @@ protected:
    */ - class Intvar_log_event: public Log_event { public: @@ -2228,15 +2270,34 @@ private: written in 4.1.1 for PASSWORD() (but the fact that it is written is just a waste, it does not cause bugs). + The state of the random number generation consists of 128 bits, + which are stored internally as two 64-bit numbers. + @section Rand_log_event_binary_format Binary Format This event type has no Post-Header. The Body of this event type has two components: - @li seed1 (8 bytes): 64 bit random seed1. - @li seed2 (8 bytes): 64 bit random seed2. + + - The state of the random number generation consists of 128 bits, - which are stored internally as two 64-bit numbers. + + + + + + + + + + + + + + + + + +
    Post-Header for Intvar_log_event
    NameFormatDescription
    seed18 byte unsigned integer64 bit random seed1.
    seed28 byte unsigned integer64 bit random seed2.
    */ class Rand_log_event: public Log_event @@ -2423,14 +2484,14 @@ private: Name - Size
    + Format Description - pos + position 8 byte integer - ???TODO + The position within the binlog to rotate to. @@ -2442,17 +2503,17 @@ private: Name - Size
    + Format Description - new_log_ident + new_log variable length string without trailing zero, extending to the end of the event (determined by the length field of the Common-Header) - ???TODO + Name of the binlog to rotate to. @@ -2841,10 +2902,316 @@ char *str_to_hex(char *to, const char *from, uint len); /** @class Table_map_log_event - Create a mapping from a (database name, table name) couple to a table - identifier (an integer number). + In row-based mode, every row operation event is preceded by a + Table_map_log_event which maps a table definition to a number. The + table definition consists of database name, table name, and column + definitions. @section Table_map_log_event_binary_format Binary Format + + The Post-Header has the following components: + + + + + + + + + + + + + + + + + + + + + + +
    Post-Header for Table_map_log_event
    NameFormatDescription
    table_id6 bytes unsigned integerThe number that identifies the table.
    flags2 byte bitfieldReserved for future use; currently always 0.
    + + The Body has the following components: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Body for Table_map_log_event
    NameFormatDescription
    database_nameone byte string length, followed by null-terminated stringThe name of the database in which the table resides. The name + is represented as a one byte unsigned integer representing the + number of bytes in the name, followed by length bytes containing + the database name, followed by a terminating 0 byte. (Note the + redundancy in the representation of the length.)
    table_nameone byte string length, followed by null-terminated stringThe name of the table, encoded the same way as the database + name above.
    column_count@ref packed_integer "Packed Integer"The number of columns in the table, represented as a packed + variable-length integer.
    column_typeList of column_count 1 byte enumeration valuesThe type of each column in the table, listed from left to + right. Each byte is mapped to a column type according to the + enumeration type enum_field_types defined in mysql_com.h. The + mapping of types to numbers is listed in the table @ref + Table_table_map_log_event_column_types "below" (along with + description of the associated metadata field).
    metadata_length@ref packed_integer "Packed Integer"The length of the following metadata block
    metadatalist of metadata for each columnFor each column from left to right, a chunk of data who's + length and semantics depends on the type of the column. The + length and semantics for the metadata for each column are listed + in the table @ref Table_table_map_log_event_column_types + "below".
    null_bitscolumn_count bits, rounded up to nearest byteFor each column, a bit indicating whether data in the column + can be NULL or not. The number of bytes needed for this is + int((column_count+7)/8). The flag for the first column from the + left is in the least-significant bit of the first byte, the second + is in the second least significant bit of the first byte, the + ninth is in the least significant bit of the second byte, and so + on.
    + + The table below lists all column types, along with the numerical + identifier for it and the size and interpretation of meta-data used + to describe the type. + + @anchor Table_table_map_log_event_column_types + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Table_map_log_event column types: numerical identifier and + metadata
    NameIdentifierSize of metadata in bytesDescription of metadata
    MYSQL_TYPE_DECIMAL00No column metadata.
    MYSQL_TYPE_TINY10No column metadata.
    MYSQL_TYPE_SHORT20No column metadata.
    MYSQL_TYPE_LONG30No column metadata.
    MYSQL_TYPE_FLOAT41 byte1 byte unsigned integer, representing the "pack_length", which + is equal to sizeof(float) on the server from which the event + originates.
    MYSQL_TYPE_DOUBLE51 byte1 byte unsigned integer, representing the "pack_length", which + is equal to sizeof(double) on the server from which the event + originates.
    MYSQL_TYPE_NULL60No column metadata.
    MYSQL_TYPE_TIMESTAMP70No column metadata.
    MYSQL_TYPE_LONGLONG80No column metadata.
    MYSQL_TYPE_INT2490No column metadata.
    MYSQL_TYPE_DATE100No column metadata.
    MYSQL_TYPE_TIME110No column metadata.
    MYSQL_TYPE_DATETIME120No column metadata.
    MYSQL_TYPE_YEAR130No column metadata.
    MYSQL_TYPE_NEWDATE14This enumeration value is only used internally and cannot + exist in a binlog.
    MYSQL_TYPE_VARCHAR152 bytes2 byte unsigned integer representing the maximum length of + the string.
    MYSQL_TYPE_BIT162 bytesA 1 byte unsigned int representing the length in bits of the + bitfield (0 to 64), followed by a 1 byte unsigned int + representing the number of bytes occupied by the bitfield. The + number of bytes is either int((length+7)/8) or int(length/8).
    MYSQL_TYPE_NEWDECIMAL2462 bytesA 1 byte unsigned int representing the precision, followed + by a 1 byte unsigned int representing the number of decimals.
    MYSQL_TYPE_ENUM247This enumeration value is only used internally and cannot + exist in a binlog.
    MYSQL_TYPE_SET248This enumeration value is only used internally and cannot + exist in a binlog.
    MYSQL_TYPE_TINY_BLOB249This enumeration value is only used internally and cannot + exist in a binlog.
    MYSQL_TYPE_MEDIUM_BLOB250This enumeration value is only used internally and cannot + exist in a binlog.
    MYSQL_TYPE_LONG_BLOB251This enumeration value is only used internally and cannot + exist in a binlog.
    MYSQL_TYPE_BLOB2521 byteThe pack length, i.e., the number of bytes needed to represent + the length of the blob: 1, 2, 3, or 4.
    MYSQL_TYPE_VAR_STRING2532 bytesThis is used to store both strings and enumeration values. + The first byte is a enumeration value storing the real + type, which may be either MYSQL_TYPE_VAR_STRING or + MYSQL_TYPE_ENUM. The second byte is a 1 byte unsigned integer + representing the field size, i.e., the number of bytes needed to + store the length of the string.
    MYSQL_TYPE_STRING2542 bytesThe first byte is always MYSQL_TYPE_VAR_STRING (i.e., 253). + The second byte is the field size, i.e., the number of bytes in + the representation of size of the string: 3 or 4.
    MYSQL_TYPE_GEOMETRY2551 byteThe pack length, i.e., the number of bytes needed to represent + the length of the geometry: 1, 2, 3, or 4.
    */ class Table_map_log_event : public Log_event { @@ -3131,6 +3498,8 @@ protected: ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT); int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, &m_curr_row_end, &m_master_reclength); + if (m_curr_row_end > m_rows_end) + my_error(ER_SLAVE_CORRUPT_EVENT, MYF(0)); ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT); return result; } @@ -3408,7 +3777,7 @@ protected: Incident event format Symbol - Size
    (bytes) + Format Description diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 7621bdc6291..13f9763debe 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -2078,7 +2078,7 @@ Old_rows_log_event::write_row(const Relay_log_info *const rli, /* fill table->record[0] with default values */ - if ((error= prepare_record(rli, table, m_width, + if ((error= prepare_record(table, m_width, TRUE /* check if columns have def. values */))) DBUG_RETURN(error); @@ -2289,7 +2289,7 @@ int Old_rows_log_event::find_row(const Relay_log_info *rli) /* unpack row - missing fields get default values */ // TODO: shall we check and report errors here? - prepare_record(NULL,table,m_width,FALSE /* don't check errors */); + prepare_record(table, m_width, FALSE /* don't check errors */); error= unpack_current_row(rli); #ifndef DBUG_OFF diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f5ccbfffa0d..8cb98573103 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1873,9 +1873,9 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache) /* It's safe to broadcast outside a lock (COND... is not deleted here) */ DBUG_PRINT("signal", ("Broadcasting COND_thread_count")); + my_thread_end(); (void) pthread_cond_broadcast(&COND_thread_count); - my_thread_end(); pthread_exit(0); DBUG_RETURN(0); // Impossible } diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index eb32897f937..7c74dcba5a0 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -307,17 +307,15 @@ unpack_row(Relay_log_info const *rli, If @c check is true, fields are explicitly initialized only if they have default value or can be NULL. Otherwise error is reported. - @param log Used to report errors. @param table Table whose record[0] buffer is prepared. @param skip Number of columns for which default value initialization should be skipped. @param check Indicates if errors should be checked when setting default values. - @returns 0 on success. + @returns 0 on success or a handler level error code */ -int prepare_record(const Slave_reporting_capability *const log, - TABLE *const table, +int prepare_record(TABLE *const table, const uint skip, const bool check) { DBUG_ENTER("prepare_record"); @@ -337,14 +335,8 @@ int prepare_record(const Slave_reporting_capability *const log, if (check && ((f->flags & mask) == mask)) { - DBUG_ASSERT(log); - error= ER_NO_DEFAULT_FOR_FIELD; - log->report(ERROR_LEVEL, error, - "Field `%s` of table `%s`.`%s` " - "has no default value and cannot be NULL", - f->field_name, table->s->db.str, - table->s->table_name.str); - my_error(error, MYF(0), f->field_name); + my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), f->field_name); + error = HA_ERR_ROWS_EVENT_APPLY; } else f->set_default(); diff --git a/sql/rpl_record.h b/sql/rpl_record.h index 0d6ceda7433..f9e64f0ab1d 100644 --- a/sql/rpl_record.h +++ b/sql/rpl_record.h @@ -30,8 +30,7 @@ int unpack_row(Relay_log_info const *rli, uchar const **const row_end, ulong *const master_reclength); // Fill table's record[0] with default values. -int prepare_record(const Slave_reporting_capability *const, TABLE *const, - const uint =0, const bool =FALSE); +int prepare_record(TABLE *const, const uint =0, const bool =FALSE); #endif #endif diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 026a0023660..ee3a7e6080a 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6119,3 +6119,5 @@ ER_SLAVE_AMBIGOUS_EXEC_MODE ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT eng "The BINLOG statement of type `%s` was not preceded by a format description BINLOG statement." +ER_SLAVE_CORRUPT_EVENT + eng "Corrupted replication event was detected" diff --git a/sql/slave.cc b/sql/slave.cc index 9dd52c60dad..ea0dde942da 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1337,14 +1337,15 @@ bool show_master_info(THD* thd, Master_info* mi) protocol->prepare_for_resend(); /* - TODO: we read slave_running without run_lock, whereas these variables - are updated under run_lock and not data_lock. In 5.0 we should lock - run_lock on top of data_lock (with good order). + slave_running can be accessed without run_lock but not other + non-volotile members like mi->io_thd, which is guarded by the mutex. */ + pthread_mutex_lock(&mi->run_lock); + protocol->store(mi->io_thd ? mi->io_thd->proc_info : "", &my_charset_bin); + pthread_mutex_unlock(&mi->run_lock); + pthread_mutex_lock(&mi->data_lock); pthread_mutex_lock(&mi->rli.data_lock); - - protocol->store(mi->io_thd ? mi->io_thd->proc_info : "", &my_charset_bin); protocol->store(mi->host, &my_charset_bin); protocol->store(mi->user, &my_charset_bin); protocol->store((uint32) mi->port); diff --git a/sql/slave.h b/sql/slave.h index f1772bbc1fc..b4f1b7f7467 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -80,8 +80,8 @@ class Master_info; mi->rli does not either. In Master_info: run_lock, data_lock - run_lock protects all information about the run state: slave_running, and the - existence of the I/O thread (to stop/start it, you need this mutex). + run_lock protects all information about the run state: slave_running, thd + and the existence of the I/O thread to stop/start it, you need this mutex). data_lock protects some moving members of the struct: counters (log name, position) and relay log (MYSQL_BIN_LOG object). diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index f1fbe6eb4b7..462806ab10d 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -155,14 +155,13 @@ void mysql_client_binlog_statement(THD* thd) */ if (!have_fd_event) { - if (bufptr[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT) + int type = bufptr[EVENT_TYPE_OFFSET]; + if (type == FORMAT_DESCRIPTION_EVENT || type == START_EVENT_V3) have_fd_event= TRUE; else { my_error(ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT, - MYF(0), - Log_event::get_type_str( - (Log_event_type)bufptr[EVENT_TYPE_OFFSET])); + MYF(0), Log_event::get_type_str((Log_event_type)type)); goto end; } } @@ -235,6 +234,7 @@ void mysql_client_binlog_statement(THD* thd) send_ok(thd); end: + thd->rli_fake->clear_tables_to_lock(); my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); DBUG_VOID_RETURN; } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 351e5e8aae8..461a59425d4 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -871,7 +871,10 @@ THD::~THD() #endif #ifndef EMBEDDED_LIBRARY if (rli_fake) + { delete rli_fake; + rli_fake= NULL; + } #endif free_root(&main_mem_root, MYF(0)); diff --git a/storage/ndb/include/kernel/ndb_limits.h b/storage/ndb/include/kernel/ndb_limits.h index 682f904d99a..9a9521e82ef 100644 --- a/storage/ndb/include/kernel/ndb_limits.h +++ b/storage/ndb/include/kernel/ndb_limits.h @@ -28,6 +28,17 @@ #define MAX_NODES 64 #define UNDEF_NODEGROUP 0xFFFF +/************************************************************************** + * IT SHOULD BE (MAX_NDB_NODES - 1). + * WHEN MAX_NDB_NODE IS CHANGED, IT SHOULD BE CHANGED ALSO + **************************************************************************/ +#define MAX_DATA_NODE_ID 48 +/************************************************************************** + * IT SHOULD BE (MAX_NODES - 1). + * WHEN MAX_NODES IS CHANGED, IT SHOULD BE CHANGED ALSO + **************************************************************************/ +#define MAX_NODES_ID 63 + /** * MAX_API_NODES = MAX_NODES - No of NDB Nodes in use */ diff --git a/storage/ndb/include/kernel/signaldata/CreateFilegroupImpl.hpp b/storage/ndb/include/kernel/signaldata/CreateFilegroupImpl.hpp index 6140e78cc5a..bbd3e818681 100644 --- a/storage/ndb/include/kernel/signaldata/CreateFilegroupImpl.hpp +++ b/storage/ndb/include/kernel/signaldata/CreateFilegroupImpl.hpp @@ -163,7 +163,8 @@ struct CreateFileImplRef { InvalidFileMetadata = 1510, OutOfMemory = 1511, FileReadError = 1512, - FilegroupNotOnline = 1513 + FilegroupNotOnline = 1513, + FileSizeTooLarge = 1515 }; Uint32 senderData; diff --git a/storage/ndb/include/mgmapi/ndb_logevent.h b/storage/ndb/include/mgmapi/ndb_logevent.h index 6640b4a46e8..70691f6fd28 100644 --- a/storage/ndb/include/mgmapi/ndb_logevent.h +++ b/storage/ndb/include/mgmapi/ndb_logevent.h @@ -553,7 +553,13 @@ extern "C" { /** Log event specific data for for corresponding NDB_LE_ log event */ struct { int gth; - unsigned page_size_kb; + /* union is for compatibility backward. + * page_size_kb member variable should be removed in the future + */ + union { + unsigned page_size_kb; + unsigned page_size_bytes; + }; unsigned pages_used; unsigned pages_total; unsigned block; diff --git a/storage/ndb/include/ndbapi/Ndb.hpp b/storage/ndb/include/ndbapi/Ndb.hpp index dca19c2ead0..f31638db283 100644 --- a/storage/ndb/include/ndbapi/Ndb.hpp +++ b/storage/ndb/include/ndbapi/Ndb.hpp @@ -1515,37 +1515,40 @@ public: TupleIdRange() {} Uint64 m_first_tuple_id; Uint64 m_last_tuple_id; + Uint64 m_highest_seen; void reset() { m_first_tuple_id = ~(Uint64)0; m_last_tuple_id = ~(Uint64)0; + m_highest_seen = 0; }; }; int initAutoIncrement(); int getAutoIncrementValue(const char* aTableName, - Uint64 & tupleId, Uint32 cacheSize, + Uint64 & autoValue, Uint32 cacheSize, Uint64 step = 1, Uint64 start = 1); int getAutoIncrementValue(const NdbDictionary::Table * aTable, - Uint64 & tupleId, Uint32 cacheSize, + Uint64 & autoValue, Uint32 cacheSize, Uint64 step = 1, Uint64 start = 1); int getAutoIncrementValue(const NdbDictionary::Table * aTable, - TupleIdRange & range, Uint64 & tupleId, + TupleIdRange & range, Uint64 & autoValue, Uint32 cacheSize, Uint64 step = 1, Uint64 start = 1); int readAutoIncrementValue(const char* aTableName, - Uint64 & tupleId); + Uint64 & autoValue); int readAutoIncrementValue(const NdbDictionary::Table * aTable, - Uint64 & tupleId); + Uint64 & autoValue); int readAutoIncrementValue(const NdbDictionary::Table * aTable, - TupleIdRange & range, Uint64 & tupleId); + TupleIdRange & range, Uint64 & autoValue); int setAutoIncrementValue(const char* aTableName, - Uint64 tupleId, bool increase); + Uint64 autoValue, bool modify); int setAutoIncrementValue(const NdbDictionary::Table * aTable, - Uint64 tupleId, bool increase); + Uint64 autoValue, bool modify); int setAutoIncrementValue(const NdbDictionary::Table * aTable, - TupleIdRange & range, Uint64 tupleId, - bool increase); + TupleIdRange & range, Uint64 autoValue, + bool modify); + bool checkUpdateAutoIncrementValue(TupleIdRange & range, Uint64 autoValue); private: int getTupleIdFromNdb(const NdbTableImpl* table, TupleIdRange & range, Uint64 & tupleId, @@ -1553,7 +1556,9 @@ private: int readTupleIdFromNdb(const NdbTableImpl* table, TupleIdRange & range, Uint64 & tupleId); int setTupleIdInNdb(const NdbTableImpl* table, - TupleIdRange & range, Uint64 tupleId, bool increase); + TupleIdRange & range, Uint64 tupleId, bool modify); + int checkTupleIdInNdb(TupleIdRange & range, + Uint64 tupleId); int opTupleIdOnNdb(const NdbTableImpl* table, TupleIdRange & range, Uint64 & opValue, Uint32 op); public: diff --git a/storage/ndb/include/ndbapi/ndbapi_limits.h b/storage/ndb/include/ndbapi/ndbapi_limits.h index e283913d059..98551866edc 100644 --- a/storage/ndb/include/ndbapi/ndbapi_limits.h +++ b/storage/ndb/include/ndbapi/ndbapi_limits.h @@ -26,6 +26,7 @@ #define NDB_MAX_TUPLE_SIZE (NDB_MAX_TUPLE_SIZE_IN_WORDS*4) #define NDB_MAX_ACTIVE_EVENTS 100 -#define NDB_MAX_SCANFILTER_SIZE_IN_WORDS 50000 +/* TUP ZATTR_BUFFER_SIZE 16384 (minus 1) minus place for getValue()s */ +#define NDB_MAX_SCANFILTER_SIZE_IN_WORDS (16384 - 1 - 1024) #endif diff --git a/storage/ndb/include/util/Bitmask.hpp b/storage/ndb/include/util/Bitmask.hpp index de47b79d393..d1663b7c76d 100644 --- a/storage/ndb/include/util/Bitmask.hpp +++ b/storage/ndb/include/util/Bitmask.hpp @@ -139,6 +139,7 @@ public: /** * setField - Set bitfield at given position and length (max 32 bits) + * Note : length == 0 not supported. */ static void setField(unsigned size, Uint32 data[], unsigned pos, unsigned len, Uint32 val); @@ -146,6 +147,7 @@ public: /** * getField - Get bitfield at given position and length + * Note : length == 0 not supported. */ static void getField(unsigned size, const Uint32 data[], unsigned pos, unsigned len, Uint32 dst[]); @@ -918,7 +920,10 @@ BitmaskImpl::getField(unsigned size, const Uint32 src[], unsigned pos, unsigned len, Uint32 dst[]) { assert(pos + len <= (size << 5)); - + assert (len != 0); + if (len == 0) + return; + src += (pos >> 5); Uint32 offset = pos & 31; * dst = (* src >> offset) & (len >= 32 ? ~0 : (1 << len) - 1); @@ -937,6 +942,9 @@ BitmaskImpl::setField(unsigned size, Uint32 dst[], unsigned pos, unsigned len, const Uint32 src[]) { assert(pos + len <= (size << 5)); + assert(len != 0); + if (len == 0) + return; dst += (pos >> 5); Uint32 offset = pos & 31; diff --git a/storage/ndb/src/common/debugger/SignalLoggerManager.cpp b/storage/ndb/src/common/debugger/SignalLoggerManager.cpp index 471bea64f64..48cacb6bc1a 100644 --- a/storage/ndb/src/common/debugger/SignalLoggerManager.cpp +++ b/storage/ndb/src/common/debugger/SignalLoggerManager.cpp @@ -129,7 +129,7 @@ SignalLoggerManager::log(LogMode logMode, const char * params) const int count = getParameter(blocks, "BLOCK=", params); int cnt = 0; - if((count == 1 && blocks[0] == "ALL") || + if((count == 1 && !strcmp(blocks[0], "ALL")) || count == 0){ for (int number = 0; number < NO_OF_BLOCKS; ++number){ diff --git a/storage/ndb/src/common/debugger/signaldata/ScanTab.cpp b/storage/ndb/src/common/debugger/signaldata/ScanTab.cpp index 9668c9d0605..4f6b69ebfba 100644 --- a/storage/ndb/src/common/debugger/signaldata/ScanTab.cpp +++ b/storage/ndb/src/common/debugger/signaldata/ScanTab.cpp @@ -70,7 +70,7 @@ printSCANTABCONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 recei sig->transId1, sig->transId2); fprintf(output, " requestInfo: Eod: %d OpCount: %d\n", - (requestInfo & ScanTabConf::EndOfData == ScanTabConf::EndOfData), + (requestInfo & ScanTabConf::EndOfData) == ScanTabConf::EndOfData, (requestInfo & (~ScanTabConf::EndOfData))); size_t op_count= requestInfo & (~ScanTabConf::EndOfData); if(op_count){ diff --git a/storage/ndb/src/common/transporter/TCP_Transporter.cpp b/storage/ndb/src/common/transporter/TCP_Transporter.cpp index 298e43710b0..8b386483bff 100644 --- a/storage/ndb/src/common/transporter/TCP_Transporter.cpp +++ b/storage/ndb/src/common/transporter/TCP_Transporter.cpp @@ -317,22 +317,32 @@ TCP_Transporter::doSend() { // Empty the SendBuffers - const char * const sendPtr = m_sendBuffer.sendPtr; - const Uint32 sizeToSend = m_sendBuffer.sendDataSize; - if (sizeToSend > 0){ + bool sent_any = true; + while (m_sendBuffer.dataSize > 0) + { + const char * const sendPtr = m_sendBuffer.sendPtr; + const Uint32 sizeToSend = m_sendBuffer.sendDataSize; const int nBytesSent = send(theSocket, sendPtr, sizeToSend, 0); - if (nBytesSent > 0) { + if (nBytesSent > 0) + { + sent_any = true; m_sendBuffer.bytesSent(nBytesSent); sendCount ++; sendSize += nBytesSent; - if(sendCount == reportFreq){ + if(sendCount == reportFreq) + { reportSendLen(get_callback_obj(), remoteNodeId, sendCount, sendSize); sendCount = 0; sendSize = 0; } - } else { + } + else + { + if (nBytesSent < 0 && InetErrno == EAGAIN && sent_any) + break; + // Send failed #if defined DEBUG_TRANSPORTER g_eventLogger.error("Send Failure(disconnect==%d) to node = %d nBytesSent = %d " diff --git a/storage/ndb/src/common/util/Bitmask.cpp b/storage/ndb/src/common/util/Bitmask.cpp index edfe2363039..22919fe585a 100644 --- a/storage/ndb/src/common/util/Bitmask.cpp +++ b/storage/ndb/src/common/util/Bitmask.cpp @@ -20,28 +20,59 @@ void BitmaskImpl::getFieldImpl(const Uint32 src[], unsigned shiftL, unsigned len, Uint32 dst[]) { + /* Copy whole words of src to dst, shifting src left + * by shiftL. Undefined bits of the last written dst word + * should be zeroed. + */ assert(shiftL < 32); unsigned shiftR = 32 - shiftL; unsigned undefined = shiftL ? ~0 : 0; + /* Merge first word with previously set bits if there's a shift */ * dst = shiftL ? * dst : 0; - - while(len >= 32) + + /* Treat the zero-shift case separately to avoid + * trampling or reading past the end of src + */ + if (shiftL == 0) { - * dst++ |= (* src) << shiftL; - * dst = ((* src++) >> shiftR) & undefined; - len -= 32; + while(len >= 32) + { + * dst++ = * src++; + len -=32; + } + + if (len != 0) + { + /* Last word has some bits set */ + Uint32 mask= ((1 << len) -1); // 0000111 + * dst = (* src) & mask; + } } - - if(len < shiftR) + else // shiftL !=0, need to build each word from two words shifted { - * dst |= ((* src) & ((1 << len) - 1)) << shiftL; - } - else - { - * dst++ |= ((* src) << shiftL); - * dst = ((* src) >> shiftR) & ((1 << (len - shiftR)) - 1) & undefined; + while(len >= 32) + { + * dst++ |= (* src) << shiftL; + * dst = ((* src++) >> shiftR) & undefined; + len -= 32; + } + + /* Have space for shiftR more bits in the current dst word + * is that enough? + */ + if(len <= shiftR) + { + /* Fit the remaining bits in the current dst word */ + * dst |= ((* src) & ((1 << len) - 1)) << shiftL; + } + else + { + /* Need to write to two dst words */ + * dst++ |= ((* src) << shiftL); + * dst = ((* src) >> shiftR) & ((1 << (len - shiftR)) - 1) & undefined; + } } } @@ -64,370 +95,23 @@ BitmaskImpl::setFieldImpl(Uint32 dst[], len -= 32; } + /* Copy last bits */ Uint32 mask = ((1 << len) -1); * dst = (* dst & ~mask); - if(len < shiftR) + if(len <= shiftR) { + /* Remaining bits fit in current word */ * dst |= ((* src++) >> shiftL) & mask; } else { + /* Remaining bits update 2 words */ * dst |= ((* src++) >> shiftL); * dst |= ((* src) & ((1 << (len - shiftR)) - 1)) << shiftR ; } } -#ifdef __TEST_BITMASK__ -static -void print(const Uint32 src[], Uint32 len, Uint32 pos = 0) -{ - printf("b'"); - for(unsigned i = 0; i> 5, src, i+pos)) - printf("1"); - else - printf("0"); - if((i & 31) == 31) - printf(" "); - } -} - - -#define DEBUG 0 -#include -static void do_test(int bitmask_size); - -int -main(int argc, char** argv) -{ - int loops = argc > 1 ? atoi(argv[1]) : 1000; - int max_size = argc > 2 ? atoi(argv[2]) : 1000; - - - for(int i = 0; i data; -}; - -static void require(bool b) -{ - if(!b) abort(); -} - -static -bool cmp(const Uint32 b1[], const Uint32 b2[], Uint32 len) -{ - Uint32 sz32 = (len + 31) >> 5; - for(int i = 0; i> 5, dst, i, (lrand() % 1000) > 500); -} - -static -void simple(int pos, int size) -{ - ndbout_c("simple pos: %d size: %d", pos, size); - Vector _mask; - Vector _src; - Vector _dst; - Uint32 sz32 = (size + pos + 32) >> 5; - const Uint32 sz = 4 * sz32; - - Uint32 zero = 0; - _mask.fill(sz32+1, zero); - _src.fill(sz32+1, zero); - _dst.fill(sz32+1, zero); - - Uint32 * src = _src.getBase(); - Uint32 * dst = _dst.getBase(); - Uint32 * mask = _mask.getBase(); - - memset(src, 0x0, sz); - memset(dst, 0x0, sz); - memset(mask, 0xFF, sz); - rand(src, size); - BitmaskImpl::setField(sz32, mask, pos, size, src); - BitmaskImpl::getField(sz32, mask, pos, size, dst); - printf("src: "); print(src, size+31); printf("\n"); - printf("msk: "); print(mask, (sz32 << 5) + 31); printf("\n"); - printf("dst: "); print(dst, size+31); printf("\n"); - require(cmp(src, dst, size+31)); -}; - -static -void simple2(int size, int loops) -{ - ndbout_c("simple2 %d - ", size); - Vector _mask; - Vector _src; - Vector _dst; - - Uint32 sz32 = (size + 32) >> 5; - Uint32 sz = sz32 << 2; - - Uint32 zero = 0; - _mask.fill(sz32+1, zero); - _src.fill(sz32+1, zero); - _dst.fill(sz32+1, zero); - - Uint32 * src = _src.getBase(); - Uint32 * dst = _dst.getBase(); - Uint32 * mask = _mask.getBase(); - - Vector save; - for(int i = 0; i alloc_list; - bitmask_size = (bitmask_size + 31) & ~31; - Uint32 sz32 = (bitmask_size >> 5); - Vector alloc_mask; - Vector test_mask; - - ndbout_c("Testing bitmask of size %d", bitmask_size); - Uint32 zero = 0; - alloc_mask.fill(sz32, zero); - test_mask.fill(sz32, zero); - - for(int i = 0; i<5000; i++) - { - Vector tmp; - tmp.fill(sz32, zero); - - int pos = lrand() % (bitmask_size - 1); - int free = 0; - if(BitmaskImpl::get(sz32, alloc_mask.getBase(), pos)) - { - // Bit was allocated - // 1) Look up allocation - // 2) Check data - // 3) free it - size_t j; - int min, max; - for(j = 0; j= min && pos < max) - { - break; - } - } - require(pos >= min && pos < max); - BitmaskImpl::getField(sz32, test_mask.getBase(), min, max-min, - tmp.getBase()); - if(DEBUG) - { - printf("freeing [ %d %d ]", min, max); - printf("- mask: "); - print(tmp.getBase(), max - min); - - printf(" save: "); - size_t k; - Alloc& a = alloc_list[j]; - for(k = 0; k> 3; - if(!cmp(tmp.getBase(), alloc_list[j].data.getBase(), max - min)) - { - abort(); - } - while(min < max) - BitmaskImpl::clear(sz32, alloc_mask.getBase(), min++); - alloc_list.erase(j); - } - else - { - Vector tmp; - tmp.fill(sz32, zero); - - // Bit was free - // 1) Check how much space is avaiable - // 2) Create new allocation of lrandom size - // 3) Fill data with lrandom data - // 4) Update alloc mask - while(pos+free < bitmask_size && - !BitmaskImpl::get(sz32, alloc_mask.getBase(), pos+free)) - free++; - - Uint32 sz = - (free <= 64 && ((lrand() % 100) > 80)) ? free : (lrand() % free); - sz = sz ? sz : 1; - sz = pos + sz == bitmask_size ? sz - 1 : sz; - Alloc a; - a.pos = pos; - a.size = sz; - a.data.fill(((sz+31)>> 5)-1, zero); - if(DEBUG) - printf("pos %d -> alloc [ %d %d ]", pos, pos, pos+sz); - for(size_t j = 0; j 500) - BitmaskImpl::set((sz + 31) >> 5, a.data.getBase(), j); - } - if(DEBUG) - { - printf("- mask: "); - print(a.data.getBase(), sz); - printf("\n"); - } - BitmaskImpl::setField(sz32, test_mask.getBase(), pos, sz, - a.data.getBase()); - alloc_list.push_back(a); - } - } - - for(Uint32 i = 0; i<1000; i++) - { - Uint32 sz32 = 10+rand() % 100; - Uint32 zero = 0; - Vector map; - map.fill(sz32, zero); - - Uint32 sz = 32 * sz32; - Uint32 start = (rand() % sz); - Uint32 stop = start + ((rand() % (sz - start)) & 0xFFFFFFFF); - - Vector check; - check.fill(sz32, zero); - - for(Uint32 j = 0; j= start && j= start && j; -template class Vector; - -#endif +/* Bitmask testcase code moved from here to + * storage/ndb/test/ndbapi/testBitfield.cpp + * to get coverage from automated testing + */ diff --git a/storage/ndb/src/common/util/NdbOut.cpp b/storage/ndb/src/common/util/NdbOut.cpp index 7ca7c91e266..61de2be7572 100644 --- a/storage/ndb/src/common/util/NdbOut.cpp +++ b/storage/ndb/src/common/util/NdbOut.cpp @@ -29,7 +29,7 @@ static const char * fms[] = { "%d", "0x%08x", // Int32 "%u", "0x%08x", // Uint32 "%lld", "0x%016llx", // Int64 - "%llu", "0x%016llx" // Uint64 + "%llu", "0x%016llx", // Uint64 "%llu", "0x%016llx" // UintPtr }; diff --git a/storage/ndb/src/kernel/blocks/ERROR_codes.txt b/storage/ndb/src/kernel/blocks/ERROR_codes.txt index 72791cb0ebc..150400b9deb 100644 --- a/storage/ndb/src/kernel/blocks/ERROR_codes.txt +++ b/storage/ndb/src/kernel/blocks/ERROR_codes.txt @@ -3,15 +3,18 @@ Next NDBCNTR 1002 Next NDBFS 2000 Next DBACC 3002 Next DBTUP 4029 -Next DBLQH 5047 +Next DBLQH 5050 Next DBDICT 6008 Next DBDIH 7195 -Next DBTC 8054 +Next DBTC 8058 Next CMVMI 9000 Next BACKUP 10038 Next DBUTIL 11002 Next DBTUX 12008 Next SUMA 13034 +Next SUMA 13036 +Next LGMAN 15001 +Next TSMAN 16001 TESTING NODE FAILURE, ARBITRATION --------------------------------- @@ -260,6 +263,9 @@ Delay execution of ABORTCONF signal 2 seconds to generate time-out. 8053: Crash in timeOutFoundLab, state CS_WAIT_COMMIT_CONF +5048: Crash in execCOMMIT +5049: SET_ERROR_INSERT_VALUE(5048) + ERROR CODES FOR TESTING TIME-OUT HANDLING IN DBTC ------------------------------------------------- @@ -316,6 +322,8 @@ ABORT OF TCKEYREQ 8038 : Simulate API disconnect just after SCAN_TAB_REQ +8057 : Send only 1 COMMIT per timeslice + 8052 : Simulate failure of TransactionBufferMemory allocation for OI lookup 8051 : Simulate failure of allocation for saveINDXKEYINFO @@ -547,3 +555,11 @@ NDBCNTR: 1000: Crash insertion on SystemError::CopyFragRef 1001: Delay sending NODE_FAILREP (to own node), until error is cleared + +LGMAN: +----- +15000: Fail to create log file + +TSMAN: +----- +16000: Fail to create data file diff --git a/storage/ndb/src/kernel/blocks/backup/Backup.cpp b/storage/ndb/src/kernel/blocks/backup/Backup.cpp index 45501bf50d5..5cc486ff83b 100644 --- a/storage/ndb/src/kernel/blocks/backup/Backup.cpp +++ b/storage/ndb/src/kernel/blocks/backup/Backup.cpp @@ -326,16 +326,18 @@ Backup::execCONTINUEB(Signal* signal) ptr.p->files.getPtr(filePtr, ptr.p->ctlFilePtr); FsBuffer & buf = filePtr.p->operation.dataBuffer; - if(buf.getFreeSize() + buf.getMinRead() < buf.getUsableSize()) { + if(buf.getFreeSize() < buf.getMaxWrite()) { jam(); TablePtr tabPtr LINT_SET_PTR; c_tablePool.getPtr(tabPtr, Tdata2); - DEBUG_OUT("Backup - Buffer full - " << buf.getFreeSize() - << " + " << buf.getMinRead() - << " < " << buf.getUsableSize() - << " - tableId = " << tabPtr.p->tableId); - + DEBUG_OUT("Backup - Buffer full - " + << buf.getFreeSize() + << " < " << buf.getMaxWrite() + << " (sz: " << buf.getUsableSize() + << " getMinRead: " << buf.getMinRead() + << ") - tableId = " << tabPtr.p->tableId); + signal->theData[0] = BackupContinueB::BUFFER_FULL_META; signal->theData[1] = Tdata1; signal->theData[2] = Tdata2; @@ -967,6 +969,7 @@ Backup::checkNodeFail(Signal* signal, ref->backupPtr = ptr.i; ref->backupId = ptr.p->backupId; ref->errorCode = AbortBackupOrd::BackupFailureDueToNodeFail; + ref->nodeId = getOwnNodeId(); gsn= GSN_STOP_BACKUP_REF; len= StopBackupRef::SignalLength; pos= &ref->nodeId - signal->getDataPtr(); @@ -2081,6 +2084,15 @@ Backup::sendDropTrig(Signal* signal, BackupRecordPtr ptr) /** * Insert footers */ + //if backup error, we needn't insert footers + if(ptr.p->checkError()) + { + jam(); + closeFiles(signal, ptr); + ptr.p->errorCode = 0; + return; + } + { BackupFilePtr filePtr LINT_SET_PTR; ptr.p->files.getPtr(filePtr, ptr.p->logFilePtr); @@ -4187,6 +4199,37 @@ Backup::checkFile(Signal* signal, BackupFilePtr filePtr) #if 0 ndbout << "Ptr to data = " << hex << tmp << endl; #endif + BackupRecordPtr ptr LINT_SET_PTR; + c_backupPool.getPtr(ptr, filePtr.p->backupPtr); + + if (ERROR_INSERTED(10036)) + { + jam(); + filePtr.p->m_flags &= ~(Uint32)BackupFile::BF_FILE_THREAD; + filePtr.p->errorCode = 2810; + ptr.p->setErrorCode(2810); + + if(ptr.p->m_gsn == GSN_STOP_BACKUP_REQ) + { + jam(); + closeFile(signal, ptr, filePtr); + } + return; + } + + if(filePtr.p->errorCode != 0) + { + jam(); + ptr.p->setErrorCode(filePtr.p->errorCode); + + if(ptr.p->m_gsn == GSN_STOP_BACKUP_REQ) + { + jam(); + closeFile(signal, ptr, filePtr); + } + return; + } + if (!ready_to_write(ready, sz, eof, filePtr.p)) { jam(); @@ -4218,8 +4261,6 @@ Backup::checkFile(Signal* signal, BackupFilePtr filePtr) ndbrequire(flags & BackupFile::BF_OPEN); ndbrequire(flags & BackupFile::BF_FILE_THREAD); - BackupRecordPtr ptr LINT_SET_PTR; - c_backupPool.getPtr(ptr, filePtr.p->backupPtr); closeFile(signal, ptr, filePtr); } @@ -4582,6 +4623,22 @@ Backup::closeFilesDone(Signal* signal, BackupRecordPtr ptr) jam(); + //error when do insert footer or close file + if(ptr.p->checkError()) + { + StopBackupRef * ref = (StopBackupRef*)signal->getDataPtr(); + ref->backupPtr = ptr.i; + ref->backupId = ptr.p->backupId; + ref->errorCode = ptr.p->errorCode; + ref->nodeId = getOwnNodeId(); + sendSignal(ptr.p->masterRef, GSN_STOP_BACKUP_REF, signal, + StopBackupConf::SignalLength, JBB); + + ptr.p->m_gsn = GSN_STOP_BACKUP_REF; + ptr.p->slaveState.setState(CLEANING); + return; + } + StopBackupConf* conf = (StopBackupConf*)signal->getDataPtrSend(); conf->backupId = ptr.p->backupId; conf->backupPtr = ptr.i; diff --git a/storage/ndb/src/kernel/blocks/backup/Backup.hpp b/storage/ndb/src/kernel/blocks/backup/Backup.hpp index 3fd9b2967fd..ad6e3b8fadc 100644 --- a/storage/ndb/src/kernel/blocks/backup/Backup.hpp +++ b/storage/ndb/src/kernel/blocks/backup/Backup.hpp @@ -557,8 +557,8 @@ public: NDB_TICKS m_reset_disk_speed_time; static const int DISK_SPEED_CHECK_DELAY = 100; - STATIC_CONST(NO_OF_PAGES_META_FILE = - (MAX_WORDS_META_FILE + BACKUP_WORDS_PER_PAGE - 1) / + STATIC_CONST(NO_OF_PAGES_META_FILE = + (2*MAX_WORDS_META_FILE + BACKUP_WORDS_PER_PAGE - 1) / BACKUP_WORDS_PER_PAGE); /** diff --git a/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp b/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp index 63d22bd0a37..1805d6ef4f8 100644 --- a/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp +++ b/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp @@ -3210,7 +3210,6 @@ Dbacc::readTablePk(Uint32 localkey1, Uint32 eh, Ptr opPtr) { dump_lock_queue(opPtr); ndbrequire(opPtr.p->nextParallelQue == RNIL); - ndbrequire(opPtr.p->nextSerialQue == RNIL); ndbrequire(opPtr.p->m_op_bits & Operationrec::OP_ELEMENT_DISAPPEARED); ndbrequire(opPtr.p->m_op_bits & Operationrec::OP_COMMIT_DELETE_CHECK); ndbrequire((opPtr.p->m_op_bits & Operationrec::OP_STATE_MASK) == Operationrec::OP_STATE_RUNNING); diff --git a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp index 7ced078144a..a61a5bc035c 100644 --- a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp +++ b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp @@ -4086,9 +4086,7 @@ Dbdict::execALTER_TABLE_REQ(Signal* signal) bool ok = false; switch(tabState){ case TableRecord::NOT_DEFINED: - case TableRecord::REORG_TABLE_PREPARED: case TableRecord::DEFINING: - case TableRecord::CHECKED: jam(); alterTableRef(signal, req, AlterTableRef::NoSuchTable); return; @@ -4339,9 +4337,7 @@ Dbdict::execALTER_TAB_REQ(Signal * signal) bool ok = false; switch(tabState){ case TableRecord::NOT_DEFINED: - case TableRecord::REORG_TABLE_PREPARED: case TableRecord::DEFINING: - case TableRecord::CHECKED: jam(); alterTabRef(signal, req, AlterTableRef::NoSuchTable); return; @@ -6690,9 +6686,7 @@ Dbdict::execDROP_TABLE_REQ(Signal* signal){ bool ok = false; switch(tabState){ case TableRecord::NOT_DEFINED: - case TableRecord::REORG_TABLE_PREPARED: case TableRecord::DEFINING: - case TableRecord::CHECKED: jam(); dropTableRef(signal, req, DropTableRef::NoSuchTable); return; @@ -7718,7 +7712,6 @@ Dbdict::execLIST_TABLES_REQ(Signal* signal) if(DictTabInfo::isTable(type)){ switch (tablePtr.p->tabState) { case TableRecord::DEFINING: - case TableRecord::CHECKED: conf->setTableState(pos, DictTabInfo::StateBuilding); break; case TableRecord::PREPARE_DROPPING: diff --git a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp index 3fff330d699..1189b23c14d 100644 --- a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp +++ b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp @@ -320,9 +320,7 @@ public: enum TabState { NOT_DEFINED = 0, - REORG_TABLE_PREPARED = 1, DEFINING = 2, - CHECKED = 3, DEFINED = 4, PREPARE_DROPPING = 5, DROPPING = 6, diff --git a/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index bbacb300089..e2b1058242d 100644 --- a/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -8464,6 +8464,12 @@ void Dbdih::execDIHNDBTAMPER(Signal* signal) } else if (tuserpointer < 15000) { jam(); tuserblockref = DBDICT_REF; + } else if (tuserpointer < 16000) { + jam(); + tuserblockref = LGMAN_REF; + } else if (tuserpointer < 17000) { + jam(); + tuserblockref = TSMAN_REF; } else if (tuserpointer < 30000) { /*--------------------------------------------------------------------*/ // Ignore errors in the 20000-range. diff --git a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index 83d38595c1f..bc8adf6fd32 100644 --- a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -5959,6 +5959,12 @@ void Dblqh::execCOMMIT(Signal* signal) TcConnectionrec * const regTcPtr = tcConnectptr.p; TRACE_OP(regTcPtr, "COMMIT"); + + CRASH_INSERTION(5048); + if (ERROR_INSERTED(5049)) + { + SET_ERROR_INSERT_VALUE(5048); + } commitReqLab(signal, gci); return; diff --git a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index e584883e3b6..043df5d5038 100644 --- a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -4495,7 +4495,7 @@ void Dbtc::commit020Lab(Signal* signal) if (localTcConnectptr.i != RNIL) { Tcount = Tcount + 1; - if (Tcount < 16) { + if (Tcount < 16 && !ERROR_INSERTED(8057)) { ptrCheckGuard(localTcConnectptr, TtcConnectFilesize, localTcConnectRecord); jam(); @@ -4514,6 +4514,9 @@ void Dbtc::commit020Lab(Signal* signal) }//if } else { jam(); + if (ERROR_INSERTED(8057)) + CLEAR_ERROR_INSERT_VALUE; + regApiPtr->apiConnectstate = CS_COMMIT_SENT; return; }//if diff --git a/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp b/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp index 45d124b8d7d..decb47e9758 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp +++ b/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp @@ -251,6 +251,7 @@ inline const Uint32* ALIGN_WORD(const void* ptr) #define ZUNSUPPORTED_BRANCH 892 #define ZSTORED_SEIZE_ATTRINBUFREC_ERROR 873 // Part of Scan +#define ZSTORED_TOO_MUCH_ATTRINFO_ERROR 874 #define ZREAD_ONLY_CONSTRAINT_VIOLATION 893 #define ZVAR_SIZED_NOT_SUPPORTED 894 @@ -1330,6 +1331,11 @@ typedef Ptr HostBufferPtr; struct Tuple_header { union { + /** + * List of prepared operations for this tuple. + * Points to most recent/last operation, ie. to walk the list must follow + * regOperPtr->prevActiveOp links. + */ Uint32 m_operation_ptr_i; // OperationPtrI Uint32 m_base_record_ref; // For disk tuple, ref to MM tuple }; @@ -1558,7 +1564,7 @@ public: /* * TUX checks if tuple is visible to scan. */ - bool tuxQueryTh(Uint32 fragPtrI, Uint32 tupAddr, Uint32 tupVersion, Uint32 transId1, Uint32 transId2, Uint32 savePointId); + bool tuxQueryTh(Uint32 fragPtrI, Uint32 pageId, Uint32 pageIndex, Uint32 tupVersion, Uint32 transId1, Uint32 transId2, bool dirty, Uint32 savepointId); int load_diskpage(Signal*, Uint32 opRec, Uint32 fragPtrI, Uint32 local_key, Uint32 flags); @@ -2202,17 +2208,20 @@ private: void checkImmediateTriggersAfterInsert(KeyReqStruct *req_struct, Operationrec* regOperPtr, - Tablerec* tablePtr); + Tablerec* tablePtr, + bool disk); void checkImmediateTriggersAfterUpdate(KeyReqStruct *req_struct, Operationrec* regOperPtr, - Tablerec* tablePtr); + Tablerec* tablePtr, + bool disk); void checkImmediateTriggersAfterDelete(KeyReqStruct *req_struct, Operationrec* regOperPtr, - Tablerec* tablePtr); + Tablerec* tablePtr, + bool disk); #if 0 void checkDeferredTriggers(Signal* signal, @@ -2226,7 +2235,8 @@ private: void fireImmediateTriggers(KeyReqStruct *req_struct, DLList& triggerList, - Operationrec* regOperPtr); + Operationrec* regOperPtr, + bool disk); void fireDeferredTriggers(KeyReqStruct *req_struct, DLList& triggerList, @@ -2239,12 +2249,13 @@ private: void executeTriggers(KeyReqStruct *req_struct, DLList& triggerList, - Operationrec* regOperPtr); + Operationrec* regOperPtr, + bool disk); void executeTrigger(KeyReqStruct *req_struct, TupTriggerData* trigPtr, Operationrec* regOperPtr, - bool disk = true); + bool disk); bool readTriggerInfo(TupTriggerData* trigPtr, Operationrec* regOperPtr, @@ -2421,6 +2432,7 @@ private: void setNullBits(Uint32*, Tablerec* regTabPtr); bool checkNullAttributes(KeyReqStruct * const, Tablerec* const); + bool find_savepoint(OperationrecPtr& loopOpPtr, Uint32 savepointId); bool setup_read(KeyReqStruct* req_struct, Operationrec* regOperPtr, Fragrecord* regFragPtr, @@ -2533,7 +2545,8 @@ private: Operationrec* regOperPtr, Uint32 lenAttrInfo); void storedSeizeAttrinbufrecErrorLab(Signal* signal, - Operationrec* regOperPtr); + Operationrec* regOperPtr, + Uint32 errorCode); bool storedProcedureAttrInfo(Signal* signal, Operationrec* regOperPtr, const Uint32* data, @@ -2874,7 +2887,7 @@ private: void verify_page_lists(Disk_alloc_info&) {} #endif - void fix_commit_order(OperationrecPtr); + void findFirstOp(OperationrecPtr&); void commit_operation(Signal*, Uint32, Tuple_header*, PagePtr, Operationrec*, Fragrecord*, Tablerec*); @@ -3036,4 +3049,21 @@ Dbtup::get_dd_ptr(PagePtr* pagePtr, NdbOut& operator<<(NdbOut&, const Dbtup::Tablerec&); +inline +bool Dbtup::find_savepoint(OperationrecPtr& loopOpPtr, Uint32 savepointId) +{ + while (true) { + if (savepointId > loopOpPtr.p->savepointId) { + jam(); + return true; + } + loopOpPtr.i = loopOpPtr.p->prevActiveOp; + if (loopOpPtr.i == RNIL) { + break; + } + c_operation_pool.getPtr(loopOpPtr); + } + return false; +} + #endif diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp index 59adfbfde89..93a160a4df3 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp @@ -385,3 +385,38 @@ void Dbtup::send_TUPKEYREF(Signal* signal, TupKeyRef::SignalLength, JBB); } +/** + * Unlink one operation from the m_operation_ptr_i list in the tuple. + */ +void Dbtup::removeActiveOpList(Operationrec* const regOperPtr, + Tuple_header *tuple_ptr) +{ + OperationrecPtr raoOperPtr; + + if(!regOperPtr->m_copy_tuple_location.isNull()) + { + jam(); + c_undo_buffer.free_copy_tuple(®OperPtr->m_copy_tuple_location); + } + + if (regOperPtr->op_struct.in_active_list) { + regOperPtr->op_struct.in_active_list= false; + if (regOperPtr->nextActiveOp != RNIL) { + jam(); + raoOperPtr.i= regOperPtr->nextActiveOp; + c_operation_pool.getPtr(raoOperPtr); + raoOperPtr.p->prevActiveOp= regOperPtr->prevActiveOp; + } else { + jam(); + tuple_ptr->m_operation_ptr_i = regOperPtr->prevActiveOp; + } + if (regOperPtr->prevActiveOp != RNIL) { + jam(); + raoOperPtr.i= regOperPtr->prevActiveOp; + c_operation_pool.getPtr(raoOperPtr); + raoOperPtr.p->nextActiveOp= regOperPtr->nextActiveOp; + } + regOperPtr->prevActiveOp= RNIL; + regOperPtr->nextActiveOp= RNIL; + } +} diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp index 812f071e037..f56e772c8b9 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp @@ -97,39 +97,6 @@ void Dbtup::execTUP_WRITELOG_REQ(Signal* signal) } while (true); } -void Dbtup::removeActiveOpList(Operationrec* const regOperPtr, - Tuple_header *tuple_ptr) -{ - OperationrecPtr raoOperPtr; - - /** - * Release copy tuple - */ - if(!regOperPtr->m_copy_tuple_location.isNull()) - c_undo_buffer.free_copy_tuple(®OperPtr->m_copy_tuple_location); - - if (regOperPtr->op_struct.in_active_list) { - regOperPtr->op_struct.in_active_list= false; - if (regOperPtr->nextActiveOp != RNIL) { - jam(); - raoOperPtr.i= regOperPtr->nextActiveOp; - c_operation_pool.getPtr(raoOperPtr); - raoOperPtr.p->prevActiveOp= regOperPtr->prevActiveOp; - } else { - jam(); - tuple_ptr->m_operation_ptr_i = regOperPtr->prevActiveOp; - } - if (regOperPtr->prevActiveOp != RNIL) { - jam(); - raoOperPtr.i= regOperPtr->prevActiveOp; - c_operation_pool.getPtr(raoOperPtr); - raoOperPtr.p->nextActiveOp= regOperPtr->nextActiveOp; - } - regOperPtr->prevActiveOp= RNIL; - regOperPtr->nextActiveOp= RNIL; - } -} - /* ---------------------------------------------------------------- */ /* INITIALIZATION OF ONE CONNECTION RECORD TO PREPARE FOR NEXT OP. */ /* ---------------------------------------------------------------- */ @@ -142,6 +109,7 @@ void Dbtup::initOpConnection(Operationrec* regOperPtr) regOperPtr->op_struct.m_disk_preallocated= 0; regOperPtr->op_struct.m_load_diskpage_on_commit= 0; regOperPtr->op_struct.m_wait_log_buffer= 0; + regOperPtr->op_struct.in_active_list = false; regOperPtr->m_undo_buffer_space= 0; } @@ -170,6 +138,7 @@ Dbtup::dealloc_tuple(Signal* signal, Uint32 extra_bits = Tuple_header::FREED; if (bits & Tuple_header::DISK_PART) { + jam(); Local_key disk; memcpy(&disk, ptr->get_disk_ref_ptr(regTabPtr), sizeof(disk)); PagePtr tmpptr; @@ -182,6 +151,7 @@ Dbtup::dealloc_tuple(Signal* signal, if (! (bits & (Tuple_header::LCP_SKIP | Tuple_header::ALLOC)) && lcpScan_ptr_i != RNIL) { + jam(); ScanOpPtr scanOp; c_scanOpPool.getPtr(scanOp, lcpScan_ptr_i); Local_key rowid = regOperPtr->m_tuple_location; @@ -189,6 +159,7 @@ Dbtup::dealloc_tuple(Signal* signal, rowid.m_page_no = page->frag_page_id; if (rowid > scanpos) { + jam(); extra_bits = Tuple_header::LCP_KEEP; // Note REMOVE FREE ptr->m_operation_ptr_i = lcp_keep_list; regFragPtr->m_lcp_keep_list = rowid.ref(); @@ -229,11 +200,13 @@ Dbtup::commit_operation(Signal* signal, Uint32 mm_vars= regTabPtr->m_attributes[MM].m_no_of_varsize; if(mm_vars == 0) { + jam(); memcpy(tuple_ptr, copy, 4*fixsize); disk_ptr= (Tuple_header*)(((Uint32*)copy)+fixsize); } else { + jam(); /** * Var_part_ref is only stored in *allocated* tuple * so memcpy from copy, will over write it... @@ -258,6 +231,7 @@ Dbtup::commit_operation(Signal* signal, if(copy_bits & Tuple_header::MM_SHRINK) { + jam(); vpagePtrP->shrink_entry(tmp.m_page_idx, (sz + 3) >> 2); update_free_page_list(regFragPtr, vpagePtr); } @@ -268,6 +242,7 @@ Dbtup::commit_operation(Signal* signal, if (regTabPtr->m_no_of_disk_attributes && (copy_bits & Tuple_header::DISK_INLINE)) { + jam(); Local_key key; memcpy(&key, copy->get_disk_ref_ptr(regTabPtr), sizeof(Local_key)); Uint32 logfile_group_id= regFragPtr->m_logfile_group_id; @@ -278,22 +253,26 @@ Dbtup::commit_operation(Signal* signal, Uint32 sz, *dst; if(copy_bits & Tuple_header::DISK_ALLOC) { + jam(); disk_page_alloc(signal, regTabPtr, regFragPtr, &key, diskPagePtr, gci); } if(regTabPtr->m_attributes[DD].m_no_of_varsize == 0) { + jam(); sz= regTabPtr->m_offsets[DD].m_fix_header_size; dst= ((Fix_page*)diskPagePtr.p)->get_ptr(key.m_page_idx, sz); } else { + jam(); dst= ((Var_page*)diskPagePtr.p)->get_ptr(key.m_page_idx); sz= ((Var_page*)diskPagePtr.p)->get_entry_len(key.m_page_idx); } if(! (copy_bits & Tuple_header::DISK_ALLOC)) { + jam(); disk_page_undo_update(diskPagePtr.p, &key, dst, sz, gci, logfile_group_id); } @@ -307,6 +286,7 @@ Dbtup::commit_operation(Signal* signal, if(lcpScan_ptr_i != RNIL && (bits & Tuple_header::ALLOC)) { + jam(); ScanOpPtr scanOp; c_scanOpPool.getPtr(scanOp, lcpScan_ptr_i); Local_key rowid = regOperPtr->m_tuple_location; @@ -314,6 +294,7 @@ Dbtup::commit_operation(Signal* signal, rowid.m_page_no = pagePtr.p->frag_page_id; if(rowid > scanpos) { + jam(); copy_bits |= Tuple_header::LCP_SKIP; } } @@ -372,7 +353,10 @@ Dbtup::disk_page_commit_callback(Signal* signal, execTUP_COMMITREQ(signal); if(signal->theData[0] == 0) + { + jam(); c_lqh->tupcommit_conf_callback(signal, regOperPtr.p->userpointer); + } } void @@ -407,35 +391,21 @@ Dbtup::disk_page_log_buffer_callback(Signal* signal, c_lqh->tupcommit_conf_callback(signal, regOperPtr.p->userpointer); } +/** + * Move to the first operation performed on this tuple + */ void -Dbtup::fix_commit_order(OperationrecPtr opPtr) +Dbtup::findFirstOp(OperationrecPtr & firstPtr) { - ndbassert(!opPtr.p->is_first_operation()); - OperationrecPtr firstPtr = opPtr; + jam(); + printf("Detect out-of-order commit(%u) -> ", firstPtr.i); + ndbassert(!firstPtr.p->is_first_operation()); while(firstPtr.p->prevActiveOp != RNIL) { firstPtr.i = firstPtr.p->prevActiveOp; c_operation_pool.getPtr(firstPtr); } - - ndbout_c("fix_commit_order (swapping %d and %d)", - opPtr.i, firstPtr.i); - - /** - * Swap data between first and curr - */ - Uint32 prev= opPtr.p->prevActiveOp; - Uint32 next= opPtr.p->nextActiveOp; - Uint32 seco= firstPtr.p->nextActiveOp; - - Operationrec tmp = *opPtr.p; - * opPtr.p = * firstPtr.p; - * firstPtr.p = tmp; - - c_operation_pool.getPtr(seco)->prevActiveOp = opPtr.i; - c_operation_pool.getPtr(prev)->nextActiveOp = firstPtr.i; - if(next != RNIL) - c_operation_pool.getPtr(next)->prevActiveOp = firstPtr.i; + ndbout_c("%u", firstPtr.i); } /* ----------------------------------------------------------------- */ @@ -448,22 +418,17 @@ void Dbtup::execTUP_COMMITREQ(Signal* signal) TablerecPtr regTabPtr; KeyReqStruct req_struct; TransState trans_state; - Uint32 no_of_fragrec, no_of_tablerec, hash_value, gci; + Uint32 no_of_fragrec, no_of_tablerec; TupCommitReq * const tupCommitReq= (TupCommitReq *)signal->getDataPtr(); regOperPtr.i= tupCommitReq->opPtr; + Uint32 hash_value= tupCommitReq->hashValue; + Uint32 gci = tupCommitReq->gci; + jamEntry(); c_operation_pool.getPtr(regOperPtr); - if(!regOperPtr.p->is_first_operation()) - { - /** - * Out of order commit XXX check effect on triggers - */ - fix_commit_order(regOperPtr); - } - ndbassert(regOperPtr.p->is_first_operation()); regFragPtr.i= regOperPtr.p->fragmentPtr; trans_state= get_trans_state(regOperPtr.p); @@ -486,8 +451,10 @@ void Dbtup::execTUP_COMMITREQ(Signal* signal) #ifdef VM_TRACE if (tupCommitReq->diskpage == RNIL) { - m_pgman.m_ptr.setNull(); - req_struct.m_disk_page_ptr.setNull(); + m_pgman.m_ptr.i = RNIL; + m_pgman.m_ptr.p = 0; + req_struct.m_disk_page_ptr.i = RNIL; + req_struct.m_disk_page_ptr.p = 0; } #endif @@ -496,19 +463,63 @@ void Dbtup::execTUP_COMMITREQ(Signal* signal) PagePtr page; Tuple_header* tuple_ptr= (Tuple_header*) get_ptr(&page, ®OperPtr.p->m_tuple_location, regTabPtr.p); + + /** + * NOTE: This has to be run before potential time-slice when + * waiting for disk, as otherwise the "other-ops" in a multi-op + * commit might run while we're waiting for disk + * + */ + if (!regTabPtr.p->tuxCustomTriggers.isEmpty()) + { + if(get_tuple_state(regOperPtr.p) == TUPLE_PREPARED) + { + jam(); + + OperationrecPtr loopPtr = regOperPtr; + if (unlikely(!regOperPtr.p->is_first_operation())) + { + findFirstOp(loopPtr); + } + + /** + * Execute all tux triggers at first commit + * since previous tuple is otherwise removed... + */ + jam(); + goto first; + while(loopPtr.i != RNIL) + { + c_operation_pool.getPtr(loopPtr); + first: + executeTuxCommitTriggers(signal, + loopPtr.p, + regFragPtr.p, + regTabPtr.p); + set_tuple_state(loopPtr.p, TUPLE_TO_BE_COMMITTED); + loopPtr.i = loopPtr.p->nextActiveOp; + } + } + } bool get_page = false; if(regOperPtr.p->op_struct.m_load_diskpage_on_commit) { + jam(); Page_cache_client::Request req; - ndbassert(regOperPtr.p->is_first_operation() && - regOperPtr.p->is_last_operation()); + + /** + * Only last op on tuple needs "real" commit, + * hence only this one should have m_load_diskpage_on_commit + */ + ndbassert(tuple_ptr->m_operation_ptr_i == regOperPtr.i); /** * Check for page */ if(!regOperPtr.p->m_copy_tuple_location.isNull()) { + jam(); Tuple_header* tmp= (Tuple_header*) c_undo_buffer.get_ptr(®OperPtr.p->m_copy_tuple_location); @@ -518,23 +529,26 @@ void Dbtup::execTUP_COMMITREQ(Signal* signal) if (unlikely(regOperPtr.p->op_struct.op_type == ZDELETE && tmp->m_header_bits & Tuple_header::DISK_ALLOC)) { - jam(); + jam(); /** * Insert+Delete */ - regOperPtr.p->op_struct.m_load_diskpage_on_commit = 0; - regOperPtr.p->op_struct.m_wait_log_buffer = 0; - disk_page_abort_prealloc(signal, regFragPtr.p, + regOperPtr.p->op_struct.m_load_diskpage_on_commit = 0; + regOperPtr.p->op_struct.m_wait_log_buffer = 0; + disk_page_abort_prealloc(signal, regFragPtr.p, &req.m_page, req.m_page.m_page_idx); - - c_lgman->free_log_space(regFragPtr.p->m_logfile_group_id, + + c_lgman->free_log_space(regFragPtr.p->m_logfile_group_id, regOperPtr.p->m_undo_buffer_space); - if (0) ndbout_c("insert+delete"); goto skip_disk; + if (0) ndbout_c("insert+delete"); + jamEntry(); + goto skip_disk; } } else { + jam(); // initial delete ndbassert(regOperPtr.p->op_struct.op_type == ZDELETE); memcpy(&req.m_page, @@ -558,11 +572,14 @@ void Dbtup::execTUP_COMMITREQ(Signal* signal) /** * Timeslice */ + jam(); signal->theData[0] = 1; return; case -1: ndbrequire("NOT YET IMPLEMENTED" == 0); break; + default: + jam(); } get_page = true; @@ -579,8 +596,12 @@ void Dbtup::execTUP_COMMITREQ(Signal* signal) if(regOperPtr.p->op_struct.m_wait_log_buffer) { - ndbassert(regOperPtr.p->is_first_operation() && - regOperPtr.p->is_last_operation()); + jam(); + /** + * Only last op on tuple needs "real" commit, + * hence only this one should have m_wait_log_buffer + */ + ndbassert(tuple_ptr->m_operation_ptr_i == regOperPtr.i); Callback cb; cb.m_callbackData= regOperPtr.i; @@ -590,51 +611,39 @@ void Dbtup::execTUP_COMMITREQ(Signal* signal) Logfile_client lgman(this, c_lgman, regFragPtr.p->m_logfile_group_id); int res= lgman.get_log_buffer(signal, sz, &cb); + jamEntry(); switch(res){ case 0: + jam(); signal->theData[0] = 1; return; case -1: ndbrequire("NOT YET IMPLEMENTED" == 0); break; + default: + jam(); } } - if(!tuple_ptr) - { - tuple_ptr = (Tuple_header*) - get_ptr(&page, ®OperPtr.p->m_tuple_location,regTabPtr.p); - } + assert(tuple_ptr); skip_disk: req_struct.m_tuple_ptr = tuple_ptr; - if(get_tuple_state(regOperPtr.p) == TUPLE_PREPARED) - { - /** - * Execute all tux triggers at first commit - * since previous tuple is otherwise removed... - * btw...is this a "good" solution?? - * - * why can't we instead remove "own version" (when approriate ofcourse) - */ - if (!regTabPtr.p->tuxCustomTriggers.isEmpty()) { - jam(); - OperationrecPtr loopPtr= regOperPtr; - while(loopPtr.i != RNIL) - { - c_operation_pool.getPtr(loopPtr); - executeTuxCommitTriggers(signal, - loopPtr.p, - regFragPtr.p, - regTabPtr.p); - set_tuple_state(loopPtr.p, TUPLE_TO_BE_COMMITTED); - loopPtr.i = loopPtr.p->nextActiveOp; - } - } - } - - if(regOperPtr.p->is_last_operation()) + Uint32 nextOp = regOperPtr.p->nextActiveOp; + Uint32 prevOp = regOperPtr.p->prevActiveOp; + /** + * The trigger code (which is shared between detached/imediate) + * check op-list to check were to read before values from + * detached triggers should always read from original tuple value + * from before transaction start, not from any intermediate update + * + * Setting the op-list has this effect + */ + regOperPtr.p->nextActiveOp = RNIL; + regOperPtr.p->prevActiveOp = RNIL; + if(tuple_ptr->m_operation_ptr_i == regOperPtr.i) { + jam(); /** * Perform "real" commit */ @@ -643,24 +652,38 @@ skip_disk: checkDetachedTriggers(&req_struct, regOperPtr.p, regTabPtr.p, disk != RNIL); + tuple_ptr->m_operation_ptr_i = RNIL; + if(regOperPtr.p->op_struct.op_type != ZDELETE) { + jam(); commit_operation(signal, gci, tuple_ptr, page, regOperPtr.p, regFragPtr.p, regTabPtr.p); - removeActiveOpList(regOperPtr.p, tuple_ptr); } else { - removeActiveOpList(regOperPtr.p, tuple_ptr); + jam(); if (get_page) ndbassert(tuple_ptr->m_header_bits & Tuple_header::DISK_PART); dealloc_tuple(signal, gci, page.p, tuple_ptr, regOperPtr.p, regFragPtr.p, regTabPtr.p); } } - else + + if (nextOp != RNIL) { - removeActiveOpList(regOperPtr.p, tuple_ptr); + c_operation_pool.getPtr(nextOp)->prevActiveOp = prevOp; + } + + if (prevOp != RNIL) + { + c_operation_pool.getPtr(prevOp)->nextActiveOp = nextOp; + } + + if(!regOperPtr.p->m_copy_tuple_location.isNull()) + { + jam(); + c_undo_buffer.free_copy_tuple(®OperPtr.p->m_copy_tuple_location); } initOpConnection(regOperPtr.p); diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp index 8420e7f2bde..3a3c1155657 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp @@ -282,6 +282,7 @@ Dbtup::update_extent_pos(Disk_alloc_info& alloc, void Dbtup::restart_setup_page(Disk_alloc_info& alloc, PagePtr pagePtr) { + jam(); /** * Link to extent, clear uncommitted_used_space */ @@ -302,6 +303,7 @@ Dbtup::restart_setup_page(Disk_alloc_info& alloc, PagePtr pagePtr) ddassert(real_free >= estimated); if (real_free != estimated) { + jam(); extentPtr.p->m_free_space += (real_free - estimated); update_extent_pos(alloc, extentPtr); } @@ -374,6 +376,7 @@ Dbtup::disk_page_prealloc(Signal* signal, key->m_file_no= tmp.p->m_file_no; if (DBG_DISK) ndbout << " found dirty page " << *key << endl; + jam(); return 0; // Page in memory } } @@ -395,6 +398,7 @@ Dbtup::disk_page_prealloc(Signal* signal, * key = req.p->m_key; if (DBG_DISK) ndbout << " found transit page " << *key << endl; + jam(); return 0; } } @@ -404,6 +408,7 @@ Dbtup::disk_page_prealloc(Signal* signal, */ if (!c_page_request_pool.seize(req)) { + jam(); err= 1; //XXX set error code ndbout_c("no free request"); @@ -468,6 +473,7 @@ Dbtup::disk_page_prealloc(Signal* signal, err = c_lgman->alloc_log_space(logfile_group_id, sizeof(Disk_undo::AllocExtent)>>2); + jamEntry(); if(unlikely(err)) { return -err; @@ -568,6 +574,7 @@ Dbtup::disk_page_prealloc(Signal* signal, Uint32 newPageBits= alloc.calc_page_free_bits(new_size); if (newPageBits != (Uint32)pageBits) { + jam(); ddassert(ext.p->m_free_page_count[pageBits] > 0); ext.p->m_free_page_count[pageBits]--; ext.p->m_free_page_count[newPageBits]++; @@ -595,6 +602,7 @@ Dbtup::disk_page_prealloc(Signal* signal, int flags= Page_cache_client::ALLOC_REQ; if (pageBits == 0) { + jam(); //XXX empty page -> fast to map flags |= Page_cache_client::EMPTY_PAGE; preq.m_callback.m_callbackFunction = @@ -606,11 +614,13 @@ Dbtup::disk_page_prealloc(Signal* signal, switch(res) { case 0: + jam(); break; case -1: ndbassert(false); break; default: + jam(); execute(signal, preq.m_callback, res); // run callback } @@ -622,6 +632,7 @@ Dbtup::disk_page_prealloc_dirty_page(Disk_alloc_info & alloc, PagePtr pagePtr, Uint32 old_idx, Uint32 sz) { + jam(); ddassert(pagePtr.p->list_index == old_idx); Uint32 free= pagePtr.p->free_space; @@ -637,6 +648,7 @@ Dbtup::disk_page_prealloc_dirty_page(Disk_alloc_info & alloc, if (old_idx != new_idx) { + jam(); LocalDLList old_list(*pool, alloc.m_dirty_pages[old_idx]); LocalDLList new_list(*pool, alloc.m_dirty_pages[new_idx]); old_list.remove(pagePtr); @@ -660,6 +672,7 @@ Dbtup::disk_page_prealloc_transit_page(Disk_alloc_info& alloc, Ptr req, Uint32 old_idx, Uint32 sz) { + jam(); ddassert(req.p->m_list_index == old_idx); Uint32 free= req.p->m_estimated_free_space; @@ -674,6 +687,7 @@ Dbtup::disk_page_prealloc_transit_page(Disk_alloc_info& alloc, if (old_idx != new_idx) { + jam(); Page_request_list::Head *lists = alloc.m_page_requests; Local_page_request_list old_list(c_page_request_pool, lists[old_idx]); Local_page_request_list new_list(c_page_request_pool, lists[new_idx]); @@ -698,6 +712,7 @@ void Dbtup::disk_page_prealloc_callback(Signal* signal, Uint32 page_request, Uint32 page_id) { + jamEntry(); //ndbout_c("disk_alloc_page_callback id: %d", page_id); Ptr req; @@ -727,6 +742,7 @@ Dbtup::disk_page_prealloc_initial_callback(Signal*signal, Uint32 page_request, Uint32 page_id) { + jamEntry(); //ndbout_c("disk_alloc_page_callback_initial id: %d", page_id); /** * 1) lookup page request @@ -818,6 +834,7 @@ Dbtup::disk_page_prealloc_callback_common(Signal* signal, if (old_idx != new_idx || free != real_free) { + jam(); Ptr extentPtr; c_extent_pool.getPtr(extentPtr, ext); @@ -825,6 +842,7 @@ Dbtup::disk_page_prealloc_callback_common(Signal* signal, if (old_idx != new_idx) { + jam(); ddassert(extentPtr.p->m_free_page_count[old_idx]); extentPtr.p->m_free_page_count[old_idx]--; extentPtr.p->m_free_page_count[new_idx]++; @@ -843,9 +861,11 @@ Dbtup::disk_page_prealloc_callback_common(Signal* signal, void Dbtup::disk_page_set_dirty(PagePtr pagePtr) { + jam(); Uint32 idx = pagePtr.p->list_index; if ((idx & 0x8000) == 0) { + jam(); /** * Already in dirty list */ @@ -874,7 +894,6 @@ Dbtup::disk_page_set_dirty(PagePtr pagePtr) Uint32 used = pagePtr.p->uncommitted_used_space; if (unlikely(pagePtr.p->m_restart_seq != globalData.m_restart_seq)) { - jam(); restart_setup_page(alloc, pagePtr); idx = alloc.calc_page_free_bits(free); used = 0; @@ -918,6 +937,7 @@ Dbtup::disk_page_unmap_callback(Uint32 when, type != File_formats::PT_Tup_varsize_page) || f_undo_done == false)) { + jam(); return ; } @@ -1014,6 +1034,7 @@ Dbtup::disk_page_unmap_callback(Uint32 when, << endl; } tsman.update_page_free_bits(&key, alloc.calc_page_free_bits(real_free)); + jamEntry(); } } @@ -1022,6 +1043,7 @@ Dbtup::disk_page_alloc(Signal* signal, Tablerec* tabPtrP, Fragrecord* fragPtrP, Local_key* key, PagePtr pagePtr, Uint32 gci) { + jam(); Uint32 logfile_group_id= fragPtrP->m_logfile_group_id; Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info; @@ -1050,6 +1072,7 @@ Dbtup::disk_page_free(Signal *signal, Tablerec *tabPtrP, Fragrecord * fragPtrP, Local_key* key, PagePtr pagePtr, Uint32 gci) { + jam(); if (DBG_DISK) ndbout << " disk_page_free " << *key << endl; @@ -1100,6 +1123,7 @@ Dbtup::disk_page_free(Signal *signal, if (old_idx != new_idx) { + jam(); ddassert(extentPtr.p->m_free_page_count[old_idx]); extentPtr.p->m_free_page_count[old_idx]--; extentPtr.p->m_free_page_count[new_idx]++; @@ -1126,6 +1150,7 @@ void Dbtup::disk_page_abort_prealloc(Signal *signal, Fragrecord* fragPtrP, Local_key* key, Uint32 sz) { + jam(); Page_cache_client::Request req; req.m_callback.m_callbackData= sz; req.m_callback.m_callbackFunction = @@ -1139,9 +1164,13 @@ Dbtup::disk_page_abort_prealloc(Signal *signal, Fragrecord* fragPtrP, switch(res) { case 0: + jam(); + break; case -1: + ndbrequire(false); break; default: + jam(); Ptr gpage; m_global_page_pool.getPtr(gpage, (Uint32)res); PagePtr pagePtr; @@ -1157,7 +1186,7 @@ Dbtup::disk_page_abort_prealloc_callback(Signal* signal, Uint32 sz, Uint32 page_id) { //ndbout_c("disk_alloc_page_callback id: %d", page_id); - + jamEntry(); Ptr gpage; m_global_page_pool.getPtr(gpage, page_id); @@ -1200,12 +1229,14 @@ Dbtup::disk_page_abort_prealloc_callback_1(Signal* signal, c_extent_pool.getPtr(extentPtr, ext); if (old_idx != new_idx) { + jam(); ddassert(extentPtr.p->m_free_page_count[old_idx]); extentPtr.p->m_free_page_count[old_idx]--; extentPtr.p->m_free_page_count[new_idx]++; if (old_idx == page_idx) { + jam(); ArrayPool *pool= (ArrayPool*)&m_global_page_pool; LocalDLList old_list(*pool, alloc.m_dirty_pages[old_idx]); LocalDLList new_list(*pool, alloc.m_dirty_pages[new_idx]); @@ -1215,6 +1246,7 @@ Dbtup::disk_page_abort_prealloc_callback_1(Signal* signal, } else { + jam(); pagePtr.p->list_index = new_idx | 0x8000; } } @@ -1272,6 +1304,7 @@ Uint64 Dbtup::disk_page_undo_alloc(Page* page, const Local_key* key, Uint32 sz, Uint32 gci, Uint32 logfile_group_id) { + jam(); Logfile_client lgman(this, c_lgman, logfile_group_id); Disk_undo::Alloc alloc; @@ -1293,6 +1326,7 @@ Dbtup::disk_page_undo_update(Page* page, const Local_key* key, const Uint32* src, Uint32 sz, Uint32 gci, Uint32 logfile_group_id) { + jam(); Logfile_client lgman(this, c_lgman, logfile_group_id); Disk_undo::Update update; @@ -1323,6 +1357,7 @@ Dbtup::disk_page_undo_free(Page* page, const Local_key* key, const Uint32* src, Uint32 sz, Uint32 gci, Uint32 logfile_group_id) { + jam(); Logfile_client lgman(this, c_lgman, logfile_group_id); Disk_undo::Free free; diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp index a642d704eb9..8c096681b58 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp @@ -75,9 +75,17 @@ void Dbtup::copyAttrinfo(Operationrec * regOperPtr, jam(); ndbrequire(copyAttrBufPtr.i < RnoOfAttrBufrec); ptrAss(copyAttrBufPtr, attrbufrec); - RbufLen= copyAttrBufPtr.p->attrbuf[ZBUF_DATA_LEN]; - Rnext= copyAttrBufPtr.p->attrbuf[ZBUF_NEXT]; - Rfirst= cfirstfreeAttrbufrec; + RbufLen = copyAttrBufPtr.p->attrbuf[ZBUF_DATA_LEN]; + Rnext = copyAttrBufPtr.p->attrbuf[ZBUF_NEXT]; + Rfirst = cfirstfreeAttrbufrec; + /* + * ATTRINFO comes from 2 mutually exclusive places: + * 1) TUPKEYREQ (also interpreted part) + * 2) STORED_PROCREQ before scan start + * Assert here that both have a check for overflow. + * The "<" instead of "<=" is intentional. + */ + ndbrequire(RinBufIndex + RbufLen < ZATTR_BUFFER_SIZE); MEMCOPY_NO_WORDS(&inBuffer[RinBufIndex], ©AttrBufPtr.p->attrbuf[0], RbufLen); @@ -221,7 +229,7 @@ Dbtup::calculateChecksum(Tuple_header* tuple_ptr, // includes tupVersion //printf("%p - ", tuple_ptr); - for (i= 0; i < rec_size-2; i++) { + for (i= 0; i < rec_size-Tuple_header::HeaderSize; i++) { checksum ^= tuple_header[i]; //printf("%.8x ", tuple_header[i]); } @@ -358,21 +366,7 @@ Dbtup::setup_read(KeyReqStruct *req_struct, dirty= false; } - OperationrecPtr prevOpPtr = currOpPtr; - bool found= false; - while(true) - { - if (savepointId > currOpPtr.p->savepointId) { - found= true; - break; - } - if (currOpPtr.p->is_first_operation()){ - break; - } - prevOpPtr= currOpPtr; - currOpPtr.i = currOpPtr.p->prevActiveOp; - c_operation_pool.getPtr(currOpPtr); - } + bool found= find_savepoint(currOpPtr, savepointId); Uint32 currOp= currOpPtr.p->op_struct.op_type; @@ -763,7 +757,8 @@ void Dbtup::execTUPKEYREQ(Signal* signal) } checkImmediateTriggersAfterInsert(&req_struct, regOperPtr, - regTabPtr); + regTabPtr, + disk_page != RNIL); set_change_mask_state(regOperPtr, SET_ALL_MASK); sendTUPKEYCONF(signal, &req_struct, regOperPtr); return; @@ -796,7 +791,8 @@ void Dbtup::execTUPKEYREQ(Signal* signal) } checkImmediateTriggersAfterUpdate(&req_struct, regOperPtr, - regTabPtr); + regTabPtr, + disk_page != RNIL); // XXX use terrorCode for now since all methods are void if (terrorCode != 0) { @@ -827,7 +823,8 @@ void Dbtup::execTUPKEYREQ(Signal* signal) */ checkImmediateTriggersAfterDelete(&req_struct, regOperPtr, - regTabPtr); + regTabPtr, + disk_page != RNIL); set_change_mask_state(regOperPtr, DELETE_CHANGES); sendTUPKEYCONF(signal, &req_struct, regOperPtr); return; @@ -1506,32 +1503,22 @@ int Dbtup::handleDeleteReq(Signal* signal, else { regOperPtr->tupVersion= req_struct->m_tuple_ptr->get_tuple_version(); - if(regTabPtr->m_no_of_disk_attributes) + } + + if(disk && regOperPtr->m_undo_buffer_space == 0) + { + regOperPtr->op_struct.m_wait_log_buffer = 1; + regOperPtr->op_struct.m_load_diskpage_on_commit = 1; + Uint32 sz= regOperPtr->m_undo_buffer_space= + (sizeof(Dbtup::Disk_undo::Free) >> 2) + + regTabPtr->m_offsets[DD].m_fix_header_size - 1; + + terrorCode= c_lgman->alloc_log_space(regFragPtr->m_logfile_group_id, + sz); + if(unlikely(terrorCode)) { - Uint32 sz; - if(regTabPtr->m_attributes[DD].m_no_of_varsize) - { - /** - * Need to have page in memory to read size - * to alloc undo space - */ - abort(); - } - else - sz= (sizeof(Dbtup::Disk_undo::Free) >> 2) + - regTabPtr->m_offsets[DD].m_fix_header_size - 1; - - regOperPtr->m_undo_buffer_space= sz; - - int res; - if((res= c_lgman->alloc_log_space(regFragPtr->m_logfile_group_id, - sz))) - { - terrorCode= res; - regOperPtr->m_undo_buffer_space= 0; - goto error; - } - + regOperPtr->m_undo_buffer_space= 0; + goto error; } } if (req_struct->attrinfo_len == 0) @@ -1540,7 +1527,9 @@ int Dbtup::handleDeleteReq(Signal* signal, } if (regTabPtr->need_expand(disk)) + { prepare_read(req_struct, regTabPtr, disk); + } { Uint32 RlogSize; diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp index 0427f1c7612..0a4477db0d0 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp @@ -15,6 +15,7 @@ #define DBTUP_C #define DBTUP_INDEX_CPP +#include #include "Dbtup.hpp" #include #include @@ -319,13 +320,25 @@ Dbtup::accReadPk(Uint32 tableId, Uint32 fragId, Uint32 fragPageId, Uint32 pageIn return ret; } +/* + * TUX index contains all tuple versions. A scan in TUX has scanned + * one of them and asks if it can be returned as scan result. This + * depends on trans id, dirty read flag, and savepoint within trans. + * + * Previously this faked a ZREAD operation and used getPage(). + * In TUP getPage() is run after ACC locking, but TUX comes here + * before ACC access. Instead of modifying getPage() it is more + * clear to do the full check here. + */ bool Dbtup::tuxQueryTh(Uint32 fragPtrI, - Uint32 tupAddr, + Uint32 pageId, + Uint32 pageIndex, Uint32 tupVersion, Uint32 transId1, Uint32 transId2, - Uint32 savePointId) + bool dirty, + Uint32 savepointId) { jamEntry(); FragrecordPtr fragPtr; @@ -334,35 +347,83 @@ Dbtup::tuxQueryTh(Uint32 fragPtrI, TablerecPtr tablePtr; tablePtr.i= fragPtr.p->fragTableId; ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec); - // get page - Uint32 fragPageId= tupAddr >> MAX_TUPLES_BITS; - Uint32 pageIndex= tupAddr & ((1 << MAX_TUPLES_BITS ) - 1); - // use temp op rec - Operationrec tempOp; + PagePtr pagePtr; + pagePtr.i = pageId; + c_page_pool.getPtr(pagePtr); + KeyReqStruct req_struct; - tempOp.m_tuple_location.m_page_no= getRealpid(fragPtr.p, fragPageId); - tempOp.m_tuple_location.m_page_idx= pageIndex; - tempOp.savepointId= savePointId; - tempOp.op_struct.op_type= ZREAD; - req_struct.frag_page_id= fragPageId; - req_struct.trans_id1= transId1; - req_struct.trans_id2= transId2; - req_struct.dirty_op= 1; - - setup_fixed_part(&req_struct, &tempOp, tablePtr.p); - if (setup_read(&req_struct, &tempOp, fragPtr.p, tablePtr.p, false)) { - /* - * We use the normal getPage which will return the tuple to be used - * for this transaction and savepoint id. If its tuple version - * equals the requested then we have a visible tuple otherwise not. - */ + + { + Operationrec tmpOp; + tmpOp.m_tuple_location.m_page_no = pageId; + tmpOp.m_tuple_location.m_page_idx = pageIndex; + setup_fixed_part(&req_struct, &tmpOp, tablePtr.p); + } + + Tuple_header* tuple_ptr = req_struct.m_tuple_ptr; + + OperationrecPtr currOpPtr; + currOpPtr.i = tuple_ptr->m_operation_ptr_i; + if (currOpPtr.i == RNIL) { jam(); - if (req_struct.m_tuple_ptr->get_tuple_version() == tupVersion) { + // tuple has no operation, any scan can see it + return true; + } + c_operation_pool.getPtr(currOpPtr); + + const bool sameTrans = + c_lqh->is_same_trans(currOpPtr.p->userpointer, transId1, transId2); + + bool res = false; + OperationrecPtr loopOpPtr = currOpPtr; + + if (!sameTrans) { + jam(); + if (!dirty) { jam(); - return true; + if (currOpPtr.p->nextActiveOp == RNIL) { + jam(); + // last op - TUX makes ACC lock request in same timeslice + res = true; + } + } + else { + // loop to first op (returns false) + find_savepoint(loopOpPtr, 0); + const Uint32 op_type = loopOpPtr.p->op_struct.op_type; + + if (op_type != ZINSERT) { + jam(); + // read committed version + const Uint32 origVersion = tuple_ptr->get_tuple_version(); + if (origVersion == tupVersion) { + jam(); + res = true; + } + } } } - return false; + else { + jam(); + // for own trans, ignore dirty flag + + if (find_savepoint(loopOpPtr, savepointId)) { + jam(); + const Uint32 op_type = loopOpPtr.p->op_struct.op_type; + + if (op_type != ZDELETE) { + jam(); + // check if this op has produced the scanned version + Uint32 loopVersion = loopOpPtr.p->tupVersion; + if (loopVersion == tupVersion) { + jam(); + res = true; + } + } + } + } + + return res; } // ordered index build diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp index 5e9306909b4..4c5fb7b645f 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp @@ -54,7 +54,14 @@ Dbtup::execACC_SCANREQ(Signal* signal) // flags Uint32 bits = 0; - if (!AccScanReq::getLcpScanFlag(req->requestInfo)) + + if (AccScanReq::getLcpScanFlag(req->requestInfo)) + { + jam(); + bits |= ScanOp::SCAN_LCP; + c_scanOpPool.getPtr(scanPtr, c_lcp_scan_op); + } + else { // seize from pool and link to per-fragment list LocalDLList list(c_scanOpPool, frag.m_scanList); @@ -62,37 +69,26 @@ Dbtup::execACC_SCANREQ(Signal* signal) jam(); break; } - - if (!AccScanReq::getNoDiskScanFlag(req->requestInfo) - && tablePtr.p->m_no_of_disk_attributes) - { - bits |= ScanOp::SCAN_DD; - } + } + + if (!AccScanReq::getNoDiskScanFlag(req->requestInfo) + && tablePtr.p->m_no_of_disk_attributes) + { + bits |= ScanOp::SCAN_DD; + } + + bool mm = (bits & ScanOp::SCAN_DD); + if (tablePtr.p->m_attributes[mm].m_no_of_varsize > 0) { + bits |= ScanOp::SCAN_VS; - bool mm = (bits & ScanOp::SCAN_DD); - if (tablePtr.p->m_attributes[mm].m_no_of_varsize > 0) { - bits |= ScanOp::SCAN_VS; - - // disk pages have fixed page format - ndbrequire(! (bits & ScanOp::SCAN_DD)); - } - if (! AccScanReq::getReadCommittedFlag(req->requestInfo)) { - if (AccScanReq::getLockMode(req->requestInfo) == 0) - bits |= ScanOp::SCAN_LOCK_SH; - else - bits |= ScanOp::SCAN_LOCK_EX; - } - } else { - jam(); - // LCP scan and disk - - ndbrequire(frag.m_lcp_scan_op == c_lcp_scan_op); - c_scanOpPool.getPtr(scanPtr, frag.m_lcp_scan_op); - ndbrequire(scanPtr.p->m_fragPtrI == fragPtr.i); - bits |= ScanOp::SCAN_LCP; - if (tablePtr.p->m_attributes[MM].m_no_of_varsize > 0) { - bits |= ScanOp::SCAN_VS; - } + // disk pages have fixed page format + ndbrequire(! (bits & ScanOp::SCAN_DD)); + } + if (! AccScanReq::getReadCommittedFlag(req->requestInfo)) { + if (AccScanReq::getLockMode(req->requestInfo) == 0) + bits |= ScanOp::SCAN_LOCK_SH; + else + bits |= ScanOp::SCAN_LOCK_EX; } if (AccScanReq::getNRScanFlag(req->requestInfo)) @@ -112,6 +108,13 @@ Dbtup::execACC_SCANREQ(Signal* signal) jam(); scanPtr.p->m_endPage = RNIL; } + + if (AccScanReq::getLcpScanFlag(req->requestInfo)) + { + jam(); + ndbrequire((bits & ScanOp::SCAN_DD) == 0); + ndbrequire((bits & ScanOp::SCAN_LOCK) == 0); + } // set up scan op new (scanPtr.p) ScanOp(); @@ -618,6 +621,24 @@ Dbtup::scanNext(Signal* signal, ScanOpPtr scanPtr) if (lcp && lcp_list != RNIL) goto found_lcp_keep; + + switch(pos.m_get){ + case ScanPos::Get_next_tuple: + case ScanPos::Get_next_tuple_fs: + jam(); + key.m_page_idx += size; + // fall through + case ScanPos::Get_tuple: + case ScanPos::Get_tuple_fs: + jam(); + /** + * We need to refetch page after timeslice + */ + pos.m_get = ScanPos::Get_page; + break; + default: + break; + } while (true) { switch (pos.m_get) { @@ -1141,16 +1162,17 @@ Dbtup::releaseScanOp(ScanOpPtr& scanPtr) fragPtr.i = scanPtr.p->m_fragPtrI; ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord); - if(! (scanPtr.p->m_bits & ScanOp::SCAN_LCP)) + if(scanPtr.p->m_bits & ScanOp::SCAN_LCP) { - LocalDLList list(c_scanOpPool, fragPtr.p->m_scanList); - list.release(scanPtr); + jam(); + fragPtr.p->m_lcp_scan_op = RNIL; + scanPtr.p->m_fragPtrI = RNIL; } else { - ndbrequire(fragPtr.p->m_lcp_scan_op == scanPtr.i); - fragPtr.p->m_lcp_scan_op = RNIL; - scanPtr.p->m_fragPtrI = RNIL; + jam(); + LocalDLList list(c_scanOpPool, fragPtr.p->m_scanList); + list.release(scanPtr); } } @@ -1163,21 +1185,24 @@ Dbtup::execLCP_FRAG_ORD(Signal* signal) tablePtr.i = req->tableId; ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec); - jam(); - FragrecordPtr fragPtr; - Uint32 fragId = req->fragmentId; - fragPtr.i = RNIL; - getFragmentrec(fragPtr, fragId, tablePtr.p); - ndbrequire(fragPtr.i != RNIL); - Fragrecord& frag = *fragPtr.p; - - ndbrequire(frag.m_lcp_scan_op == RNIL && c_lcp_scan_op != RNIL); - frag.m_lcp_scan_op = c_lcp_scan_op; - ScanOpPtr scanPtr; - c_scanOpPool.getPtr(scanPtr, frag.m_lcp_scan_op); - ndbrequire(scanPtr.p->m_fragPtrI == RNIL); - scanPtr.p->m_fragPtrI = fragPtr.i; - - scanFirst(signal, scanPtr); - scanPtr.p->m_state = ScanOp::First; + if (tablePtr.p->m_no_of_disk_attributes) + { + jam(); + FragrecordPtr fragPtr; + Uint32 fragId = req->fragmentId; + fragPtr.i = RNIL; + getFragmentrec(fragPtr, fragId, tablePtr.p); + ndbrequire(fragPtr.i != RNIL); + Fragrecord& frag = *fragPtr.p; + + ndbrequire(frag.m_lcp_scan_op == RNIL && c_lcp_scan_op != RNIL); + frag.m_lcp_scan_op = c_lcp_scan_op; + ScanOpPtr scanPtr; + c_scanOpPool.getPtr(scanPtr, frag.m_lcp_scan_op); + ndbrequire(scanPtr.p->m_fragPtrI == RNIL); + scanPtr.p->m_fragPtrI = fragPtr.i; + + scanFirst(signal, scanPtr); + scanPtr.p->m_state = ScanOp::First; + } } diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp index 12d5f8aba38..a1e350853ce 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp @@ -106,6 +106,11 @@ void Dbtup::scanProcedure(Signal* signal, regOperPtr->attrinbufLen = lenAttrInfo; regOperPtr->currentAttrinbufLen = 0; regOperPtr->storedProcPtr = storedPtr.i; + if (lenAttrInfo >= ZATTR_BUFFER_SIZE) { // yes ">=" + jam(); + // send REF and change state to ignore the ATTRINFO to come + storedSeizeAttrinbufrecErrorLab(signal, regOperPtr, ZSTORED_TOO_MUCH_ATTRINFO_ERROR); + } }//Dbtup::scanProcedure() void Dbtup::copyProcedure(Signal* signal, @@ -146,7 +151,7 @@ bool Dbtup::storedProcedureAttrInfo(Signal* signal, Uint32 RnoFree = cnoFreeAttrbufrec; if (ERROR_INSERTED(4004) && !copyProcedure) { CLEAR_ERROR_INSERT_VALUE; - storedSeizeAttrinbufrecErrorLab(signal, regOperPtr); + storedSeizeAttrinbufrecErrorLab(signal, regOperPtr, ZSTORED_SEIZE_ATTRINBUFREC_ERROR); return false; }//if regOperPtr->currentAttrinbufLen += length; @@ -162,7 +167,7 @@ bool Dbtup::storedProcedureAttrInfo(Signal* signal, regAttrPtr.p->attrbuf[ZBUF_NEXT] = RNIL; } else { jam(); - storedSeizeAttrinbufrecErrorLab(signal, regOperPtr); + storedSeizeAttrinbufrecErrorLab(signal, regOperPtr, ZSTORED_SEIZE_ATTRINBUFREC_ERROR); return false; }//if if (regOperPtr->firstAttrinbufrec == RNIL) { @@ -190,7 +195,7 @@ bool Dbtup::storedProcedureAttrInfo(Signal* signal, }//if if (ERROR_INSERTED(4005) && !copyProcedure) { CLEAR_ERROR_INSERT_VALUE; - storedSeizeAttrinbufrecErrorLab(signal, regOperPtr); + storedSeizeAttrinbufrecErrorLab(signal, regOperPtr, ZSTORED_SEIZE_ATTRINBUFREC_ERROR); return false; }//if @@ -212,7 +217,8 @@ bool Dbtup::storedProcedureAttrInfo(Signal* signal, }//Dbtup::storedProcedureAttrInfo() void Dbtup::storedSeizeAttrinbufrecErrorLab(Signal* signal, - Operationrec* regOperPtr) + Operationrec* regOperPtr, + Uint32 errorCode) { StoredProcPtr storedPtr; c_storedProcPool.getPtr(storedPtr, regOperPtr->storedProcPtr); @@ -224,7 +230,7 @@ void Dbtup::storedSeizeAttrinbufrecErrorLab(Signal* signal, regOperPtr->m_any_value = 0; set_trans_state(regOperPtr, TRANS_ERROR_WAIT_STORED_PROCREQ); signal->theData[0] = regOperPtr->userpointer; - signal->theData[1] = ZSTORED_SEIZE_ATTRINBUFREC_ERROR; + signal->theData[1] = errorCode; signal->theData[2] = regOperPtr->storedProcPtr; sendSignal(DBLQH_REF, GSN_STORED_PROCREF, signal, 3, JBB); }//Dbtup::storedSeizeAttrinbufrecErrorLab() diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp index 09d71a19add..0ae6d0f4ac6 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp @@ -369,7 +369,8 @@ Dbtup::dropTrigger(Tablerec* table, const DropTrigReq* req, BlockNumber sender) void Dbtup::checkImmediateTriggersAfterInsert(KeyReqStruct *req_struct, Operationrec *regOperPtr, - Tablerec *regTablePtr) + Tablerec *regTablePtr, + bool disk) { if(refToBlock(req_struct->TC_ref) != DBTC) { return; @@ -380,14 +381,16 @@ Dbtup::checkImmediateTriggersAfterInsert(KeyReqStruct *req_struct, jam(); fireImmediateTriggers(req_struct, regTablePtr->afterInsertTriggers, - regOperPtr); + regOperPtr, + disk); } } void Dbtup::checkImmediateTriggersAfterUpdate(KeyReqStruct *req_struct, Operationrec* regOperPtr, - Tablerec* regTablePtr) + Tablerec* regTablePtr, + bool disk) { if(refToBlock(req_struct->TC_ref) != DBTC) { return; @@ -398,21 +401,24 @@ Dbtup::checkImmediateTriggersAfterUpdate(KeyReqStruct *req_struct, jam(); fireImmediateTriggers(req_struct, regTablePtr->afterUpdateTriggers, - regOperPtr); + regOperPtr, + disk); } if ((regOperPtr->op_struct.primary_replica) && (!(regTablePtr->constraintUpdateTriggers.isEmpty()))) { jam(); fireImmediateTriggers(req_struct, regTablePtr->constraintUpdateTriggers, - regOperPtr); + regOperPtr, + disk); } } void Dbtup::checkImmediateTriggersAfterDelete(KeyReqStruct *req_struct, Operationrec* regOperPtr, - Tablerec* regTablePtr) + Tablerec* regTablePtr, + bool disk) { if(refToBlock(req_struct->TC_ref) != DBTC) { return; @@ -423,7 +429,8 @@ Dbtup::checkImmediateTriggersAfterDelete(KeyReqStruct *req_struct, jam(); executeTriggers(req_struct, regTablePtr->afterDeleteTriggers, - regOperPtr); + regOperPtr, + disk); } } @@ -547,7 +554,8 @@ end: void Dbtup::fireImmediateTriggers(KeyReqStruct *req_struct, DLList& triggerList, - Operationrec* const regOperPtr) + Operationrec* const regOperPtr, + bool disk) { TriggerPtr trigPtr; triggerList.first(trigPtr); @@ -558,7 +566,8 @@ Dbtup::fireImmediateTriggers(KeyReqStruct *req_struct, jam(); executeTrigger(req_struct, trigPtr.p, - regOperPtr); + regOperPtr, + disk); }//if triggerList.next(trigPtr); }//while @@ -621,7 +630,8 @@ Dbtup::fireDetachedTriggers(KeyReqStruct *req_struct, void Dbtup::executeTriggers(KeyReqStruct *req_struct, DLList& triggerList, - Operationrec* regOperPtr) + Operationrec* regOperPtr, + bool disk) { TriggerPtr trigPtr; triggerList.first(trigPtr); @@ -629,7 +639,8 @@ void Dbtup::executeTriggers(KeyReqStruct *req_struct, jam(); executeTrigger(req_struct, trigPtr.p, - regOperPtr); + regOperPtr, + disk); triggerList.next(trigPtr); } diff --git a/storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp b/storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp index e6ee2374056..8cef61038a6 100644 --- a/storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp +++ b/storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp @@ -987,7 +987,8 @@ Dbtux::scanVisible(ScanOpPtr scanPtr, TreeEnt ent) const ScanOp& scan = *scanPtr.p; const Frag& frag = *c_fragPool.getPtr(scan.m_fragPtrI); Uint32 tableFragPtrI = frag.m_tupTableFragPtrI; - Uint32 tupAddr = getTupAddr(frag, ent); + Uint32 pageId = ent.m_tupLoc.getPageId(); + Uint32 pageOffset = ent.m_tupLoc.getPageOffset(); Uint32 tupVersion = ent.m_tupVersion; // check for same tuple twice in row if (scan.m_scanEnt.m_tupLoc == ent.m_tupLoc) @@ -997,8 +998,9 @@ Dbtux::scanVisible(ScanOpPtr scanPtr, TreeEnt ent) } Uint32 transId1 = scan.m_transId1; Uint32 transId2 = scan.m_transId2; + bool dirty = scan.m_readCommitted; Uint32 savePointId = scan.m_savePointId; - bool ret = c_tup->tuxQueryTh(tableFragPtrI, tupAddr, tupVersion, transId1, transId2, savePointId); + bool ret = c_tup->tuxQueryTh(tableFragPtrI, pageId, pageOffset, tupVersion, transId1, transId2, dirty, savePointId); jamEntry(); return ret; } diff --git a/storage/ndb/src/kernel/blocks/lgman.cpp b/storage/ndb/src/kernel/blocks/lgman.cpp index 0481f7b399b..53cb1e113e1 100644 --- a/storage/ndb/src/kernel/blocks/lgman.cpp +++ b/storage/ndb/src/kernel/blocks/lgman.cpp @@ -547,6 +547,22 @@ Lgman::execCREATE_FILE_REQ(Signal* signal) break; } + if(ERROR_INSERTED(15000) || + (sizeof(void*) == 4 && req->file_size_hi & 0xFFFFFFFF)) + { + jam(); + if(signal->getNoOfSections()) + releaseSections(signal); + + CreateFileImplRef* ref= (CreateFileImplRef*)signal->getDataPtr(); + ref->senderData = senderData; + ref->senderRef = reference(); + ref->errorCode = CreateFileImplRef::FileSizeTooLarge; + sendSignal(senderRef, GSN_CREATE_FILE_REF, signal, + CreateFileImplRef::SignalLength, JBB); + return; + } + new (file_ptr.p) Undofile(req, ptr.i); Local_undofile_list tmp(m_file_pool, ptr.p->m_meta_files); @@ -902,7 +918,7 @@ Lgman::alloc_logbuffer_memory(Ptr ptr, Uint32 bytes) { Uint32 ptrI; Uint32 cnt = pages > 64 ? 64 : pages; - m_ctx.m_mm.alloc(&ptrI, &cnt, 1); + m_ctx.m_mm.alloc_pages(RG_DISK_OPERATIONS, &ptrI, &cnt, 1); if (cnt) { Buffer_idx range; @@ -1021,7 +1037,7 @@ Lgman::free_logbuffer_memory(Ptr ptr) ndbrequire(map.next(it)); tmp[1] = *it.data; - m_ctx.m_mm.release(range.m_ptr_i, range.m_idx); + m_ctx.m_mm.release_pages(RG_DISK_OPERATIONS, range.m_ptr_i, range.m_idx); map.next(it); } map.release(); diff --git a/storage/ndb/src/kernel/blocks/suma/Suma.cpp b/storage/ndb/src/kernel/blocks/suma/Suma.cpp index 113b63a19d3..5f0510cf43a 100644 --- a/storage/ndb/src/kernel/blocks/suma/Suma.cpp +++ b/storage/ndb/src/kernel/blocks/suma/Suma.cpp @@ -4908,6 +4908,21 @@ Suma::release_gci(Signal* signal, Uint32 buck, Uint32 gci) if(gci >= head.m_max_gci) { jam(); + if (ERROR_INSERTED(13034)) + { + jam(); + SET_ERROR_INSERT_VALUE(13035); + return; + } + if (ERROR_INSERTED(13035)) + { + CLEAR_ERROR_INSERT_VALUE; + NodeReceiverGroup rg(CMVMI, c_nodes_in_nodegroup_mask); + rg.m_nodes.clear(getOwnNodeId()); + signal->theData[0] = 9999; + sendSignal(rg, GSN_NDB_TAMPER, signal, 1, JBA); + return; + } head.m_page_pos = 0; head.m_max_gci = gci; head.m_last_gci = 0; @@ -4979,7 +4994,6 @@ Suma::start_resend(Signal* signal, Uint32 buck) if(min > max) { - ndbrequire(pos.m_page_pos <= 2); ndbrequire(pos.m_page_id == bucket->m_buffer_tail); m_active_buckets.set(buck); m_gcp_complete_rep_count ++; diff --git a/storage/ndb/src/kernel/blocks/suma/SumaInit.cpp b/storage/ndb/src/kernel/blocks/suma/SumaInit.cpp index bf5c07b5b97..0248833978c 100644 --- a/storage/ndb/src/kernel/blocks/suma/SumaInit.cpp +++ b/storage/ndb/src/kernel/blocks/suma/SumaInit.cpp @@ -27,6 +27,8 @@ Suma::Suma(Block_context& ctx) : Restart(*this), c_gcp_list(c_gcp_pool) { + BLOCK_CONSTRUCTOR(Suma); + // Add received signals addRecSignal(GSN_READ_CONFIG_REQ, &Suma::execREAD_CONFIG_REQ); addRecSignal(GSN_STTOR, &Suma::execSTTOR); diff --git a/storage/ndb/src/kernel/blocks/tsman.cpp b/storage/ndb/src/kernel/blocks/tsman.cpp index 3a7003d56c8..8e68e118f98 100644 --- a/storage/ndb/src/kernel/blocks/tsman.cpp +++ b/storage/ndb/src/kernel/blocks/tsman.cpp @@ -537,6 +537,22 @@ Tsman::execCREATE_FILE_REQ(Signal* signal){ break; } + if(ERROR_INSERTED(16000) || + (sizeof(void*) == 4 && req->file_size_hi & 0xFFFFFFFF)) + { + jam(); + if(signal->getNoOfSections()) + releaseSections(signal); + + CreateFileImplRef* ref= (CreateFileImplRef*)signal->getDataPtr(); + ref->senderData = senderData; + ref->senderRef = reference(); + ref->errorCode = CreateFileImplRef::FileSizeTooLarge; + sendSignal(senderRef, GSN_CREATE_FILE_REF, signal, + CreateFileImplRef::SignalLength, JBB); + return; + } + new (file_ptr.p) Datafile(req); Local_datafile_list tmp(m_file_pool, ptr.p->m_meta_files); tmp.add(file_ptr); diff --git a/storage/ndb/src/kernel/vm/DLHashTable.hpp b/storage/ndb/src/kernel/vm/DLHashTable.hpp index df56dcb8846..b9d5f7c597f 100644 --- a/storage/ndb/src/kernel/vm/DLHashTable.hpp +++ b/storage/ndb/src/kernel/vm/DLHashTable.hpp @@ -46,8 +46,8 @@ public: /** * Seize element from pool - return i * - * Note must be either added using add or released - * using release + * Note *must* be added using add (even before hash.release) + * or be released using pool */ bool seize(Ptr &); @@ -360,7 +360,14 @@ DLHashTableImpl::remove(Ptr & ptr) else { const Uint32 hv = ptr.p->hashValue() & mask; - hashValues[hv] = next; + if (hashValues[hv] == ptr.i) + { + hashValues[hv] = next; + } + else + { + // Will add assert in 5.1 + } } if(next != RNIL) @@ -386,7 +393,14 @@ DLHashTableImpl::release(Ptr & ptr) else { const Uint32 hv = ptr.p->hashValue() & mask; - hashValues[hv] = next; + if (hashValues[hv] == ptr.i) + { + hashValues[hv] = next; + } + else + { + // Will add assert in 5.1 + } } if(next != RNIL) diff --git a/storage/ndb/src/kernel/vm/DLHashTable2.hpp b/storage/ndb/src/kernel/vm/DLHashTable2.hpp index 23ced757d8b..05340317adb 100644 --- a/storage/ndb/src/kernel/vm/DLHashTable2.hpp +++ b/storage/ndb/src/kernel/vm/DLHashTable2.hpp @@ -42,8 +42,8 @@ public: /** * Seize element from pool - return i * - * Note must be either added using add or released - * using release + * Note *must* be added using add (even before hash.release) + * or be released using pool */ bool seize(Ptr &); @@ -374,7 +374,14 @@ DLHashTable2::remove(Ptr & ptr){ prevP->nextHash = next; } else { const Uint32 hv = ptr.p->hashValue() & mask; - hashValues[hv] = next; + if (hashValues[hv] == ptr.i) + { + hashValues[hv] = next; + } + else + { + // Will add assert in 5.1 + } } if(next != RNIL){ @@ -395,7 +402,14 @@ DLHashTable2::release(Ptr & ptr){ prevP->nextHash = next; } else { const Uint32 hv = ptr.p->hashValue() & mask; - hashValues[hv] = next; + if (hashValues[hv] == ptr.i) + { + hashValues[hv] = next; + } + else + { + // Will add assert in 5.1 + } } if(next != RNIL){ diff --git a/storage/ndb/src/kernel/vm/NdbdSuperPool.cpp b/storage/ndb/src/kernel/vm/NdbdSuperPool.cpp index 14545e23820..717c354a180 100644 --- a/storage/ndb/src/kernel/vm/NdbdSuperPool.cpp +++ b/storage/ndb/src/kernel/vm/NdbdSuperPool.cpp @@ -48,7 +48,7 @@ NdbdSuperPool::NdbdSuperPool(class Ndbd_mem_manager & mm, { m_memRoot = m_mm.get_memroot(); - m_shift = Ndbd_mem_manager::log2((1 << (BMW_2LOG + 2)) / pageSize) - 1; + m_shift = Ndbd_mem_manager::ndb_log2((1 << (BMW_2LOG + 2)) / pageSize) - 1; m_add = (1 << m_shift) - 1; } diff --git a/storage/ndb/src/kernel/vm/Pool.cpp b/storage/ndb/src/kernel/vm/Pool.cpp index 29c4aec4ee3..f252a601ac2 100644 --- a/storage/ndb/src/kernel/vm/Pool.cpp +++ b/storage/ndb/src/kernel/vm/Pool.cpp @@ -20,7 +20,8 @@ void* Pool_context::alloc_page(Uint32 type_id, Uint32 *i) { - return m_block->m_ctx.m_mm.alloc_page(type_id, i); + return m_block->m_ctx.m_mm.alloc_page(type_id, i, + Ndbd_mem_manager::NDB_ZONE_LO); } void diff --git a/storage/ndb/src/kernel/vm/ndbd_malloc_impl.cpp b/storage/ndb/src/kernel/vm/ndbd_malloc_impl.cpp index 70637a362d0..e2100e66baa 100644 --- a/storage/ndb/src/kernel/vm/ndbd_malloc_impl.cpp +++ b/storage/ndb/src/kernel/vm/ndbd_malloc_impl.cpp @@ -25,19 +25,22 @@ extern EventLogger g_eventLogger; extern EventLogger g_eventLogger; #endif -#ifdef NDBD_MALLOC_METHOD -#if NDBD_MALLOC_METHOD == sbrk -static const char * f_method = "sbrk"; +static int f_method_idx = 0; +#ifdef NDBD_MALLOC_METHOD_SBRK +static const char * f_method = "SMsm"; #else -static const char * f_method = "malloc"; -#endif -#elif SIZEOF_CHARP == 8 -static const char * f_method = "sbrk"; -#else -static const char * f_method = "malloc"; +static const char * f_method = "MSms"; #endif #define MAX_CHUNKS 10 +#define ZONE_LO 0 +#define ZONE_HI 1 + +/** + * POOL_RECORD_BITS == 13 => 32 - 13 = 19 bits for page + */ +#define ZONE_LO_BOUND (1u << 19) + struct InitChunk { Uint32 m_cnt; @@ -54,28 +57,42 @@ do_malloc(Uint32 pages, InitChunk* chunk) pages += 1; void * ptr = 0; Uint32 sz = pages; - if (strcmp(f_method, "sbrk") == 0) + +retry: + char method = f_method[f_method_idx]; + switch(method){ + case 0: + return false; + case 'S': + case 's': { ptr = 0; while (ptr == 0) { ptr = sbrk(sizeof(Alloc_page) * sz); + if (ptr == (void*)-1) { + if (method == 'S') + { + f_method_idx++; + goto retry; + } + ptr = 0; sz = 1 + (9 * sz) / 10; if (pages >= 32 && sz < 32) { sz = pages; - f_method = "malloc"; - g_eventLogger.info("sbrk(%lld) failed, trying malloc", - (Uint64)(sizeof(Alloc_page) * sz)); - break; + f_method_idx++; + goto retry; } } } + break; } - if (strcmp(f_method, "malloc") == 0) + case 'M': + case 'm': { ptr = 0; while (ptr == 0) @@ -83,15 +100,26 @@ do_malloc(Uint32 pages, InitChunk* chunk) ptr = malloc(sizeof(Alloc_page) * sz); if (ptr == 0) { + if (method == 'M') + { + f_method_idx++; + goto retry; + } + sz = 1 + (9 * sz) / 10; if (pages >= 32 && sz < 32) { - return false; + f_method_idx++; + goto retry; } } } + break; } - + default: + return false; + } + chunk->m_cnt = sz; chunk->m_ptr = (Alloc_page*)ptr; const UintPtr align = sizeof(Alloc_page) - 1; @@ -125,7 +153,7 @@ do_malloc(Uint32 pages, InitChunk* chunk) } Uint32 -Ndbd_mem_manager::log2(Uint32 input) +Ndbd_mem_manager::ndb_log2(Uint32 input) { input = input | (input >> 8); input = input | (input >> 4); @@ -151,6 +179,12 @@ Ndbd_mem_manager::Ndbd_mem_manager() } } +/** + * m_min = reserved + * m_curr = current + * m_max = max alloc, 0 = no limit + */ + void Ndbd_mem_manager::set_resource_limit(const Resource_limit& rl) { @@ -176,6 +210,40 @@ Ndbd_mem_manager::get_resource_limit(Uint32 id, Resource_limit& rl) const return false; } +static +inline +void +check_resource_limits(Resource_limit* rl) +{ +#ifdef VM_TRACE + Uint32 curr = 0; + Uint32 res_alloc = 0; + Uint32 shared_alloc = 0; + Uint32 sumres = 0; + for (Uint32 i = 1; i rl[i].m_min) + { + shared_alloc += rl[i].m_curr - rl[i].m_min; + res_alloc += rl[i].m_min; + } + else + { + res_alloc += rl[i].m_curr; + } + } + assert(curr == rl[0].m_curr); + assert(res_alloc + shared_alloc == curr); + assert(res_alloc <= sumres); + assert(sumres == res_alloc + rl[0].m_min); + assert(rl[0].m_curr <= rl[0].m_max); +#endif +} + + bool Ndbd_mem_manager::init(bool alloc_less_memory) { @@ -292,6 +360,8 @@ Ndbd_mem_manager::init(bool alloc_less_memory) grow(chunks[i].m_start, chunks[i].m_cnt); } + check_resource_limits(m_resource_limit); + return true; } @@ -321,35 +391,68 @@ Ndbd_mem_manager::grow(Uint32 start, Uint32 cnt) cnt--; // last page is always marked as empty } - if (!m_used_bitmap_pages.get(start_bmp)) - { - if (start != (start_bmp << BPP_2LOG)) - { - ndbout_c("ndbd_malloc_impl.cpp:%d:grow(%d, %d) %d!=%d" - " - Unable to use due to bitmap pages missaligned!!", - __LINE__, start, cnt, start, (start_bmp << BPP_2LOG)); - g_eventLogger.error("ndbd_malloc_impl.cpp:%d:grow(%d, %d)" - " - Unable to use due to bitmap pages missaligned!!", - __LINE__, start, cnt); - return; - } + for (Uint32 i = 0; i> (20 - 15))); + g_eventLogger.error("ndbd_malloc_impl.cpp:%d:grow(%d, %d) not using %uMb" + " - Unable to use due to bitmap pages missaligned!!", + __LINE__, start, cnt, + (cnt >> (20 - 15))); + + dump(); + return; + } + +#ifdef UNIT_TEST + ndbout_c("creating bitmap page %d", start_bmp); +#endif + + { Alloc_page* bmp = m_base_page + start; memset(bmp, 0, sizeof(Alloc_page)); - m_used_bitmap_pages.set(start_bmp); cnt--; start++; } - + m_used_bitmap_pages.push_back(start_bmp); + +found: if (cnt) { m_resource_limit[0].m_curr += cnt; m_resource_limit[0].m_max += cnt; - release(start, cnt); + if (start >= ZONE_LO_BOUND) + { + Uint64 mbytes = ((Uint64(cnt) * 32) + 1023) / 1024; + ndbout_c("Adding %uMb to ZONE_HI (%u,%u)", (Uint32)mbytes, start, cnt); + release(start, cnt); + } + else if (start + cnt <= ZONE_LO_BOUND) + { + Uint64 mbytes = ((Uint64(cnt)*32) + 1023) / 1024; + ndbout_c("Adding %uMb to ZONE_LO (%u,%u)", (Uint32)mbytes, start, cnt); + release(start, cnt); + } + else + { + Uint32 cnt0 = ZONE_LO_BOUND - start; + Uint32 cnt1 = start + cnt - ZONE_LO_BOUND; + Uint64 mbytes0 = ((Uint64(cnt0)*32) + 1023) / 1024; + Uint64 mbytes1 = ((Uint64(cnt1)*32) + 1023) / 1024; + ndbout_c("Adding %uMb to ZONE_LO (split %u,%u)", (Uint32)mbytes0, + start, cnt0); + ndbout_c("Adding %uMb to ZONE_HI (split %u,%u)", (Uint32)mbytes1, + ZONE_LO_BOUND, cnt1); + release(start, cnt0); + release(ZONE_LO_BOUND, cnt1); + } } } @@ -362,64 +465,82 @@ Ndbd_mem_manager::release(Uint32 start, Uint32 cnt) set(start, start+cnt-1); - release_impl(start, cnt); + Uint32 zone = start < ZONE_LO_BOUND ? 0 : 1; + release_impl(zone, start, cnt); } void -Ndbd_mem_manager::release_impl(Uint32 start, Uint32 cnt) +Ndbd_mem_manager::release_impl(Uint32 zone, Uint32 start, Uint32 cnt) { assert(start); Uint32 test = check(start-1, start+cnt); - if (test & 1) + if (start != ZONE_LO_BOUND && test & 1) { Free_page_data *fd = get_free_page_data(m_base_page + start - 1, start - 1); Uint32 sz = fd->m_size; Uint32 left = start - sz; - remove_free_list(left, fd->m_list); + remove_free_list(zone, left, fd->m_list); cnt += sz; start = left; } Uint32 right = start + cnt; - if (test & 2) + if (right != ZONE_LO_BOUND && test & 2) { Free_page_data *fd = get_free_page_data(m_base_page+right, right); Uint32 sz = fd->m_size; - remove_free_list(right, fd->m_list); + remove_free_list(zone, right, fd->m_list); cnt += sz; } - insert_free_list(start, cnt); + insert_free_list(zone, start, cnt); } void -Ndbd_mem_manager::alloc(Uint32* ret, Uint32 *pages, Uint32 min) +Ndbd_mem_manager::alloc(AllocZone zone, + Uint32* ret, Uint32 *pages, Uint32 min) +{ + if (zone == NDB_ZONE_ANY) + { + Uint32 save = * pages; + alloc_impl(ZONE_HI, ret, pages, min); + if (*pages) + return; + * pages = save; + } + + alloc_impl(ZONE_LO, ret, pages, min); +} + +void +Ndbd_mem_manager::alloc_impl(Uint32 zone, + Uint32* ret, Uint32 *pages, Uint32 min) { Int32 i; Uint32 start; Uint32 cnt = * pages; - Uint32 list = log2(cnt - 1); + Uint32 list = ndb_log2(cnt - 1); assert(cnt); assert(list <= 16); for (i = list; i < 16; i++) { - if ((start = m_buddy_lists[i])) + if ((start = m_buddy_lists[zone][i])) { /* ---------------------------------------------------------------- */ /* PROPER AMOUNT OF PAGES WERE FOUND. NOW SPLIT THE FOUND */ /* AREA AND RETURN THE PART NOT NEEDED. */ /* ---------------------------------------------------------------- */ - Uint32 sz = remove_free_list(start, i); + Uint32 sz = remove_free_list(zone, start, i); Uint32 extra = sz - cnt; assert(sz >= cnt); if (extra) { - insert_free_list(start + cnt, extra); + insert_free_list(zone, start + cnt, extra); clear_and_set(start, start+cnt-1); } else @@ -427,8 +548,7 @@ Ndbd_mem_manager::alloc(Uint32* ret, Uint32 *pages, Uint32 min) clear(start, start+cnt-1); } * ret = start; - m_resource_limit[0].m_curr += cnt; - assert(m_resource_limit[0].m_curr <= m_resource_limit[0].m_max); + assert(m_resource_limit[0].m_curr + cnt <= m_resource_limit[0].m_max); return; } } @@ -438,17 +558,17 @@ Ndbd_mem_manager::alloc(Uint32* ret, Uint32 *pages, Uint32 min) * search in other lists... */ - Int32 min_list = log2(min - 1); + Int32 min_list = ndb_log2(min - 1); assert((Int32)list >= min_list); for (i = list - 1; i >= min_list; i--) { - if ((start = m_buddy_lists[i])) + if ((start = m_buddy_lists[zone][i])) { - Uint32 sz = remove_free_list(start, i); + Uint32 sz = remove_free_list(zone, start, i); Uint32 extra = sz - cnt; if (sz > cnt) { - insert_free_list(start + cnt, extra); + insert_free_list(zone, start + cnt, extra); sz -= extra; clear_and_set(start, start+sz-1); } @@ -459,8 +579,7 @@ Ndbd_mem_manager::alloc(Uint32* ret, Uint32 *pages, Uint32 min) * ret = start; * pages = sz; - m_resource_limit[0].m_curr += sz; - assert(m_resource_limit[0].m_curr <= m_resource_limit[0].m_max); + assert(m_resource_limit[0].m_curr + sz <= m_resource_limit[0].m_max); return; } } @@ -468,12 +587,12 @@ Ndbd_mem_manager::alloc(Uint32* ret, Uint32 *pages, Uint32 min) } void -Ndbd_mem_manager::insert_free_list(Uint32 start, Uint32 size) +Ndbd_mem_manager::insert_free_list(Uint32 zone, Uint32 start, Uint32 size) { - Uint32 list = log2(size) - 1; + Uint32 list = ndb_log2(size) - 1; Uint32 last = start + size - 1; - Uint32 head = m_buddy_lists[list]; + Uint32 head = m_buddy_lists[zone][list]; Free_page_data* fd_first = get_free_page_data(m_base_page+start, start); fd_first->m_list = list; @@ -495,11 +614,11 @@ Ndbd_mem_manager::insert_free_list(Uint32 start, Uint32 size) fd->m_prev = start; } - m_buddy_lists[list] = start; + m_buddy_lists[zone][list] = start; } Uint32 -Ndbd_mem_manager::remove_free_list(Uint32 start, Uint32 list) +Ndbd_mem_manager::remove_free_list(Uint32 zone, Uint32 start, Uint32 list) { Free_page_data* fd = get_free_page_data(m_base_page+start, start); Uint32 size = fd->m_size; @@ -509,7 +628,7 @@ Ndbd_mem_manager::remove_free_list(Uint32 start, Uint32 list) if (prev) { - assert(m_buddy_lists[list] != start); + assert(m_buddy_lists[zone][list] != start); fd = get_free_page_data(m_base_page+prev, prev); assert(fd->m_next == start); assert(fd->m_list == list); @@ -517,8 +636,8 @@ Ndbd_mem_manager::remove_free_list(Uint32 start, Uint32 list) } else { - assert(m_buddy_lists[list] == start); - m_buddy_lists[list] = next; + assert(m_buddy_lists[zone][list] == start); + m_buddy_lists[zone][list] = next; } if (next) @@ -535,42 +654,62 @@ Ndbd_mem_manager::remove_free_list(Uint32 start, Uint32 list) void Ndbd_mem_manager::dump() const { - for(Uint32 i = 0; i<16; i++) + for (Uint32 zone = 0; zone < 2; zone ++) { - printf(" list: %d - ", i); - Uint32 head = m_buddy_lists[i]; - while(head) + for (Uint32 i = 0; i<16; i++) { - Free_page_data* fd = get_free_page_data(m_base_page+head, head); - printf("[ i: %d prev %d next %d list %d size %d ] ", - head, fd->m_prev, fd->m_next, fd->m_list, fd->m_size); - head = fd->m_next; + printf(" list: %d - ", i); + Uint32 head = m_buddy_lists[zone][i]; + while(head) + { + Free_page_data* fd = get_free_page_data(m_base_page+head, head); + printf("[ i: %d prev %d next %d list %d size %d ] ", + head, fd->m_prev, fd->m_next, fd->m_list, fd->m_size); + head = fd->m_next; + } + printf("EOL\n"); + } + + for (Uint32 i = 0; i= res0); + + if (likely(res0 == 1 || (limit == 0 && free == 1))) { - Uint32 cnt = 1; - alloc(i, &cnt, 1); - assert(cnt); - m_resource_limit[0].m_curr = tot.m_curr + add; - m_resource_limit[idx].m_curr = rl.m_curr + 1; - return m_base_page + *i; + alloc(zone, i, &cnt, 1); + if (likely(cnt)) + { + m_resource_limit[0].m_curr = tot.m_curr + cnt; + m_resource_limit[0].m_min = tot.m_min - res0; + m_resource_limit[idx].m_curr = rl.m_curr + cnt; + + check_resource_limits(m_resource_limit); + return m_base_page + *i; + } } + return 0; } @@ -582,10 +721,102 @@ Ndbd_mem_manager::release_page(Uint32 type, Uint32 i) Resource_limit tot = m_resource_limit[0]; Resource_limit rl = m_resource_limit[idx]; - Uint32 sub = (rl.m_curr < rl.m_min) ? 0 : 1; // Over min ? + Uint32 sub = (rl.m_curr <= rl.m_min) ? 1 : 0; // Over min ? release(i, 1); - m_resource_limit[0].m_curr = tot.m_curr - sub; + m_resource_limit[0].m_curr = tot.m_curr - 1; + m_resource_limit[0].m_min = tot.m_min + sub; m_resource_limit[idx].m_curr = rl.m_curr - 1; + + check_resource_limits(m_resource_limit); +} + +void +Ndbd_mem_manager::alloc_pages(Uint32 type, Uint32* i, Uint32 *cnt, Uint32 min) +{ + Uint32 idx = type & RG_MASK; + assert(idx && idx < XX_RL_COUNT); + Resource_limit tot = m_resource_limit[0]; + Resource_limit rl = m_resource_limit[idx]; + + Uint32 req = *cnt; + + Uint32 max = rl.m_max - rl.m_curr; + Uint32 res0 = rl.m_min - rl.m_curr; + Uint32 free_shared = tot.m_max - (tot.m_min + tot.m_curr); + + Uint32 res1; + if (rl.m_curr + req <= rl.m_min) + { + // all is reserved... + res0 = req; + res1 = 0; + } + else + { + req = rl.m_max ? max : req; + res0 = (rl.m_curr > rl.m_min) ? 0 : res0; + res1 = req - res0; + + if (unlikely(res1 > free_shared)) + { + res1 = free_shared; + req = res0 + res1; + } + } + + // req = pages to alloc + // res0 = portion that is reserved + // res1 = part that is over reserver + assert (res0 + res1 == req); + assert (tot.m_min >= res0); + + if (likely(req)) + { + // Hi order allocations can always use any zone + alloc(NDB_ZONE_ANY, i, &req, 1); + * cnt = req; + if (unlikely(req < res0)) // Got min than what was reserved :-( + { + res0 = req; + } + assert(tot.m_min >= res0); + assert(tot.m_curr + req <= tot.m_max); + + m_resource_limit[0].m_curr = tot.m_curr + req; + m_resource_limit[0].m_min = tot.m_min - res0; + m_resource_limit[idx].m_curr = rl.m_curr + req; + check_resource_limits(m_resource_limit); + return ; + } + * cnt = req; + return; +} + +void +Ndbd_mem_manager::release_pages(Uint32 type, Uint32 i, Uint32 cnt) +{ + Uint32 idx = type & RG_MASK; + assert(idx && idx < XX_RL_COUNT); + Resource_limit tot = m_resource_limit[0]; + Resource_limit rl = m_resource_limit[idx]; + + release(i, cnt); + + Uint32 currnew = rl.m_curr - cnt; + if (rl.m_curr > rl.m_min) + { + if (currnew < rl.m_min) + { + m_resource_limit[0].m_min = tot.m_min + (rl.m_min - currnew); + } + } + else + { + m_resource_limit[0].m_min = tot.m_min + cnt; + } + m_resource_limit[0].m_curr = tot.m_curr - cnt; + m_resource_limit[idx].m_curr = currnew; + check_resource_limits(m_resource_limit); } #ifdef UNIT_TEST @@ -781,3 +1012,4 @@ main(int argc, char** argv) template class Vector; #endif +template class Vector; diff --git a/storage/ndb/src/kernel/vm/ndbd_malloc_impl.hpp b/storage/ndb/src/kernel/vm/ndbd_malloc_impl.hpp index d87927d9c45..78e41f1cabd 100644 --- a/storage/ndb/src/kernel/vm/ndbd_malloc_impl.hpp +++ b/storage/ndb/src/kernel/vm/ndbd_malloc_impl.hpp @@ -20,6 +20,7 @@ #include #include #include "Pool.hpp" +#include /** * 13 -> 8192 words -> 32768 bytes @@ -59,46 +60,53 @@ public: bool init(bool allow_alloc_less_than_requested = true); void* get_memroot() const { return (void*)m_base_page;} - void alloc(Uint32* ret, Uint32 *pages, Uint32 min_requested); - void release(Uint32 start, Uint32 cnt); - void dump() const ; - void* alloc_page(Uint32 type, Uint32* i); + enum AllocZone + { + NDB_ZONE_LO = 0, // Only allocate with page_id < (1 << 13) + NDB_ZONE_ANY = 1 // Allocate with any page_id + }; + + void* alloc_page(Uint32 type, Uint32* i, enum AllocZone); void release_page(Uint32 type, Uint32 i); - void* alloc_pages(Uint32 type, Uint32* i, Uint32 *cnt, Uint32 min = 1); - void release_pages(Uint32 type, Uint32 i, void*p, Uint32 cnt); + void alloc_pages(Uint32 type, Uint32* i, Uint32 *cnt, Uint32 min = 1); + void release_pages(Uint32 type, Uint32 i, Uint32 cnt); /** * Compute 2log of size * @note size = 0 -> 0 * @note size > 65536 -> 16 */ - static Uint32 log2(Uint32 size); + static Uint32 ndb_log2(Uint32 size); private: void grow(Uint32 start, Uint32 cnt); -#define XX_RL_COUNT 3 +#define XX_RL_COUNT 4 /** * Return pointer to free page data on page */ static Free_page_data* get_free_page_data(Alloc_page*, Uint32 idx); - Bitmask<1> m_used_bitmap_pages; + Vector m_used_bitmap_pages; - Uint32 m_buddy_lists[16]; + Uint32 m_buddy_lists[2][16]; Resource_limit m_resource_limit[XX_RL_COUNT]; // RG_COUNT in record_types.hpp Alloc_page * m_base_page; - void release_impl(Uint32 start, Uint32 cnt); - void insert_free_list(Uint32 start, Uint32 cnt); - Uint32 remove_free_list(Uint32 start, Uint32 list); + void release_impl(Uint32 zone, Uint32 start, Uint32 cnt); + void insert_free_list(Uint32 zone, Uint32 start, Uint32 cnt); + Uint32 remove_free_list(Uint32 zone, Uint32 start, Uint32 list); void set(Uint32 first, Uint32 last); void clear(Uint32 first, Uint32 last); void clear_and_set(Uint32 first, Uint32 last); Uint32 check(Uint32 first, Uint32 last); + + void alloc(AllocZone, Uint32* ret, Uint32 *pages, Uint32 min_requested); + void alloc_impl(Uint32 zone, Uint32* ret, Uint32 *pages, Uint32 min); + void release(Uint32 start, Uint32 cnt); }; inline diff --git a/storage/ndb/src/kernel/vm/pc.hpp b/storage/ndb/src/kernel/vm/pc.hpp index 194d5534646..cf03f676ae1 100644 --- a/storage/ndb/src/kernel/vm/pc.hpp +++ b/storage/ndb/src/kernel/vm/pc.hpp @@ -49,7 +49,7 @@ theEmulatedJamBlockNumber = number(); \ Uint32 tEmulatedJamIndex = theEmulatedJamIndex; \ *(Uint32*)(theEmulatedJam + tEmulatedJamIndex) = \ - ((theEmulatedJamBlockNumber << 20) | line); \ + ((theEmulatedJamBlockNumber << 20) | (line)); \ theEmulatedJamIndex = (tEmulatedJamIndex + 4) & JAM_MASK; } #else @@ -72,7 +72,7 @@ theEmulatedJamBlockNumber = number(); \ Uint32 tEmulatedJamIndex = theEmulatedJamIndex; \ *(Uint32*)((UintPtr)theEmulatedJam + (Uint32)tEmulatedJamIndex) = \ - ((theEmulatedJamBlockNumber << 20) | line); \ + ((theEmulatedJamBlockNumber << 20) | (line)); \ theEmulatedJamIndex = (tEmulatedJamIndex + 4) & JAM_MASK; } #endif @@ -231,6 +231,6 @@ #define MEMCOPY_PAGE(to, from, page_size_in_bytes) \ memcpy((void*)(to), (void*)(from), (size_t)(page_size_in_bytes)); #define MEMCOPY_NO_WORDS(to, from, no_of_words) \ - memcpy((to), (void*)(from), (size_t)(no_of_words << 2)); + memcpy((to), (void*)(from), (size_t)((no_of_words) << 2)); #endif diff --git a/storage/ndb/src/mgmapi/ndb_logevent.cpp b/storage/ndb/src/mgmapi/ndb_logevent.cpp index ed72db297ab..fbf026fd79d 100644 --- a/storage/ndb/src/mgmapi/ndb_logevent.cpp +++ b/storage/ndb/src/mgmapi/ndb_logevent.cpp @@ -256,7 +256,7 @@ struct Ndb_logevent_body_row ndb_logevent_body[]= { ROW( ReceiveBytesStatistic, "mean_received_bytes", 2, mean_received_bytes), ROW( MemoryUsage, "gth", 1, gth), - ROW( MemoryUsage, "page_size_kb", 2, page_size_kb), + ROW( MemoryUsage, "page_size_bytes", 2, page_size_bytes), ROW( MemoryUsage, "pages_used", 3, pages_used), ROW( MemoryUsage, "pages_total", 4, pages_total), ROW( MemoryUsage, "block", 5, block), diff --git a/storage/ndb/src/mgmclient/CommandInterpreter.cpp b/storage/ndb/src/mgmclient/CommandInterpreter.cpp index 9e8910c9649..7057525efc7 100644 --- a/storage/ndb/src/mgmclient/CommandInterpreter.cpp +++ b/storage/ndb/src/mgmclient/CommandInterpreter.cpp @@ -859,10 +859,14 @@ event_thread_run(void* p) { do_event_thread= 1; do { - if (ndb_logevent_get_next(log_handle, &log_event, 2000) <= 0) - continue; - Guard g(printmutex); - printLogEvent(&log_event); + int res= ndb_logevent_get_next(log_handle, &log_event, 2000); + if (res > 0) + { + Guard g(printmutex); + printLogEvent(&log_event); + } + else if (res < 0) + break; } while(do_event_thread); ndb_mgm_destroy_logevent_handle(&log_handle); } @@ -2663,8 +2667,9 @@ CommandInterpreter::executeStartBackup(char* parameters, bool interactive) { int count = 0; int retry = 0; + int res; do { - if (ndb_logevent_get_next(log_handle, &log_event, 60000) > 0) + if ((res= ndb_logevent_get_next(log_handle, &log_event, 60000)) > 0) { int print = 0; switch (log_event.type) { @@ -2694,7 +2699,7 @@ CommandInterpreter::executeStartBackup(char* parameters, bool interactive) { retry++; } - } while(count < 2 && retry < 3); + } while(res >= 0 && count < 2 && retry < 3); if (retry >= 3) ndbout << "get backup event failed for " << retry << " times" << endl; diff --git a/storage/ndb/src/mgmsrv/ConfigInfo.cpp b/storage/ndb/src/mgmsrv/ConfigInfo.cpp index 9cbb7d93ceb..6e560ff2701 100644 --- a/storage/ndb/src/mgmsrv/ConfigInfo.cpp +++ b/storage/ndb/src/mgmsrv/ConfigInfo.cpp @@ -397,7 +397,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { ConfigInfo::CI_INT, MANDATORY, "1", - STR_VALUE(MAX_NODES) }, + STR_VALUE(MAX_DATA_NODE_ID) }, { CFG_NODE_ID, @@ -409,7 +409,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { ConfigInfo::CI_INT, MANDATORY, "1", - STR_VALUE(MAX_NODES) }, + STR_VALUE(MAX_DATA_NODE_ID) }, { KEY_INTERNAL, @@ -1404,7 +1404,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { ConfigInfo::CI_INT, MANDATORY, "1", - STR_VALUE(MAX_NODES) }, + STR_VALUE(MAX_NODES_ID) }, { CFG_NODE_ID, @@ -1416,7 +1416,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { ConfigInfo::CI_INT, MANDATORY, "1", - STR_VALUE(MAX_NODES) }, + STR_VALUE(MAX_NODES_ID) }, { KEY_INTERNAL, @@ -1547,7 +1547,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { ConfigInfo::CI_INT, MANDATORY, "1", - STR_VALUE(MAX_NODES) }, + STR_VALUE(MAX_NODES_ID) }, { CFG_NODE_ID, @@ -1559,7 +1559,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { ConfigInfo::CI_INT, MANDATORY, "1", - STR_VALUE(MAX_NODES) }, + STR_VALUE(MAX_NODES_ID) }, { CFG_LOG_DESTINATION, diff --git a/storage/ndb/src/ndbapi/Ndb.cpp b/storage/ndb/src/ndbapi/Ndb.cpp index 15647861eef..e6a1c2cfcfd 100644 --- a/storage/ndb/src/ndbapi/Ndb.cpp +++ b/storage/ndb/src/ndbapi/Ndb.cpp @@ -942,6 +942,7 @@ Parameters: aTableName (IN) : The table name. step (IN) : Specifies the step between the autoincrement values. start (IN) : Start value for first value +Returns: 0 if succesful, -1 if error encountered Remark: Returns a new autoincrement value to the application. The autoincrement values can be increased by steps (default 1) and a number of values can be prefetched @@ -1072,9 +1073,18 @@ Ndb::getTupleIdFromNdb(const NdbTableImpl* table, DBUG_RETURN(0); } +/**************************************************************************** +int readAutoIncrementValue( const char* aTableName, + Uint64 & autoValue); + +Parameters: aTableName (IN) : The table name. + autoValue (OUT) : The current autoincrement value +Returns: 0 if succesful, -1 if error encountered +Remark: Returns the current autoincrement value to the application. +****************************************************************************/ int Ndb::readAutoIncrementValue(const char* aTableName, - Uint64 & tupleId) + Uint64 & autoValue) { DBUG_ENTER("Ndb::readAutoIncrementValue"); ASSERT_NOT_MYSQLD; @@ -1088,15 +1098,15 @@ Ndb::readAutoIncrementValue(const char* aTableName, } const NdbTableImpl* table = info->m_table_impl; TupleIdRange & range = info->m_tuple_id_range; - if (readTupleIdFromNdb(table, range, tupleId) == -1) + if (readTupleIdFromNdb(table, range, autoValue) == -1) DBUG_RETURN(-1); - DBUG_PRINT("info", ("value %lu", (ulong)tupleId)); + DBUG_PRINT("info", ("value %lu", (ulong)autoValue)); DBUG_RETURN(0); } int Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable, - Uint64 & tupleId) + Uint64 & autoValue) { DBUG_ENTER("Ndb::readAutoIncrementValue"); ASSERT_NOT_MYSQLD; @@ -1111,23 +1121,23 @@ Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable, DBUG_RETURN(-1); } TupleIdRange & range = info->m_tuple_id_range; - if (readTupleIdFromNdb(table, range, tupleId) == -1) + if (readTupleIdFromNdb(table, range, autoValue) == -1) DBUG_RETURN(-1); - DBUG_PRINT("info", ("value %lu", (ulong)tupleId)); + DBUG_PRINT("info", ("value %lu", (ulong)autoValue)); DBUG_RETURN(0); } int Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable, - TupleIdRange & range, Uint64 & tupleId) + TupleIdRange & range, Uint64 & autoValue) { DBUG_ENTER("Ndb::readAutoIncrementValue"); assert(aTable != 0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); - if (readTupleIdFromNdb(table, range, tupleId) == -1) + if (readTupleIdFromNdb(table, range, autoValue) == -1) DBUG_RETURN(-1); - DBUG_PRINT("info", ("value %lu", (ulong)tupleId)); + DBUG_PRINT("info", ("value %lu", (ulong)autoValue)); DBUG_RETURN(0); } @@ -1155,9 +1165,20 @@ Ndb::readTupleIdFromNdb(const NdbTableImpl* table, DBUG_RETURN(0); } +/**************************************************************************** +int setAutoIncrementValue( const char* aTableName, + Uint64 autoValue, + bool modify); + +Parameters: aTableName (IN) : The table name. + autoValue (IN) : The new autoincrement value + modify (IN) : Modify existing value (not initialization) +Returns: 0 if succesful, -1 if error encountered +Remark: Sets a new autoincrement value for the application. +****************************************************************************/ int Ndb::setAutoIncrementValue(const char* aTableName, - Uint64 tupleId, bool increase) + Uint64 autoValue, bool modify) { DBUG_ENTER("Ndb::setAutoIncrementValue"); ASSERT_NOT_MYSQLD; @@ -1171,14 +1192,14 @@ Ndb::setAutoIncrementValue(const char* aTableName, } const NdbTableImpl* table = info->m_table_impl; TupleIdRange & range = info->m_tuple_id_range; - if (setTupleIdInNdb(table, range, tupleId, increase) == -1) + if (setTupleIdInNdb(table, range, autoValue, modify) == -1) DBUG_RETURN(-1); DBUG_RETURN(0); } int Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable, - Uint64 tupleId, bool increase) + Uint64 autoValue, bool modify) { DBUG_ENTER("Ndb::setAutoIncrementValue"); ASSERT_NOT_MYSQLD; @@ -1193,52 +1214,55 @@ Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable, DBUG_RETURN(-1); } TupleIdRange & range = info->m_tuple_id_range; - if (setTupleIdInNdb(table, range, tupleId, increase) == -1) + if (setTupleIdInNdb(table, range, autoValue, modify) == -1) DBUG_RETURN(-1); DBUG_RETURN(0); } int Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable, - TupleIdRange & range, Uint64 tupleId, - bool increase) + TupleIdRange & range, Uint64 autoValue, + bool modify) { DBUG_ENTER("Ndb::setAutoIncrementValue"); assert(aTable != 0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); - if (setTupleIdInNdb(table, range, tupleId, increase) == -1) + if (setTupleIdInNdb(table, range, autoValue, modify) == -1) DBUG_RETURN(-1); DBUG_RETURN(0); } int Ndb::setTupleIdInNdb(const NdbTableImpl* table, - TupleIdRange & range, Uint64 tupleId, bool increase) + TupleIdRange & range, Uint64 tupleId, bool modify) { DBUG_ENTER("Ndb::setTupleIdInNdb"); - if (increase) + if (modify) { - if (range.m_first_tuple_id != range.m_last_tuple_id) + if (checkTupleIdInNdb(range, tupleId)) { - assert(range.m_first_tuple_id < range.m_last_tuple_id); - if (tupleId <= range.m_first_tuple_id + 1) - DBUG_RETURN(0); - if (tupleId <= range.m_last_tuple_id) + if (range.m_first_tuple_id != range.m_last_tuple_id) { - range.m_first_tuple_id = tupleId - 1; - DBUG_PRINT("info", - ("Setting next auto increment cached value to %lu", - (ulong)tupleId)); - DBUG_RETURN(0); + assert(range.m_first_tuple_id < range.m_last_tuple_id); + if (tupleId <= range.m_first_tuple_id + 1) + DBUG_RETURN(0); + if (tupleId <= range.m_last_tuple_id) + { + range.m_first_tuple_id = tupleId - 1; + DBUG_PRINT("info", + ("Setting next auto increment cached value to %lu", + (ulong)tupleId)); + DBUG_RETURN(0); + } } + /* + * if tupleId <= NEXTID, do nothing. otherwise update NEXTID to + * tupleId and set cached range to first = last = tupleId - 1. + */ + if (opTupleIdOnNdb(table, range, tupleId, 2) == -1) + DBUG_RETURN(-1); } - /* - * if tupleId <= NEXTID, do nothing. otherwise update NEXTID to - * tupleId and set cached range to first = last = tupleId - 1. - */ - if (opTupleIdOnNdb(table, range, tupleId, 2) == -1) - DBUG_RETURN(-1); } else { @@ -1277,6 +1301,39 @@ int Ndb::initAutoIncrement() return 0; } +bool +Ndb::checkUpdateAutoIncrementValue(TupleIdRange & range, Uint64 autoValue) +{ + return(checkTupleIdInNdb(range, autoValue) != 0); +} + +int +Ndb::checkTupleIdInNdb(TupleIdRange & range, Uint64 tupleId) +{ + DBUG_ENTER("Ndb::checkTupleIdIndNdb"); + if ((range.m_first_tuple_id != ~(Uint64)0) && + (range.m_first_tuple_id > tupleId)) + { + /* + * If we have ever cached a value in this object and this cached + * value is larger than the value we're trying to set then we + * need not check with the real value in the SYSTAB_0 table. + */ + DBUG_RETURN(0); + } + if (range.m_highest_seen > tupleId) + { + /* + * Although we've never cached any higher value we have read + * a higher value and again it isn't necessary to change the + * auto increment value. + */ + DBUG_RETURN(0); + } + DBUG_RETURN(1); +} + + int Ndb::opTupleIdOnNdb(const NdbTableImpl* table, TupleIdRange & range, Uint64 & opValue, Uint32 op) @@ -1342,15 +1399,15 @@ Ndb::opTupleIdOnNdb(const NdbTableImpl* table, tOperation->write_attr("NEXTID", 1); tOperation->interpret_exit_ok(); tOperation->def_label(0); - tOperation->interpret_exit_nok(9999); - + tOperation->interpret_exit_ok(); + tRecAttrResult = tOperation->getValue("NEXTID"); if (tConnection->execute( NdbTransaction::Commit ) == -1) { - if (tConnection->theError.code != 9999) - goto error_handler; + goto error_handler; } else { + range.m_highest_seen = tRecAttrResult->u_64_value(); DBUG_PRINT("info", ("Setting next auto increment value (db) to %lu", (ulong) opValue)); @@ -1363,7 +1420,7 @@ Ndb::opTupleIdOnNdb(const NdbTableImpl* table, tRecAttrResult = tOperation->getValue("NEXTID"); if (tConnection->execute( NdbTransaction::Commit ) == -1 ) goto error_handler; - opValue = tRecAttrResult->u_64_value(); // out + range.m_highest_seen = opValue = tRecAttrResult->u_64_value(); // out break; default: goto error_handler; @@ -1819,11 +1876,7 @@ Ndb::printState(const char* fmt, ...) NdbMutex_Lock(ndb_print_state_mutex); bool dups = false; unsigned i; - ndbout << buf << " ndb=" << hex << this << dec; -#ifndef NDB_WIN32 - ndbout << " thread=" << (int)pthread_self(); -#endif - ndbout << endl; + ndbout << buf << " ndb=" << hex << (void*)this << endl; for (unsigned n = 0; n < MAX_NDB_NODES; n++) { NdbTransaction* con = theConnectionArray[n]; if (con != 0) { diff --git a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp index ab6d90ad59e..0d226a97621 100644 --- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #define DEBUG_PRINT 0 #define INCOMPATIBLE_VERSION -2 @@ -1777,7 +1778,23 @@ NdbDictInterface::dictSignal(NdbApiSignal* sig, { DBUG_ENTER("NdbDictInterface::dictSignal"); DBUG_PRINT("enter", ("useMasterNodeId: %d", node_specification)); - for(Uint32 i = 0; i 0) + NdbSleep_MilliSleep(sleep + 10 * (rand() % mod)); + if (i == RETRIES / 2) + { + mod = 10; + } + if (i == 3*RETRIES/4) + { + sleep = 100; + } + m_buffer.clear(); // Protected area @@ -2340,6 +2357,22 @@ NdbDictionaryImpl::createTable(NdbTableImpl &t) { DBUG_ENTER("NdbDictionaryImpl::createTable"); + + bool autoIncrement = false; + Uint64 initialValue = 0; + for (Uint32 i = 0; i < t.m_columns.size(); i++) { + const NdbColumnImpl* c = t.m_columns[i]; + assert(c != NULL); + if (c->m_autoIncrement) { + if (autoIncrement) { + m_error.code = 4335; + DBUG_RETURN(-1); + } + autoIncrement = true; + initialValue = c->m_autoIncrementInitialValue; + } + } + // if the new name has not been set, use the copied name if (t.m_newExternalName.empty()) { @@ -2377,21 +2410,6 @@ NdbDictionaryImpl::createTable(NdbTableImpl &t) // auto-increment - use "t" because initial value is not in DICT { - bool autoIncrement = false; - Uint64 initialValue = 0; - for (Uint32 i = 0; i < t.m_columns.size(); i++) { - const NdbColumnImpl* c = t.m_columns[i]; - assert(c != NULL); - if (c->m_autoIncrement) { - if (autoIncrement) { - m_error.code = 4335; - delete t2; - DBUG_RETURN(-1); - } - autoIncrement = true; - initialValue = c->m_autoIncrementInitialValue; - } - } if (autoIncrement) { // XXX unlikely race condition - t.m_id may no longer be same table // the tuple id range is not used on input diff --git a/storage/ndb/src/ndbapi/NdbScanOperation.cpp b/storage/ndb/src/ndbapi/NdbScanOperation.cpp index afbec070ac8..96a3ce4332e 100644 --- a/storage/ndb/src/ndbapi/NdbScanOperation.cpp +++ b/storage/ndb/src/ndbapi/NdbScanOperation.cpp @@ -1340,29 +1340,41 @@ NdbIndexScanOperation::readTuples(LockMode lm, if(insertATTRINFO(word) == -1) res = -1; } - if(!res && order_by){ - m_ordered = true; + if (!res) + { + /** + * Note that it is valid to have order_desc true and order_by false. + * + * This means that there will be no merge sort among partitions, but + * each partition will still be returned in descending sort order. + * + * This is useful eg. if it is known that the scan spans only one + * partition. + */ if (order_desc) { m_descending = true; ScanTabReq * req = CAST_PTR(ScanTabReq, theSCAN_TABREQ->getDataPtrSend()); ScanTabReq::setDescendingFlag(req->requestInfo, true); } - Uint32 cnt = m_accessTable->getNoOfColumns() - 1; - m_sort_columns = cnt; // -1 for NDB$NODE - m_current_api_receiver = m_sent_receivers_count; - m_api_receivers_count = m_sent_receivers_count; + if (order_by) { + m_ordered = true; + Uint32 cnt = m_accessTable->getNoOfColumns() - 1; + m_sort_columns = cnt; // -1 for NDB$NODE + m_current_api_receiver = m_sent_receivers_count; + m_api_receivers_count = m_sent_receivers_count; - m_sort_columns = cnt; - for(Uint32 i = 0; im_index->m_columns[i]; - const NdbColumnImpl* col = m_currentTable->getColumn(key->m_keyInfoPos); - NdbRecAttr* tmp = NdbScanOperation::getValue_impl(col, (char*)-1); - UintPtr newVal = UintPtr(tmp); - theTupleKeyDefined[i][0] = FAKE_PTR; - theTupleKeyDefined[i][1] = (newVal & 0xFFFFFFFF); + m_sort_columns = cnt; + for(Uint32 i = 0; im_index->m_columns[i]; + const NdbColumnImpl* col = m_currentTable->getColumn(key->m_keyInfoPos); + NdbRecAttr* tmp = NdbScanOperation::getValue_impl(col, (char*)-1); + UintPtr newVal = UintPtr(tmp); + theTupleKeyDefined[i][0] = FAKE_PTR; + theTupleKeyDefined[i][1] = (newVal & 0xFFFFFFFF); #if (SIZEOF_CHARP == 8) - theTupleKeyDefined[i][2] = (newVal >> 32); + theTupleKeyDefined[i][2] = (newVal >> 32); #endif + } } } m_this_bound_start = 0; diff --git a/storage/ndb/src/ndbapi/ndberror.c b/storage/ndb/src/ndbapi/ndberror.c index e7f946118f2..363e25fc519 100644 --- a/storage/ndb/src/ndbapi/ndberror.c +++ b/storage/ndb/src/ndbapi/ndberror.c @@ -314,6 +314,7 @@ ErrorBundle ErrorCodes[] = { { 242, DMEC, AE, "Zero concurrency in scan"}, { 244, DMEC, AE, "Too high concurrency in scan"}, { 269, DMEC, AE, "No condition and attributes to read in scan"}, + { 874, DMEC, AE, "Too much attrinfo (e.g. scan filter) for scan in tuple manager" }, { 4600, DMEC, AE, "Transaction is already started"}, { 4601, DMEC, AE, "Transaction is not started"}, { 4602, DMEC, AE, "You must call getNdbOperation before executeScan" }, @@ -426,6 +427,7 @@ ErrorBundle ErrorCodes[] = { { 1512, DMEC, SE, "File read error" }, { 1513, DMEC, IE, "Filegroup not online" }, { 1514, DMEC, SE, "Currently there is a limit of one logfile group" }, + { 1515, DMEC, SE, "Currently there is a 4G limit of one undo/data-file in 32-bit host" }, { 773, DMEC, SE, "Out of string memory, please modify StringMemory config parameter" }, { 775, DMEC, SE, "Create file is not supported when Diskless=1" }, @@ -625,6 +627,8 @@ ErrorBundle ErrorCodes[] = { { 4274, DMEC, IE, "Corrupted main table PK in blob operation" }, { 4275, DMEC, AE, "The blob method is incompatible with operation type or lock mode" }, { 4294, DMEC, AE, "Scan filter is too large, discarded" }, + { 2810, DMEC, TR, "No space left on the device" }, + { 2815, DMEC, TR, "Error in reading files, please check file system" }, { NO_CONTACT_WITH_PROCESS, DMEC, AE, "No contact with the process (dead ?)."}, diff --git a/storage/ndb/test/include/AtrtClient.hpp b/storage/ndb/test/include/AtrtClient.hpp new file mode 100644 index 00000000000..5728aca2500 --- /dev/null +++ b/storage/ndb/test/include/AtrtClient.hpp @@ -0,0 +1,56 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef ATRT_CLIENT_HPP +#define ATRT_CLIENT_HPP + +#include + +class AtrtClient: public DbUtil { +public: + + enum AtrtCommandType { + ATCT_CHANGE_VERSION= 1, + ATCT_RESET_PROC= 2 + }; + + AtrtClient(const char* _user= "root", + const char* _password= "", + const char* _suffix= ".1.atrt"); + AtrtClient(MYSQL*); + ~AtrtClient(); + + + // Command functions + bool changeVersion(int process_id, const char* process_args); + bool resetProc(int process_id); + + // Query functions + bool getConnectString(int cluster_id, SqlResultSet& result); + bool getClusters(SqlResultSet& result); + bool getMgmds(int cluster_id, SqlResultSet& result); + bool getNdbds(int cluster_id, SqlResultSet& result); + +private: + int writeCommand(AtrtCommandType _type, + const Properties& args); + bool readCommand(uint command_id, + SqlResultSet& result); + + bool doCommand(AtrtCommandType _type, + const Properties& args); +}; + +#endif diff --git a/storage/ndb/test/include/DbUtil.hpp b/storage/ndb/test/include/DbUtil.hpp new file mode 100755 index 00000000000..d865c92f9a3 --- /dev/null +++ b/storage/ndb/test/include/DbUtil.hpp @@ -0,0 +1,176 @@ +/* Copyright (C) 2007 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +// dbutil.h: interface for the database utilities class. +// Supplies a database to the test application + +#ifndef DBUTIL_HPP +#define DBUTIL_HPP + +#include +#include +#include +#include +#include + +//#define DEBUG +#define DIE_UNLESS(expr) \ + ((void) ((expr) ? 0 : (Die(__FILE__, __LINE__, #expr), 0))) +#define DIE(expr) \ + Die(__FILE__, __LINE__, #expr) +#define myerror(msg) printError(msg) +#define mysterror(stmt, msg) printStError(stmt, msg) +#define CheckStmt(stmt) \ +{ \ +if ( stmt == 0) \ + myerror(NULL); \ +DIE_UNLESS(stmt != 0); \ +} + +#define check_execute(stmt, r) \ +{ \ +if (r) \ + mysterror(stmt, NULL); \ +DIE_UNLESS(r == 0);\ +} + + +class SqlResultSet : public Properties { +public: + + // Get row with number + bool get_row(int row_num); + // Load next row + bool next(void); + // Reset iterator + void reset(void); + // Remove current row from resultset + void remove(); + + SqlResultSet(); + ~SqlResultSet(); + + const char* column(const char* col_name); + uint columnAsInt(const char* col_name); + + uint insertId(); + uint affectedRows(); + uint numRows(void); + uint mysqlErrno(); + const char* mysqlError(); + const char* mysqlSqlstate(); + +private: + uint get_int(const char* name); + const char* get_string(const char* name); + + const Properties* m_curr_row; + uint m_curr_row_num; +}; + + +#define DBU_FAILED 1 +#define DBU_OK 0 + +class DbUtil +{ +public: + + DbUtil(MYSQL* mysql); + DbUtil(const char* dbname = "mysql", + const char* user = "root", + const char* pass = "", + const char* suffix = NULL); + ~DbUtil(); + + bool doQuery(const char* query); + bool doQuery(const char* query, SqlResultSet& result); + bool doQuery(const char* query, const Properties& args, SqlResultSet& result); + + bool doQuery(BaseString& str); + bool doQuery(BaseString& str, SqlResultSet& result); + bool doQuery(BaseString& str, const Properties& args, SqlResultSet& result); + + bool waitConnected(int timeout); + + /* Deprecated, see connect() */ + void databaseLogin(const char * system, + const char * usr, + const char * password, + unsigned int portIn, + const char * sockIn, + bool transactional); + + const char * getDbName() {return m_dbname.c_str();}; + const char * getUser() {return m_user.c_str();}; + const char * getPassword(){return m_pass.c_str();}; + const char * getHost() {return m_host.c_str();}; + const char * getSocket() {return m_socket.c_str();}; + const char * getServerType(){return mysql_get_server_info(m_mysql);}; + const char * getError(); + + MYSQL * getMysql(){return m_mysql;}; + MYSQL_STMT * STDCALL mysqlSimplePrepare(const char *query); + + void databaseLogout(); + void mysqlCloseStmHandle(MYSQL_STMT *my_stmt); + + int connect(); + void disconnect(); + int selectDb(); + int selectDb(const char *); + int createDb(BaseString&); + int getErrorNumber(); + + unsigned long selectCountTable(const char * table); + +protected: + + bool runQuery(const char* query, + const Properties& args, + SqlResultSet& rows); + + bool isConnected(); + + MYSQL * m_mysql; + bool m_free_mysql; /* Don't free mysql* if allocated elsewhere */ + +private: + + bool m_connected; + + BaseString m_host; // Computer to connect to + BaseString m_user; // MySQL User + BaseString m_pass; // MySQL User Password + BaseString m_dbname; // Database to use + BaseString m_socket; // MySQL Server Unix Socket + BaseString m_default_file; + BaseString m_default_group; + + unsigned int m_port; // MySQL Server port + + void setDbName(const char * name){m_dbname.assign(name);}; + void setUser(const char * user_name){m_user.assign(user_name);}; + void setPassword(const char * password){m_pass.assign(password);}; + void setHost(const char * system){m_host.assign(system);}; + void setPort(unsigned int portIn){m_port=portIn;}; + void setSocket(const char * sockIn){m_socket.assign(sockIn);}; + void printError(const char *msg); + void printStError(MYSQL_STMT *stmt, const char *msg); + void die(const char *file, int line, const char *expr); // stop program + +}; +#endif + diff --git a/storage/ndb/test/include/dbutil.hpp b/storage/ndb/test/include/dbutil.hpp deleted file mode 100755 index 2b36965715f..00000000000 --- a/storage/ndb/test/include/dbutil.hpp +++ /dev/null @@ -1,97 +0,0 @@ -// dbutil.h: interface for the database utilities class. -////////////////////////////////////////////////////////////////////// -// Supplies a database to the test application -////////////////////////////////////////////////////////////////////// - -#ifndef DBUTIL_HPP -#define DBUTIL_HPP - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 -#include -#include -#include -#include -//include "rand.h" -#include - -//#define DEBUG -#define DIE_UNLESS(expr) \ - ((void) ((expr) ? 0 : (Die(__FILE__, __LINE__, #expr), 0))) -#define DIE(expr) \ - Die(__FILE__, __LINE__, #expr) -#define myerror(msg) PrintError(msg) -#define mysterror(stmt, msg) PrintStError(stmt, msg) -#define CheckStmt(stmt) \ -{ \ -if ( stmt == 0) \ - myerror(NULL); \ -DIE_UNLESS(stmt != 0); \ -} - -#define check_execute(stmt, r) \ -{ \ -if (r) \ - mysterror(stmt, NULL); \ -DIE_UNLESS(r == 0);\ -} - -#define TRUE 1 -#define FALSE 0 - - -class dbutil -{ -public: - - dbutil(const char * databaseName); - ~dbutil(); - - void DatabaseLogin(const char * system, - const char * usr, - const char * password, - unsigned int portIn, - const char * sockIn, - bool transactional); - char * GetDbName(){return dbs;}; - char * GetUser(){return user;}; - char * GetPassword(){return pass;}; - char * GetHost(){return host;}; - char * GetSocket(){return socket;}; - const char * GetServerType(){return mysql_get_server_info(myDbHandel);}; - MYSQL* GetDbHandel(){return myDbHandel;}; - MYSQL_STMT *STDCALL MysqlSimplePrepare(const char *query); - int Select_DB(); - int Do_Query(char * stm); - const char * GetError(); - int GetErrorNumber(); - unsigned long SelectCountTable(const char * table); - -private: - - //Connect variables - char * databaseName; //hold results file name - char host[256]; // Computer to connect to - char user[256]; // MySQL User - char pass[256]; // MySQL User Password - char dbs[256]; // Database to use (TPCB) - unsigned int port; // MySQL Server port - char socket[256]; // MySQL Server Unix Socket - MYSQL *myDbHandel; - - void DatabaseLogout(); - - void SetDbName(const char * name){strcpy((char *)dbs, name);}; - void SetUser(const char * userName){strcpy((char *)user, userName);}; - void SetPassword(const char * password){strcpy((char *)pass,password);}; - void SetHost(const char * system){strcpy((char*)host, system);}; - void SetPort(unsigned int portIn){port=portIn;}; - void SetSocket(const char * sockIn){strcpy((char *)socket, sockIn);}; - void PrintError(const char *msg); - void PrintStError(MYSQL_STMT *stmt, const char *msg); - void Die(const char *file, int line, const char *expr); // stop program - -}; -#endif - diff --git a/storage/ndb/test/ndbapi/Makefile.am b/storage/ndb/test/ndbapi/Makefile.am index ad509dbbafe..81bb346417f 100644 --- a/storage/ndb/test/ndbapi/Makefile.am +++ b/storage/ndb/test/ndbapi/Makefile.am @@ -52,7 +52,9 @@ testBitfield \ DbCreate DbAsyncGenerator \ testSRBank \ test_event_merge \ -testIndexStat +testIndexStat \ +testNDBT \ +NdbRepStress EXTRA_PROGRAMS = \ test_event \ @@ -98,7 +100,10 @@ ndbapi_slow_select_SOURCES = slow_select.cpp testReadPerf_SOURCES = testReadPerf.cpp testLcp_SOURCES = testLcp.cpp testPartitioning_SOURCES = testPartitioning.cpp +testNDBT_SOURCES = testNDBT.cpp +testNDBT_LDADD = $(LDADD) $(top_srcdir)/libmysql_r/libmysqlclient_r.la testBitfield_SOURCES = testBitfield.cpp +NdbRepStress_SOURCES = acrt/NdbRepStress.cpp DbCreate_SOURCES = bench/mainPopulate.cpp bench/dbPopulate.cpp bench/userInterface.cpp bench/dbPopulate.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp DbAsyncGenerator_SOURCES = bench/mainAsyncGenerator.cpp bench/asyncGenerator.cpp bench/ndb_async2.cpp bench/dbGenerator.h bench/macros.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp testSRBank_SOURCES = testSRBank.cpp @@ -115,8 +120,10 @@ include $(top_srcdir)/storage/ndb/config/type_ndbapitest.mk.am ##testIndex_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/include/kernel ##testSystemRestart_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/include/kernel ##testTransactions_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/include/kernel +NdbRepStress_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/test/include -I$(top_srcdir)/include testBackup_LDADD = $(LDADD) bank/libbank.a testSRBank_LDADD = bank/libbank.a $(LDADD) +NdbRepStress_LDADD = $(LDADD) $(top_builddir)/libmysql_r/libmysqlclient_r.la # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/storage/ndb/test/ndbapi/acrt/NdbRepStress.cpp b/storage/ndb/test/ndbapi/acrt/NdbRepStress.cpp new file mode 100644 index 00000000000..644405636ba --- /dev/null +++ b/storage/ndb/test/ndbapi/acrt/NdbRepStress.cpp @@ -0,0 +1,456 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + 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 +#include +#include +#include +#include + +/* +Will include restart testing in future phases +#include +#include +*/ + +/**** TOOL SECTION ****/ + +static uint +urandom() +{ + uint r = (uint)random(); + return r; +} + +static uint +urandom(uint m) +{ + if (m == 0) + return NDBT_OK; + uint r = urandom(); + r = r % m; + return r; +} + +#define GETNDB(ps) ((NDBT_NdbApiStep*)ps)->getNdb() +/* +*/ + +int +syncSlaveWithMaster() +{ + /* + We need to look at the MAX epoch of the + mysql.ndb_binlog_index table so we will + know when the slave has caught up + */ + + SqlResultSet result; + unsigned int masterEpoch = 0; + unsigned int slaveEpoch = 0; + unsigned int slaveEpochOld = 0; + int maxLoops = 100; + int loopCnt = 0; + + //Create a DbUtil object for the master + DbUtil master("mysql",""); + + //Login to Master + if (!master.connect()) + { + return NDBT_FAILED; + } + + //Get max epoch from master + if(master.doQuery("SELECT MAX(epoch) FROM mysql.ndb_binlog_index", result)) + { + return NDBT_FAILED; + } + masterEpoch = result.columnAsInt("epoch"); + + /* + Now we will pull current epoch from slave. If not the + same as master, we will continue to retrieve the epoch + and compare until it matches or we reach the max loops + allowed. + */ + + //Create a dbutil object for the slave + DbUtil slave("mysql",".slave"); + + //Login to slave + if (!slave.connect()) + { + return NDBT_FAILED; + } + + while(slaveEpoch != masterEpoch && loopCnt < maxLoops) + { + if(slave.doQuery("SELECT epoch FROM mysql.ndb_apply_status",result)) + { + return NDBT_FAILED; + } + slaveEpoch = result.columnAsInt("epoch"); + + if(slaveEpoch != slaveEpochOld) + { + slaveEpochOld = slaveEpoch; + if(loopCnt > 0) + loopCnt--; + sleep(3); + } + else + { + sleep(1); + loopCnt++; + } + } + + if(slaveEpoch != masterEpoch) + { + g_err << "Slave not in sync with master!" << endl; + return NDBT_FAILED; + } + return NDBT_OK; +} + +int +verifySlaveLoad(BaseString &table) +{ + //BaseString sqlStm; + BaseString db; + unsigned int masterCount = 0; + unsigned int slaveCount = 0; + + db.assign("TEST_DB"); + //sqlStm.assfmt("SELECT COUNT(*) FROM %s", table); + + //First thing to do is sync slave + if(syncSlaveWithMaster()) + { + g_err << "Verify Load -> Syncing with slave failed" << endl; + return NDBT_FAILED; + } + + //Now that slave is sync we can verify load + DbUtil master(db.c_str()," "); + + //Login to Master + if (!master.connect()) + { + return NDBT_FAILED; + } + + if((masterCount = master.selectCountTable(table.c_str())) == 0 ) + { + return NDBT_FAILED; + } + + //Create a DB Object for slave + DbUtil slave(db.c_str(),".slave"); + + //Login to slave + if (!slave.connect()) + { + return NDBT_FAILED; + } + + if((slaveCount = slave.selectCountTable(table.c_str())) == 0 ) + { + return NDBT_FAILED; + } + + if(slaveCount != masterCount) + { + g_err << "Verify Load -> Slave Count != Master Count " + << endl; + return NDBT_FAILED; + } + return NDBT_OK; +} + +int +createTEST_DB(NDBT_Context* ctx, NDBT_Step* step) +{ + BaseString cdb; + cdb.assign("TEST_DB"); + + //Create a dbutil object + DbUtil master("mysql",""); + + if (master.connect()) + { + if (master.createDb(cdb) == NDBT_OK) + { + return NDBT_OK; + } + } + return NDBT_FAILED; +} + +int +dropTEST_DB(NDBT_Context* ctx, NDBT_Step* step) +{ + //Create an SQL Object + DbUtil master("mysql",""); + + //Login to Master + if (!master.connect()) + { + return NDBT_FAILED; + } + + if(master.doQuery("DROP DATABASE TEST_DB") != NDBT_OK) + { + return NDBT_FAILED; + } + + if(syncSlaveWithMaster() != NDBT_OK) + { + g_err << "Drop DB -> Syncing with slave failed" + << endl; + return NDBT_FAILED; + } + return NDBT_OK; +} + +int +verifySlave(BaseString& sqlStm, BaseString& db, BaseString& column) +{ + SqlResultSet result; + float masterSum; + float slaveSum; + + //Create SQL Objects + DbUtil master(db.c_str(),""); + DbUtil slave(db.c_str(),".slave"); + + if(syncSlaveWithMaster() != NDBT_OK) + { + g_err << "Verify Slave rep1 -> Syncing with slave failed" + << endl; + return NDBT_FAILED; + } + + //Login to Master + if (!master.connect()) + { + return NDBT_FAILED; + } + + if(master.doQuery(sqlStm.c_str(),result) != NDBT_OK) + { + return NDBT_FAILED; + } + masterSum = result.columnAsInt(column.c_str()); + + //Login to slave + if (!slave.connect()) + { + return NDBT_FAILED; + } + + if(slave.doQuery(sqlStm.c_str(),result) != NDBT_OK) + { + return NDBT_FAILED; + } + slaveSum = result.columnAsInt(column.c_str()); + + if(masterSum != slaveSum) + { + g_err << "VerifySlave -> masterSum != slaveSum..." << endl; + return NDBT_FAILED; + } + return NDBT_OK; +} + + +/**** Test Section ****/ + +int +createDB(NDBT_Context* ctx, NDBT_Step* step) +{ + BaseString cdb; + cdb.assign("TEST_DB"); + + //Create a dbutil object + DbUtil master("mysql",""); + + if (master.connect()) + { + if (master.createDb(cdb) == NDBT_OK) + { + return NDBT_OK; + } + } + return NDBT_FAILED; +} + +int +createTable_rep1(NDBT_Context* ctx, NDBT_Step* step) +{ + BaseString table; + BaseString db; + + table.assign("rep1"); + db.assign("TEST_DB"); + + //Ensure slave is up and ready + if(syncSlaveWithMaster() != NDBT_OK) + { + g_err << "Create Table -> Syncing with slave failed" + << endl; + return NDBT_FAILED; + } + + //Create an SQL Object + DbUtil master(db.c_str(),""); + + //Login to Master + if (!master.connect()) + { + return NDBT_FAILED; + } + + if (master.doQuery("CREATE TABLE rep1 (c1 MEDIUMINT NOT NULL AUTO_INCREMENT," + " c2 FLOAT, c3 CHAR(5), c4 bit(8), c5 FLOAT, c6 INT," + " c7 INT, PRIMARY KEY (c1))ENGINE=NDB")) + { + return NDBT_FAILED; + } + ctx->setProperty("TABLES",table.c_str()); + HugoTransactions hugoTrans(*ctx->getTab()); + + if (hugoTrans.loadTable(GETNDB(step), ctx->getNumRecords(), 1, true, 0) != NDBT_OK) + { + g_err << "Create Table -> Load failed!" << endl; + return NDBT_FAILED; + } + + if(verifySlaveLoad(table)!= NDBT_OK) + { + g_err << "Create Table -> Failed on verify slave load!" + << endl; + return NDBT_FAILED; + } + //else everything is okay + return NDBT_OK; +} + +int +stressNDB_rep1(NDBT_Context* ctx, NDBT_Step* step) +{ + const NdbDictionary::Table * table= ctx->getTab(); + HugoTransactions hugoTrans(* table); + while(!ctx->isTestStopped()) + { + if (hugoTrans.pkUpdateRecords(GETNDB(step), ctx->getNumRecords(), 1, 30) != 0) + { + g_err << "pkUpdate Failed!" << endl; + return NDBT_FAILED; + } + if (hugoTrans.scanUpdateRecords(GETNDB(step), ctx->getNumRecords(), 1, 30) != 0) + { + g_err << "scanUpdate Failed!" << endl; + return NDBT_FAILED; + } + } + return NDBT_OK; +} + +int +stressSQL_rep1(NDBT_Context* ctx, NDBT_Step* step) +{ + BaseString sqlStm; + + DbUtil master("TEST_DB",""); + int loops = ctx->getNumLoops(); + uint record = 0; + + //Login to Master + if (!master.connect()) + { + ctx->stopTest(); + return NDBT_FAILED; + } + + for (int j= 0; loops == 0 || j < loops; j++) + { + record = urandom(ctx->getNumRecords()); + sqlStm.assfmt("UPDATE TEST_DB.rep1 SET c2 = 33.3221 where c1 = %u", record); + if(master.doQuery(sqlStm.c_str())) + { + return NDBT_FAILED; + } + } + ctx->stopTest(); + return NDBT_OK; +} + +int +verifySlave_rep1(NDBT_Context* ctx, NDBT_Step* step) +{ + BaseString sql; + BaseString db; + BaseString column; + + sql.assign("SELECT SUM(c3) FROM rep1"); + db.assign("TEST_DB"); + column.assign("c3"); + + if (verifySlave(sql,db,column) != NDBT_OK) + return NDBT_FAILED; + return NDBT_OK; +} + +/* TOOLS LIST + + syncSlaveWithMaster() + {ensures slave is at same epoch as master} + + verifySlaveLoad(BaseString *table) + {ensures slave table has same record count as master} + + createTEST_DB() + {Creates TEST_DB database on master} + + dropTEST_DB() + {Drops TEST_DB database on master} + + verifySlave(BaseString& sql, BaseSting& db, BaseSting& column) + {The SQL statement must sum a column and will verify + that the sum of the column is equal on master & slave} +*/ + + +NDBT_TESTSUITE(NdbRepStress); +TESTCASE("PHASE_I_Stress","Basic Replication Stressing") +{ + INITIALIZER(createDB); + INITIALIZER(createTable_rep1); + STEP(stressNDB_rep1); + STEP(stressSQL_rep1); + FINALIZER(verifySlave_rep1); + FINALIZER(dropTEST_DB); +} +NDBT_TESTSUITE_END(NdbRepStress); + +int main(int argc, const char** argv){ + ndb_init(); + NdbRepStress.setCreateAllTables(true); + return NdbRepStress.execute(argc, argv); +} + diff --git a/storage/ndb/test/ndbapi/testBitfield.cpp b/storage/ndb/test/ndbapi/testBitfield.cpp index 8ba8f3d92ef..41bb7b4622c 100644 --- a/storage/ndb/test/ndbapi/testBitfield.cpp +++ b/storage/ndb/test/ndbapi/testBitfield.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include static const char* _dbname = "TEST_DB"; static int g_loops = 7; @@ -37,6 +39,7 @@ static int unique_indexes(Ndb*, const NdbDictionary::Table* tab); static int ordered_indexes(Ndb*, const NdbDictionary::Table* tab); static int node_restart(Ndb*, const NdbDictionary::Table* tab); static int system_restart(Ndb*, const NdbDictionary::Table* tab); +static int testBitmask(); int main(int argc, char** argv){ @@ -49,6 +52,15 @@ main(int argc, char** argv){ ndb_std_get_one_option))) return NDBT_ProgramExit(NDBT_WRONGARGS); + int res = NDBT_FAILED; + + /* Run cluster-independent tests */ + for (int i=0; i<(10*g_loops); i++) + { + if (NDBT_OK != (res= testBitmask())) + return NDBT_ProgramExit(res); + } + Ndb_cluster_connection con(opt_connect_str); if(con.connect(12, 5, 1)) { @@ -60,7 +72,6 @@ main(int argc, char** argv){ pNdb = new Ndb(&con, _dbname); pNdb->init(); while (pNdb->waitUntilReady() != 0); - int res = NDBT_FAILED; NdbDictionary::Dictionary * dict = pNdb->getDictionary(); @@ -121,14 +132,12 @@ create_random_table(Ndb* pNdb) do { NdbDictionary::Table tab; Uint32 cols = 1 + (rand() % (NDB_MAX_ATTRIBUTES_IN_TABLE - 1)); - Uint32 keys = NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY; Uint32 length = 4090; - Uint32 key_size = NDB_MAX_KEYSIZE_IN_WORDS; BaseString name; name.assfmt("TAB_%d", rand() & 65535); tab.setName(name.c_str()); - for(int i = 0; i 2; i++) + for(Uint32 i = 0; i 2; i++) { NdbDictionary::Column col; name.assfmt("COL_%d", i); @@ -206,3 +215,394 @@ system_restart(Ndb* pNdb, const NdbDictionary::Table* tab) { return 0; } + +/* Note : folowing classes test functionality of storage/ndb/src/common/util/Bitmask.cpp + * and were originally defined there. + * Set BITMASK_DEBUG to 1 to get more test debugging info. + */ +#define BITMASK_DEBUG 0 + +static +bool cmp(const Uint32 b1[], const Uint32 b2[], Uint32 len) +{ + Uint32 sz32 = (len + 31) >> 5; + for(Uint32 i = 0; i> 5, src, i+pos)) + printf("1"); + else + printf("0"); + if((i & 31) == 31) + printf(" "); + } +} + +static int lrand() +{ + return rand(); +} + +static +void rand(Uint32 dst[], Uint32 len) +{ + for(Uint32 i = 0; i> 5, dst, i, (lrand() % 1000) > 500); +} + +static +int checkNoTramplingGetSetField(const Uint32 totalTests) +{ + const Uint32 numWords= 67; + const Uint32 maxBitsToCopy= (numWords * 32); + Uint32 sourceBuf[numWords]; + Uint32 targetBuf[numWords]; + + ndbout << "Testing : Bitmask NoTrampling\n"; + + memset(sourceBuf, 0x00, (numWords*4)); + + for (Uint32 test=0; test= srcStart) && + (bitNum < (srcStart + length))); + bool actualValue= (((targetWord >> bit) & 1) == 1); + if (BITMASK_DEBUG) + ndbout << "bitNum=%u expectedValue=%u, actual value=%u" + << bitNum << expectedValue << actualValue; + + if (actualValue != expectedValue) + { + ndbout << "Notrampling setField failed for srcStart " + << srcStart + << " length " << length + << " at word " << word << " bit " << bit << "\n"; + ndbout << "bitNum=%u expectedValue=%u, actual value=%u" + << bitNum << expectedValue << actualValue; + return -1; + } + } + } + + } + + return 0; +} + +static +int simple(int pos, int size) +{ + ndbout << "Testing : Bitmask simple pos: " << pos << " size: " << size << "\n"; + Vector _mask; + Vector _src; + Vector _dst; + Uint32 sz32 = (size + pos + 32) >> 5; + const Uint32 sz = 4 * sz32; + + Uint32 zero = 0; + _mask.fill(sz32+1, zero); + _src.fill(sz32+1, zero); + _dst.fill(sz32+1, zero); + + Uint32 * src = _src.getBase(); + Uint32 * dst = _dst.getBase(); + Uint32 * mask = _mask.getBase(); + + memset(src, 0x0, sz); + memset(dst, 0x0, sz); + memset(mask, 0xFF, sz); + rand(src, size); + BitmaskImpl::setField(sz32, mask, pos, size, src); + BitmaskImpl::getField(sz32, mask, pos, size, dst); + if (BITMASK_DEBUG) + { + printf("src: "); print(src, size+31); printf("\n"); + printf("msk: "); print(mask, (sz32 << 5) + 31); printf("\n"); + printf("dst: "); print(dst, size+31); printf("\n"); + } + return (cmp(src, dst, size+31)?0 : -1); +}; + +struct Alloc +{ + Uint32 pos; + Uint32 size; + Vector data; +}; + +static +int +testRanges(Uint32 bitmask_size) +{ + Vector alloc_list; + bitmask_size = (bitmask_size + 31) & ~31; + Uint32 sz32 = (bitmask_size >> 5); + Vector alloc_mask; + Vector test_mask; + + ndbout_c("Testing : Bitmask ranges for bitmask of size %d", bitmask_size); + Uint32 zero = 0; + alloc_mask.fill(sz32, zero); + test_mask.fill(sz32, zero); + + /* Loop a number of times, setting and clearing bits in the mask + * and tracking the modifications in a separate structure. + * Check that both structures remain in sync + */ + for(int i = 0; i<5000; i++) + { + Vector tmp; + tmp.fill(sz32, zero); + + Uint32 pos = lrand() % (bitmask_size - 1); + Uint32 free = 0; + if(BitmaskImpl::get(sz32, alloc_mask.getBase(), pos)) + { + // Bit was allocated + // 1) Look up allocation + // 2) Check data + // 3) free it + size_t j; + Uint32 min, max; + for(j = 0; j= min && pos < max) + { + break; + } + } + if (! ((pos >= min) && (pos < max))) + { + printf("Failed with pos %u, min %u, max %u\n", + pos, min, max); + return -1; + } + BitmaskImpl::getField(sz32, test_mask.getBase(), min, max-min, + tmp.getBase()); + if(BITMASK_DEBUG) + { + printf("freeing [ %d %d ]", min, max); + printf("- mask: "); + print(tmp.getBase(), max - min); + + printf(" save: "); + size_t k; + Alloc& a = alloc_list[j]; + for(k = 0; k tmp; + tmp.fill(sz32, zero); + + // Bit was free + // 1) Check how much space is avaiable + // 2) Create new allocation of lrandom size + // 3) Fill data with lrandom data + // 4) Update alloc mask + while(pos+free < bitmask_size && + !BitmaskImpl::get(sz32, alloc_mask.getBase(), pos+free)) + free++; + + Uint32 sz = + (free <= 64 && ((lrand() % 100) > 80)) ? free : (lrand() % free); + sz = sz ? sz : 1; + sz = pos + sz == bitmask_size ? sz - 1 : sz; + Alloc a; + a.pos = pos; + a.size = sz; + a.data.fill(((sz+31)>> 5)-1, zero); + if(BITMASK_DEBUG) + printf("pos %d -> alloc [ %d %d ]", pos, pos, pos+sz); + for(size_t j = 0; j 500) + BitmaskImpl::set((sz + 31) >> 5, a.data.getBase(), j); + } + if(BITMASK_DEBUG) + { + printf("- mask: "); + print(a.data.getBase(), sz); + printf("\n"); + } + BitmaskImpl::setField(sz32, test_mask.getBase(), pos, sz, + a.data.getBase()); + alloc_list.push_back(a); + } + } + +#define NDB_BM_SUPPORT_RANGE +#ifdef NDB_BM_SUPPORT_RANGE + for(Uint32 i = 0; i<1000; i++) + { + Uint32 sz32 = 10+rand() % 100; + Uint32 zero = 0; + Vector map; + map.fill(sz32, zero); + + Uint32 sz = 32 * sz32; + Uint32 start = (rand() % sz); + Uint32 stop = start + ((rand() % (sz - start)) & 0xFFFFFFFF); + + Vector check; + check.fill(sz32, zero); + + /* Verify range setting method works correctly */ + for(Uint32 j = 0; j= start && j= start && j; +template class Vector; diff --git a/storage/ndb/test/ndbapi/testDict.cpp b/storage/ndb/test/ndbapi/testDict.cpp index e1b8f2b3c7f..ae940074067 100644 --- a/storage/ndb/test/ndbapi/testDict.cpp +++ b/storage/ndb/test/ndbapi/testDict.cpp @@ -2357,6 +2357,168 @@ runBug24631(NDBT_Context* ctx, NDBT_Step* step) return NDBT_OK; } +int +runBug29186(NDBT_Context* ctx, NDBT_Step* step) +{ + int lgError = 15000; + int tsError = 16000; + int res; + char lgname[256]; + char ufname[256]; + char tsname[256]; + char dfname[256]; + + NdbRestarter restarter; + + if (restarter.getNumDbNodes() < 2){ + ctx->stopTest(); + return NDBT_OK; + } + + Ndb* pNdb = GETNDB(step); + NdbDictionary::Dictionary* pDict = pNdb->getDictionary(); + NdbDictionary::Dictionary::List list; + + if (pDict->listObjects(list) == -1) + return NDBT_FAILED; + + // 1.create logfile group + const char * lgfound = 0; + + for (Uint32 i = 0; icreateLogfileGroup(lg) != 0) + { + g_err << "Failed to create logfilegroup:" + << endl << pDict->getNdbError() << endl; + return NDBT_FAILED; + } + } + else + { + BaseString::snprintf(lgname, sizeof(lgname), "%s", lgfound); + } + + if(restarter.waitClusterStarted(60)){ + g_err << "waitClusterStarted failed"<< endl; + return NDBT_FAILED; + } + + if(restarter.insertErrorInAllNodes(lgError) != 0){ + g_err << "failed to set error insert"<< endl; + return NDBT_FAILED; + } + + g_info << "error inserted" << endl; + g_info << "waiting some before add log file" << endl; + g_info << "starting create log file group" << endl; + + NdbDictionary::Undofile uf; + BaseString::snprintf(ufname, sizeof(ufname), "%s-%u", lgname, rand()); + uf.setPath(ufname); + uf.setSize(2*1024*1024); + uf.setLogfileGroup(lgname); + + if(pDict->createUndofile(uf) == 0) + { + g_err << "Create log file group should fail on error_insertion " << lgError << endl; + return NDBT_FAILED; + } + + //clear lg error + if(restarter.insertErrorInAllNodes(15099) != 0){ + g_err << "failed to set error insert"<< endl; + return NDBT_FAILED; + } + NdbSleep_SecSleep(5); + + //lg error has been cleared, so we can add undo file + if(pDict->createUndofile(uf) != 0) + { + g_err << "Failed to create undofile:" + << endl << pDict->getNdbError() << endl; + return NDBT_FAILED; + } + + if(restarter.waitClusterStarted(60)){ + g_err << "waitClusterStarted failed"<< endl; + return NDBT_FAILED; + } + + if(restarter.insertErrorInAllNodes(tsError) != 0){ + g_err << "failed to set error insert"<< endl; + return NDBT_FAILED; + } + g_info << "error inserted" << endl; + g_info << "waiting some before create table space" << endl; + g_info << "starting create table space" << endl; + + //r = runCreateTablespace(ctx, step); + BaseString::snprintf(tsname, sizeof(tsname), "TS-%u", rand()); + BaseString::snprintf(dfname, sizeof(dfname), "%s-%u-1.dat", tsname, rand()); + + NdbDictionary::Tablespace ts; + ts.setName(tsname); + ts.setExtentSize(1024*1024); + ts.setDefaultLogfileGroup(lgname); + + if(pDict->createTablespace(ts) != 0) + { + g_err << "Failed to create tablespace:" + << endl << pDict->getNdbError() << endl; + return NDBT_FAILED; + } + + NdbDictionary::Datafile df; + df.setPath(dfname); + df.setSize(1*1024*1024); + df.setTablespace(tsname); + + if(pDict->createDatafile(df) == 0) + { + g_err << "Create table space should fail on error_insertion " << tsError << endl; + return NDBT_FAILED; + } + //Clear the inserted error + if(restarter.insertErrorInAllNodes(16099) != 0){ + g_err << "failed to set error insert"<< endl; + return NDBT_FAILED; + } + NdbSleep_SecSleep(5); + + if (pDict->dropTablespace(pDict->getTablespace(tsname)) != 0) + { + g_err << "Failed to drop tablespace: " << pDict->getNdbError() << endl; + return NDBT_FAILED; + } + + if (lgfound == 0) + { + if (pDict->dropLogfileGroup(pDict->getLogfileGroup(lgname)) != 0) + return NDBT_FAILED; + } + + return NDBT_OK; +} + struct RandSchemaOp { struct Obj @@ -3123,6 +3285,10 @@ TESTCASE("Bug24631", ""){ INITIALIZER(runBug24631); } +TESTCASE("Bug29186", + ""){ + INITIALIZER(runBug29186); +} NDBT_TESTSUITE_END(testDict); int main(int argc, const char** argv){ diff --git a/storage/ndb/test/ndbapi/testInterpreter.cpp b/storage/ndb/test/ndbapi/testInterpreter.cpp index 0dc032ba7aa..22b810107b4 100644 --- a/storage/ndb/test/ndbapi/testInterpreter.cpp +++ b/storage/ndb/test/ndbapi/testInterpreter.cpp @@ -77,6 +77,11 @@ int runTestIncValue32(NDBT_Context* ctx, NDBT_Step* step){ const NdbDictionary::Table * pTab = ctx->getTab(); Ndb* pNdb = GETNDB(step); + if (strcmp(pTab->getName(), "T1") != 0) { + g_err << "runTestBug19537: skip, table != T1" << endl; + return NDBT_OK; + } + NdbConnection* pTrans = pNdb->startTransaction(); if (pTrans == NULL){ @@ -258,6 +263,84 @@ int runTestBug19537(NDBT_Context* ctx, NDBT_Step* step){ } +int runTestBug34107(NDBT_Context* ctx, NDBT_Step* step){ + int result = NDBT_OK; + const NdbDictionary::Table * pTab = ctx->getTab(); + Ndb* pNdb = GETNDB(step); + + int i; + for (i = 0; i <= 1; i++) { + g_info << "bug34107:" << (i == 0 ? " small" : " too big") << endl; + + NdbConnection* pTrans = pNdb->startTransaction(); + if (pTrans == NULL){ + ERR(pNdb->getNdbError()); + return NDBT_FAILED; + } + + NdbScanOperation* pOp = pTrans->getNdbScanOperation(pTab->getName()); + if (pOp == NULL) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + if (pOp->readTuples() == -1) { + ERR(pOp->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + int n = i == 0 ? 10000 : 30000; + int k; + + for (k = 0; k < n; k++) { + + // inserts 1 word ATTRINFO + + if (pOp->interpret_exit_ok() == -1) { + ERR(pOp->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + } + + if (pTrans->execute(NoCommit) == -1) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + int ret; + while ((ret = pOp->nextResult()) == 0) + ; + g_info << "ret=" << ret << " err=" << pOp->getNdbError().code << endl; + + if (i == 0 && ret != 1) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + if (i == 1 && ret != -1) { + g_err << "unexpected big filter success" << endl; + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + if (i == 1 && pOp->getNdbError().code != 874) { + g_err << "unexpected big filter error code, wanted 874" << endl; + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + pNdb->closeTransaction(pTrans); + } + + return NDBT_OK; +} + + NDBT_TESTSUITE(testInterpreter); TESTCASE("IncValue32", "Test incValue for 32 bit integer\n"){ @@ -277,6 +360,12 @@ TESTCASE("Bug19537", INITIALIZER(runTestBug19537); FINALIZER(runClearTable); } +TESTCASE("Bug34107", + "Test too big scan filter (error 874)\n"){ + INITIALIZER(runLoadTable); + INITIALIZER(runTestBug34107); + FINALIZER(runClearTable); +} #if 0 TESTCASE("MaxTransactions", "Start transactions until no more can be created\n"){ diff --git a/storage/ndb/test/ndbapi/testNDBT.cpp b/storage/ndb/test/ndbapi/testNDBT.cpp new file mode 100644 index 00000000000..9c911b9a9d9 --- /dev/null +++ b/storage/ndb/test/ndbapi/testNDBT.cpp @@ -0,0 +1,173 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + 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 +#include +#include + + +int runTestAtrtClient(NDBT_Context* ctx, NDBT_Step* step){ + AtrtClient atrt; + + SqlResultSet clusters; + if (!atrt.getClusters(clusters)) + return NDBT_FAILED; + + int i= 0; + while(clusters.next()) + { + ndbout << clusters.column("name") << endl; + if (i++ == 1){ + ndbout << "removing: " << clusters.column("name") << endl; + clusters.remove(); + } + } + + clusters.reset(); + while(clusters.next()) + { + ndbout << clusters.column("name") << endl; + } + + return NDBT_OK; +} + + +int runTestDbUtil(NDBT_Context* ctx, NDBT_Step* step){ + DbUtil sql; + + { + // Select all rows from mysql.user + SqlResultSet result; + if (!sql.doQuery("SELECT * FROM mysql.user", result)) + return NDBT_FAILED; + // result.print(); + + while(result.next()) + { + ndbout << result.column("host") << ", " + << result.column("uSer") << ", " + << result.columnAsInt("max_updates") << ", " + << endl; + } + + result.reset(); + while(result.next()) + { + ndbout << result.column("host") << endl; + } + } + + { + // No column name, query should fail + Properties args; + SqlResultSet result; + if (sql.doQuery("SELECT * FROM mysql.user WHERE name=?", args, result)) + return NDBT_FAILED; + result.print(); + } + + { + // Select nonexisiting rows from mysql.user + Properties args; + SqlResultSet result; + args.put("0", "no_such_host"); + if (!sql.doQuery("SELECT * FROM mysql.user WHERE host=?", args, result)) + return NDBT_FAILED; + ndbout << "no rows" << endl; + result.print(); + + // Change args to an find one row + args.clear(); + args.put("0", "localhost"); + if (!sql.doQuery("SELECT host, user FROM mysql.user WHERE host=?", + args, result)) + return NDBT_FAILED; + result.print(); + } + + { + if (!sql.doQuery("CREATE TABLE sql_client_test (a int, b varchar(255))")) + return NDBT_FAILED; + + if (!sql.doQuery("INSERT INTO sql_client_test VALUES(1, 'hello'), (2, 'bye')")) + return NDBT_FAILED; + + // Select all rows from sql_client_test + SqlResultSet result; + if (!sql.doQuery("SELECT * FROM sql_client_test", result)) + return NDBT_FAILED; + // result.print(); + + while(result.next()) + { + } + + // Select second row from sql_client_test + Properties args; + args.put("0", 2); + if (!sql.doQuery("SELECT * FROM sql_client_test WHERE a=?", args,result)) + return NDBT_FAILED; + result.print(); + + result.reset(); + while(result.next()) + { + ndbout << "a: " << result.columnAsInt("a") << endl; + ndbout << "b: " << result.column("b") << endl; + if (result.columnAsInt("a") != 2){ + ndbout << "hepp1" << endl; + return NDBT_FAILED; + } + + if (strcmp(result.column("b"), "bye")){ + ndbout << "hepp2" << endl; + return NDBT_FAILED; + } + + } + + if (sql.selectCountTable("sql_client_test") != 2) + { + ndbout << "Got wrong count" << endl; + return NDBT_FAILED; + } + + + if (!sql.doQuery("DROP TABLE sql_client_test")) + return NDBT_FAILED; + + } + + return NDBT_OK; +} + +NDBT_TESTSUITE(testNDBT); +TESTCASE("AtrtClient", + "Test AtrtClient class"){ + INITIALIZER(runTestAtrtClient); +} +TESTCASE("DbUtil", + "Test DbUtil class"){ + INITIALIZER(runTestDbUtil); +} +NDBT_TESTSUITE_END(testNDBT); + +int main(int argc, const char** argv){ + ndb_init(); + return testNDBT.execute(argc, argv); +} + diff --git a/storage/ndb/test/ndbapi/testNodeRestart.cpp b/storage/ndb/test/ndbapi/testNodeRestart.cpp index 751134c43c5..17c81fd0a26 100644 --- a/storage/ndb/test/ndbapi/testNodeRestart.cpp +++ b/storage/ndb/test/ndbapi/testNodeRestart.cpp @@ -23,6 +23,7 @@ #include #include #include +#include int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){ @@ -121,15 +122,57 @@ int runPkReadUntilStopped(NDBT_Context* ctx, NDBT_Step* step){ int runPkUpdateUntilStopped(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; int records = ctx->getNumRecords(); + int multiop = ctx->getProperty("MULTI_OP", 1); + Ndb* pNdb = GETNDB(step); int i = 0; - HugoTransactions hugoTrans(*ctx->getTab()); - while (ctx->isTestStopped() == false) { + + HugoOperations hugoOps(*ctx->getTab()); + while (ctx->isTestStopped() == false) + { g_info << i << ": "; - int rows = (rand()%records)+1; - int batch = (rand()%rows)+1; - if (hugoTrans.pkUpdateRecords(GETNDB(step), rows, batch) != 0){ - return NDBT_FAILED; + int batch = (rand()%records)+1; + int row = rand() % records; + + if (batch > 25) + batch = 25; + + if(row + batch > records) + batch = records - row; + + if(hugoOps.startTransaction(pNdb) != 0) + goto err; + + if(hugoOps.pkUpdateRecord(pNdb, row, batch, rand()) != 0) + goto err; + + for (int j = 1; jgetNdbError(); + hugoOps.closeTransaction(pNdb); + if (error.status == NdbError::TemporaryError){ + NdbSleep_MilliSleep(50); + continue; + } + return NDBT_FAILED; + i++; } return result; @@ -230,7 +273,7 @@ int runRestarter(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_OK; } - if(restarter.waitClusterStarted(60) != 0){ + if(restarter.waitClusterStarted() != 0){ g_err << "Cluster failed to start" << endl; return NDBT_FAILED; } @@ -241,13 +284,27 @@ int runRestarter(NDBT_Context* ctx, NDBT_Step* step){ int id = lastId % restarter.getNumDbNodes(); int nodeId = restarter.getDbNodeId(id); ndbout << "Restart node " << nodeId << endl; - if(restarter.restartOneDbNode(nodeId, false, false, true) != 0){ + if(restarter.restartOneDbNode(nodeId, false, true, true) != 0){ g_err << "Failed to restartNextDbNode" << endl; result = NDBT_FAILED; break; } - if(restarter.waitClusterStarted(60) != 0){ + if (restarter.waitNodesNoStart(&nodeId, 1)) + { + g_err << "Failed to waitNodesNoStart" << endl; + result = NDBT_FAILED; + break; + } + + if (restarter.startNodes(&nodeId, 1)) + { + g_err << "Failed to start node" << endl; + result = NDBT_FAILED; + break; + } + + if(restarter.waitClusterStarted() != 0){ g_err << "Cluster failed to start" << endl; result = NDBT_FAILED; break; @@ -1883,6 +1940,178 @@ runBug32160(NDBT_Context* ctx, NDBT_Step* step) return NDBT_OK; } +int +runBug34216(NDBT_Context* ctx, NDBT_Step* step) +{ + int result = NDBT_OK; + int loops = ctx->getNumLoops(); + NdbRestarter restarter; + int i = 0; + int lastId = 0; + HugoOperations hugoOps(*ctx->getTab()); + int records = ctx->getNumRecords(); + Ndb* pNdb = GETNDB(step); + + if (restarter.getNumDbNodes() < 2) + { + ctx->stopTest(); + return NDBT_OK; + } + + if(restarter.waitClusterStarted() != 0){ + g_err << "Cluster failed to start" << endl; + return NDBT_FAILED; + } + + char buf[100]; + const char * off = NdbEnv_GetEnv("NDB_ERR_OFFSET", buf, sizeof(buf)); + int offset = off ? atoi(off) : 0; + + while(iisTestStopped()) + { + int id = lastId % restarter.getNumDbNodes(); + int nodeId = restarter.getDbNodeId(id); + int err = 5048 + ((i+offset) % 2); + + int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 }; + + if(hugoOps.startTransaction(pNdb) != 0) + goto err; + + nodeId = hugoOps.getTransaction()->getConnectedNodeId(); + ndbout << "Restart node " << nodeId << " " << err <stopTest(); + + return result; +err: + return NDBT_FAILED; +} + + +int +runNF_commit(NDBT_Context* ctx, NDBT_Step* step) +{ + int result = NDBT_OK; + int loops = ctx->getNumLoops(); + NdbRestarter restarter; + if (restarter.getNumDbNodes() < 2) + { + ctx->stopTest(); + return NDBT_OK; + } + + if(restarter.waitClusterStarted() != 0){ + g_err << "Cluster failed to start" << endl; + return NDBT_FAILED; + } + + int i = 0; + while(iisTestStopped()) + { + int nodeId = restarter.getDbNodeId(rand() % restarter.getNumDbNodes()); + int err = 5048; + + ndbout << "Restart node " << nodeId << " " << err <stopTest(); + + return result; +} + + NDBT_TESTSUITE(testNodeRestart); TESTCASE("NoLoad", "Test that one node at a time can be stopped and then restarted "\ @@ -2255,6 +2484,21 @@ TESTCASE("Bug29364", ""){ TESTCASE("Bug32160", ""){ INITIALIZER(runBug32160); } +TESTCASE("Bug34216", ""){ + INITIALIZER(runCheckAllNodesStarted); + INITIALIZER(runLoadTable); + STEP(runBug34216); + FINALIZER(runClearTable); +} +TESTCASE("mixedmultiop", ""){ + TC_PROPERTY("MULTI_OP", 5); + INITIALIZER(runCheckAllNodesStarted); + INITIALIZER(runLoadTable); + STEP(runNF_commit); + STEP(runPkUpdateUntilStopped); + STEP(runPkUpdateUntilStopped); + FINALIZER(runClearTable); +} NDBT_TESTSUITE_END(testNodeRestart); int main(int argc, const char** argv){ diff --git a/storage/ndb/test/ndbapi/testOIBasic.cpp b/storage/ndb/test/ndbapi/testOIBasic.cpp index 8f77f0bb062..4e1c8400768 100644 --- a/storage/ndb/test/ndbapi/testOIBasic.cpp +++ b/storage/ndb/test/ndbapi/testOIBasic.cpp @@ -36,10 +36,11 @@ struct Opt { // common options - unsigned m_batch; + uint m_batch; const char* m_bound; const char* m_case; bool m_collsp; + bool m_cont; bool m_core; const char* m_csname; CHARSET_INFO* m_cs; @@ -47,26 +48,29 @@ struct Opt { bool m_dups; NdbDictionary::Object::FragmentType m_fragtype; const char* m_index; - unsigned m_loop; + uint m_loop; bool m_msglock; bool m_nologging; bool m_noverify; - unsigned m_pctnull; - unsigned m_rows; - unsigned m_samples; - unsigned m_scanbatch; - unsigned m_scanpar; - unsigned m_scanstop; + uint m_pctnull; + uint m_rows; + uint m_samples; + uint m_scanbatch; + uint m_scanpar; + uint m_scanstop; int m_seed; - unsigned m_subloop; + const char* m_skip; + uint m_sloop; + uint m_ssloop; const char* m_table; - unsigned m_threads; + uint m_threads; int m_v; // int for lint Opt() : m_batch(32), m_bound("01234"), m_case(0), m_collsp(false), + m_cont(false), m_core(false), m_csname("random"), m_cs(0), @@ -85,7 +89,9 @@ struct Opt { m_scanpar(0), m_scanstop(0), m_seed(-1), - m_subloop(4), + m_skip(0), + m_sloop(4), + m_ssloop(4), m_table(0), m_threads(4), m_v(1) { @@ -107,6 +113,7 @@ printhelp() << " -bound xyz use only these bound types 0-4 [" << d.m_bound << "]" << endl << " -case abc only given test cases (letters a-z)" << endl << " -collsp use strnncollsp instead of strnxfrm" << endl + << " -cont on error continue to next test case [" << d.m_cont << "]" << endl << " -core core dump on error [" << d.m_core << "]" << endl << " -csname S charset or collation [" << d.m_csname << "]" << endl << " -die nnn exit immediately on NDB error code nnn" << endl @@ -122,7 +129,9 @@ printhelp() << " -scanbatch N scan batch 0=default [" << d.m_scanbatch << "]" << endl << " -scanpar N scan parallel 0=default [" << d.m_scanpar << "]" << endl << " -seed N srandom seed 0=loop number -1=random [" << d.m_seed << "]" << endl - << " -subloop N subtest (and subsubtest) loop count [" << d.m_subloop << "]" << endl + << " -skip abc skip given test cases (letters a-z)" << endl + << " -sloop N level 2 (sub)loop count [" << d.m_sloop << "]" << endl + << " -ssloop N level 3 (sub)loop count [" << d.m_ssloop << "]" << endl << " -table xyz only given table numbers (digits 0-9)" << endl << " -threads N number of threads [" << d.m_threads << "]" << endl << " -vN verbosity [" << d.m_v << "]" << endl @@ -142,17 +151,17 @@ static const char* hexstr = "0123456789abcdef"; // random ints -static unsigned -urandom(unsigned n) +static uint +urandom(uint n) { if (n == 0) return 0; - unsigned i = random() % n; + uint i = random() % n; return i; } static int -irandom(unsigned n) +irandom(uint n) { if (n == 0) return 0; @@ -163,7 +172,7 @@ irandom(unsigned n) } static bool -randompct(unsigned pct) +randompct(uint pct) { if (pct == 0) return false; @@ -172,15 +181,15 @@ randompct(unsigned pct) return urandom(100) < pct; } -static unsigned -random_coprime(unsigned n) +static uint +random_coprime(uint n) { - unsigned prime[] = { 101, 211, 307, 401, 503, 601, 701, 809, 907 }; - unsigned count = sizeof(prime) / sizeof(prime[0]); + uint prime[] = { 101, 211, 307, 401, 503, 601, 701, 809, 907 }; + uint count = sizeof(prime) / sizeof(prime[0]); if (n == 0) return 0; while (1) { - unsigned i = urandom(count); + uint i = urandom(count); if (n % prime[i] != 0) return prime[i]; } @@ -189,16 +198,16 @@ random_coprime(unsigned n) // random re-sequence of 0...(n-1) struct Rsq { - Rsq(unsigned n); - unsigned next(); + Rsq(uint n); + uint next(); private: - unsigned m_n; - unsigned m_i; - unsigned m_start; - unsigned m_prime; + uint m_n; + uint m_i; + uint m_start; + uint m_prime; }; -Rsq::Rsq(unsigned n) +Rsq::Rsq(uint n) { m_n = n; m_i = 0; @@ -206,7 +215,7 @@ Rsq::Rsq(unsigned n) m_prime = random_coprime(n); } -unsigned +uint Rsq::next() { assert(m_n != 0); @@ -216,30 +225,16 @@ Rsq::next() // log and error macros static NdbMutex *ndbout_mutex = NULL; - -static unsigned getthrno(); - -static const char* -getthrstr() -{ - static char buf[20]; - unsigned n = getthrno(); - if (n == (unsigned)-1) - strcpy(buf, ""); - else { - unsigned m = - g_opt.m_threads < 10 ? 1 : - g_opt.m_threads < 100 ? 2 : 3; - sprintf(buf, "[%0*u] ", m, n); - } - return buf; -} +static const char* getthrprefix(); #define LLN(n, s) \ do { \ if ((n) > g_opt.m_v) break; \ if (g_opt.m_msglock) NdbMutex_Lock(ndbout_mutex); \ - ndbout << getthrstr() << s << endl; \ + ndbout << getthrprefix(); \ + if ((n) > 2) \ + ndbout << "line " << __LINE__ << ": "; \ + ndbout << s << endl; \ if (g_opt.m_msglock) NdbMutex_Unlock(ndbout_mutex); \ } while(0) @@ -250,6 +245,8 @@ getthrstr() #define LL4(s) LLN(4, s) #define LL5(s) LLN(5, s) +#define HEX(x) hex << (x) << dec + // following check a condition and return -1 on failure #undef CHK // simple check @@ -281,53 +278,58 @@ getthrstr() class Thr; class Con; class Tab; +class ITab; class Set; class Tmr; struct Par : public Opt { - unsigned m_no; + uint m_no; Con* m_con; Con& con() const { assert(m_con != 0); return *m_con; } const Tab* m_tab; const Tab& tab() const { assert(m_tab != 0); return *m_tab; } + const ITab* m_itab; + const ITab& itab() const { assert(m_itab != 0); return *m_itab; } Set* m_set; Set& set() const { assert(m_set != 0); return *m_set; } Tmr* m_tmr; Tmr& tmr() const { assert(m_tmr != 0); return *m_tmr; } char m_currcase[2]; - unsigned m_lno; - unsigned m_slno; - unsigned m_totrows; + uint m_lno; + uint m_slno; + uint m_totrows; // value calculation - unsigned m_range; - unsigned m_pctrange; - unsigned m_pctbrange; + uint m_range; + uint m_pctrange; + uint m_pctbrange; int m_bdir; bool m_noindexkeyupdate; // choice of key bool m_randomkey; // do verify after read bool m_verify; - // deadlock possible - bool m_deadlock; - // abort percentabge - unsigned m_abortpct; + // errors to catch (see Con) + bool m_catcherr; + // abort percentage + uint m_abortpct; NdbOperation::LockMode m_lockmode; // scan options bool m_tupscan; bool m_ordered; bool m_descending; - // timer location + // threads used by current test case + uint m_usedthreads; Par(const Opt& opt) : Opt(opt), m_no(0), m_con(0), m_tab(0), + m_itab(0), m_set(0), m_tmr(0), m_lno(0), m_slno(0), - m_totrows(m_threads * m_rows), + m_totrows(0), m_range(m_rows), m_pctrange(40), m_pctbrange(80), @@ -335,39 +337,40 @@ struct Par : public Opt { m_noindexkeyupdate(false), m_randomkey(false), m_verify(false), - m_deadlock(false), + m_catcherr(0), m_abortpct(0), m_lockmode(NdbOperation::LM_Read), m_tupscan(false), m_ordered(false), - m_descending(false) + m_descending(false), + m_usedthreads(0) { m_currcase[0] = 0; } }; static bool -usetable(Par par, unsigned i) +usetable(Par par, uint i) { return par.m_table == 0 || strchr(par.m_table, '0' + i) != 0; } static bool -useindex(Par par, unsigned i) +useindex(Par par, uint i) { return par.m_index == 0 || strchr(par.m_index, '0' + i) != 0; } -static unsigned -thrrow(Par par, unsigned j) +static uint +thrrow(Par par, uint j) { - return par.m_threads * j + par.m_no; + return par.m_usedthreads * j + par.m_no; } static bool -isthrrow(Par par, unsigned i) +isthrrow(Par par, uint i) { - return i % par.m_threads == par.m_no; + return i % par.m_usedthreads == par.m_no; } // timer @@ -375,13 +378,13 @@ isthrrow(Par par, unsigned i) struct Tmr { void clr(); void on(); - void off(unsigned cnt = 0); + void off(uint cnt = 0); const char* time(); const char* pct(const Tmr& t1); const char* over(const Tmr& t1); NDB_TICKS m_on; - unsigned m_ms; - unsigned m_cnt; + uint m_ms; + uint m_cnt; char m_time[100]; char m_text[100]; Tmr() { clr(); } @@ -401,7 +404,7 @@ Tmr::on() } void -Tmr::off(unsigned cnt) +Tmr::off(uint cnt) { NDB_TICKS off = NdbTick_CurrentMillisecond(); assert(m_on != 0 && off >= m_on); @@ -446,53 +449,18 @@ Tmr::over(const Tmr& t1) return m_text; } -// list of ints - -struct Lst { - Lst(); - unsigned m_arr[1000]; - unsigned m_cnt; - void push(unsigned i); - unsigned cnt() const; - void reset(); -}; - -Lst::Lst() : - m_cnt(0) -{ -} - -void -Lst::push(unsigned i) -{ - assert(m_cnt < sizeof(m_arr)/sizeof(m_arr[0])); - m_arr[m_cnt++] = i; -} - -unsigned -Lst::cnt() const -{ - return m_cnt; -} - -void -Lst::reset() -{ - m_cnt = 0; -} - // character sets -static const unsigned maxcsnumber = 512; -static const unsigned maxcharcount = 32; -static const unsigned maxcharsize = 4; -static const unsigned maxxmulsize = 8; +static const uint maxcsnumber = 512; +static const uint maxcharcount = 32; +static const uint maxcharsize = 4; +static const uint maxxmulsize = 8; // single mb char struct Chr { - unsigned char m_bytes[maxcharsize]; - unsigned char m_xbytes[maxxmulsize * maxcharsize]; - unsigned m_size; + uchar m_bytes[maxcharsize]; + uchar m_xbytes[maxxmulsize * maxcharsize]; + uint m_size; Chr(); }; @@ -506,7 +474,7 @@ Chr::Chr() // charset and random valid chars to use struct Chs { CHARSET_INFO* m_cs; - unsigned m_xmul; + uint m_xmul; Chr* m_chr; Chs(CHARSET_INFO* cs); ~Chs(); @@ -523,22 +491,22 @@ Chs::Chs(CHARSET_INFO* cs) : m_xmul = 1; assert(m_xmul <= maxxmulsize); m_chr = new Chr [maxcharcount]; - unsigned i = 0; - unsigned miss1 = 0; - unsigned miss2 = 0; - unsigned miss3 = 0; - unsigned miss4 = 0; + uint i = 0; + uint miss1 = 0; + uint miss2 = 0; + uint miss3 = 0; + uint miss4 = 0; while (i < maxcharcount) { - unsigned char* bytes = m_chr[i].m_bytes; - unsigned char* xbytes = m_chr[i].m_xbytes; - unsigned& size = m_chr[i].m_size; + uchar* bytes = m_chr[i].m_bytes; + uchar* xbytes = m_chr[i].m_xbytes; + uint& size = m_chr[i].m_size; bool ok; size = m_cs->mbminlen + urandom(m_cs->mbmaxlen - m_cs->mbminlen + 1); assert(m_cs->mbminlen <= size && size <= m_cs->mbmaxlen); // prefer longer chars if (size == m_cs->mbminlen && m_cs->mbminlen < m_cs->mbmaxlen && urandom(5) != 0) continue; - for (unsigned j = 0; j < size; j++) { + for (uint j = 0; j < size; j++) { bytes[j] = urandom(256); } int not_used; @@ -550,13 +518,13 @@ Chs::Chs(CHARSET_INFO* cs) : } // check no proper prefix wellformed ok = true; - for (unsigned j = 1; j < size; j++) { + for (uint j = 1; j < size; j++) { if ((*cs->cset->well_formed_len)(cs, sbytes, sbytes + j, 1, ¬_used) == j) { ok = false; break; } } - if (! ok) { + if (!ok) { miss2++; continue; } @@ -566,37 +534,37 @@ Chs::Chs(CHARSET_INFO* cs) : int xlen = (*cs->coll->strnxfrm)(cs, xbytes, m_xmul * size, bytes, size); // check we got something ok = false; - for (unsigned j = 0; j < xlen; j++) { + for (uint j = 0; j < xlen; j++) { if (xbytes[j] != 0) { ok = true; break; } } - if (! ok) { + if (!ok) { miss3++; continue; } // check for duplicate (before normalize) ok = true; - for (unsigned j = 0; j < i; j++) { + for (uint j = 0; j < i; j++) { const Chr& chr = m_chr[j]; if (chr.m_size == size && memcmp(chr.m_bytes, bytes, size) == 0) { ok = false; break; } } - if (! ok) { + if (!ok) { miss4++; continue; } i++; } bool disorder = true; - unsigned bubbles = 0; + uint bubbles = 0; while (disorder) { disorder = false; - for (unsigned i = 1; i < maxcharcount; i++) { - unsigned len = sizeof(m_chr[i].m_xbytes); + for (uint i = 1; i < maxcharcount; i++) { + uint len = sizeof(m_chr[i].m_xbytes); if (memcmp(m_chr[i-1].m_xbytes, m_chr[i].m_xbytes, len) > 0) { Chr chr = m_chr[i]; m_chr[i] = m_chr[i-1]; @@ -627,7 +595,7 @@ static Chs* cslist[maxcsnumber]; static void resetcslist() { - for (unsigned i = 0; i < maxcsnumber; i++) { + for (uint i = 0; i < maxcsnumber; i++) { delete cslist[i]; cslist[i] = 0; } @@ -641,7 +609,7 @@ getcs(Par par) cs = par.m_cs; } else { while (1) { - unsigned n = urandom(maxcsnumber); + uint n = urandom(maxcsnumber); cs = get_charset(n, MYF(0)); if (cs != 0) { // prefer complex charsets @@ -667,24 +635,24 @@ struct Col { Longvarchar = NdbDictionary::Column::Longvarchar }; const class Tab& m_tab; - unsigned m_num; + uint m_num; const char* m_name; bool m_pk; Type m_type; - unsigned m_length; - unsigned m_bytelength; // multiplied by char width - unsigned m_attrsize; // base type size - unsigned m_headsize; // length bytes - unsigned m_bytesize; // full value size + uint m_length; + uint m_bytelength; // multiplied by char width + uint m_attrsize; // base type size + uint m_headsize; // length bytes + uint m_bytesize; // full value size bool m_nullable; const Chs* m_chs; - Col(const class Tab& tab, unsigned num, const char* name, bool pk, Type type, unsigned length, bool nullable, const Chs* chs); + Col(const class Tab& tab, uint num, const char* name, bool pk, Type type, uint length, bool nullable, const Chs* chs); ~Col(); bool equal(const Col& col2) const; void wellformed(const void* addr) const; }; -Col::Col(const class Tab& tab, unsigned num, const char* name, bool pk, Type type, unsigned length, bool nullable, const Chs* chs) : +Col::Col(const class Tab& tab, uint num, const char* name, bool pk, Type type, uint length, bool nullable, const Chs* chs) : m_tab(tab), m_num(num), m_name(strcpy(new char [strlen(name) + 1], name)), @@ -735,7 +703,7 @@ Col::wellformed(const void* addr) const { CHARSET_INFO* cs = m_chs->m_cs; const char* src = (const char*)addr; - unsigned len = m_bytelength; + uint len = m_bytelength; int not_used; assert((*cs->cset->well_formed_len)(cs, src, src + len, 0xffff, ¬_used) == len); } @@ -743,9 +711,9 @@ Col::wellformed(const void* addr) const case Col::Varchar: { CHARSET_INFO* cs = m_chs->m_cs; - const unsigned char* src = (const unsigned char*)addr; + const uchar* src = (const uchar*)addr; const char* ssrc = (const char*)src; - unsigned len = src[0]; + uint len = src[0]; int not_used; assert(len <= m_bytelength); assert((*cs->cset->well_formed_len)(cs, ssrc + 1, ssrc + 1 + len, 0xffff, ¬_used) == len); @@ -754,9 +722,9 @@ Col::wellformed(const void* addr) const case Col::Longvarchar: { CHARSET_INFO* cs = m_chs->m_cs; - const unsigned char* src = (const unsigned char*)addr; + const uchar* src = (const uchar*)addr; const char* ssrc = (const char*)src; - unsigned len = src[0] + (src[1] << 8); + uint len = src[0] + (src[1] << 8); int not_used; assert(len <= m_bytelength); assert((*cs->cset->well_formed_len)(cs, ssrc + 2, ssrc + 2 + len, 0xffff, ¬_used) == len); @@ -774,7 +742,7 @@ operator<<(NdbOut& out, const Col& col) out << "col[" << col.m_num << "] " << col.m_name; switch (col.m_type) { case Col::Unsigned: - out << " unsigned"; + out << " uint"; break; case Col::Char: { @@ -808,13 +776,13 @@ operator<<(NdbOut& out, const Col& col) struct ICol { const class ITab& m_itab; - unsigned m_num; + uint m_num; const Col& m_col; - ICol(const class ITab& itab, unsigned num, const Col& col); + ICol(const class ITab& itab, uint num, const Col& col); ~ICol(); }; -ICol::ICol(const class ITab& itab, unsigned num, const Col& col) : +ICol::ICol(const class ITab& itab, uint num, const Col& col) : m_itab(itab), m_num(num), m_col(col) @@ -842,47 +810,47 @@ struct ITab { const class Tab& m_tab; const char* m_name; Type m_type; - unsigned m_icols; + uint m_icols; const ICol** m_icol; - unsigned m_colmask; - ITab(const class Tab& tab, const char* name, Type type, unsigned icols); + uint m_keymask; + ITab(const class Tab& tab, const char* name, Type type, uint icols); ~ITab(); - void icoladd(unsigned k, const ICol* icolptr); + void icoladd(uint k, const ICol* icolptr); }; -ITab::ITab(const class Tab& tab, const char* name, Type type, unsigned icols) : +ITab::ITab(const class Tab& tab, const char* name, Type type, uint icols) : m_tab(tab), m_name(strcpy(new char [strlen(name) + 1], name)), m_type(type), m_icols(icols), m_icol(new const ICol* [icols + 1]), - m_colmask(0) + m_keymask(0) { - for (unsigned k = 0; k <= m_icols; k++) + for (uint k = 0; k <= m_icols; k++) m_icol[k] = 0; } ITab::~ITab() { delete [] m_name; - for (unsigned i = 0; i < m_icols; i++) + for (uint i = 0; i < m_icols; i++) delete m_icol[i]; delete [] m_icol; } void -ITab::icoladd(unsigned k, const ICol* icolptr) +ITab::icoladd(uint k, const ICol* icolptr) { assert(k == icolptr->m_num && k < m_icols && m_icol[k] == 0); m_icol[k] = icolptr; - m_colmask |= (1 << icolptr->m_col.m_num); + m_keymask |= (1 << icolptr->m_col.m_num); } static NdbOut& operator<<(NdbOut& out, const ITab& itab) { out << "itab " << itab.m_name << " icols=" << itab.m_icols; - for (unsigned k = 0; k < itab.m_icols; k++) { + for (uint k = 0; k < itab.m_icols; k++) { const ICol& icol = *itab.m_icol[k]; out << endl << icol; } @@ -893,56 +861,60 @@ operator<<(NdbOut& out, const ITab& itab) struct Tab { const char* m_name; - unsigned m_cols; + uint m_cols; const Col** m_col; - unsigned m_itabs; + uint m_pkmask; + uint m_itabs; const ITab** m_itab; - unsigned m_orderedindexes; - unsigned m_hashindexes; + uint m_orderedindexes; + uint m_hashindexes; // pk must contain an Unsigned column - unsigned m_keycol; - void coladd(unsigned k, Col* colptr); - void itabadd(unsigned j, ITab* itab); - Tab(const char* name, unsigned cols, unsigned itabs, unsigned keycol); + uint m_keycol; + void coladd(uint k, Col* colptr); + void itabadd(uint j, ITab* itab); + Tab(const char* name, uint cols, uint itabs, uint keycol); ~Tab(); }; -Tab::Tab(const char* name, unsigned cols, unsigned itabs, unsigned keycol) : +Tab::Tab(const char* name, uint cols, uint itabs, uint keycol) : m_name(strcpy(new char [strlen(name) + 1], name)), m_cols(cols), m_col(new const Col* [cols + 1]), + m_pkmask(0), m_itabs(itabs), m_itab(new const ITab* [itabs + 1]), m_orderedindexes(0), m_hashindexes(0), m_keycol(keycol) { - for (unsigned k = 0; k <= cols; k++) + for (uint k = 0; k <= cols; k++) m_col[k] = 0; - for (unsigned j = 0; j <= itabs; j++) + for (uint j = 0; j <= itabs; j++) m_itab[j] = 0; } Tab::~Tab() { delete [] m_name; - for (unsigned i = 0; i < m_cols; i++) + for (uint i = 0; i < m_cols; i++) delete m_col[i]; delete [] m_col; - for (unsigned i = 0; i < m_itabs; i++) + for (uint i = 0; i < m_itabs; i++) delete m_itab[i]; delete [] m_itab; } void -Tab::coladd(unsigned k, Col* colptr) +Tab::coladd(uint k, Col* colptr) { assert(k == colptr->m_num && k < m_cols && m_col[k] == 0); m_col[k] = colptr; + if (colptr->m_pk) + m_pkmask |= (1 << k); } void -Tab::itabadd(unsigned j, ITab* itabptr) +Tab::itabadd(uint j, ITab* itabptr) { assert(j < m_itabs && m_itab[j] == 0 && itabptr != 0); m_itab[j] = itabptr; @@ -956,11 +928,11 @@ static NdbOut& operator<<(NdbOut& out, const Tab& tab) { out << "tab " << tab.m_name << " cols=" << tab.m_cols; - for (unsigned k = 0; k < tab.m_cols; k++) { + for (uint k = 0; k < tab.m_cols; k++) { const Col& col = *tab.m_col[k]; out << endl << col; } - for (unsigned i = 0; i < tab.m_itabs; i++) { + for (uint i = 0; i < tab.m_itabs; i++) { if (tab.m_itab[i] == 0) continue; const ITab& itab = *tab.m_itab[i]; @@ -972,20 +944,20 @@ operator<<(NdbOut& out, const Tab& tab) // make table structs static const Tab** tablist = 0; -static unsigned tabcount = 0; +static uint tabcount = 0; static void verifytables() { - for (unsigned j = 0; j < tabcount; j++) { + for (uint j = 0; j < tabcount; j++) { const Tab* t = tablist[j]; if (t == 0) continue; assert(t->m_cols != 0 && t->m_col != 0); - for (unsigned k = 0; k < t->m_cols; k++) { + for (uint k = 0; k < t->m_cols; k++) { const Col* c = t->m_col[k]; assert(c != 0 && c->m_num == k); - assert(! (c->m_pk && c->m_nullable)); + assert(!(c->m_pk && c->m_nullable)); } assert(t->m_col[t->m_cols] == 0); { @@ -994,16 +966,16 @@ verifytables() assert(c->m_pk && c->m_type == Col::Unsigned); } assert(t->m_itabs != 0 && t->m_itab != 0); - for (unsigned i = 0; i < t->m_itabs; i++) { + for (uint i = 0; i < t->m_itabs; i++) { const ITab* x = t->m_itab[i]; if (x == 0) continue; assert(x != 0 && x->m_icols != 0 && x->m_icol != 0); - for (unsigned k = 0; k < x->m_icols; k++) { + for (uint k = 0; k < x->m_icols; k++) { const ICol* c = x->m_icol[k]; assert(c != 0 && c->m_num == k && c->m_col.m_num < t->m_cols); if (x->m_type == ITab::UniqueHashIndex) { - assert(! c->m_col.m_nullable); + assert(!c->m_col.m_nullable); } } } @@ -1019,11 +991,11 @@ makebuiltintables(Par par) tabcount = 3; if (tablist == 0) { tablist = new const Tab* [tabcount]; - for (unsigned j = 0; j < tabcount; j++) { + for (uint j = 0; j < tabcount; j++) { tablist[j] = 0; } } else { - for (unsigned j = 0; j < tabcount; j++) { + for (uint j = 0; j < tabcount; j++) { delete tablist[j]; tablist[j] = 0; } @@ -1202,7 +1174,8 @@ static Ndb_cluster_connection* g_ncc = 0; struct Con { Ndb* m_ndb; NdbDictionary::Dictionary* m_dic; - NdbConnection* m_tx; + NdbTransaction* m_tx; + Uint64 m_txid; NdbOperation* m_op; NdbIndexOperation* m_indexop; NdbScanOperation* m_scanop; @@ -1210,10 +1183,16 @@ struct Con { NdbScanFilter* m_scanfilter; enum ScanMode { ScanNo = 0, Committed, Latest, Exclusive }; ScanMode m_scanmode; - enum ErrType { ErrNone = 0, ErrDeadlock, ErrNospace, ErrOther }; + enum ErrType { + ErrNone = 0, + ErrDeadlock = 1, + ErrNospace = 2, + ErrOther = 4 + }; ErrType m_errtype; + char m_errname[100]; Con() : - m_ndb(0), m_dic(0), m_tx(0), m_op(0), m_indexop(0), + m_ndb(0), m_dic(0), m_tx(0), m_txid(0), m_op(0), m_indexop(0), m_scanop(0), m_indexscanop(0), m_scanfilter(0), m_scanmode(ScanNo), m_errtype(ErrNone) {} ~Con() { @@ -1237,18 +1216,20 @@ struct Con { int setBound(int num, int type, const void* value); int beginFilter(int group); int endFilter(); - int setFilter(int num, int cond, const void* value, unsigned len); - int execute(ExecType t); - int execute(ExecType t, bool& deadlock, bool& nospace); + int setFilter(int num, int cond, const void* value, uint len); + int execute(ExecType et); + int execute(ExecType et, uint& err); + int readTuple(Par par); int readTuples(Par par); int readIndexTuples(Par par); int executeScan(); int nextScanResult(bool fetchAllowed); - int nextScanResult(bool fetchAllowed, bool& deadlock); + int nextScanResult(bool fetchAllowed, uint& err); int updateScanTuple(Con& con2); int deleteScanTuple(Con& con2); void closeScan(); void closeTransaction(); + const char* errname(uint err); void printerror(NdbOut& out); }; @@ -1259,7 +1240,7 @@ Con::connect() m_ndb = new Ndb(g_ncc, "TEST_DB"); CHKCON(m_ndb->init() == 0, *this); CHKCON(m_ndb->waitUntilReady(30) == 0, *this); - m_tx = 0, m_op = 0; + m_tx = 0, m_txid = 0, m_op = 0; return 0; } @@ -1274,7 +1255,7 @@ void Con::disconnect() { delete m_ndb; - m_ndb = 0, m_dic = 0, m_tx = 0, m_op = 0; + m_ndb = 0, m_dic = 0, m_tx = 0, m_txid = 0, m_op = 0; } int @@ -1284,6 +1265,7 @@ Con::startTransaction() if (m_tx != 0) closeTransaction(); CHKCON((m_tx = m_ndb->startTransaction()) != 0, *this); + m_txid = m_tx->getTransactionId(); return 0; } @@ -1307,7 +1289,7 @@ int Con::getNdbIndexOperation(const ITab& itab, const Tab& tab) { assert(m_tx != 0); - unsigned tries = 0; + uint tries = 0; while (1) { if (getNdbIndexOperation1(itab, tab) == 0) break; @@ -1337,7 +1319,7 @@ int Con::getNdbIndexScanOperation(const ITab& itab, const Tab& tab) { assert(m_tx != 0); - unsigned tries = 0; + uint tries = 0; while (1) { if (getNdbIndexScanOperation1(itab, tab) == 0) break; @@ -1405,7 +1387,7 @@ Con::endFilter() } int -Con::setFilter(int num, int cond, const void* value, unsigned len) +Con::setFilter(int num, int cond, const void* value, uint len) { assert(m_tx != 0 && m_scanfilter != 0); CHKCON(m_scanfilter->cmp((NdbScanFilter::BinaryCondition)cond, num, value, len) == 0, *this); @@ -1413,33 +1395,45 @@ Con::setFilter(int num, int cond, const void* value, unsigned len) } int -Con::execute(ExecType t) +Con::execute(ExecType et) { assert(m_tx != 0); - CHKCON(m_tx->execute(t) == 0, *this); + CHKCON(m_tx->execute(et) == 0, *this); return 0; } int -Con::execute(ExecType t, bool& deadlock, bool& nospace) +Con::execute(ExecType et, uint& err) { - int ret = execute(t); - if (ret != 0 && deadlock && m_errtype == ErrDeadlock) { - LL3("caught deadlock"); - ret = 0; - } else { - deadlock = false; - } - if (ret != 0 && nospace && m_errtype == ErrNospace) { - LL3("caught nospace"); - ret = 0; - } else { - nospace = false; + int ret = execute(et); + // err in: errors to catch, out: error caught + const uint errin = err; + err = 0; + if (ret == -1) { + if (m_errtype == ErrDeadlock && (errin & ErrDeadlock)) { + LL3("caught deadlock"); + err = ErrDeadlock; + ret = 0; + } + if (m_errtype == ErrNospace && (errin & ErrNospace)) { + LL3("caught nospace"); + err = ErrNospace; + ret = 0; + } } CHK(ret == 0); return 0; } +int +Con::readTuple(Par par) +{ + assert(m_tx != 0 && m_op != 0); + NdbOperation::LockMode lm = par.m_lockmode; + CHKCON(m_op->readTuple(lm) == 0, *this); + return 0; +} + int Con::readTuples(Par par) { @@ -1477,23 +1471,25 @@ Con::nextScanResult(bool fetchAllowed) int ret; assert(m_scanop != 0); CHKCON((ret = m_scanop->nextResult(fetchAllowed)) != -1, *this); - assert(ret == 0 || ret == 1 || (! fetchAllowed && ret == 2)); + assert(ret == 0 || ret == 1 || (!fetchAllowed && ret == 2)); return ret; } int -Con::nextScanResult(bool fetchAllowed, bool& deadlock) +Con::nextScanResult(bool fetchAllowed, uint& err) { int ret = nextScanResult(fetchAllowed); + // err in: errors to catch, out: error caught + const uint errin = err; + err = 0; if (ret == -1) { - if (deadlock && m_errtype == ErrDeadlock) { + if (m_errtype == ErrDeadlock && (errin & ErrDeadlock)) { LL3("caught deadlock"); + err = ErrDeadlock; ret = 0; } - } else { - deadlock = false; } - CHK(ret == 0 || ret == 1 || (! fetchAllowed && ret == 2)); + CHK(ret == 0 || ret == 1 || (!fetchAllowed && ret == 2)); return ret; } @@ -1502,6 +1498,7 @@ Con::updateScanTuple(Con& con2) { assert(con2.m_tx != 0); CHKCON((con2.m_op = m_scanop->updateCurrentTuple(con2.m_tx)) != 0, *this); + con2.m_txid = m_txid; // in the kernel return 0; } @@ -1510,6 +1507,7 @@ Con::deleteScanTuple(Con& con2) { assert(con2.m_tx != 0); CHKCON(m_scanop->deleteCurrentTuple(con2.m_tx) == 0, *this); + con2.m_txid = m_txid; // in the kernel return 0; } @@ -1527,15 +1525,26 @@ Con::closeTransaction() { assert(m_ndb != 0 && m_tx != 0); m_ndb->closeTransaction(m_tx); - m_tx = 0, m_op = 0; + m_tx = 0, m_txid = 0, m_op = 0; m_scanop = 0, m_indexscanop = 0; } +const char* +Con::errname(uint err) +{ + sprintf(m_errname, "0x%x", err); + if (err & ErrDeadlock) + strcat(m_errname, ",deadlock"); + if (err & ErrNospace) + strcat(m_errname, ",nospace"); + return m_errname; +} + void Con::printerror(NdbOut& out) { m_errtype = ErrOther; - unsigned any = 0; + uint any = 0; int code; int die = 0; if (m_ndb) { @@ -1563,7 +1572,7 @@ Con::printerror(NdbOut& out) } } } - if (! any) { + if (!any) { LL0("failed but no NDB error code"); } if (die) { @@ -1589,7 +1598,7 @@ invalidateindex(Par par) { Con& con = par.con(); const Tab& tab = par.tab(); - for (unsigned i = 0; i < tab.m_itabs; i++) { + for (uint i = 0; i < tab.m_itabs; i++) { if (tab.m_itab[i] == 0) continue; const ITab& itab = *tab.m_itab[i]; @@ -1639,7 +1648,7 @@ createtable(Par par) if (par.m_nologging) { t.setLogging(false); } - for (unsigned k = 0; k < tab.m_cols; k++) { + for (uint k = 0; k < tab.m_cols; k++) { const Col& col = *tab.m_col[k]; NdbDictionary::Column c(col.m_name); c.setType((NdbDictionary::Column::Type)col.m_type); @@ -1677,7 +1686,7 @@ static int dropindex(Par par) { const Tab& tab = par.tab(); - for (unsigned i = 0; i < tab.m_itabs; i++) { + for (uint i = 0; i < tab.m_itabs; i++) { if (tab.m_itab[i] == 0) continue; const ITab& itab = *tab.m_itab[i]; @@ -1699,7 +1708,7 @@ createindex(Par par, const ITab& itab) if (par.m_nologging || itab.m_type == ITab::OrderedIndex) { x.setLogging(false); } - for (unsigned k = 0; k < itab.m_icols; k++) { + for (uint k = 0; k < itab.m_icols; k++) { const ICol& icol = *itab.m_icol[k]; const Col& col = icol.m_col; x.addColumnName(col.m_name); @@ -1714,7 +1723,7 @@ static int createindex(Par par) { const Tab& tab = par.tab(); - for (unsigned i = 0; i < tab.m_itabs; i++) { + for (uint i = 0; i < tab.m_itabs; i++) { if (tab.m_itab[i] == 0) continue; const ITab& itab = *tab.m_itab[i]; @@ -1731,27 +1740,29 @@ struct Val { const Col& m_col; union { Uint32 m_uint32; - unsigned char* m_char; - unsigned char* m_varchar; - unsigned char* m_longvarchar; + uchar* m_char; + uchar* m_varchar; + uchar* m_longvarchar; }; + bool m_null; + // construct Val(const Col& col); ~Val(); void copy(const Val& val2); void copy(const void* addr); const void* dataaddr() const; - bool m_null; - int equal(Par par) const; - int equal(Par par, const ICol& icol) const; - int setval(Par par) const; - void calc(Par par, unsigned i); - void calckey(Par par, unsigned i); - void calckeychars(Par par, unsigned i, unsigned& n, unsigned char* buf); + void calc(Par par, uint i); + void calckey(Par par, uint i); + void calckeychars(Par par, uint i, uint& n, uchar* buf); void calcnokey(Par par); - void calcnokeychars(Par par, unsigned& n, unsigned char* buf); - int verify(Par par, const Val& val2) const; + void calcnokeychars(Par par, uint& n, uchar* buf); + // operations + int setval(Par par) const; + int setval(Par par, const ICol& icol) const; + // compare int cmp(Par par, const Val& val2) const; - int cmpchars(Par par, const unsigned char* buf1, unsigned len1, const unsigned char* buf2, unsigned len2) const; + int cmpchars(Par par, const uchar* buf1, uint len1, const uchar* buf2, uint len2) const; + int verify(Par par, const Val& val2) const; private: Val& operator=(const Val& val2); }; @@ -1759,20 +1770,26 @@ private: static NdbOut& operator<<(NdbOut& out, const Val& val); +// construct + Val::Val(const Col& col) : m_col(col) { switch (col.m_type) { case Col::Unsigned: + m_uint32 = 0x7e7e7e7e; break; case Col::Char: - m_char = new unsigned char [col.m_bytelength]; + m_char = new uchar [col.m_bytelength]; + memset(m_char, 0x7e, col.m_bytelength); break; case Col::Varchar: - m_varchar = new unsigned char [1 + col.m_bytelength]; + m_varchar = new uchar [1 + col.m_bytelength]; + memset(m_char, 0x7e, 1 + col.m_bytelength); break; case Col::Longvarchar: - m_longvarchar = new unsigned char [2 + col.m_bytelength]; + m_longvarchar = new uchar [2 + col.m_bytelength]; + memset(m_char, 0x7e, 2 + col.m_bytelength); break; default: assert(false); @@ -1858,52 +1875,17 @@ Val::dataaddr() const return 0; } -int -Val::equal(Par par) const -{ - Con& con = par.con(); - const Col& col = m_col; - assert(col.m_pk && ! m_null); - const char* addr = (const char*)dataaddr(); - LL5("equal [" << col << "] " << *this); - CHK(con.equal(col.m_num, addr) == 0); - return 0; -} - -int -Val::equal(Par par, const ICol& icol) const -{ - Con& con = par.con(); - assert(! m_null); - const char* addr = (const char*)dataaddr(); - LL5("equal [" << icol << "] " << *this); - CHK(con.equal(icol.m_num, addr) == 0); - return 0; -} - -int -Val::setval(Par par) const -{ - Con& con = par.con(); - const Col& col = m_col; - assert(! col.m_pk); - const char* addr = ! m_null ? (const char*)dataaddr() : 0; - LL5("setval [" << col << "] " << *this); - CHK(con.setValue(col.m_num, addr) == 0); - return 0; -} - void -Val::calc(Par par, unsigned i) +Val::calc(Par par, uint i) { const Col& col = m_col; col.m_pk ? calckey(par, i) : calcnokey(par); - if (! m_null) + if (!m_null) col.wellformed(dataaddr()); } void -Val::calckey(Par par, unsigned i) +Val::calckey(Par par, uint i) { const Col& col = m_col; m_null = false; @@ -1915,7 +1897,7 @@ Val::calckey(Par par, unsigned i) { const Chs* chs = col.m_chs; CHARSET_INFO* cs = chs->m_cs; - unsigned n = 0; + uint n = 0; calckeychars(par, i, n, m_char); // extend by appropriate space (*cs->cset->fill)(cs, (char*)&m_char[n], col.m_bytelength - n, 0x20); @@ -1923,7 +1905,7 @@ Val::calckey(Par par, unsigned i) break; case Col::Varchar: { - unsigned n = 0; + uint n = 0; calckeychars(par, i, n, m_varchar + 1); // set length and pad with nulls m_varchar[0] = n; @@ -1932,7 +1914,7 @@ Val::calckey(Par par, unsigned i) break; case Col::Longvarchar: { - unsigned n = 0; + uint n = 0; calckeychars(par, i, n, m_longvarchar + 2); // set length and pad with nulls m_longvarchar[0] = (n & 0xff); @@ -1947,13 +1929,13 @@ Val::calckey(Par par, unsigned i) } void -Val::calckeychars(Par par, unsigned i, unsigned& n, unsigned char* buf) +Val::calckeychars(Par par, uint i, uint& n, uchar* buf) { const Col& col = m_col; const Chs* chs = col.m_chs; CHARSET_INFO* cs = chs->m_cs; n = 0; - unsigned len = 0; + uint len = 0; while (len < col.m_length) { if (i % (1 + n) == 0) { break; @@ -1980,7 +1962,7 @@ Val::calcnokey(Par par) if (r < 0 && par.m_bdir > 0 || r > 0 && par.m_bdir < 0) r = -r; } - unsigned v = par.m_range + r; + uint v = par.m_range + r; switch (col.m_type) { case Col::Unsigned: m_uint32 = v; @@ -1989,7 +1971,7 @@ Val::calcnokey(Par par) { const Chs* chs = col.m_chs; CHARSET_INFO* cs = chs->m_cs; - unsigned n = 0; + uint n = 0; calcnokeychars(par, n, m_char); // extend by appropriate space (*cs->cset->fill)(cs, (char*)&m_char[n], col.m_bytelength - n, 0x20); @@ -1997,7 +1979,7 @@ Val::calcnokey(Par par) break; case Col::Varchar: { - unsigned n = 0; + uint n = 0; calcnokeychars(par, n, m_varchar + 1); // set length and pad with nulls m_varchar[0] = n; @@ -2006,7 +1988,7 @@ Val::calcnokey(Par par) break; case Col::Longvarchar: { - unsigned n = 0; + uint n = 0; calcnokeychars(par, n, m_longvarchar + 2); // set length and pad with nulls m_longvarchar[0] = (n & 0xff); @@ -2021,24 +2003,24 @@ Val::calcnokey(Par par) } void -Val::calcnokeychars(Par par, unsigned& n, unsigned char* buf) +Val::calcnokeychars(Par par, uint& n, uchar* buf) { const Col& col = m_col; const Chs* chs = col.m_chs; CHARSET_INFO* cs = chs->m_cs; n = 0; - unsigned len = 0; + uint len = 0; while (len < col.m_length) { if (urandom(1 + col.m_bytelength) == 0) { break; } - unsigned half = maxcharcount / 2; + uint half = maxcharcount / 2; int r = irandom((par.m_pctrange * half) / 100); if (par.m_bdir != 0 && urandom(10) != 0) { if (r < 0 && par.m_bdir > 0 || r > 0 && par.m_bdir < 0) r = -r; } - unsigned i = half + r; + uint i = half + r; assert(i < maxcharcount); const Chr& chr = chs->m_chr[i]; assert(n + chr.m_size <= col.m_bytelength); @@ -2048,13 +2030,39 @@ Val::calcnokeychars(Par par, unsigned& n, unsigned char* buf) } } +// operations + int -Val::verify(Par par, const Val& val2) const +Val::setval(Par par) const { - CHK(cmp(par, val2) == 0); + Con& con = par.con(); + const Col& col = m_col; + if (col.m_pk) { + assert(!m_null); + const char* addr = (const char*)dataaddr(); + LL5("setval pk [" << col << "] " << *this); + CHK(con.equal(col.m_num, addr) == 0); + } else { + const char* addr = !m_null ? (const char*)dataaddr() : 0; + LL5("setval non-pk [" << col << "] " << *this); + CHK(con.setValue(col.m_num, addr) == 0); + } return 0; } +int +Val::setval(Par par, const ICol& icol) const +{ + Con& con = par.con(); + assert(!m_null); + const char* addr = (const char*)dataaddr(); + LL5("setval key [" << icol << "] " << *this); + CHK(con.equal(icol.m_num, addr) == 0); + return 0; +} + +// compare + int Val::cmp(Par par, const Val& val2) const { @@ -2062,9 +2070,9 @@ Val::cmp(Par par, const Val& val2) const const Col& col2 = val2.m_col; assert(col.equal(col2)); if (m_null || val2.m_null) { - if (! m_null) + if (!m_null) return +1; - if (! val2.m_null) + if (!val2.m_null) return -1; return 0; } @@ -2084,21 +2092,21 @@ Val::cmp(Par par, const Val& val2) const break; case Col::Char: { - unsigned len = col.m_bytelength; + uint len = col.m_bytelength; return cmpchars(par, m_char, len, val2.m_char, len); } break; case Col::Varchar: { - unsigned len1 = m_varchar[0]; - unsigned len2 = val2.m_varchar[0]; + uint len1 = m_varchar[0]; + uint len2 = val2.m_varchar[0]; return cmpchars(par, m_varchar + 1, len1, val2.m_varchar + 1, len2); } break; case Col::Longvarchar: { - unsigned len1 = m_longvarchar[0] + (m_longvarchar[1] << 8); - unsigned len2 = val2.m_longvarchar[0] + (val2.m_longvarchar[1] << 8); + uint len1 = m_longvarchar[0] + (m_longvarchar[1] << 8); + uint len2 = val2.m_longvarchar[0] + (val2.m_longvarchar[1] << 8); return cmpchars(par, m_longvarchar + 2, len1, val2.m_longvarchar + 2, len2); } break; @@ -2110,17 +2118,17 @@ Val::cmp(Par par, const Val& val2) const } int -Val::cmpchars(Par par, const unsigned char* buf1, unsigned len1, const unsigned char* buf2, unsigned len2) const +Val::cmpchars(Par par, const uchar* buf1, uint len1, const uchar* buf2, uint len2) const { const Col& col = m_col; const Chs* chs = col.m_chs; CHARSET_INFO* cs = chs->m_cs; int k; - if (! par.m_collsp) { - unsigned char x1[maxxmulsize * 8000]; - unsigned char x2[maxxmulsize * 8000]; + if (!par.m_collsp) { + uchar x1[maxxmulsize * 8000]; + uchar x2[maxxmulsize * 8000]; // make strxfrm pad both to same length - unsigned len = maxxmulsize * col.m_bytelength; + uint len = maxxmulsize * col.m_bytelength; int n1 = NdbSqlUtil::strnxfrm_bug7284(cs, x1, chs->m_xmul * len, buf1, len1); int n2 = NdbSqlUtil::strnxfrm_bug7284(cs, x2, chs->m_xmul * len, buf2, len2); assert(n1 != -1 && n1 == n2); @@ -2131,8 +2139,17 @@ Val::cmpchars(Par par, const unsigned char* buf1, unsigned len1, const unsigned return k < 0 ? -1 : k > 0 ? +1 : 0; } +int +Val::verify(Par par, const Val& val2) const +{ + CHK(cmp(par, val2) == 0); + return 0; +} + +// print + static void -printstring(NdbOut& out, const unsigned char* str, unsigned len, bool showlen) +printstring(NdbOut& out, const uchar* str, uint len, bool showlen) { char buf[4 * 8000]; char *p = buf; @@ -2141,12 +2158,12 @@ printstring(NdbOut& out, const unsigned char* str, unsigned len, bool showlen) sprintf(p, "%u:", len); p += strlen(p); } - for (unsigned i = 0; i < len; i++) { - unsigned char c = str[i]; + for (uint i = 0; i < len; i++) { + uchar c = str[i]; if (c == '\\') { *p++ = '\\'; *p++ = c; - } else if (0x20 <= c && c < 0x7e) { + } else if (0x20 <= c && c <= 0x7e) { *p++ = c; } else { *p++ = '\\'; @@ -2173,19 +2190,19 @@ operator<<(NdbOut& out, const Val& val) break; case Col::Char: { - unsigned len = col.m_bytelength; + uint len = col.m_bytelength; printstring(out, val.m_char, len, false); } break; case Col::Varchar: { - unsigned len = val.m_varchar[0]; + uint len = val.m_varchar[0]; printstring(out, val.m_varchar + 1, len, true); } break; case Col::Longvarchar: { - unsigned len = val.m_longvarchar[0] + (val.m_longvarchar[1] << 8); + uint len = val.m_longvarchar[0] + (val.m_longvarchar[1] << 8); printstring(out, val.m_longvarchar + 2, len, true); } break; @@ -2202,16 +2219,36 @@ operator<<(NdbOut& out, const Val& val) struct Row { const Tab& m_tab; Val** m_val; - bool m_exist; - enum Op { NoOp = 0, ReadOp = 1, InsOp = 2, UpdOp = 4, DelOp = 8, AnyOp = 15 }; - Op m_pending; - Row* m_dbrow; // copy of db row before update + enum St { + StUndef = 0, + StDefine = 1, + StPrepare = 2, + StCommit = 3 + }; + enum Op { + OpNone = 0, + OpIns = 2, + OpUpd = 4, + OpDel = 8, + OpRead = 16, + OpReadEx = 32, + OpReadCom = 64, + OpDML = 2 | 4 | 8, + OpREAD = 16 | 32 | 64 + }; + St m_st; + Op m_op; + Uint64 m_txid; + Row* m_bi; + // construct Row(const Tab& tab); ~Row(); - void copy(const Row& row2); - void calc(Par par, unsigned i, unsigned mask = 0); - const Row& dbrow() const; - int verify(Par par, const Row& row2, bool pkonly) const; + void copy(const Row& row2, bool copy_bi); + void copyval(const Row& row2, uint colmask = ~0); + void calc(Par par, uint i, uint colmask = ~0); + // operations + int setval(Par par, uint colmask = ~0); + int setval(Par par, const ITab& itab); int insrow(Par par); int updrow(Par par); int updrow(Par par, const ITab& itab); @@ -2220,91 +2257,115 @@ struct Row { int selrow(Par par); int selrow(Par par, const ITab& itab); int setrow(Par par); + // compare int cmp(Par par, const Row& row2) const; int cmp(Par par, const Row& row2, const ITab& itab) const; + int verify(Par par, const Row& row2, bool pkonly) const; private: Row& operator=(const Row& row2); }; +static NdbOut& +operator<<(NdbOut& out, const Row* rowp); + +static NdbOut& +operator<<(NdbOut& out, const Row& row); + +// construct + Row::Row(const Tab& tab) : m_tab(tab) { m_val = new Val* [tab.m_cols]; - for (unsigned k = 0; k < tab.m_cols; k++) { + for (uint k = 0; k < tab.m_cols; k++) { const Col& col = *tab.m_col[k]; m_val[k] = new Val(col); } - m_exist = false; - m_pending = NoOp; - m_dbrow = 0; + m_st = StUndef; + m_op = OpNone; + m_txid = 0; + m_bi = 0; } Row::~Row() { const Tab& tab = m_tab; - for (unsigned k = 0; k < tab.m_cols; k++) { + for (uint k = 0; k < tab.m_cols; k++) { delete m_val[k]; } delete [] m_val; - delete m_dbrow; + delete m_bi; } void -Row::copy(const Row& row2) +Row::copy(const Row& row2, bool copy_bi) +{ + const Tab& tab = m_tab; + copyval(row2); + m_st = row2.m_st; + m_op = row2.m_op; + m_txid = row2.m_txid; + assert(m_bi == 0); + if (copy_bi && row2.m_bi != 0) { + m_bi = new Row(tab); + m_bi->copy(*row2.m_bi, copy_bi); + } +} + +void +Row::copyval(const Row& row2, uint colmask) { const Tab& tab = m_tab; assert(&tab == &row2.m_tab); - for (unsigned k = 0; k < tab.m_cols; k++) { + for (uint k = 0; k < tab.m_cols; k++) { Val& val = *m_val[k]; const Val& val2 = *row2.m_val[k]; - val.copy(val2); - } - m_exist = row2.m_exist; - m_pending = row2.m_pending; - if (row2.m_dbrow == 0) { - m_dbrow = 0; - } else { - assert(row2.m_dbrow->m_dbrow == 0); - if (m_dbrow == 0) - m_dbrow = new Row(tab); - m_dbrow->copy(*row2.m_dbrow); + if ((1 << k) & colmask) + val.copy(val2); } } void -Row::calc(Par par, unsigned i, unsigned mask) +Row::calc(Par par, uint i, uint colmask) { const Tab& tab = m_tab; - for (unsigned k = 0; k < tab.m_cols; k++) { - if (! (mask & (1 << k))) { + for (uint k = 0; k < tab.m_cols; k++) { + if ((1 << k) & colmask) { Val& val = *m_val[k]; val.calc(par, i); } } } -const Row& -Row::dbrow() const +// operations + +int +Row::setval(Par par, uint colmask) { - if (m_dbrow == 0) - return *this; - assert(m_pending == Row::UpdOp || m_pending == Row::DelOp); - return *m_dbrow; + const Tab& tab = m_tab; + Rsq rsq(tab.m_cols); + for (uint k = 0; k < tab.m_cols; k++) { + uint k2 = rsq.next(); + if ((1 << k2) & colmask) { + const Val& val = *m_val[k2]; + CHK(val.setval(par) == 0); + } + } + return 0; } int -Row::verify(Par par, const Row& row2, bool pkonly) const +Row::setval(Par par, const ITab& itab) { - const Tab& tab = m_tab; - const Row& row1 = *this; - assert(&row1.m_tab == &row2.m_tab && row1.m_exist && row2.m_exist); - for (unsigned k = 0; k < tab.m_cols; k++) { - const Col& col = row1.m_val[k]->m_col; - if (! pkonly || col.m_pk) { - const Val& val1 = *row1.m_val[k]; - const Val& val2 = *row2.m_val[k]; - CHK(val1.verify(par, val2) == 0); - } + Con& con = par.con(); + Rsq rsq(itab.m_icols); + for (uint k = 0; k < itab.m_icols; k++) { + uint k2 = rsq.next(); + const ICol& icol = *itab.m_icol[k2]; + const Col& col = icol.m_col; + uint m = col.m_num; + const Val& val = *m_val[m]; + CHK(val.setval(par, icol) == 0); } return 0; } @@ -2314,26 +2375,14 @@ Row::insrow(Par par) { Con& con = par.con(); const Tab& tab = m_tab; - assert(! m_exist); CHK(con.getNdbOperation(tab) == 0); CHKCON(con.m_op->insertTuple() == 0, con); - Rsq rsq1(tab.m_cols); - for (unsigned k = 0; k < tab.m_cols; k++) { - unsigned k2 = rsq1.next(); - const Val& val = *m_val[k2]; - const Col& col = val.m_col; - if (col.m_pk) - CHK(val.equal(par) == 0); - } - Rsq rsq2(tab.m_cols); - for (unsigned k = 0; k < tab.m_cols; k++) { - unsigned k2 = rsq2.next(); - const Val& val = *m_val[k2]; - const Col& col = val.m_col; - if (! col.m_pk) - CHK(val.setval(par) == 0); - } - m_pending = InsOp; + CHK(setval(par, tab.m_pkmask) == 0); + CHK(setval(par, ~tab.m_pkmask) == 0); + assert(m_st == StUndef); + m_st = StDefine; + m_op = OpIns; + m_txid = con.m_txid; return 0; } @@ -2342,26 +2391,14 @@ Row::updrow(Par par) { Con& con = par.con(); const Tab& tab = m_tab; - assert(m_exist); CHK(con.getNdbOperation(tab) == 0); CHKCON(con.m_op->updateTuple() == 0, con); - Rsq rsq1(tab.m_cols); - for (unsigned k = 0; k < tab.m_cols; k++) { - unsigned k2 = rsq1.next(); - const Val& val = *m_val[k2]; - const Col& col = val.m_col; - if (col.m_pk) - CHK(val.equal(par) == 0); - } - Rsq rsq2(tab.m_cols); - for (unsigned k = 0; k < tab.m_cols; k++) { - unsigned k2 = rsq2.next(); - const Val& val = *m_val[k2]; - const Col& col = val.m_col; - if (! col.m_pk) - CHK(val.setval(par) == 0); - } - m_pending = UpdOp; + CHK(setval(par, tab.m_pkmask) == 0); + CHK(setval(par, ~tab.m_pkmask) == 0); + assert(m_st == StUndef); + m_st = StDefine; + m_op = OpUpd; + m_txid = con.m_txid; return 0; } @@ -2371,27 +2408,14 @@ Row::updrow(Par par, const ITab& itab) Con& con = par.con(); const Tab& tab = m_tab; assert(itab.m_type == ITab::UniqueHashIndex && &itab.m_tab == &tab); - assert(m_exist); CHK(con.getNdbIndexOperation(itab, tab) == 0); CHKCON(con.m_op->updateTuple() == 0, con); - Rsq rsq1(itab.m_icols); - for (unsigned k = 0; k < itab.m_icols; k++) { - unsigned k2 = rsq1.next(); - const ICol& icol = *itab.m_icol[k2]; - const Col& col = icol.m_col; - unsigned m = col.m_num; - const Val& val = *m_val[m]; - CHK(val.equal(par, icol) == 0); - } - Rsq rsq2(tab.m_cols); - for (unsigned k = 0; k < tab.m_cols; k++) { - unsigned k2 = rsq2.next(); - const Val& val = *m_val[k2]; - const Col& col = val.m_col; - if (! col.m_pk) - CHK(val.setval(par) == 0); - } - m_pending = UpdOp; + CHK(setval(par, itab) == 0); + CHK(setval(par, ~tab.m_pkmask) == 0); + assert(m_st == StUndef); + m_st = StDefine; + m_op = OpUpd; + m_txid = con.m_txid; return 0; } @@ -2400,18 +2424,13 @@ Row::delrow(Par par) { Con& con = par.con(); const Tab& tab = m_tab; - assert(m_exist); CHK(con.getNdbOperation(m_tab) == 0); CHKCON(con.m_op->deleteTuple() == 0, con); - Rsq rsq1(tab.m_cols); - for (unsigned k = 0; k < tab.m_cols; k++) { - unsigned k2 = rsq1.next(); - const Val& val = *m_val[k2]; - const Col& col = val.m_col; - if (col.m_pk) - CHK(val.equal(par) == 0); - } - m_pending = DelOp; + CHK(setval(par, tab.m_pkmask) == 0); + assert(m_st == StUndef); + m_st = StDefine; + m_op = OpDel; + m_txid = con.m_txid; return 0; } @@ -2421,19 +2440,13 @@ Row::delrow(Par par, const ITab& itab) Con& con = par.con(); const Tab& tab = m_tab; assert(itab.m_type == ITab::UniqueHashIndex && &itab.m_tab == &tab); - assert(m_exist); CHK(con.getNdbIndexOperation(itab, tab) == 0); CHKCON(con.m_op->deleteTuple() == 0, con); - Rsq rsq1(itab.m_icols); - for (unsigned k = 0; k < itab.m_icols; k++) { - unsigned k2 = rsq1.next(); - const ICol& icol = *itab.m_icol[k2]; - const Col& col = icol.m_col; - unsigned m = col.m_num; - const Val& val = *m_val[m]; - CHK(val.equal(par, icol) == 0); - } - m_pending = DelOp; + CHK(setval(par, itab) == 0); + assert(m_st == StUndef); + m_st = StDefine; + m_op = OpDel; + m_txid = con.m_txid; return 0; } @@ -2443,15 +2456,9 @@ Row::selrow(Par par) Con& con = par.con(); const Tab& tab = m_tab; CHK(con.getNdbOperation(m_tab) == 0); - CHKCON(con.m_op->readTuple() == 0, con); - Rsq rsq1(tab.m_cols); - for (unsigned k = 0; k < tab.m_cols; k++) { - unsigned k2 = rsq1.next(); - const Val& val = *m_val[k2]; - const Col& col = val.m_col; - if (col.m_pk) - CHK(val.equal(par) == 0); - } + CHKCON(con.readTuple(par) == 0, con); + CHK(setval(par, tab.m_pkmask) == 0); + // TODO state return 0; } @@ -2462,16 +2469,9 @@ Row::selrow(Par par, const ITab& itab) const Tab& tab = m_tab; assert(itab.m_type == ITab::UniqueHashIndex && &itab.m_tab == &tab); CHK(con.getNdbIndexOperation(itab, tab) == 0); - CHKCON(con.m_op->readTuple() == 0, con); - Rsq rsq1(itab.m_icols); - for (unsigned k = 0; k < itab.m_icols; k++) { - unsigned k2 = rsq1.next(); - const ICol& icol = *itab.m_icol[k2]; - const Col& col = icol.m_col; - unsigned m = col.m_num; - const Val& val = *m_val[m]; - CHK(val.equal(par, icol) == 0); - } + CHKCON(con.readTuple(par) == 0, con); + CHK(setval(par, itab) == 0); + // TODO state return 0; } @@ -2480,25 +2480,23 @@ Row::setrow(Par par) { Con& con = par.con(); const Tab& tab = m_tab; - Rsq rsq1(tab.m_cols); - for (unsigned k = 0; k < tab.m_cols; k++) { - unsigned k2 = rsq1.next(); - const Val& val = *m_val[k2]; - const Col& col = val.m_col; - if (! col.m_pk) - CHK(val.setval(par) == 0); - } - m_pending = UpdOp; + CHK(setval(par, ~tab.m_pkmask) == 0); + assert(m_st == StUndef); + m_st = StDefine; + m_op = OpUpd; + m_txid = con.m_txid; return 0; } +// compare + int Row::cmp(Par par, const Row& row2) const { const Tab& tab = m_tab; assert(&tab == &row2.m_tab); int c = 0; - for (unsigned k = 0; k < tab.m_cols; k++) { + for (uint k = 0; k < tab.m_cols; k++) { const Val& val = *m_val[k]; const Val& val2 = *row2.m_val[k]; if ((c = val.cmp(par, val2)) != 0) @@ -2512,10 +2510,10 @@ Row::cmp(Par par, const Row& row2, const ITab& itab) const { const Tab& tab = m_tab; int c = 0; - for (unsigned i = 0; i < itab.m_icols; i++) { + for (uint i = 0; i < itab.m_icols; i++) { const ICol& icol = *itab.m_icol[i]; const Col& col = icol.m_col; - unsigned k = col.m_num; + uint k = col.m_num; assert(k < tab.m_cols); const Val& val = *m_val[k]; const Val& val2 = *row2.m_val[k]; @@ -2525,19 +2523,70 @@ Row::cmp(Par par, const Row& row2, const ITab& itab) const return c; } +int +Row::verify(Par par, const Row& row2, bool pkonly) const +{ + const Tab& tab = m_tab; + const Row& row1 = *this; + assert(&row1.m_tab == &row2.m_tab); + for (uint k = 0; k < tab.m_cols; k++) { + const Col& col = row1.m_val[k]->m_col; + if (!pkonly || col.m_pk) { + const Val& val1 = *row1.m_val[k]; + const Val& val2 = *row2.m_val[k]; + CHK(val1.verify(par, val2) == 0); + } + } + return 0; +} + +// print + +static NdbOut& +operator<<(NdbOut& out, const Row::St st) +{ + if (st == Row::StUndef) + out << "StUndef"; + else if (st == Row::StDefine) + out << "StDefine"; + else if (st == Row::StPrepare) + out << "StPrepare"; + else if (st == Row::StCommit) + out << "StCommit"; + else + out << "st=" << st; + return out; +} + static NdbOut& operator<<(NdbOut& out, const Row::Op op) { - if (op == Row::NoOp) - out << "NoOp"; - else if (op == Row::InsOp) - out << "InsOp"; - else if (op == Row::UpdOp) - out << "UpdOp"; - else if (op == Row::DelOp) - out << "DelOp"; + if (op == Row::OpNone) + out << "OpNone"; + else if (op == Row::OpIns) + out << "OpIns"; + else if (op == Row::OpUpd) + out << "OpUpd"; + else if (op == Row::OpDel) + out << "OpDel"; + else if (op == Row::OpRead) + out << "OpRead"; + else if (op == Row::OpReadEx) + out << "OpReadEx"; + else if (op == Row::OpReadCom) + out << "OpReadCom"; else - out << op; + out << "op=" << op; + return out; +} + +static NdbOut& +operator<<(NdbOut& out, const Row* rowp) +{ + if (rowp == 0) + out << "[null]"; + else + out << *rowp; return out; } @@ -2545,26 +2594,18 @@ static NdbOut& operator<<(NdbOut& out, const Row& row) { const Tab& tab = row.m_tab; - for (unsigned i = 0; i < tab.m_cols; i++) { + out << "["; + for (uint i = 0; i < tab.m_cols; i++) { if (i > 0) out << " "; out << *row.m_val[i]; } - out << " exist=" << row.m_exist; - if (row.m_pending) - out << " pending=" << row.m_pending; - if (row.m_dbrow != 0) - out << " [dbrow=" << *row.m_dbrow << "]"; - return out; -} - -static NdbOut& -operator<<(NdbOut& out, const Row* rowptr) -{ - if (rowptr == 0) - out << "null"; - else - out << *rowptr; + out << " " << row.m_st; + out << " " << row.m_op; + out << " " << HEX(row.m_txid); + if (row.m_bi != 0) + out << " " << row.m_bi; + out << "]"; return out; } @@ -2572,45 +2613,38 @@ operator<<(NdbOut& out, const Row* rowptr) struct Set { const Tab& m_tab; - unsigned m_rows; + uint m_rows; Row** m_row; - unsigned* m_rowkey; // maps row number (from 0) in scan to tuple key + uint* m_rowkey; // maps row number (from 0) in scan to tuple key Row* m_keyrow; NdbRecAttr** m_rec; - Set(const Tab& tab, unsigned rows); + // construct + Set(const Tab& tab, uint rows); ~Set(); void reset(); - unsigned count() const; - // old and new values - bool exist(unsigned i) const; - void dbsave(unsigned i); - void calc(Par par, unsigned i, unsigned mask = 0); - bool pending(unsigned i, unsigned mask) const; - void notpending(unsigned i, ExecType et = Commit); - void notpending(const Lst& lst, ExecType et = Commit); - void dbdiscard(unsigned i); - void dbdiscard(const Lst& lst); - const Row& dbrow(unsigned i) const; + bool compat(Par par, uint i, const Row::Op op) const; + void push(uint i); + void copyval(uint i, uint colmask = ~0); // from bi + void calc(Par par, uint i, uint colmask = ~0); + uint count() const; + const Row* getrow(uint i, bool dirty = false) const; + // transaction + void post(Par par, ExecType et); // operations - int insrow(Par par, unsigned i); - int updrow(Par par, unsigned i); - int updrow(Par par, const ITab& itab, unsigned i); - int delrow(Par par, unsigned i); - int delrow(Par par, const ITab& itab, unsigned i); + int insrow(Par par, uint i); + int updrow(Par par, uint i); + int updrow(Par par, const ITab& itab, uint i); + int delrow(Par par, uint i); + int delrow(Par par, const ITab& itab, uint i); int selrow(Par par, const Row& keyrow); int selrow(Par par, const ITab& itab, const Row& keyrow); - // set and get - void setkey(Par par, const Row& keyrow); - void setkey(Par par, const ITab& itab, const Row& keyrow); - int setrow(Par par, unsigned i); + int setrow(Par par, uint i); int getval(Par par); - int getkey(Par par, unsigned* i); - int putval(unsigned i, bool force, unsigned n = ~0); - // sort rows in-place according to ordered index + int getkey(Par par, uint* i); + int putval(uint i, bool force, uint n = ~0); + // compare void sort(Par par, const ITab& itab); - void sort(Par par, const ITab& itab, unsigned lo, unsigned hi); - // verify - int verify(Par par, const Set& set2, bool pkonly) const; + int verify(Par par, const Set& set2, bool pkonly, bool dirty = false) const; int verifyorder(Par par, const ITab& itab, bool descending) const; // protect structure NdbMutex* m_mutex; @@ -2621,26 +2655,27 @@ struct Set { NdbMutex_Unlock(m_mutex); } private: + void sort(Par par, const ITab& itab, uint lo, uint hi); Set& operator=(const Set& set2); }; -Set::Set(const Tab& tab, unsigned rows) : +// construct + +Set::Set(const Tab& tab, uint rows) : m_tab(tab) { m_rows = rows; m_row = new Row* [m_rows]; - for (unsigned i = 0; i < m_rows; i++) { - // allocate on need to save space + for (uint i = 0; i < m_rows; i++) { m_row[i] = 0; } - m_rowkey = new unsigned [m_rows]; - for (unsigned n = 0; n < m_rows; n++) { - // initialize to null + m_rowkey = new uint [m_rows]; + for (uint n = 0; n < m_rows; n++) { m_rowkey[n] = ~0; } m_keyrow = new Row(tab); m_rec = new NdbRecAttr* [tab.m_cols]; - for (unsigned k = 0; k < tab.m_cols; k++) { + for (uint k = 0; k < tab.m_cols; k++) { m_rec[k] = 0; } m_mutex = NdbMutex_Create(); @@ -2649,7 +2684,7 @@ Set::Set(const Tab& tab, unsigned rows) : Set::~Set() { - for (unsigned i = 0; i < m_rows; i++) { + for (uint i = 0; i < m_rows; i++) { delete m_row[i]; } delete [] m_row; @@ -2662,132 +2697,203 @@ Set::~Set() void Set::reset() { - for (unsigned i = 0; i < m_rows; i++) { - if (m_row[i] != 0) { - Row& row = *m_row[i]; - row.m_exist = false; - } + for (uint i = 0; i < m_rows; i++) { + m_row[i] = 0; } } -unsigned +// this sucks +bool +Set::compat(Par par, uint i, const Row::Op op) const +{ + Con& con = par.con(); + int ret = -1; + int place = 0; + do { + const Row* rowp = getrow(i); + if (rowp == 0) { + ret = op == Row::OpIns; + place = 1; + break; + } + const Row& row = *rowp; + if (!(op & Row::OpREAD)) { + if (row.m_st == Row::StDefine || row.m_st == Row::StPrepare) { + assert(row.m_op & Row::OpDML); + assert(row.m_txid != 0); + if (con.m_txid != row.m_txid) { + ret = false; + place = 2; + break; + } + if (row.m_op != Row::OpDel) { + ret = op == Row::OpUpd || op == Row::OpDel; + place = 3; + break; + } + ret = op == Row::OpIns; + place = 4; + break; + } + if (row.m_st == Row::StCommit) { + assert(row.m_op == Row::OpNone); + assert(row.m_txid == 0); + ret = op == Row::OpUpd || op == Row::OpDel; + place = 5; + break; + } + } + if (op & Row::OpREAD) { + bool dirty = + con.m_txid != row.m_txid && + par.m_lockmode == NdbOperation::LM_CommittedRead; + const Row* rowp2 = getrow(i, dirty); + if (rowp2 == 0 || rowp2->m_op == Row::OpDel) { + ret = false; + place = 6; + break; + } + ret = true; + place = 7; + break; + } + } while (0); + LL4("compat ret=" << ret << " place=" << place); + assert(ret == false || ret == true); + return ret; +} + +void +Set::push(uint i) +{ + const Tab& tab = m_tab; + assert(i < m_rows); + Row* bi = m_row[i]; + m_row[i] = new Row(tab); + Row& row = *m_row[i]; + row.m_bi = bi; + if (bi != 0) + row.copyval(*bi); +} + +void +Set::copyval(uint i, uint colmask) +{ + assert(m_row[i] != 0); + Row& row = *m_row[i]; + assert(row.m_bi != 0); + row.copyval(*row.m_bi, colmask); +} + +void +Set::calc(Par par, uint i, uint colmask) +{ + assert(m_row[i] != 0); + Row& row = *m_row[i]; + row.calc(par, i, colmask); +} + +uint Set::count() const { - unsigned count = 0; - for (unsigned i = 0; i < m_rows; i++) { - if (m_row[i] != 0) { - Row& row = *m_row[i]; - if (row.m_exist) - count++; - } + uint count = 0; + for (uint i = 0; i < m_rows; i++) { + if (m_row[i] != 0) + count++; } return count; } -// old and new values - -bool -Set::exist(unsigned i) const +const Row* +Set::getrow(uint i, bool dirty) const { assert(i < m_rows); - if (m_row[i] == 0) // not allocated => not exist - return false; - return m_row[i]->m_exist; -} - -void -Set::dbsave(unsigned i) -{ - const Tab& tab = m_tab; - assert(i < m_rows && m_row[i] != 0); - Row& row = *m_row[i]; - LL5("dbsave " << i << ": " << row); - assert(row.m_exist && ! row.m_pending && row.m_dbrow == 0); - // could swap pointers but making copy is safer - Row* rowptr = new Row(tab); - rowptr->copy(row); - row.m_dbrow = rowptr; -} - -void -Set::calc(Par par, unsigned i, unsigned mask) -{ - const Tab& tab = m_tab; - if (m_row[i] == 0) - m_row[i] = new Row(tab); - Row& row = *m_row[i]; - row.calc(par, i, mask); -} - -bool -Set::pending(unsigned i, unsigned mask) const -{ - assert(i < m_rows); - if (m_row[i] == 0) // not allocated => not pending - return Row::NoOp; - return m_row[i]->m_pending & mask; -} - -void -Set::notpending(unsigned i, ExecType et) -{ - assert(m_row[i] != 0); - Row& row = *m_row[i]; - if (et == Commit) { - if (row.m_pending == Row::InsOp) - row.m_exist = true; - if (row.m_pending == Row::DelOp) - row.m_exist = false; - } else { - if (row.m_pending == Row::InsOp) - row.m_exist = false; - if (row.m_pending == Row::DelOp) - row.m_exist = true; + const Row* rowp = m_row[i]; + if (dirty) { + while (rowp != 0) { + bool b1 = rowp->m_op == Row::OpNone; + bool b2 = rowp->m_st == Row::StCommit; + assert(b1 == b2); + if (b1) { + assert(rowp->m_bi == 0); + break; + } + rowp = rowp->m_bi; + } } - row.m_pending = Row::NoOp; + return rowp; } +// transaction + void -Set::notpending(const Lst& lst, ExecType et) +Set::post(Par par, ExecType et) { - for (unsigned j = 0; j < lst.m_cnt; j++) { - unsigned i = lst.m_arr[j]; - notpending(i, et); - } -} - -void -Set::dbdiscard(unsigned i) -{ - assert(m_row[i] != 0); - Row& row = *m_row[i]; - LL5("dbdiscard " << i << ": " << row); - assert(row.m_dbrow != 0); - delete row.m_dbrow; - row.m_dbrow = 0; -} - -const Row& -Set::dbrow(unsigned i) const -{ - assert(m_row[i] != 0); - Row& row = *m_row[i]; - return row.dbrow(); -} - -void -Set::dbdiscard(const Lst& lst) -{ - for (unsigned j = 0; j < lst.m_cnt; j++) { - unsigned i = lst.m_arr[j]; - dbdiscard(i); + LL4("post"); + Con& con = par.con(); + assert(con.m_txid != 0); + uint i; + for (i = 0; i < m_rows; i++) { + Row* rowp = m_row[i]; + if (rowp == 0) { + LL5("skip " << i << " " << rowp); + continue; + } + if (rowp->m_st == Row::StCommit) { + assert(rowp->m_op == Row::OpNone); + assert(rowp->m_txid == 0); + assert(rowp->m_bi == 0); + LL5("skip committed " << i << " " << rowp); + continue; + } + assert(rowp->m_st == Row::StDefine || rowp->m_st == Row::StPrepare); + assert(rowp->m_txid != 0); + if (con.m_txid != rowp->m_txid) { + LL5("skip txid " << i << " " << HEX(con.m_txid) << " " << rowp); + continue; + } + // TODO read ops + assert(rowp->m_op & Row::OpDML); + LL4("post BEFORE " << rowp); + if (et == NoCommit) { + if (rowp->m_st == Row::StDefine) { + rowp->m_st = Row::StPrepare; + Row* bi = rowp->m_bi; + while (bi != 0 && bi->m_st == Row::StDefine) { + bi->m_st = Row::StPrepare; + bi = bi->m_bi; + } + } + } else if (et == Commit) { + if (rowp->m_op != Row::OpDel) { + rowp->m_st = Row::StCommit; + rowp->m_op = Row::OpNone; + rowp->m_txid = 0; + delete rowp->m_bi; + rowp->m_bi = 0; + } else { + delete rowp; + rowp = 0; + } + } else if (et == Rollback) { + while (rowp != 0 && rowp->m_st != Row::StCommit) { + Row* tmp = rowp; + rowp = rowp->m_bi; + tmp->m_bi = 0; + delete tmp; + } + } else { + assert(false); + } + m_row[i] = rowp; + LL4("post AFTER " << rowp); } } // operations int -Set::insrow(Par par, unsigned i) +Set::insrow(Par par, uint i) { assert(m_row[i] != 0); Row& row = *m_row[i]; @@ -2796,7 +2902,7 @@ Set::insrow(Par par, unsigned i) } int -Set::updrow(Par par, unsigned i) +Set::updrow(Par par, uint i) { assert(m_row[i] != 0); Row& row = *m_row[i]; @@ -2805,7 +2911,7 @@ Set::updrow(Par par, unsigned i) } int -Set::updrow(Par par, const ITab& itab, unsigned i) +Set::updrow(Par par, const ITab& itab, uint i) { assert(m_row[i] != 0); Row& row = *m_row[i]; @@ -2814,7 +2920,7 @@ Set::updrow(Par par, const ITab& itab, unsigned i) } int -Set::delrow(Par par, unsigned i) +Set::delrow(Par par, uint i) { assert(m_row[i] != 0); Row& row = *m_row[i]; @@ -2823,7 +2929,7 @@ Set::delrow(Par par, unsigned i) } int -Set::delrow(Par par, const ITab& itab, unsigned i) +Set::delrow(Par par, const ITab& itab, uint i) { assert(m_row[i] != 0); Row& row = *m_row[i]; @@ -2836,8 +2942,8 @@ Set::selrow(Par par, const Row& keyrow) { Con& con = par.con(); const Tab& tab = par.tab(); - setkey(par, keyrow); - LL5("selrow " << tab.m_name << ": keyrow: " << keyrow); + LL5("selrow " << tab.m_name << " keyrow " << keyrow); + m_keyrow->copyval(keyrow, tab.m_pkmask); CHK(m_keyrow->selrow(par) == 0); CHK(getval(par) == 0); return 0; @@ -2847,45 +2953,15 @@ int Set::selrow(Par par, const ITab& itab, const Row& keyrow) { Con& con = par.con(); - setkey(par, itab, keyrow); - LL5("selrow " << itab.m_name << ": keyrow: " << keyrow); + LL5("selrow " << itab.m_name << " keyrow " << keyrow); + m_keyrow->copyval(keyrow, itab.m_keymask); CHK(m_keyrow->selrow(par, itab) == 0); CHK(getval(par) == 0); return 0; } -// set and get - -void -Set::setkey(Par par, const Row& keyrow) -{ - const Tab& tab = m_tab; - for (unsigned k = 0; k < tab.m_cols; k++) { - const Col& col = *tab.m_col[k]; - if (col.m_pk) { - Val& val1 = *m_keyrow->m_val[k]; - const Val& val2 = *keyrow.dbrow().m_val[k]; - val1.copy(val2); - } - } -} - -void -Set::setkey(Par par, const ITab& itab, const Row& keyrow) -{ - const Tab& tab = m_tab; - for (unsigned k = 0; k < itab.m_icols; k++) { - const ICol& icol = *itab.m_icol[k]; - const Col& col = icol.m_col; - unsigned m = col.m_num; - Val& val1 = *m_keyrow->m_val[m]; - const Val& val2 = *keyrow.dbrow().m_val[m]; - val1.copy(val2); - } -} - int -Set::setrow(Par par, unsigned i) +Set::setrow(Par par, uint i) { Con& con = par.con(); assert(m_row[i] != 0); @@ -2899,18 +2975,18 @@ Set::getval(Par par) Con& con = par.con(); const Tab& tab = m_tab; Rsq rsq1(tab.m_cols); - for (unsigned k = 0; k < tab.m_cols; k++) { - unsigned k2 = rsq1.next(); + for (uint k = 0; k < tab.m_cols; k++) { + uint k2 = rsq1.next(); CHK(con.getValue(k2, m_rec[k2]) == 0); } return 0; } int -Set::getkey(Par par, unsigned* i) +Set::getkey(Par par, uint* i) { const Tab& tab = m_tab; - unsigned k = tab.m_keycol; + uint k = tab.m_keycol; assert(m_rec[k] != 0); const char* aRef = m_rec[k]->aRef(); Uint32 key = *(const Uint32*)aRef; @@ -2921,14 +2997,18 @@ Set::getkey(Par par, unsigned* i) } int -Set::putval(unsigned i, bool force, unsigned n) +Set::putval(uint i, bool force, uint n) { const Tab& tab = m_tab; - if (m_row[i] == 0) - m_row[i] = new Row(tab); + LL4("putval key=" << i << " row=" << n << " old=" << m_row[i]); + if (m_row[i] != 0) { + assert(force); + delete m_row[i]; + m_row[i] = 0; + } + m_row[i] = new Row(tab); Row& row = *m_row[i]; - CHK(! row.m_exist || force); - for (unsigned k = 0; k < tab.m_cols; k++) { + for (uint k = 0; k < tab.m_cols; k++) { Val& val = *row.m_val[k]; NdbRecAttr* rec = m_rec[k]; assert(rec != 0); @@ -2940,13 +3020,13 @@ Set::putval(unsigned i, bool force, unsigned n) val.copy(aRef); val.m_null = false; } - if (! row.m_exist) - row.m_exist = true; if (n != ~0) m_rowkey[n] = i; return 0; } +// compare + void Set::sort(Par par, const ITab& itab) { @@ -2955,12 +3035,12 @@ Set::sort(Par par, const ITab& itab) } void -Set::sort(Par par, const ITab& itab, unsigned lo, unsigned hi) +Set::sort(Par par, const ITab& itab, uint lo, uint hi) { assert(lo < m_rows && hi < m_rows && lo <= hi); Row* const p = m_row[lo]; - unsigned i = lo; - unsigned j = hi; + uint i = lo; + uint j = hi; while (i < j) { while (i < j && m_row[j]->cmp(par, *p, itab) >= 0) j--; @@ -2982,22 +3062,48 @@ Set::sort(Par par, const ITab& itab, unsigned lo, unsigned hi) sort(par, itab, i + 1, hi); } +/* + * set1 (self) is from dml and can contain un-committed operations. + * set2 is from read and contains no operations. "dirty" applies + * to set1: false = use latest row, true = use committed row. + */ int -Set::verify(Par par, const Set& set2, bool pkonly) const +Set::verify(Par par, const Set& set2, bool pkonly, bool dirty) const { - assert(&m_tab == &set2.m_tab && m_rows == set2.m_rows); - LL4("verify set1 count=" << count() << " vs set2 count=" << set2.count()); - for (unsigned i = 0; i < m_rows; i++) { + const Set& set1 = *this; + assert(&set1.m_tab == &set2.m_tab && set1.m_rows == set2.m_rows); + LL3("verify dirty:" << dirty); + for (uint i = 0; i < set1.m_rows; i++) { + // the row versions we actually compare + const Row* row1p = set1.getrow(i, dirty); + const Row* row2p = set2.getrow(i); bool ok = true; - if (exist(i) != set2.exist(i)) { - ok = false; - } else if (exist(i)) { - if (dbrow(i).verify(par, set2.dbrow(i), pkonly) != 0) + int place = 0; + if (row1p == 0) { + if (row2p != 0) { ok = false; + place = 1; + } + } else { + Row::Op op1 = row1p->m_op; + if (op1 != Row::OpDel) { + if (row2p == 0) { + ok = false; + place = 2; + } else if (row1p->verify(par, *row2p, pkonly) == -1) { + ok = false; + place = 3; + } + } else if (row2p != 0) { + ok = false; + place = 4; + } } - if (! ok) { - LL1("verify failed: key=" << i << " row1=" << m_row[i] << " row2=" << set2.m_row[i]); - CHK(0 == 1); + if (!ok) { + LL1("verify " << i << " failed at " << place); + LL1("row1 " << row1p); + LL1("row2 " << row2p); + CHK(false); } } return 0; @@ -3007,18 +3113,17 @@ int Set::verifyorder(Par par, const ITab& itab, bool descending) const { const Tab& tab = m_tab; - for (unsigned n = 0; n < m_rows; n++) { - unsigned i2 = m_rowkey[n]; + for (uint n = 0; n < m_rows; n++) { + uint i2 = m_rowkey[n]; if (i2 == ~0) break; if (n == 0) continue; - unsigned i1 = m_rowkey[n - 1]; - assert(i1 < m_rows && i2 < m_rows); + uint i1 = m_rowkey[n - 1]; + assert(m_row[i1] != 0 && m_row[i2] != 0); const Row& row1 = *m_row[i1]; const Row& row2 = *m_row[i2]; - assert(row1.m_exist && row2.m_exist); - if (! descending) + if (!descending) CHK(row1.cmp(par, row2, itab) <= 0); else CHK(row1.cmp(par, row2, itab) >= 0); @@ -3026,10 +3131,12 @@ Set::verifyorder(Par par, const ITab& itab, bool descending) const return 0; } +// print + static NdbOut& operator<<(NdbOut& out, const Set& set) { - for (unsigned i = 0; i < set.m_rows; i++) { + for (uint i = 0; i < set.m_rows; i++) { const Row& row = *set.m_row[i]; if (i > 0) out << endl; @@ -3058,8 +3165,8 @@ int BVal::setbnd(Par par) const { Con& con = par.con(); - assert(g_compare_null || ! m_null); - const char* addr = ! m_null ? (const char*)dataaddr() : 0; + assert(g_compare_null || !m_null); + const char* addr = !m_null ? (const char*)dataaddr() : 0; const ICol& icol = m_icol; CHK(con.setBound(icol.m_num, m_type, addr) == 0); return 0; @@ -3068,7 +3175,7 @@ BVal::setbnd(Par par) const int BVal::setflt(Par par) const { - static unsigned index_bound_to_filter_bound[5] = { + static uint index_bound_to_filter_bound[5] = { NdbScanFilter::COND_GE, NdbScanFilter::COND_GT, NdbScanFilter::COND_LE, @@ -3076,12 +3183,12 @@ BVal::setflt(Par par) const NdbScanFilter::COND_EQ }; Con& con = par.con(); - assert(g_compare_null || ! m_null); - const char* addr = ! m_null ? (const char*)dataaddr() : 0; + assert(g_compare_null || !m_null); + const char* addr = !m_null ? (const char*)dataaddr() : 0; const ICol& icol = m_icol; const Col& col = icol.m_col; - unsigned length = col.m_bytesize; - unsigned cond = index_bound_to_filter_bound[m_type]; + uint length = col.m_bytesize; + uint cond = index_bound_to_filter_bound[m_type]; CHK(con.setFilter(col.m_num, cond, addr, length) == 0); return 0; } @@ -3104,27 +3211,27 @@ operator<<(NdbOut& out, const BVal& bval) struct BSet { const Tab& m_tab; const ITab& m_itab; - unsigned m_alloc; - unsigned m_bvals; + uint m_alloc; + uint m_bvals; BVal** m_bval; - BSet(const Tab& tab, const ITab& itab, unsigned rows); + BSet(const Tab& tab, const ITab& itab); ~BSet(); void reset(); void calc(Par par); - void calcpk(Par par, unsigned i); + void calcpk(Par par, uint i); int setbnd(Par par) const; int setflt(Par par) const; void filter(Par par, const Set& set, Set& set2) const; }; -BSet::BSet(const Tab& tab, const ITab& itab, unsigned rows) : +BSet::BSet(const Tab& tab, const ITab& itab) : m_tab(tab), m_itab(itab), m_alloc(2 * itab.m_icols), m_bvals(0) { m_bval = new BVal* [m_alloc]; - for (unsigned i = 0; i < m_alloc; i++) { + for (uint i = 0; i < m_alloc; i++) { m_bval[i] = 0; } } @@ -3138,7 +3245,7 @@ void BSet::reset() { while (m_bvals > 0) { - unsigned i = --m_bvals; + uint i = --m_bvals; delete m_bval[i]; m_bval[i] = 0; } @@ -3150,10 +3257,10 @@ BSet::calc(Par par) const ITab& itab = m_itab; par.m_pctrange = par.m_pctbrange; reset(); - for (unsigned k = 0; k < itab.m_icols; k++) { + for (uint k = 0; k < itab.m_icols; k++) { const ICol& icol = *itab.m_icol[k]; const Col& col = icol.m_col; - for (unsigned i = 0; i <= 1; i++) { + for (uint i = 0; i <= 1; i++) { if (m_bvals == 0 && urandom(100) == 0) return; if (m_bvals != 0 && urandom(3) == 0) @@ -3162,7 +3269,7 @@ BSet::calc(Par par) BVal& bval = *new BVal(icol); m_bval[m_bvals++] = &bval; bval.m_null = false; - unsigned sel; + uint sel; do { // equality bound only on i==0 sel = urandom(5 - i); @@ -3175,7 +3282,7 @@ BSet::calc(Par par) bval.m_type = 4; if (k + 1 < itab.m_icols) bval.m_type = 4; - if (! g_compare_null) + if (!g_compare_null) par.m_pctnull = 0; if (bval.m_type == 0 || bval.m_type == 1) par.m_bdir = -1; @@ -3199,11 +3306,11 @@ BSet::calc(Par par) } void -BSet::calcpk(Par par, unsigned i) +BSet::calcpk(Par par, uint i) { const ITab& itab = m_itab; reset(); - for (unsigned k = 0; k < itab.m_icols; k++) { + for (uint k = 0; k < itab.m_icols; k++) { const ICol& icol = *itab.m_icol[k]; const Col& col = icol.m_col; assert(col.m_pk); @@ -3220,14 +3327,14 @@ BSet::setbnd(Par par) const { if (m_bvals != 0) { Rsq rsq1(m_bvals); - for (unsigned j = 0; j < m_bvals; j++) { - unsigned j2 = rsq1.next(); + for (uint j = 0; j < m_bvals; j++) { + uint j2 = rsq1.next(); const BVal& bval = *m_bval[j2]; CHK(bval.setbnd(par) == 0); } // duplicate if (urandom(5) == 0) { - unsigned j3 = urandom(m_bvals); + uint j3 = urandom(m_bvals); const BVal& bval = *m_bval[j3]; CHK(bval.setbnd(par) == 0); } @@ -3243,14 +3350,14 @@ BSet::setflt(Par par) const CHK(con.beginFilter(NdbScanFilter::AND) == 0); if (m_bvals != 0) { Rsq rsq1(m_bvals); - for (unsigned j = 0; j < m_bvals; j++) { - unsigned j2 = rsq1.next(); + for (uint j = 0; j < m_bvals; j++) { + uint j2 = rsq1.next(); const BVal& bval = *m_bval[j2]; CHK(bval.setflt(par) == 0); } // duplicate if (urandom(5) == 0) { - unsigned j3 = urandom(m_bvals); + uint j3 = urandom(m_bvals); const BVal& bval = *m_bval[j3]; CHK(bval.setflt(par) == 0); } @@ -3266,57 +3373,59 @@ BSet::filter(Par par, const Set& set, Set& set2) const const ITab& itab = m_itab; assert(&tab == &set2.m_tab && set.m_rows == set2.m_rows); assert(set2.count() == 0); - for (unsigned i = 0; i < set.m_rows; i++) { - if (! set.exist(i)) - continue; + for (uint i = 0; i < set.m_rows; i++) { set.lock(); - const Row& row = set.dbrow(i); - set.unlock(); - if (! g_store_null_key) { - bool ok1 = false; - for (unsigned k = 0; k < itab.m_icols; k++) { - const ICol& icol = *itab.m_icol[k]; + do { + if (set.m_row[i] == 0) { + break; + } + const Row& row = *set.m_row[i]; + if (!g_store_null_key) { + bool ok1 = false; + for (uint k = 0; k < itab.m_icols; k++) { + const ICol& icol = *itab.m_icol[k]; + const Col& col = icol.m_col; + const Val& val = *row.m_val[col.m_num]; + if (!val.m_null) { + ok1 = true; + break; + } + } + if (!ok1) + break; + } + bool ok2 = true; + for (uint j = 0; j < m_bvals; j++) { + const BVal& bval = *m_bval[j]; + const ICol& icol = bval.m_icol; const Col& col = icol.m_col; const Val& val = *row.m_val[col.m_num]; - if (! val.m_null) { - ok1 = true; - break; + int ret = bval.cmp(par, val); + LL5("cmp: ret=" << ret << " " << bval << " vs " << val); + if (bval.m_type == 0) + ok2 = (ret <= 0); + else if (bval.m_type == 1) + ok2 = (ret < 0); + else if (bval.m_type == 2) + ok2 = (ret >= 0); + else if (bval.m_type == 3) + ok2 = (ret > 0); + else if (bval.m_type == 4) + ok2 = (ret == 0); + else { + assert(false); } + if (!ok2) + break; } - if (! ok1) - continue; - } - bool ok2 = true; - for (unsigned j = 0; j < m_bvals; j++) { - const BVal& bval = *m_bval[j]; - const ICol& icol = bval.m_icol; - const Col& col = icol.m_col; - const Val& val = *row.m_val[col.m_num]; - int ret = bval.cmp(par, val); - LL5("cmp: ret=" << ret << " " << bval << " vs " << val); - if (bval.m_type == 0) - ok2 = (ret <= 0); - else if (bval.m_type == 1) - ok2 = (ret < 0); - else if (bval.m_type == 2) - ok2 = (ret >= 0); - else if (bval.m_type == 3) - ok2 = (ret > 0); - else if (bval.m_type == 4) - ok2 = (ret == 0); - else { - assert(false); - } - if (! ok2) + if (!ok2) break; - } - if (! ok2) - continue; - if (set2.m_row[i] == 0) + assert(set2.m_row[i] == 0); set2.m_row[i] = new Row(tab); - Row& row2 = *set2.m_row[i]; - assert(! row2.m_exist); - row2.copy(row); + Row& row2 = *set2.m_row[i]; + row2.copy(row, true); + } while (0); + set.unlock(); } } @@ -3324,7 +3433,7 @@ static NdbOut& operator<<(NdbOut& out, const BSet& bset) { out << "bounds=" << bset.m_bvals; - for (unsigned j = 0; j < bset.m_bvals; j++) { + for (uint j = 0; j < bset.m_bvals; j++) { const BVal& bval = *bset.m_bval[j]; out << " [bound " << j << ": " << bval << "]"; } @@ -3341,60 +3450,41 @@ pkinsert(Par par) Set& set = par.set(); LL3("pkinsert " << tab.m_name); CHK(con.startTransaction() == 0); - Lst lst; - for (unsigned j = 0; j < par.m_rows; j++) { - unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows); - unsigned i = thrrow(par, j2); + uint batch = 0; + for (uint j = 0; j < par.m_rows; j++) { + uint j2 = !par.m_randomkey ? j : urandom(par.m_rows); + uint i = thrrow(par, j2); set.lock(); - if (set.exist(i) || set.pending(i, Row::AnyOp)) { + if (!set.compat(par, i, Row::OpIns)) { + LL3("pkinsert SKIP " << i << " " << set.getrow(i)); set.unlock(); - continue; + } else { + set.push(i); + set.calc(par, i); + CHK(set.insrow(par, i) == 0); + set.unlock(); + LL4("pkinsert key=" << i << " " << set.getrow(i)); + batch++; } - set.calc(par, i); - CHK(set.insrow(par, i) == 0); - set.unlock(); - LL4("pkinsert " << i << ": " << *set.m_row[i]); - lst.push(i); - if (lst.cnt() == par.m_batch) { - bool deadlock = par.m_deadlock; - bool nospace = true; - ExecType et = randompct(par.m_abortpct) ? Rollback : Commit; - CHK(con.execute(et, deadlock, nospace) == 0); - con.closeTransaction(); - if (deadlock) { - LL1("pkinsert: stop on deadlock [at 1]"); - return 0; - } - if (nospace) { - LL1("pkinsert: cnt=" << j << " stop on nospace"); - return 0; - } + bool lastbatch = (batch != 0 && j + 1 == par.m_rows); + if (batch == par.m_batch || lastbatch) { + uint err = par.m_catcherr; + ExecType et = !randompct(par.m_abortpct) ? Commit : Rollback; + CHK(con.execute(et, err) == 0); set.lock(); - set.notpending(lst, et); + set.post(par, !err ? et : Rollback); set.unlock(); - lst.reset(); - CHK(con.startTransaction() == 0); + if (err) { + LL1("pkinsert key=" << i << " stop on " << con.errname(err)); + break; + } + batch = 0; + if (!lastbatch) { + con.closeTransaction(); + CHK(con.startTransaction() == 0); + } } } - if (lst.cnt() != 0) { - bool deadlock = par.m_deadlock; - bool nospace = true; - ExecType et = randompct(par.m_abortpct) ? Rollback : Commit; - CHK(con.execute(et, deadlock, nospace) == 0); - con.closeTransaction(); - if (deadlock) { - LL1("pkinsert: stop on deadlock [at 2]"); - return 0; - } - if (nospace) { - LL1("pkinsert: end: stop on nospace"); - return 0; - } - set.lock(); - set.notpending(lst, et); - set.unlock(); - return 0; - } con.closeTransaction(); return 0; } @@ -3407,59 +3497,40 @@ pkupdate(Par par) Set& set = par.set(); LL3("pkupdate " << tab.m_name); CHK(con.startTransaction() == 0); - Lst lst; - bool deadlock = false; - bool nospace = false; - for (unsigned j = 0; j < par.m_rows; j++) { - unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows); - unsigned i = thrrow(par, j2); + uint batch = 0; + for (uint j = 0; j < par.m_rows; j++) { + uint j2 = !par.m_randomkey ? j : urandom(par.m_rows); + uint i = thrrow(par, j2); set.lock(); - if (! set.exist(i) || set.pending(i, Row::AnyOp)) { + if (!set.compat(par, i, Row::OpUpd)) { + LL3("pkupdate SKIP " << i << " " << set.getrow(i)); set.unlock(); - continue; - } - set.dbsave(i); - set.calc(par, i); - CHK(set.updrow(par, i) == 0); - set.unlock(); - LL4("pkupdate " << i << ": " << *set.m_row[i]); - lst.push(i); - if (lst.cnt() == par.m_batch) { - deadlock = par.m_deadlock; - nospace = true; - ExecType et = randompct(par.m_abortpct) ? Rollback : Commit; - CHK(con.execute(et, deadlock, nospace) == 0); - if (deadlock) { - LL1("pkupdate: stop on deadlock [at 1]"); - break; - } - if (nospace) { - LL1("pkupdate: cnt=" << j << " stop on nospace [at 1]"); - break; - } - con.closeTransaction(); - set.lock(); - set.notpending(lst, et); - set.dbdiscard(lst); - set.unlock(); - lst.reset(); - CHK(con.startTransaction() == 0); - } - } - if (! deadlock && ! nospace && lst.cnt() != 0) { - deadlock = par.m_deadlock; - nospace = true; - ExecType et = randompct(par.m_abortpct) ? Rollback : Commit; - CHK(con.execute(et, deadlock, nospace) == 0); - if (deadlock) { - LL1("pkupdate: stop on deadlock [at 2]"); - } else if (nospace) { - LL1("pkupdate: end: stop on nospace [at 2]"); } else { - set.lock(); - set.notpending(lst, et); - set.dbdiscard(lst); + set.push(i); + set.copyval(i, tab.m_pkmask); + set.calc(par, i, ~tab.m_pkmask); + CHK(set.updrow(par, i) == 0); set.unlock(); + LL4("pkupdate key=" << i << " " << set.getrow(i)); + batch++; + } + bool lastbatch = (batch != 0 && j + 1 == par.m_rows); + if (batch == par.m_batch || lastbatch) { + uint err = par.m_catcherr; + ExecType et = !randompct(par.m_abortpct) ? Commit : Rollback; + CHK(con.execute(et, err) == 0); + set.lock(); + set.post(par, !err ? et : Rollback); + set.unlock(); + if (err) { + LL1("pkupdate key=" << i << ": stop on " << con.errname(err)); + break; + } + batch = 0; + if (!lastbatch) { + con.closeTransaction(); + CHK(con.startTransaction() == 0); + } } } con.closeTransaction(); @@ -3474,49 +3545,39 @@ pkdelete(Par par) Set& set = par.set(); LL3("pkdelete " << tab.m_name); CHK(con.startTransaction() == 0); - Lst lst; - bool deadlock = false; - bool nospace = false; - for (unsigned j = 0; j < par.m_rows; j++) { - unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows); - unsigned i = thrrow(par, j2); + uint batch = 0; + for (uint j = 0; j < par.m_rows; j++) { + uint j2 = !par.m_randomkey ? j : urandom(par.m_rows); + uint i = thrrow(par, j2); set.lock(); - if (! set.exist(i) || set.pending(i, Row::AnyOp)) { + if (!set.compat(par, i, Row::OpDel)) { + LL3("pkdelete SKIP " << i << " " << set.getrow(i)); set.unlock(); - continue; + } else { + set.push(i); + set.copyval(i, tab.m_pkmask); + CHK(set.delrow(par, i) == 0); + set.unlock(); + LL4("pkdelete key=" << i << " " << set.getrow(i)); + batch++; } - CHK(set.delrow(par, i) == 0); - set.unlock(); - LL4("pkdelete " << i << ": " << *set.m_row[i]); - lst.push(i); - if (lst.cnt() == par.m_batch) { - deadlock = par.m_deadlock; - nospace = true; - ExecType et = randompct(par.m_abortpct) ? Rollback : Commit; - CHK(con.execute(et, deadlock, nospace) == 0); - if (deadlock) { - LL1("pkdelete: stop on deadlock [at 1]"); + bool lastbatch = (batch != 0 && j + 1 == par.m_rows); + if (batch == par.m_batch || lastbatch) { + uint err = par.m_catcherr; + ExecType et = !randompct(par.m_abortpct) ? Commit : Rollback; + CHK(con.execute(et, err) == 0); + set.lock(); + set.post(par, !err ? et : Rollback); + set.unlock(); + if (err) { + LL1("pkdelete key=" << i << " stop on " << con.errname(err)); break; } - con.closeTransaction(); - set.lock(); - set.notpending(lst, et); - set.unlock(); - lst.reset(); - CHK(con.startTransaction() == 0); - } - } - if (! deadlock && ! nospace && lst.cnt() != 0) { - deadlock = par.m_deadlock; - nospace = true; - ExecType et = randompct(par.m_abortpct) ? Rollback : Commit; - CHK(con.execute(et, deadlock, nospace) == 0); - if (deadlock) { - LL1("pkdelete: stop on deadlock [at 2]"); - } else { - set.lock(); - set.notpending(lst, et); - set.unlock(); + batch = 0; + if (!lastbatch) { + con.closeTransaction(); + CHK(con.startTransaction() == 0); + } } } con.closeTransaction(); @@ -3533,9 +3594,11 @@ pkread(Par par) // expected const Set& set1 = set; Set set2(tab, set.m_rows); - for (unsigned i = 0; i < set.m_rows; i++) { + for (uint i = 0; i < set.m_rows; i++) { set.lock(); - if (! set.exist(i)) { + // TODO lock mode + if (!set.compat(par, i, Row::OpREAD)) { + LL3("pkread SKIP " << i << " " << set.getrow(i)); set.unlock(); continue; } @@ -3543,10 +3606,10 @@ pkread(Par par) CHK(con.startTransaction() == 0); CHK(set2.selrow(par, *set1.m_row[i]) == 0); CHK(con.execute(Commit) == 0); - unsigned i2 = (unsigned)-1; + uint i2 = (uint)-1; CHK(set2.getkey(par, &i2) == 0 && i == i2); CHK(set2.putval(i, false) == 0); - LL4("row " << set2.count() << ": " << *set2.m_row[i]); + LL4("row " << set2.count() << " " << set2.getrow(i)); con.closeTransaction(); } if (par.m_verify) @@ -3555,7 +3618,7 @@ pkread(Par par) } static int -pkreadfast(Par par, unsigned count) +pkreadfast(Par par, uint count) { Con& con = par.con(); const Tab& tab = par.tab(); @@ -3563,9 +3626,9 @@ pkreadfast(Par par, unsigned count) LL3("pkfast " << tab.m_name); Row keyrow(tab); // not batched on purpose - for (unsigned j = 0; j < count; j++) { - unsigned i = urandom(set.m_rows); - assert(set.exist(i)); + for (uint j = 0; j < count; j++) { + uint i = urandom(set.m_rows); + assert(set.compat(par, i, Row::OpREAD)); CHK(con.startTransaction() == 0); // define key keyrow.calc(par, i); @@ -3585,53 +3648,46 @@ static int hashindexupdate(Par par, const ITab& itab) { Con& con = par.con(); + const Tab& tab = par.tab(); Set& set = par.set(); LL3("hashindexupdate " << itab.m_name); CHK(con.startTransaction() == 0); - Lst lst; - bool deadlock = false; - bool nospace = false; - for (unsigned j = 0; j < par.m_rows; j++) { - unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows); - unsigned i = thrrow(par, j2); + uint batch = 0; + for (uint j = 0; j < par.m_rows; j++) { + uint j2 = !par.m_randomkey ? j : urandom(par.m_rows); + uint i = thrrow(par, j2); set.lock(); - if (! set.exist(i) || set.pending(i, Row::AnyOp)) { + if (!set.compat(par, i, Row::OpUpd)) { + LL3("hashindexupdate SKIP " << i << " " << set.getrow(i)); set.unlock(); - continue; + } else { + // table pk and index key are not updated + set.push(i); + uint keymask = tab.m_pkmask | itab.m_keymask; + set.copyval(i, keymask); + set.calc(par, i, ~keymask); + CHK(set.updrow(par, itab, i) == 0); + set.unlock(); + LL4("hashindexupdate " << i << " " << set.getrow(i)); + batch++; } - set.dbsave(i); - // index key columns are not re-calculated - set.calc(par, i, itab.m_colmask); - CHK(set.updrow(par, itab, i) == 0); - set.unlock(); - LL4("hashindexupdate " << i << ": " << *set.m_row[i]); - lst.push(i); - if (lst.cnt() == par.m_batch) { - deadlock = par.m_deadlock; - CHK(con.execute(Commit, deadlock, nospace) == 0); - if (deadlock) { - LL1("hashindexupdate: stop on deadlock [at 1]"); + bool lastbatch = (batch != 0 && j + 1 == par.m_rows); + if (batch == par.m_batch || lastbatch) { + uint err = par.m_catcherr; + ExecType et = !randompct(par.m_abortpct) ? Commit : Rollback; + CHK(con.execute(et, err) == 0); + set.lock(); + set.post(par, !err ? et : Rollback); + set.unlock(); + if (err) { + LL1("hashindexupdate " << i << " stop on " << con.errname(err)); break; } - con.closeTransaction(); - set.lock(); - set.notpending(lst); - set.dbdiscard(lst); - set.unlock(); - lst.reset(); - CHK(con.startTransaction() == 0); - } - } - if (! deadlock && lst.cnt() != 0) { - deadlock = par.m_deadlock; - CHK(con.execute(Commit, deadlock, nospace) == 0); - if (deadlock) { - LL1("hashindexupdate: stop on deadlock [at 2]"); - } else { - set.lock(); - set.notpending(lst); - set.dbdiscard(lst); - set.unlock(); + batch = 0; + if (!lastbatch) { + con.closeTransaction(); + CHK(con.startTransaction() == 0); + } } } con.closeTransaction(); @@ -3645,45 +3701,39 @@ hashindexdelete(Par par, const ITab& itab) Set& set = par.set(); LL3("hashindexdelete " << itab.m_name); CHK(con.startTransaction() == 0); - Lst lst; - bool deadlock = false; - bool nospace = false; - for (unsigned j = 0; j < par.m_rows; j++) { - unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows); - unsigned i = thrrow(par, j2); + uint batch = 0; + for (uint j = 0; j < par.m_rows; j++) { + uint j2 = !par.m_randomkey ? j : urandom(par.m_rows); + uint i = thrrow(par, j2); set.lock(); - if (! set.exist(i) || set.pending(i, Row::AnyOp)) { + if (!set.compat(par, i, Row::OpDel)) { + LL3("hashindexdelete SKIP " << i << " " << set.getrow(i)); set.unlock(); - continue; + } else { + set.push(i); + set.copyval(i, itab.m_keymask); + CHK(set.delrow(par, itab, i) == 0); + set.unlock(); + LL4("hashindexdelete " << i << " " << set.getrow(i)); + batch++; } - CHK(set.delrow(par, itab, i) == 0); - set.unlock(); - LL4("hashindexdelete " << i << ": " << *set.m_row[i]); - lst.push(i); - if (lst.cnt() == par.m_batch) { - deadlock = par.m_deadlock; - CHK(con.execute(Commit, deadlock, nospace) == 0); - if (deadlock) { - LL1("hashindexdelete: stop on deadlock [at 1]"); + bool lastbatch = (batch != 0 && j + 1 == par.m_rows); + if (batch == par.m_batch || lastbatch) { + uint err = par.m_catcherr; + ExecType et = !randompct(par.m_abortpct) ? Commit : Rollback; + CHK(con.execute(et, err) == 0); + set.lock(); + set.post(par, !err ? et : Rollback); + set.unlock(); + if (err) { + LL1("hashindexdelete " << i << " stop on " << con.errname(err)); break; } - con.closeTransaction(); - set.lock(); - set.notpending(lst); - set.unlock(); - lst.reset(); - CHK(con.startTransaction() == 0); - } - } - if (! deadlock && lst.cnt() != 0) { - deadlock = par.m_deadlock; - CHK(con.execute(Commit, deadlock, nospace) == 0); - if (deadlock) { - LL1("hashindexdelete: stop on deadlock [at 2]"); - } else { - set.lock(); - set.notpending(lst); - set.unlock(); + batch = 0; + if (!lastbatch) { + con.closeTransaction(); + CHK(con.startTransaction() == 0); + } } } con.closeTransaction(); @@ -3700,9 +3750,11 @@ hashindexread(Par par, const ITab& itab) // expected const Set& set1 = set; Set set2(tab, set.m_rows); - for (unsigned i = 0; i < set.m_rows; i++) { + for (uint i = 0; i < set.m_rows; i++) { set.lock(); - if (! set.exist(i)) { + // TODO lock mode + if (!set.compat(par, i, Row::OpREAD)) { + LL3("hashindexread SKIP " << i << " " << set.getrow(i)); set.unlock(); continue; } @@ -3710,10 +3762,10 @@ hashindexread(Par par, const ITab& itab) CHK(con.startTransaction() == 0); CHK(set2.selrow(par, itab, *set1.m_row[i]) == 0); CHK(con.execute(Commit) == 0); - unsigned i2 = (unsigned)-1; + uint i2 = (uint)-1; CHK(set2.getkey(par, &i2) == 0 && i == i2); CHK(set2.putval(i, false) == 0); - LL4("row " << set2.count() << ": " << *set2.m_row[i]); + LL4("row " << set2.count() << " " << *set2.m_row[i]); con.closeTransaction(); } if (par.m_verify) @@ -3731,40 +3783,39 @@ scanreadtable(Par par) const Set& set = par.set(); // expected const Set& set1 = set; - LL3("scanread " << tab.m_name << " lockmode=" << par.m_lockmode << " tupscan=" << par.m_tupscan << " expect=" << set1.count() << " verify=" << par.m_verify); + LL3("scanreadtable " << tab.m_name << " lockmode=" << par.m_lockmode << " tupscan=" << par.m_tupscan << " expect=" << set1.count() << " verify=" << par.m_verify); Set set2(tab, set.m_rows); CHK(con.startTransaction() == 0); CHK(con.getNdbScanOperation(tab) == 0); CHK(con.readTuples(par) == 0); set2.getval(par); CHK(con.executeScan() == 0); - unsigned n = 0; - bool deadlock = false; + uint n = 0; while (1) { int ret; - deadlock = par.m_deadlock; - CHK((ret = con.nextScanResult(true, deadlock)) == 0 || ret == 1); + uint err = par.m_catcherr; + CHK((ret = con.nextScanResult(true, err)) == 0 || ret == 1); if (ret == 1) break; - if (deadlock) { - LL1("scanreadtable: stop on deadlock"); + if (err) { + LL1("scanreadtable stop on " << con.errname(err)); break; } - unsigned i = (unsigned)-1; + uint i = (uint)-1; CHK(set2.getkey(par, &i) == 0); CHK(set2.putval(i, false, n) == 0); - LL4("row " << n << ": " << *set2.m_row[i]); + LL4("row " << n << " " << *set2.m_row[i]); n++; } con.closeTransaction(); if (par.m_verify) CHK(set1.verify(par, set2, false) == 0); - LL3("scanread " << tab.m_name << " done rows=" << n); + LL3("scanreadtable " << tab.m_name << " done rows=" << n); return 0; } static int -scanreadtablefast(Par par, unsigned countcheck) +scanreadtablefast(Par par, uint countcheck) { Con& con = par.con(); const Tab& tab = par.tab(); @@ -3777,7 +3828,7 @@ scanreadtablefast(Par par, unsigned countcheck) NdbRecAttr* rec; CHK(con.getValue((Uint32)0, rec) == 0); CHK(con.executeScan() == 0); - unsigned count = 0; + uint count = 0; while (1) { int ret; CHK((ret = con.nextScanResult(true)) == 0 || ret == 1); @@ -3797,7 +3848,7 @@ calcscanbounds(Par par, const ITab& itab, BSet& bset, const Set& set, Set& set1) while (true) { bset.calc(par); bset.filter(par, set, set1); - unsigned n = set1.count(); + uint n = set1.count(); // prefer proper subset if (0 < n && n < set.m_rows) break; @@ -3819,7 +3870,7 @@ scanreadindex(Par par, const ITab& itab, BSet& bset, bool calc) } else { bset.filter(par, set, set1); } - LL3("scanread " << itab.m_name << " " << bset << " lockmode=" << par.m_lockmode << " expect=" << set1.count() << " ordered=" << par.m_ordered << " descending=" << par.m_descending << " verify=" << par.m_verify); + LL3("scanreadindex " << itab.m_name << " " << bset << " lockmode=" << par.m_lockmode << " expect=" << set1.count() << " ordered=" << par.m_ordered << " descending=" << par.m_descending << " verify=" << par.m_verify); Set set2(tab, set.m_rows); CHK(con.startTransaction() == 0); CHK(con.getNdbIndexScanOperation(itab, tab) == 0); @@ -3827,22 +3878,21 @@ scanreadindex(Par par, const ITab& itab, BSet& bset, bool calc) CHK(bset.setbnd(par) == 0); set2.getval(par); CHK(con.executeScan() == 0); - unsigned n = 0; - bool deadlock = false; + uint n = 0; while (1) { int ret; - deadlock = par.m_deadlock; - CHK((ret = con.nextScanResult(true, deadlock)) == 0 || ret == 1); + uint err = par.m_catcherr; + CHK((ret = con.nextScanResult(true, err)) == 0 || ret == 1); if (ret == 1) break; - if (deadlock) { - LL1("scanreadindex: stop on deadlock"); + if (err) { + LL1("scanreadindex stop on " << con.errname(err)); break; } - unsigned i = (unsigned)-1; + uint i = (uint)-1; CHK(set2.getkey(par, &i) == 0); CHK(set2.putval(i, par.m_dups, n) == 0); - LL4("key " << i << " row " << n << ": " << *set2.m_row[i]); + LL4("key " << i << " row " << n << " " << *set2.m_row[i]); n++; } con.closeTransaction(); @@ -3851,12 +3901,12 @@ scanreadindex(Par par, const ITab& itab, BSet& bset, bool calc) if (par.m_ordered) CHK(set2.verifyorder(par, itab, par.m_descending) == 0); } - LL3("scanread " << itab.m_name << " done rows=" << n); + LL3("scanreadindex " << itab.m_name << " done rows=" << n); return 0; } static int -scanreadindexfast(Par par, const ITab& itab, const BSet& bset, unsigned countcheck) +scanreadindexfast(Par par, const ITab& itab, const BSet& bset, uint countcheck) { Con& con = par.con(); const Tab& tab = par.tab(); @@ -3871,7 +3921,7 @@ scanreadindexfast(Par par, const ITab& itab, const BSet& bset, unsigned countche NdbRecAttr* rec; CHK(con.getValue((Uint32)0, rec) == 0); CHK(con.executeScan() == 0); - unsigned count = 0; + uint count = 0; while (1) { int ret; CHK((ret = con.nextScanResult(true)) == 0 || ret == 1); @@ -3904,22 +3954,21 @@ scanreadfilter(Par par, const ITab& itab, BSet& bset, bool calc) CHK(bset.setflt(par) == 0); set2.getval(par); CHK(con.executeScan() == 0); - unsigned n = 0; - bool deadlock = false; + uint n = 0; while (1) { int ret; - deadlock = par.m_deadlock; - CHK((ret = con.nextScanResult(true, deadlock)) == 0 || ret == 1); + uint err = par.m_catcherr; + CHK((ret = con.nextScanResult(true, err)) == 0 || ret == 1); if (ret == 1) break; - if (deadlock) { - LL1("scanfilter: stop on deadlock"); + if (err) { + LL1("scanfilter stop on " << con.errname(err)); break; } - unsigned i = (unsigned)-1; + uint i = (uint)-1; CHK(set2.getkey(par, &i) == 0); CHK(set2.putval(i, par.m_dups, n) == 0); - LL4("key " << i << " row " << n << ": " << *set2.m_row[i]); + LL4("key " << i << " row " << n << " " << *set2.m_row[i]); n++; } con.closeTransaction(); @@ -3934,9 +3983,9 @@ static int scanreadindex(Par par, const ITab& itab) { const Tab& tab = par.tab(); - for (unsigned i = 0; i < par.m_subloop; i++) { + for (uint i = 0; i < par.m_ssloop; i++) { if (itab.m_type == ITab::OrderedIndex) { - BSet bset(tab, itab, par.m_rows); + BSet bset(tab, itab); CHK(scanreadfilter(par, itab, bset, true) == 0); CHK(scanreadindex(par, itab, bset, true) == 0); } @@ -3948,7 +3997,7 @@ static int scanreadindex(Par par) { const Tab& tab = par.tab(); - for (unsigned i = 0; i < tab.m_itabs; i++) { + for (uint i = 0; i < tab.m_itabs; i++) { if (tab.m_itab[i] == 0) continue; const ITab& itab = *tab.m_itab[i]; @@ -3985,7 +4034,7 @@ timescanpkindex(Par par) { const Tab& tab = par.tab(); const ITab& itab = *tab.m_itab[0]; // 1st index is on PK - BSet bset(tab, itab, par.m_rows); + BSet bset(tab, itab); par.tmr().on(); CHK(scanreadindexfast(par, itab, bset, par.m_totrows) == 0); par.tmr().off(par.set().m_rows); @@ -3996,7 +4045,7 @@ static int timepkreadtable(Par par) { par.tmr().on(); - unsigned count = par.m_samples; + uint count = par.m_samples; if (count == 0) count = par.m_totrows; CHK(pkreadfast(par, count) == 0); @@ -4009,13 +4058,13 @@ timepkreadindex(Par par) { const Tab& tab = par.tab(); const ITab& itab = *tab.m_itab[0]; // 1st index is on PK - BSet bset(tab, itab, par.m_rows); - unsigned count = par.m_samples; + BSet bset(tab, itab); + uint count = par.m_samples; if (count == 0) count = par.m_totrows; par.tmr().on(); - for (unsigned j = 0; j < count; j++) { - unsigned i = urandom(par.m_totrows); + for (uint j = 0; j < count; j++) { + uint i = urandom(par.m_totrows); bset.calcpk(par, i); CHK(scanreadindexfast(par, itab, bset, 1) == 0); } @@ -4031,7 +4080,7 @@ scanupdatetable(Par par) Con& con = par.con(); const Tab& tab = par.tab(); Set& set = par.set(); - LL3("scan update " << tab.m_name); + LL3("scanupdatetable " << tab.m_name); Set set2(tab, set.m_rows); par.m_lockmode = NdbOperation::LM_Exclusive; CHK(con.startTransaction() == 0); @@ -4039,87 +4088,70 @@ scanupdatetable(Par par) CHK(con.readTuples(par) == 0); set2.getval(par); CHK(con.executeScan() == 0); - unsigned count = 0; + uint count = 0; // updating trans Con con2; con2.connect(con); CHK(con2.startTransaction() == 0); - Lst lst; - bool deadlock = false; - bool nospace = false; + uint batch = 0; while (1) { int ret; - deadlock = par.m_deadlock; - CHK((ret = con.nextScanResult(true, deadlock)) == 0 || ret == 1); - if (ret == 1) + uint32 err = par.m_catcherr; + CHK((ret = con.nextScanResult(true, err)) != -1); + if (ret != 0) break; - if (deadlock) { - LL1("scanupdatetable: stop on deadlock [at 1]"); + if (err) { + LL1("scanupdatetable [scan] stop on " << con.errname(err)); break; } if (par.m_scanstop != 0 && urandom(par.m_scanstop) == 0) { con.closeScan(); break; } - do { - unsigned i = (unsigned)-1; + while (1) { + uint i = (uint)-1; CHK(set2.getkey(par, &i) == 0); - const Row& row = *set.m_row[i]; set.lock(); - if (! set.exist(i) || set.pending(i, Row::AnyOp)) { - LL4("scan update " << tab.m_name << ": skip: " << row); + if (!set.compat(par, i, Row::OpUpd)) { + LL3("scanupdatetable SKIP " << i << " " << set.getrow(i)); } else { CHKTRY(set2.putval(i, false) == 0, set.unlock()); CHKTRY(con.updateScanTuple(con2) == 0, set.unlock()); Par par2 = par; par2.m_con = &con2; - set.dbsave(i); - set.calc(par, i); + set.push(i); + set.calc(par, i, ~tab.m_pkmask); CHKTRY(set.setrow(par2, i) == 0, set.unlock()); - LL4("scan update " << tab.m_name << ": " << row); - lst.push(i); + LL4("scanupdatetable " << i << " " << set.getrow(i)); + batch++; } set.unlock(); - if (lst.cnt() == par.m_batch) { - deadlock = par.m_deadlock; - CHK(con2.execute(Commit, deadlock, nospace) == 0); - if (deadlock) { - LL1("scanupdatetable: stop on deadlock [at 2]"); + CHK((ret = con.nextScanResult(false)) != -1); + bool lastbatch = (batch != 0 && ret != 0); + if (batch == par.m_batch || lastbatch) { + uint err = par.m_catcherr; + ExecType et = Commit; + CHK(con2.execute(et, err) == 0); + set.lock(); + set.post(par, !err ? et : Rollback); + set.unlock(); + if (err) { + LL1("scanupdatetable [update] stop on " << con2.errname(err)); goto out; } + LL4("scanupdatetable committed batch"); + count += batch; + batch = 0; con2.closeTransaction(); - set.lock(); - set.notpending(lst); - set.dbdiscard(lst); - set.unlock(); - count += lst.cnt(); - lst.reset(); CHK(con2.startTransaction() == 0); } - CHK((ret = con.nextScanResult(false)) == 0 || ret == 1 || ret == 2); - if (ret == 2 && lst.cnt() != 0) { - deadlock = par.m_deadlock; - CHK(con2.execute(Commit, deadlock, nospace) == 0); - if (deadlock) { - LL1("scanupdatetable: stop on deadlock [at 3]"); - goto out; - } - con2.closeTransaction(); - set.lock(); - set.notpending(lst); - set.dbdiscard(lst); - set.unlock(); - count += lst.cnt(); - lst.reset(); - CHK(con2.startTransaction() == 0); - } - } while (ret == 0); - if (ret == 1) - break; + if (ret != 0) + break; + } } out: con2.closeTransaction(); - LL3("scan update " << tab.m_name << " rows updated=" << count); + LL3("scanupdatetable " << tab.m_name << " rows updated=" << count); con.closeTransaction(); return 0; } @@ -4137,7 +4169,7 @@ scanupdateindex(Par par, const ITab& itab, BSet& bset, bool calc) } else { bset.filter(par, set, set1); } - LL3("scan update " << itab.m_name << " " << bset << " expect=" << set1.count() << " ordered=" << par.m_ordered << " descending=" << par.m_descending << " verify=" << par.m_verify); + LL3("scanupdateindex " << itab.m_name << " " << bset << " expect=" << set1.count() << " ordered=" << par.m_ordered << " descending=" << par.m_descending << " verify=" << par.m_verify); Set set2(tab, set.m_rows); par.m_lockmode = NdbOperation::LM_Exclusive; CHK(con.startTransaction() == 0); @@ -4146,83 +4178,67 @@ scanupdateindex(Par par, const ITab& itab, BSet& bset, bool calc) CHK(bset.setbnd(par) == 0); set2.getval(par); CHK(con.executeScan() == 0); - unsigned count = 0; + uint count = 0; // updating trans Con con2; con2.connect(con); CHK(con2.startTransaction() == 0); - Lst lst; - bool deadlock = false; - bool nospace = false; + uint batch = 0; while (1) { int ret; - deadlock = par.m_deadlock; - CHK((ret = con.nextScanResult(true, deadlock)) == 0 || ret == 1); - if (ret == 1) + uint err = par.m_catcherr; + CHK((ret = con.nextScanResult(true, err)) != -1); + if (ret != 0) break; - if (deadlock) { - LL1("scanupdateindex: stop on deadlock [at 1]"); + if (err) { + LL1("scanupdateindex [scan] stop on " << con.errname(err)); break; } if (par.m_scanstop != 0 && urandom(par.m_scanstop) == 0) { con.closeScan(); break; } - do { - unsigned i = (unsigned)-1; + while (1) { + uint i = (uint)-1; CHK(set2.getkey(par, &i) == 0); - const Row& row = *set.m_row[i]; set.lock(); - if (! set.exist(i) || set.pending(i, Row::AnyOp)) { - LL4("scan update " << itab.m_name << ": skip: " << row); + if (!set.compat(par, i, Row::OpUpd)) { + LL4("scanupdateindex SKIP " << set.getrow(i)); } else { CHKTRY(set2.putval(i, par.m_dups) == 0, set.unlock()); CHKTRY(con.updateScanTuple(con2) == 0, set.unlock()); Par par2 = par; par2.m_con = &con2; - set.dbsave(i); - set.calc(par, i, ! par.m_noindexkeyupdate ? 0 : itab.m_colmask); + set.push(i); + uint colmask = !par.m_noindexkeyupdate ? ~0 : ~itab.m_keymask; + set.calc(par, i, colmask); CHKTRY(set.setrow(par2, i) == 0, set.unlock()); - LL4("scan update " << itab.m_name << ": " << row); - lst.push(i); + LL4("scanupdateindex " << i << " " << set.getrow(i)); + batch++; } set.unlock(); - if (lst.cnt() == par.m_batch) { - deadlock = par.m_deadlock; - CHK(con2.execute(Commit, deadlock, nospace) == 0); - if (deadlock) { - LL1("scanupdateindex: stop on deadlock [at 2]"); + CHK((ret = con.nextScanResult(false)) != -1); + bool lastbatch = (batch != 0 && ret != 0); + if (batch == par.m_batch || lastbatch) { + uint err = par.m_catcherr; + ExecType et = Commit; + CHK(con2.execute(et, err) == 0); + set.lock(); + set.post(par, !err ? et : Rollback); + set.unlock(); + if (err) { + LL1("scanupdateindex [update] stop on " << con2.errname(err)); goto out; } + LL4("scanupdateindex committed batch"); + count += batch; + batch = 0; con2.closeTransaction(); - LL4("scanupdateindex: committed batch [at 1]"); - set.lock(); - set.notpending(lst); - set.dbdiscard(lst); - set.unlock(); - count += lst.cnt(); - lst.reset(); CHK(con2.startTransaction() == 0); } - CHK((ret = con.nextScanResult(false)) == 0 || ret == 1 || ret == 2); - if (ret == 2 && lst.cnt() != 0) { - deadlock = par.m_deadlock; - CHK(con2.execute(Commit, deadlock, nospace) == 0); - if (deadlock) { - LL1("scanupdateindex: stop on deadlock [at 3]"); - goto out; - } - con2.closeTransaction(); - LL4("scanupdateindex: committed batch [at 2]"); - set.lock(); - set.notpending(lst); - set.dbdiscard(lst); - set.unlock(); - count += lst.cnt(); - lst.reset(); - CHK(con2.startTransaction() == 0); - } - } while (ret == 0); + if (ret != 0) + break; + } } out: con2.closeTransaction(); @@ -4231,7 +4247,7 @@ out: if (par.m_ordered) CHK(set2.verifyorder(par, itab, par.m_descending) == 0); } - LL3("scan update " << itab.m_name << " rows updated=" << count); + LL3("scanupdateindex " << itab.m_name << " rows updated=" << count); con.closeTransaction(); return 0; } @@ -4240,9 +4256,9 @@ static int scanupdateindex(Par par, const ITab& itab) { const Tab& tab = par.tab(); - for (unsigned i = 0; i < par.m_subloop; i++) { + for (uint i = 0; i < par.m_ssloop; i++) { if (itab.m_type == ITab::OrderedIndex) { - BSet bset(tab, itab, par.m_rows); + BSet bset(tab, itab); CHK(scanupdateindex(par, itab, bset, true) == 0); } else { CHK(hashindexupdate(par, itab) == 0); @@ -4255,7 +4271,7 @@ static int scanupdateindex(Par par) { const Tab& tab = par.tab(); - for (unsigned i = 0; i < tab.m_itabs; i++) { + for (uint i = 0; i < tab.m_itabs; i++) { if (tab.m_itab[i] == 0) continue; const ITab& itab = *tab.m_itab[i]; @@ -4294,14 +4310,14 @@ readverifyfull(Par par) CHK(scanreadtable(par) == 0); } // each thread scans different indexes - for (unsigned i = 0; i < tab.m_itabs; i++) { - if (i % par.m_threads != par.m_no) + for (uint i = 0; i < tab.m_itabs; i++) { + if (i % par.m_usedthreads != par.m_no) continue; if (tab.m_itab[i] == 0) continue; const ITab& itab = *tab.m_itab[i]; if (itab.m_type == ITab::OrderedIndex) { - BSet bset(tab, itab, par.m_rows); + BSet bset(tab, itab); CHK(scanreadindex(par, itab, bset, false) == 0); } else { CHK(hashindexread(par, itab) == 0); @@ -4317,7 +4333,7 @@ readverifyindex(Par par) return 0; par.m_verify = true; par.m_lockmode = NdbOperation::LM_CommittedRead; - unsigned sel = urandom(10); + uint sel = urandom(10); if (sel < 9) { par.m_ordered = true; par.m_descending = (sel < 5); @@ -4331,8 +4347,8 @@ pkops(Par par) { const Tab& tab = par.tab(); par.m_randomkey = true; - for (unsigned i = 0; i < par.m_subloop; i++) { - unsigned j = 0; + for (uint i = 0; i < par.m_ssloop; i++) { + uint j = 0; while (j < tab.m_itabs) { if (tab.m_itab[j] != 0) { const ITab& itab = *tab.m_itab[j]; @@ -4341,7 +4357,7 @@ pkops(Par par) } j++; } - unsigned sel = urandom(10); + uint sel = urandom(10); if (par.m_slno % 2 == 0) { // favor insert if (sel < 8) { @@ -4389,8 +4405,8 @@ static int pkupdatescanread(Par par) { par.m_dups = true; - par.m_deadlock = true; - unsigned sel = urandom(10); + par.m_catcherr |= Con::ErrDeadlock; + uint sel = urandom(10); if (sel < 5) { CHK(pkupdate(par) == 0); } else if (sel < 6) { @@ -4411,9 +4427,9 @@ static int mixedoperations(Par par) { par.m_dups = true; - par.m_deadlock = true; + par.m_catcherr |= Con::ErrDeadlock; par.m_scanstop = par.m_totrows; // randomly close scans - unsigned sel = urandom(10); + uint sel = urandom(10); if (sel < 2) { CHK(pkdelete(par) == 0); } else if (sel < 4) { @@ -4434,8 +4450,8 @@ static int parallelorderedupdate(Par par) { const Tab& tab = par.tab(); - unsigned k = 0; - for (unsigned i = 0; i < tab.m_itabs; i++) { + uint k = 0; + for (uint i = 0; i < tab.m_itabs; i++) { if (tab.m_itab[i] == 0) continue; const ITab& itab = *tab.m_itab[i]; @@ -4447,10 +4463,11 @@ parallelorderedupdate(Par par) par.m_noindexkeyupdate = true; par.m_ordered = true; par.m_descending = (par.m_slno != 0); + par.m_dups = false; par.m_verify = true; - BSet bset(tab, itab, par.m_rows); // empty bounds + BSet bset(tab, itab); // empty bounds // prefer empty bounds - unsigned sel = urandom(10); + uint sel = urandom(10); CHK(scanupdateindex(par, itab, bset, sel < 2) == 0); } } @@ -4469,6 +4486,418 @@ pkupdateindexbuild(Par par) return 0; } +// savepoint tests (single thread for now) + +struct Spt { + enum Res { Committed, Latest, Deadlock }; + bool m_same; // same transaction + NdbOperation::LockMode m_lm; + Res m_res; +}; + +static Spt sptlist[] = { + { 1, NdbOperation::LM_Read, Spt::Latest }, + { 1, NdbOperation::LM_Exclusive, Spt::Latest }, + { 1, NdbOperation::LM_CommittedRead, Spt::Latest }, + { 0, NdbOperation::LM_Read, Spt::Deadlock }, + { 0, NdbOperation::LM_Exclusive, Spt::Deadlock }, + { 0, NdbOperation::LM_CommittedRead, Spt::Committed } +}; +static uint sptcount = sizeof(sptlist)/sizeof(sptlist[0]); + +static int +savepointreadpk(Par par, Spt spt) +{ + LL3("savepointreadpk"); + Con& con = par.con(); + const Tab& tab = par.tab(); + Set& set = par.set(); + const Set& set1 = set; + Set set2(tab, set.m_rows); + uint n = 0; + for (uint i = 0; i < set.m_rows; i++) { + set.lock(); + if (!set.compat(par, i, Row::OpREAD)) { + LL4("savepointreadpk SKIP " << i << " " << set.getrow(i)); + set.unlock(); + continue; + } + set.unlock(); + CHK(set2.selrow(par, *set1.m_row[i]) == 0); + uint err = par.m_catcherr | Con::ErrDeadlock; + ExecType et = NoCommit; + CHK(con.execute(et, err) == 0); + if (err) { + if (err & Con::ErrDeadlock) { + CHK(spt.m_res == Spt::Deadlock); + // all rows have same behaviour + CHK(n == 0); + } + LL1("savepointreadpk stop on " << con.errname(err)); + break; + } + uint i2 = (uint)-1; + CHK(set2.getkey(par, &i2) == 0 && i == i2); + CHK(set2.putval(i, false) == 0); + LL4("row " << set2.count() << " " << set2.getrow(i)); + n++; + } + bool dirty = (!spt.m_same && spt.m_lm == NdbOperation::LM_CommittedRead); + if (spt.m_res != Spt::Deadlock) + CHK(set1.verify(par, set2, false, dirty) == 0); + return 0; +} + +static int +savepointreadhashindex(Par par, Spt spt) +{ + if (spt.m_lm == NdbOperation::LM_CommittedRead && !spt.m_same) { + LL1("skip hash index dirty read"); + return 0; + } + LL3("savepointreadhashindex"); + Con& con = par.con(); + const Tab& tab = par.tab(); + const ITab& itab = par.itab(); + Set& set = par.set(); + const Set& set1 = set; + Set set2(tab, set.m_rows); + uint n = 0; + for (uint i = 0; i < set.m_rows; i++) { + set.lock(); + if (!set.compat(par, i, Row::OpREAD)) { + LL3("savepointreadhashindex SKIP " << i << " " << set.getrow(i)); + set.unlock(); + continue; + } + set.unlock(); + CHK(set2.selrow(par, itab, *set1.m_row[i]) == 0); + uint err = par.m_catcherr | Con::ErrDeadlock; + ExecType et = NoCommit; + CHK(con.execute(et, err) == 0); + if (err) { + if (err & Con::ErrDeadlock) { + CHK(spt.m_res == Spt::Deadlock); + // all rows have same behaviour + CHK(n == 0); + } + LL1("savepointreadhashindex stop on " << con.errname(err)); + break; + } + uint i2 = (uint)-1; + CHK(set2.getkey(par, &i2) == 0 && i == i2); + CHK(set2.putval(i, false) == 0); + LL4("row " << set2.count() << " " << *set2.m_row[i]); + n++; + } + bool dirty = (!spt.m_same && spt.m_lm == NdbOperation::LM_CommittedRead); + if (spt.m_res != Spt::Deadlock) + CHK(set1.verify(par, set2, false, dirty) == 0); + return 0; +} + +static int +savepointscantable(Par par, Spt spt) +{ + LL3("savepointscantable"); + Con& con = par.con(); + const Tab& tab = par.tab(); + const Set& set = par.set(); + const Set& set1 = set; // not modifying current set + Set set2(tab, set.m_rows); // scan result + CHK(con.getNdbScanOperation(tab) == 0); + CHK(con.readTuples(par) == 0); + set2.getval(par); // getValue all columns + CHK(con.executeScan() == 0); + bool deadlock = false; + uint n = 0; + while (1) { + int ret; + uint err = par.m_catcherr | Con::ErrDeadlock; + CHK((ret = con.nextScanResult(true, err)) == 0 || ret == 1); + if (ret == 1) + break; + if (err) { + if (err & Con::ErrDeadlock) { + CHK(spt.m_res == Spt::Deadlock); + // all rows have same behaviour + CHK(n == 0); + deadlock = true; + } + LL1("savepointscantable stop on " << con.errname(err)); + break; + } + CHK(spt.m_res != Spt::Deadlock); + uint i = (uint)-1; + CHK(set2.getkey(par, &i) == 0); + CHK(set2.putval(i, false, n) == 0); + LL4("row " << n << " key " << i << " " << set2.getrow(i)); + n++; + } + if (set1.m_rows > 0) { + if (!deadlock) + CHK(spt.m_res != Spt::Deadlock); + else + CHK(spt.m_res == Spt::Deadlock); + } + LL2("savepointscantable " << n << " rows"); + bool dirty = (!spt.m_same && spt.m_lm == NdbOperation::LM_CommittedRead); + if (spt.m_res != Spt::Deadlock) + CHK(set1.verify(par, set2, false, dirty) == 0); + return 0; +} + +static int +savepointscanindex(Par par, Spt spt) +{ + LL3("savepointscanindex"); + Con& con = par.con(); + const Tab& tab = par.tab(); + const ITab& itab = par.itab(); + const Set& set = par.set(); + const Set& set1 = set; + Set set2(tab, set.m_rows); + CHK(con.getNdbIndexScanOperation(itab, tab) == 0); + CHK(con.readIndexTuples(par) == 0); + set2.getval(par); + CHK(con.executeScan() == 0); + bool deadlock = false; + uint n = 0; + while (1) { + int ret; + uint err = par.m_catcherr | Con::ErrDeadlock; + CHK((ret = con.nextScanResult(true, err)) == 0 || ret == 1); + if (ret == 1) + break; + if (err) { + if (err & Con::ErrDeadlock) { + CHK(spt.m_res == Spt::Deadlock); + // all rows have same behaviour + CHK(n == 0); + deadlock = true; + } + LL1("savepointscanindex stop on " << con.errname(err)); + break; + } + CHK(spt.m_res != Spt::Deadlock); + uint i = (uint)-1; + CHK(set2.getkey(par, &i) == 0); + CHK(set2.putval(i, par.m_dups, n) == 0); + LL4("row " << n << " key " << i << " " << set2.getrow(i)); + n++; + } + if (set1.m_rows > 0) { + if (!deadlock) + CHK(spt.m_res != Spt::Deadlock); + else + CHK(spt.m_res == Spt::Deadlock); + } + LL2("savepointscanindex " << n << " rows"); + bool dirty = (!spt.m_same && spt.m_lm == NdbOperation::LM_CommittedRead); + if (spt.m_res != Spt::Deadlock) + CHK(set1.verify(par, set2, false, dirty) == 0); + return 0; +} + +typedef int (*SptFun)(Par, Spt); + +static int +savepointtest(Par par, Spt spt, SptFun fun) +{ + Con& con = par.con(); + Par par2 = par; + Con con2; + if (!spt.m_same) { + con2.connect(con); // copy ndb reference + par2.m_con = &con2; + CHK(con2.startTransaction() == 0); + } + par2.m_lockmode = spt.m_lm; + CHK((*fun)(par2, spt) == 0); + if (!spt.m_same) { + con2.closeTransaction(); + } + return 0; +} + +static int +savepointtest(Par par, const char* op) +{ + Con& con = par.con(); + const Tab& tab = par.tab(); + Set& set = par.set(); + LL2("savepointtest op=\"" << op << "\""); + CHK(con.startTransaction() == 0); + const char* p = op; + char c; + while ((c = *p++) != 0) { + uint j; + for (j = 0; j < par.m_rows; j++) { + uint i = thrrow(par, j); + if (c == 'c') { + ExecType et = Commit; + CHK(con.execute(et) == 0); + set.lock(); + set.post(par, et); + set.unlock(); + CHK(con.startTransaction() == 0); + } else { + set.lock(); + set.push(i); + if (c == 'i') { + set.calc(par, i); + CHK(set.insrow(par, i) == 0); + } else if (c == 'u') { + set.copyval(i, tab.m_pkmask); + set.calc(par, i, ~tab.m_pkmask); + CHK(set.updrow(par, i) == 0); + } else if (c == 'd') { + set.copyval(i, tab.m_pkmask); + CHK(set.delrow(par, i) == 0); + } else { + assert(false); + } + set.unlock(); + } + } + } + { + ExecType et = NoCommit; + CHK(con.execute(et) == 0); + set.lock(); + set.post(par, et); + set.unlock(); + } + for (uint k = 0; k < sptcount; k++) { + Spt spt = sptlist[k]; + LL2("spt lm=" << spt.m_lm << " same=" << spt.m_same); + CHK(savepointtest(par, spt, &savepointreadpk) == 0); + CHK(savepointtest(par, spt, &savepointscantable) == 0); + for (uint i = 0; i < tab.m_itabs; i++) { + if (tab.m_itab[i] == 0) + continue; + const ITab& itab = *tab.m_itab[i]; + par.m_itab = &itab; + if (itab.m_type == ITab::OrderedIndex) + CHK(savepointtest(par, spt, &savepointscanindex) == 0); + else + CHK(savepointtest(par, spt, &savepointreadhashindex) == 0); + par.m_itab = 0; + } + } + { + ExecType et = Rollback; + CHK(con.execute(et) == 0); + set.lock(); + set.post(par, et); + set.unlock(); + } + con.closeTransaction(); + return 0; +} + +static int +savepointtest(Par par) +{ + assert(par.m_usedthreads == 1); + const char* oplist[] = { + // each based on previous and "c" not last + "i", + "icu", + "uuuuu", + "d", + "dciuuuuud", + 0 + }; + int i; + for (i = 0; oplist[i] != 0; i++) { + CHK(savepointtest(par, oplist[i]) == 0); + } + return 0; +} + +static int +halloweentest(Par par, const ITab& itab) +{ + LL2("halloweentest " << itab.m_name); + Con& con = par.con(); + const Tab& tab = par.tab(); + Set& set = par.set(); + CHK(con.startTransaction() == 0); + // insert 1 row + uint i = 0; + set.push(i); + set.calc(par, i); + CHK(set.insrow(par, i) == 0); + CHK(con.execute(NoCommit) == 0); + // scan via index until Set m_rows reached + uint scancount = 0; + bool stop = false; + while (!stop) { + par.m_lockmode = // makes no difference + scancount % 2 == 0 ? NdbOperation::LM_CommittedRead : + NdbOperation::LM_Read; + Set set1(tab, set.m_rows); // expected scan result + Set set2(tab, set.m_rows); // actual scan result + BSet bset(tab, itab); + calcscanbounds(par, itab, bset, set, set1); + CHK(con.getNdbIndexScanOperation(itab, tab) == 0); + CHK(con.readIndexTuples(par) == 0); + CHK(bset.setbnd(par) == 0); + set2.getval(par); + CHK(con.executeScan() == 0); + const uint savepoint = i; + LL3("scancount=" << scancount << " savepoint=" << savepoint); + uint n = 0; + while (1) { + int ret; + CHK((ret = con.nextScanResult(true)) == 0 || ret == 1); + if (ret == 1) + break; + uint k = (uint)-1; + CHK(set2.getkey(par, &k) == 0); + CHK(set2.putval(k, false, n) == 0); + LL3("row=" << n << " key=" << k); + CHK(k <= savepoint); + if (++i == set.m_rows) { + stop = true; + break; + } + set.push(i); + set.calc(par, i); + CHK(set.insrow(par, i) == 0); + CHK(con.execute(NoCommit) == 0); + n++; + } + con.closeScan(); + LL3("scanrows=" << n); + if (!stop) { + CHK(set1.verify(par, set2, false) == 0); + } + scancount++; + } + CHK(con.execute(Commit) == 0); + set.post(par, Commit); + assert(set.count() == set.m_rows); + CHK(pkdelete(par) == 0); + return 0; +} + +static int +halloweentest(Par par) +{ + assert(par.m_usedthreads == 1); + const Tab& tab = par.tab(); + for (uint i = 0; i < tab.m_itabs; i++) { + if (tab.m_itab[i] == 0) + continue; + const ITab& itab = *tab.m_itab[i]; + if (itab.m_type == ITab::OrderedIndex) + CHK(halloweentest(par, itab) == 0); + } + return 0; +} + // threads typedef int (*TFunc)(Par par); @@ -4477,22 +4906,22 @@ enum TMode { ST = 1, MT = 2 }; extern "C" { static void* runthread(void* arg); } struct Thr { - enum State { Wait, Start, Stop, Stopped, Exit }; + enum State { Wait, Start, Stop, Exit }; State m_state; Par m_par; - Uint64 m_id; + pthread_t m_id; NdbThread* m_thread; NdbMutex* m_mutex; NdbCondition* m_cond; TFunc m_func; int m_ret; void* m_status; - Thr(Par par, unsigned n); + char m_tmp[20]; // used for debug msg prefix + Thr(Par par, uint n); ~Thr(); int run(); void start(); void stop(); - void stopped(); void exit(); // void lock() { @@ -4513,10 +4942,9 @@ struct Thr { } }; -Thr::Thr(Par par, unsigned n) : +Thr::Thr(Par par, uint n) : m_state(Wait), m_par(par), - m_id(0), m_thread(0), m_mutex(0), m_cond(0), @@ -4533,7 +4961,7 @@ Thr::Thr(Par par, unsigned n) : m_cond = NdbCondition_Create(); assert(m_mutex != 0 && m_cond != 0); // run - const unsigned stacksize = 256 * 1024; + const uint stacksize = 256 * 1024; const NDB_THREAD_PRIO prio = NDB_THREAD_PRIO_LOW; m_thread = NdbThread_Create(runthread, (void**)this, stacksize, name, prio); } @@ -4558,7 +4986,7 @@ static void* runthread(void* arg) { Thr& thr = *(Thr*)arg; - thr.m_id = (Uint64)pthread_self(); + thr.m_id = pthread_self(); if (thr.run() < 0) { LL1("exit on error"); } else { @@ -4589,11 +5017,16 @@ Thr::run() LL4("start"); assert(m_state == Start); m_ret = (*m_func)(m_par); - m_state = Stopped; + m_state = Stop; LL4("stop"); signal(); unlock(); - CHK(m_ret == 0); + if (m_ret == -1) { + if (m_par.m_cont) + LL1("continue running due to -cont"); + else + return -1; + } } con.disconnect(); return 0; @@ -4612,16 +5045,7 @@ void Thr::stop() { lock(); - m_state = Stop; - signal(); - unlock(); -} - -void -Thr::stopped() -{ - lock(); - while (m_state != Stopped) + while (m_state != Stop) wait(); m_state = Wait; unlock(); @@ -4640,27 +5064,44 @@ Thr::exit() static Thr** g_thrlist = 0; -static unsigned -getthrno() +static Thr* +getthr() { if (g_thrlist != 0) { - Uint64 id = (Uint64)pthread_self(); - for (unsigned n = 0; n < g_opt.m_threads; n++) { + pthread_t id = pthread_self(); + for (uint n = 0; n < g_opt.m_threads; n++) { if (g_thrlist[n] != 0) { - const Thr& thr = *g_thrlist[n]; - if (thr.m_id == id) - return thr.m_par.m_no; + Thr& thr = *g_thrlist[n]; + if (pthread_equal(thr.m_id, id)) + return &thr; } } } - return (unsigned)-1; + return 0; +} + +// for debug messages (par.m_no not available) +static const char* +getthrprefix() +{ + Thr* thrp = getthr(); + if (thrp != 0) { + Thr& thr = *thrp; + uint n = thr.m_par.m_no; + uint m = + g_opt.m_threads < 10 ? 1 : + g_opt.m_threads < 100 ? 2 : 3; + sprintf(thr.m_tmp, "[%0*u] ", m, n); + return thr.m_tmp; + } + return ""; } static int -runstep(Par par, const char* fname, TFunc func, unsigned mode) +runstep(Par par, const char* fname, TFunc func, uint mode) { LL2("step: " << fname); - const int threads = (mode & ST ? 1 : par.m_threads); + const int threads = (mode & ST ? 1 : par.m_usedthreads); int n; for (n = 0; n < threads; n++) { LL4("start " << n); @@ -4673,11 +5114,11 @@ runstep(Par par, const char* fname, TFunc func, unsigned mode) thr.m_func = func; thr.start(); } - unsigned errs = 0; + uint errs = 0; for (n = threads - 1; n >= 0; n--) { LL4("stop " << n); Thr& thr = *g_thrlist[n]; - thr.stopped(); + thr.stop(); if (thr.m_ret != 0) errs++; } @@ -4689,7 +5130,7 @@ runstep(Par par, const char* fname, TFunc func, unsigned mode) CHK(runstep(par, #func, func, mode) == 0) #define SUBLOOP(par) \ - "subloop: " << par.m_lno << "/" << par.m_currcase << "/" << \ + "sloop: " << par.m_lno << "/" << par.m_currcase << "/" << \ par.m_tab->m_name << "/" << par.m_slno static int @@ -4698,7 +5139,7 @@ tbuild(Par par) RUNSTEP(par, droptable, ST); RUNSTEP(par, createtable, ST); RUNSTEP(par, invalidatetable, MT); - for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { + for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) { LL1(SUBLOOP(par)); if (par.m_slno % 3 == 0) { RUNSTEP(par, createindex, ST); @@ -4718,7 +5159,7 @@ tbuild(Par par) } RUNSTEP(par, readverifyfull, MT); // leave last one - if (par.m_slno + 1 < par.m_subloop) { + if (par.m_slno + 1 < par.m_sloop) { RUNSTEP(par, pkdelete, MT); RUNSTEP(par, readverifyfull, MT); RUNSTEP(par, dropindex, ST); @@ -4737,7 +5178,7 @@ tindexscan(Par par) RUNSTEP(par, invalidateindex, MT); RUNSTEP(par, pkinsert, MT); RUNSTEP(par, readverifyfull, MT); - for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { + for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) { LL1(SUBLOOP(par)); RUNSTEP(par, readverifyindex, MT); } @@ -4753,7 +5194,7 @@ tpkops(Par par) RUNSTEP(par, invalidatetable, MT); RUNSTEP(par, createindex, ST); RUNSTEP(par, invalidateindex, MT); - for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { + for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) { LL1(SUBLOOP(par)); RUNSTEP(par, pkops, MT); LL2("rows=" << par.set().count()); @@ -4772,7 +5213,7 @@ tpkopsread(Par par) RUNSTEP(par, createindex, ST); RUNSTEP(par, invalidateindex, MT); RUNSTEP(par, readverifyfull, MT); - for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { + for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) { LL1(SUBLOOP(par)); RUNSTEP(par, pkupdatescanread, MT); RUNSTEP(par, readverifyfull, MT); @@ -4792,7 +5233,7 @@ tmixedops(Par par) RUNSTEP(par, createindex, ST); RUNSTEP(par, invalidateindex, MT); RUNSTEP(par, readverifyfull, MT); - for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { + for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) { LL1(SUBLOOP(par)); RUNSTEP(par, mixedoperations, MT); RUNSTEP(par, readverifyfull, MT); @@ -4807,7 +5248,7 @@ tbusybuild(Par par) RUNSTEP(par, createtable, ST); RUNSTEP(par, invalidatetable, MT); RUNSTEP(par, pkinsert, MT); - for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { + for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) { LL1(SUBLOOP(par)); RUNSTEP(par, pkupdateindexbuild, MT); RUNSTEP(par, invalidateindex, MT); @@ -4828,7 +5269,7 @@ trollback(Par par) RUNSTEP(par, createindex, ST); RUNSTEP(par, invalidateindex, MT); RUNSTEP(par, readverifyfull, MT); - for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { + for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) { LL1(SUBLOOP(par)); RUNSTEP(par, mixedoperations, MT); RUNSTEP(par, readverifyfull, MT); @@ -4846,7 +5287,7 @@ tparupdate(Par par) RUNSTEP(par, createindex, ST); RUNSTEP(par, invalidateindex, MT); RUNSTEP(par, readverifyfull, MT); - for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { + for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) { LL1(SUBLOOP(par)); RUNSTEP(par, parallelorderedupdate, MT); RUNSTEP(par, readverifyfull, MT); @@ -4854,6 +5295,37 @@ tparupdate(Par par) return 0; } +static int +tsavepoint(Par par) +{ + RUNSTEP(par, droptable, ST); + RUNSTEP(par, createtable, ST); + RUNSTEP(par, invalidatetable, MT); + RUNSTEP(par, createindex, ST); + RUNSTEP(par, invalidateindex, MT); + for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) { + LL1(SUBLOOP(par)); + RUNSTEP(par, savepointtest, MT); + RUNSTEP(par, readverifyfull, MT); + } + return 0; +} + +static int +thalloween(Par par) +{ + RUNSTEP(par, droptable, ST); + RUNSTEP(par, createtable, ST); + RUNSTEP(par, invalidatetable, MT); + RUNSTEP(par, createindex, ST); + RUNSTEP(par, invalidateindex, MT); + for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) { + LL1(SUBLOOP(par)); + RUNSTEP(par, halloweentest, MT); + } + return 0; +} + static int ttimebuild(Par par) { @@ -4861,7 +5333,7 @@ ttimebuild(Par par) RUNSTEP(par, droptable, ST); RUNSTEP(par, createtable, ST); RUNSTEP(par, invalidatetable, MT); - for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { + for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) { LL1(SUBLOOP(par)); RUNSTEP(par, pkinsert, MT); t1.on(); @@ -4881,7 +5353,7 @@ ttimemaint(Par par) RUNSTEP(par, droptable, ST); RUNSTEP(par, createtable, ST); RUNSTEP(par, invalidatetable, MT); - for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { + for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) { LL1(SUBLOOP(par)); RUNSTEP(par, pkinsert, MT); t1.on(); @@ -4911,7 +5383,7 @@ ttimescan(Par par) RUNSTEP(par, droptable, ST); RUNSTEP(par, createtable, ST); RUNSTEP(par, invalidatetable, MT); - for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { + for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) { LL1(SUBLOOP(par)); RUNSTEP(par, pkinsert, MT); RUNSTEP(par, createindex, ST); @@ -4938,7 +5410,7 @@ ttimepkread(Par par) RUNSTEP(par, droptable, ST); RUNSTEP(par, createtable, ST); RUNSTEP(par, invalidatetable, MT); - for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { + for (par.m_slno = 0; par.m_slno < par.m_sloop; par.m_slno++) { LL1(SUBLOOP(par)); RUNSTEP(par, pkinsert, MT); RUNSTEP(par, createindex, ST); @@ -4981,7 +5453,9 @@ tcaselist[] = { TCase("e", tmixedops, "pk operations and scan operations"), TCase("f", tbusybuild, "pk operations and index build"), TCase("g", trollback, "operations with random rollbacks"), - TCase("h", tparupdate, "parallel ordered update (bug20446)"), + TCase("h", tparupdate, "parallel ordered update bug#20446"), + TCase("i", tsavepoint, "savepoint test locking bug#31477"), + TCase("j", thalloween, "savepoint test halloween problem"), TCase("t", ttimebuild, "time index build"), TCase("u", ttimemaint, "time index maintenance"), TCase("v", ttimescan, "time full scan table vs index on pk"), @@ -4989,14 +5463,14 @@ tcaselist[] = { TCase("z", tdrop, "drop test tables") }; -static const unsigned +static const uint tcasecount = sizeof(tcaselist) / sizeof(tcaselist[0]); static void printcases() { ndbout << "test cases:" << endl; - for (unsigned i = 0; i < tcasecount; i++) { + for (uint i = 0; i < tcasecount; i++) { const TCase& tcase = tcaselist[i]; ndbout << " " << tcase.m_name << " - " << tcase.m_desc << endl; } @@ -5008,13 +5482,13 @@ printtables() Par par(g_opt); makebuiltintables(par); ndbout << "tables and indexes (x=ordered z=hash x0=on pk):" << endl; - for (unsigned j = 0; j < tabcount; j++) { + for (uint j = 0; j < tabcount; j++) { if (tablist[j] == 0) continue; const Tab& tab = *tablist[j]; const char* tname = tab.m_name; ndbout << " " << tname; - for (unsigned i = 0; i < tab.m_itabs; i++) { + for (uint i = 0; i < tab.m_itabs; i++) { if (tab.m_itab[i] == 0) continue; const ITab& itab = *tab.m_itab[i]; @@ -5023,7 +5497,7 @@ printtables() iname += strlen(tname); ndbout << " " << iname; ndbout << "("; - for (unsigned k = 0; k < itab.m_icols; k++) { + for (uint k = 0; k < itab.m_icols; k++) { if (k != 0) ndbout << ","; const ICol& icol = *itab.m_icol[k]; @@ -5036,14 +5510,48 @@ printtables() } } +static bool +setcasepar(Par& par) +{ + Opt d; + const char* c = par.m_currcase; + switch (c[0]) { + case 'i': + { + if (par.m_usedthreads > 1) { + par.m_usedthreads = 1; + LL1("case " << c << " reduce threads to " << par.m_usedthreads); + } + const uint rows = 100; + if (par.m_rows > rows) { + par.m_rows = rows; + LL1("case " << c << " reduce rows to " << rows); + } + } + break; + case 'j': + { + if (par.m_usedthreads > 1) { + par.m_usedthreads = 1; + LL1("case " << c << " reduce threads to " << par.m_usedthreads); + } + } + break; + default: + break; + } + return true; +} + static int runtest(Par par) { + int totret = 0; if (par.m_seed == -1) { // good enough for daily run - unsigned short seed = (unsigned short)getpid(); + ushort seed = (ushort)getpid(); LL0("random seed: " << seed); - srandom((unsigned)seed); + srandom((uint)seed); } else if (par.m_seed != 0) { LL0("random seed: " << par.m_seed); srandom(par.m_seed); @@ -5061,9 +5569,10 @@ runtest(Par par) Con con; CHK(con.connect() == 0); par.m_con = &con; + par.m_catcherr |= Con::ErrNospace; // threads g_thrlist = new Thr* [par.m_threads]; - unsigned n; + uint n; for (n = 0; n < par.m_threads; n++) { g_thrlist[n] = 0; } @@ -5078,23 +5587,38 @@ runtest(Par par) LL1("random seed: " << par.m_lno); srandom(par.m_lno); } - for (unsigned i = 0; i < tcasecount; i++) { + for (uint i = 0; i < tcasecount; i++) { const TCase& tcase = tcaselist[i]; - if (par.m_case != 0 && strchr(par.m_case, tcase.m_name[0]) == 0) + if (par.m_case != 0 && strchr(par.m_case, tcase.m_name[0]) == 0 || + par.m_skip != 0 && strchr(par.m_skip, tcase.m_name[0]) != 0) { continue; + } sprintf(par.m_currcase, "%c", tcase.m_name[0]); + par.m_usedthreads = par.m_threads; + if (!setcasepar(par)) { + LL1("case " << tcase.m_name << " cannot run with given options"); + continue; + } + par.m_totrows = par.m_usedthreads * par.m_rows; makebuiltintables(par); LL1("case: " << par.m_lno << "/" << tcase.m_name << " - " << tcase.m_desc); - for (unsigned j = 0; j < tabcount; j++) { + for (uint j = 0; j < tabcount; j++) { if (tablist[j] == 0) continue; const Tab& tab = *tablist[j]; par.m_tab = &tab; par.m_set = new Set(tab, par.m_totrows); LL1("table: " << par.m_lno << "/" << tcase.m_name << "/" << tab.m_name); - CHK(tcase.m_func(par) == 0); + int ret = tcase.m_func(par); delete par.m_set; par.m_set = 0; + if (ret == -1) { + if (!par.m_cont) + return -1; + totret = -1; + LL1("continue to next case due to -cont"); + break; + } } } } @@ -5110,7 +5634,7 @@ runtest(Par par) delete [] g_thrlist; g_thrlist = 0; con.disconnect(); - return 0; + return totret; } static const char* g_progname = "testOIBasic"; @@ -5119,7 +5643,7 @@ int main(int argc, char** argv) { ndb_init(); - unsigned i; + uint i; ndbout << g_progname; for (i = 1; i < argc; i++) ndbout << " " << argv[i]; @@ -5156,6 +5680,10 @@ main(int argc, char** argv) g_opt.m_collsp = true; continue; } + if (strcmp(arg, "-cont") == 0) { + g_opt.m_cont = true; + continue; + } if (strcmp(arg, "-core") == 0) { g_opt.m_core = true; continue; @@ -5252,9 +5780,21 @@ main(int argc, char** argv) continue; } } - if (strcmp(arg, "-subloop") == 0) { + if (strcmp(arg, "-skip") == 0) { if (++argv, --argc > 0) { - g_opt.m_subloop = atoi(argv[0]); + g_opt.m_skip = strdup(argv[0]); + continue; + } + } + if (strcmp(arg, "-sloop") == 0) { + if (++argv, --argc > 0) { + g_opt.m_sloop = atoi(argv[0]); + continue; + } + } + if (strcmp(arg, "-ssloop") == 0) { + if (++argv, --argc > 0) { + g_opt.m_ssloop = atoi(argv[0]); continue; } } diff --git a/storage/ndb/test/ndbapi/test_event.cpp b/storage/ndb/test/ndbapi/test_event.cpp index 18825d734a4..a7504166065 100644 --- a/storage/ndb/test/ndbapi/test_event.cpp +++ b/storage/ndb/test/ndbapi/test_event.cpp @@ -1838,6 +1838,61 @@ runBug31701(NDBT_Context* ctx, NDBT_Step* step) return NDBT_OK; } +int +runBug33793(NDBT_Context* ctx, NDBT_Step* step) +{ + int result = NDBT_OK; + int loops = ctx->getNumLoops(); + + NdbRestarter restarter; + + if (restarter.getNumDbNodes() < 2){ + ctx->stopTest(); + return NDBT_OK; + } + // This should really wait for applier to start...10s is likely enough + NdbSleep_SecSleep(10); + + while (loops-- && ctx->isTestStopped() == false) + { + int nodeId = restarter.getDbNodeId(rand() % restarter.getNumDbNodes()); + int nodecount = 0; + int nodes[255]; + printf("nodeid: %u : victims: ", nodeId); + for (int i = 0; istopTest(); + return NDBT_OK; +} + + + NDBT_TESTSUITE(test_event); TESTCASE("BasicEventOperation", "Verify that we can listen to Events" @@ -1975,6 +2030,12 @@ TESTCASE("Bug31701", ""){ FINALIZER(runDropEvent); FINALIZER(runDropShadowTable); } +TESTCASE("Bug33793", ""){ + INITIALIZER(runCreateEvent); + STEP(runEventListenerUntilStopped); + STEP(runBug33793); + FINALIZER(runDropEvent); +} NDBT_TESTSUITE_END(test_event); int main(int argc, const char** argv){ diff --git a/storage/ndb/test/run-test/daily-basic-tests.txt b/storage/ndb/test/run-test/daily-basic-tests.txt index 37db5e01dd6..70c395fab17 100644 --- a/storage/ndb/test/run-test/daily-basic-tests.txt +++ b/storage/ndb/test/run-test/daily-basic-tests.txt @@ -1,7 +1,3 @@ -max-time: 3600 -cmd: atrt-mysql-test-run -args: --force - max-time: 600 cmd: atrt-testBackup args: -n NFMaster T1 @@ -744,10 +740,10 @@ max-time: 1000 cmd: testNdbApi args: -n Bug28443 -#max-time: 500 -#cmd: testInterpreter -#args: T1 -# +max-time: 500 +cmd: testInterpreter +args: T1 + max-time: 150000 cmd: testOperations args: @@ -1046,3 +1042,15 @@ max-time: 300 cmd: testSystemRestart args: -n Bug22696 T1 +max-time: 300 +cmd: test_event +args: -n Bug33793 T1 + +max-time: 1200 +cmd: testNodeRestart +args: -n Bug34216 -l 10 T1 I3 D2 + +max-time: 1200 +cmd: testNodeRestart +args: -n mixedmultiop -l 10 T1 I2 I3 D2 + diff --git a/storage/ndb/test/src/AtrtClient.cpp b/storage/ndb/test/src/AtrtClient.cpp new file mode 100644 index 00000000000..5183242f841 --- /dev/null +++ b/storage/ndb/test/src/AtrtClient.cpp @@ -0,0 +1,215 @@ +/* Copyright (C) 2008 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + 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 +#include + +AtrtClient::AtrtClient(const char* _user, + const char* _password, + const char* _group_suffix) + : DbUtil(_user, _password, _group_suffix) +{ +} + + +AtrtClient::AtrtClient(MYSQL* mysql) + : DbUtil(mysql) +{ +} + + +AtrtClient::~AtrtClient(){ +} + + +int +AtrtClient::writeCommand(AtrtCommandType _type, + const Properties& args){ + if (!isConnected()) + return false; + + BaseString sql; + sql.assfmt("INSERT command ( "); + + const char* name; + { + Properties::Iterator iter(&args); + while((name= iter.next())){ + sql.appfmt("%s, ", name); + } + } + + sql.appfmt(" state, cmd) VALUES ("); + + { + Properties::Iterator iter(&args); + while((name= iter.next())){ + PropertiesType t; + Uint32 val_i; + BaseString val_s; + args.getTypeOf(name, &t); + switch(t) { + case PropertiesType_Uint32: + args.get(name, &val_i); + sql.appfmt("%d, ", val_i); + break; + case PropertiesType_char: + args.get(name, val_s); + sql.appfmt("'%s', ", val_s.c_str()); + break; + default: + assert(false); + break; + } + } + } + + sql.appfmt("'new', %d)", _type); + if (!doQuery(sql)){ + return -1; + } + + return mysql_insert_id(m_mysql); +} + + +bool +AtrtClient::readCommand(uint command_id, + SqlResultSet& result){ + Properties args; + args.put("0", command_id); + return runQuery("SELECT * FROM command WHERE id = ?", + args, + result); +} + + +bool +AtrtClient::doCommand(AtrtCommandType type, + const Properties& args){ + + int running_timeout= 10; + int total_timeout= 120; + int commandId= writeCommand(type, + args); + if (commandId == -1){ + g_err << "Failed to write command" << endl; + return false; + } + + while (true){ + + SqlResultSet result; + if (!readCommand(commandId, result)) + { + result.print(); + g_err << "Failed to read command "<< commandId << endl; + return false; + } + + // Get first row + result.next(); + + // Check if command has completed + BaseString state(result.column("state")); + if (state == "done") { + return true; + } + + if (state == "new"){ + if (!running_timeout--){ + g_err << "Timeout while waiting for command " + << commandId << " to start run" << endl; + return false; + } + } + else if (!total_timeout--){ + g_err << "Timeout while waiting for result of command " + << commandId << endl; + return false; + } + + + NdbSleep_SecSleep(1); + } + + return false; +} + + +bool +AtrtClient::changeVersion(int process_id, + const char* process_args){ + Properties args; + args.put("process_id", process_id); + args.put("process_args", process_args); + return doCommand(ATCT_CHANGE_VERSION, args); +} + + +bool +AtrtClient::resetProc(int process_id){ + Properties args; + args.put("process_id", process_id); + return doCommand(ATCT_RESET_PROC, args); +} + + +bool +AtrtClient::getConnectString(int cluster_id, SqlResultSet& result){ + Properties args; + args.put("0", cluster_id); + return doQuery("SELECT value as connectstring " \ + "FROM cluster c, process p, host h, options o " \ + "WHERE c.id=p.cluster_id AND p.host_id=h.id AND " \ + "p.id=o.process_id AND c.id=? AND " \ + "o.name='--ndb-connectstring=' AND type='ndb_mgmd'", + args, + result); +} + + +bool +AtrtClient::getClusters(SqlResultSet& result){ + Properties args; + return runQuery("SELECT id, name FROM cluster WHERE name != '.atrt'", + args, + result); +} + + +bool +AtrtClient::getMgmds(int cluster_id, SqlResultSet& result){ + Properties args; + args.put("0", cluster_id); + return runQuery("SELECT * FROM process WHERE cluster_id=? and type='ndb_mgmd'", + args, + result); +} + +bool +AtrtClient::getNdbds(int cluster_id, SqlResultSet& result){ + Properties args; + args.put("0", cluster_id); + return runQuery("SELECT * FROM process WHERE cluster_id=? and type='ndbd'", + args, + result); +} + + + + + diff --git a/storage/ndb/test/src/DbUtil.cpp b/storage/ndb/test/src/DbUtil.cpp new file mode 100755 index 00000000000..a52f45b46a7 --- /dev/null +++ b/storage/ndb/test/src/DbUtil.cpp @@ -0,0 +1,677 @@ +/* Copyright (C) 2008 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* DbUtil.cpp: implementation of the database utilities class.*/ + +#include "DbUtil.hpp" +#include + + +/* Constructors */ + +DbUtil::DbUtil(const char* _dbname, + const char* _user, + const char* _password, + const char* _suffix): + m_connected(false), + m_dbname(_dbname), + m_mysql(NULL), + m_free_mysql(true) +{ + const char* env= getenv("MYSQL_HOME"); + if (env && strlen(env)) + { + m_default_file.assfmt("%s/my.cnf", env); + } + + if (_suffix != NULL){ + m_default_group.assfmt("client%s", _suffix); + } + else { + m_default_group.assign("client.1.master"); + } + + ndbout << "default_file: " << m_default_file.c_str() << endl; + ndbout << "default_group: " << m_default_group.c_str() << endl; + + m_user.assign(_user); + m_pass.assign(_password); +} + + + +DbUtil::DbUtil(MYSQL* mysql): + m_connected(true), + m_mysql(mysql), + m_free_mysql(false) +{ +} + + +bool +DbUtil::isConnected(){ + if (m_connected == true) + { + assert(m_mysql); + return true; + } + return connect() == 0; +} + + +bool +DbUtil::waitConnected(int timeout) { + timeout*= 10; + while(!isConnected()){ + if (timeout-- == 0) + return false; + NdbSleep_MilliSleep(100); + } + return true; +} + + +void +DbUtil::disconnect(){ + if (m_mysql != NULL){ + if (m_free_mysql) + mysql_close(m_mysql); + m_mysql= NULL; + } + m_connected = false; +} + + +/* Destructor */ + +DbUtil::~DbUtil() +{ + disconnect(); +} + +/* Database Login */ + +void +DbUtil::databaseLogin(const char* system, const char* usr, + const char* password, unsigned int portIn, + const char* sockIn, bool transactional) +{ + if (!(m_mysql = mysql_init(NULL))) + { + myerror("DB Login-> mysql_init() failed"); + exit(DBU_FAILED); + } + setUser(usr); + setHost(system); + setPassword(password); + setPort(portIn); + setSocket(sockIn); + + if (!(mysql_real_connect(m_mysql, + m_host.c_str(), + m_user.c_str(), + m_pass.c_str(), + "test", + m_port, + m_socket.c_str(), 0))) + { + myerror("connection failed"); + mysql_close(m_mysql); + exit(DBU_FAILED); + } + + m_mysql->reconnect = TRUE; + + /* set AUTOCOMMIT */ + if(!transactional) + mysql_autocommit(m_mysql, TRUE); + else + mysql_autocommit(m_mysql, FALSE); + + #ifdef DEBUG + printf("\n\tConnected to MySQL server version: %s (%lu)\n\n", + mysql_get_server_info(m_mysql), + (unsigned long) mysql_get_server_version(m_mysql)); + #endif + selectDb(); +} + +/* Database Connect */ + +int +DbUtil::connect() +{ + if (!(m_mysql = mysql_init(NULL))) + { + myerror("DB connect-> mysql_init() failed"); + return DBU_FAILED; + } + + /* Load connection parameters file and group */ + if (mysql_options(m_mysql, MYSQL_READ_DEFAULT_FILE, m_default_file.c_str()) || + mysql_options(m_mysql, MYSQL_READ_DEFAULT_GROUP, m_default_group.c_str())) + { + myerror("DB Connect -> mysql_options failed"); + return DBU_FAILED; + } + + /* + Connect, read settings from my.cnf + NOTE! user and password can be stored there as well + */ + + if (mysql_real_connect(m_mysql, NULL, "root","", m_dbname.c_str(), + 0, NULL, 0) == NULL) + { + myerror("connection failed"); + mysql_close(m_mysql); + return DBU_FAILED; + } + selectDb(); + m_connected = true; + return DBU_OK; +} + + +/* Database Logout */ + +void +DbUtil::databaseLogout() +{ + if (m_mysql){ + #ifdef DEBUG + printf("\n\tClosing the MySQL database connection ...\n\n"); + #endif + mysql_close(m_mysql); + } +} + +/* Prepare MySQL Statements Cont */ + +MYSQL_STMT *STDCALL +DbUtil::mysqlSimplePrepare(const char *query) +{ + #ifdef DEBUG + printf("Inside DbUtil::mysqlSimplePrepare\n"); + #endif + int m_res = DBU_OK; + + MYSQL_STMT *my_stmt= mysql_stmt_init(this->getMysql()); + if (my_stmt && (m_res = mysql_stmt_prepare(my_stmt, query, strlen(query)))){ + this->printStError(my_stmt,"Prepare Statement Failed"); + mysql_stmt_close(my_stmt); + exit(DBU_FAILED); + } + return my_stmt; +} + +/* Close MySQL Statements Handle */ + +void +DbUtil::mysqlCloseStmHandle(MYSQL_STMT *my_stmt) +{ + mysql_stmt_close(my_stmt); +} + +/* Error Printing */ + +void +DbUtil::printError(const char *msg) +{ + if (m_mysql && mysql_errno(m_mysql)) + { + if (m_mysql->server_version) + printf("\n [MySQL-%s]", m_mysql->server_version); + else + printf("\n [MySQL]"); + printf("[%d] %s\n", getErrorNumber(), getError()); + } + else if (msg) + printf(" [MySQL] %s\n", msg); +} + +void +DbUtil::printStError(MYSQL_STMT *stmt, const char *msg) +{ + if (stmt && mysql_stmt_errno(stmt)) + { + if (m_mysql && m_mysql->server_version) + printf("\n [MySQL-%s]", m_mysql->server_version); + else + printf("\n [MySQL]"); + + printf("[%d] %s\n", mysql_stmt_errno(stmt), + mysql_stmt_error(stmt)); + } + else if (msg) + printf("[MySQL] %s\n", msg); +} + +/* Select which database to use */ + +int +DbUtil::selectDb() +{ + if ((getDbName()) != NULL) + { + if(mysql_select_db(m_mysql, this->getDbName())) + { + printError("mysql_select_db failed"); + return DBU_FAILED; + } + return DBU_OK; + } + printError("getDbName() == NULL"); + return DBU_FAILED; +} + +int +DbUtil::selectDb(const char * m_db) +{ + { + if(mysql_select_db(m_mysql, m_db)) + { + printError("mysql_select_db failed"); + return DBU_FAILED; + } + return DBU_OK; + } +} + +int +DbUtil::createDb(BaseString& m_db) +{ + BaseString stm; + { + if(mysql_select_db(m_mysql, m_db.c_str()) == DBU_OK) + { + stm.assfmt("DROP DATABASE %s", m_db.c_str()); + if(doQuery(m_db.c_str()) == DBU_FAILED) + return DBU_FAILED; + } + stm.assfmt("CREATE DATABASE %s", m_db.c_str()); + if(doQuery(m_db.c_str()) == DBU_FAILED) + return DBU_FAILED; + return DBU_OK; + } +} + + +/* Count Table Rows */ + +unsigned long +DbUtil::selectCountTable(const char * table) +{ + BaseString query; + SqlResultSet result; + + query.assfmt("select count(*) as count from %s", table); + if (!doQuery(query, result)) { + printError("select count(*) failed"); + return -1; + } + return result.columnAsInt("count"); +} + + +/* Run Simple Queries */ + + +static bool is_int_type(enum_field_types type){ + switch(type){ + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_ENUM: + return true; + default: + return false; + } + return false; +} + + +bool +DbUtil::runQuery(const char* sql, + const Properties& args, + SqlResultSet& rows){ + + rows.clear(); + if (!isConnected()) + return false; + + g_debug << "runQuery: " << endl + << " sql: '" << sql << "'" << endl; + + + MYSQL_STMT *stmt= mysql_stmt_init(m_mysql); + if (mysql_stmt_prepare(stmt, sql, strlen(sql))) + { + g_err << "Failed to prepare: " << mysql_error(m_mysql) << endl; + return false; + } + + uint params= mysql_stmt_param_count(stmt); + MYSQL_BIND bind_param[params]; + bzero(bind_param, sizeof(bind_param)); + + for(uint i= 0; i < mysql_stmt_param_count(stmt); i++) + { + BaseString name; + name.assfmt("%d", i); + // Parameters are named 0, 1, 2... + if (!args.contains(name.c_str())) + { + g_err << "param " << i << " missing" << endl; + assert(false); + } + PropertiesType t; + Uint32 val_i; + const char* val_s; + args.getTypeOf(name.c_str(), &t); + switch(t) { + case PropertiesType_Uint32: + args.get(name.c_str(), &val_i); + bind_param[i].buffer_type= MYSQL_TYPE_LONG; + bind_param[i].buffer= (char*)&val_i; + g_debug << " param" << name.c_str() << ": " << val_i << endl; + break; + case PropertiesType_char: + args.get(name.c_str(), &val_s); + bind_param[i].buffer_type= MYSQL_TYPE_STRING; + bind_param[i].buffer= (char*)val_s; + bind_param[i].buffer_length= strlen(val_s); + g_debug << " param" << name.c_str() << ": " << val_s << endl; + break; + default: + assert(false); + break; + } + } + if (mysql_stmt_bind_param(stmt, bind_param)) + { + g_err << "Failed to bind param: " << mysql_error(m_mysql) << endl; + mysql_stmt_close(stmt); + return false; + } + + if (mysql_stmt_execute(stmt)) + { + g_err << "Failed to execute: " << mysql_error(m_mysql) << endl; + mysql_stmt_close(stmt); + return false; + } + + /* + Update max_length, making it possible to know how big + buffers to allocate + */ + my_bool one= 1; + mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one); + + if (mysql_stmt_store_result(stmt)) + { + g_err << "Failed to store result: " << mysql_error(m_mysql) << endl; + mysql_stmt_close(stmt); + return false; + } + + uint row= 0; + MYSQL_RES* res= mysql_stmt_result_metadata(stmt); + if (res != NULL) + { + MYSQL_FIELD *fields= mysql_fetch_fields(res); + uint num_fields= mysql_num_fields(res); + MYSQL_BIND bind_result[num_fields]; + bzero(bind_result, sizeof(bind_result)); + + for (uint i= 0; i < num_fields; i++) + { + if (is_int_type(fields[i].type)){ + bind_result[i].buffer_type= MYSQL_TYPE_LONG; + bind_result[i].buffer= malloc(sizeof(int)); + } + else + { + uint max_length= fields[i].max_length + 1; + bind_result[i].buffer_type= MYSQL_TYPE_STRING; + bind_result[i].buffer= malloc(max_length); + bind_result[i].buffer_length= max_length; + } + } + + if (mysql_stmt_bind_result(stmt, bind_result)){ + g_err << "Failed to bind result: " << mysql_error(m_mysql) << endl; + mysql_stmt_close(stmt); + return false; + } + + while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) + { + Properties curr(true); + for (uint i= 0; i < num_fields; i++){ + if (is_int_type(fields[i].type)) + curr.put(fields[i].name, *(int*)bind_result[i].buffer); + else + curr.put(fields[i].name, (char*)bind_result[i].buffer); + } + rows.put("row", row++, &curr); + } + + mysql_free_result(res); + + for (uint i= 0; i < num_fields; i++) + free(bind_result[i].buffer); + + } + + // Save stats in result set + rows.put("rows", row); + rows.put("affected_rows", mysql_affected_rows(m_mysql)); + rows.put("mysql_errno", mysql_errno(m_mysql)); + rows.put("mysql_error", mysql_error(m_mysql)); + rows.put("mysql_sqlstate", mysql_sqlstate(m_mysql)); + rows.put("insert_id", mysql_insert_id(m_mysql)); + + mysql_stmt_close(stmt); + return true; +} + + +bool +DbUtil::doQuery(const char* query){ + const Properties args; + SqlResultSet result; + return doQuery(query, args, result); +} + + +bool +DbUtil::doQuery(const char* query, SqlResultSet& result){ + Properties args; + return doQuery(query, args, result); +} + + +bool +DbUtil::doQuery(const char* query, const Properties& args, + SqlResultSet& result){ + if (!runQuery(query, args, result)) + return false; + result.get_row(0); // Load first row + return true; +} + + +bool +DbUtil::doQuery(BaseString& str){ + return doQuery(str.c_str()); +} + + +bool +DbUtil::doQuery(BaseString& str, SqlResultSet& result){ + return doQuery(str.c_str(), result); +} + + +bool +DbUtil::doQuery(BaseString& str, const Properties& args, + SqlResultSet& result){ + return doQuery(str.c_str(), args, result); +} + + +/* Return MySQL Error String */ + +const char * +DbUtil::getError() +{ + return mysql_error(this->getMysql()); +} + +/* Return MySQL Error Number */ + +int +DbUtil::getErrorNumber() +{ + return mysql_errno(this->getMysql()); +} + +/* DIE */ + +void +DbUtil::die(const char *file, int line, const char *expr) +{ + printf("%s:%d: check failed: '%s'\n", file, line, expr); + abort(); +} + + +/* SqlResultSet */ + +bool +SqlResultSet::get_row(int row_num){ + if(!get("row", row_num, &m_curr_row)){ + return false; + } + return true; +} + + +bool +SqlResultSet::next(void){ + return get_row(++m_curr_row_num); +} + + +// Reset iterator +void SqlResultSet::reset(void){ + m_curr_row_num= -1; + m_curr_row= 0; +} + + +// Remove row from resultset +void SqlResultSet::remove(){ + BaseString row_name; + row_name.assfmt("row_%d", m_curr_row_num); + Properties::remove(row_name.c_str()); +} + + +SqlResultSet::SqlResultSet(): m_curr_row(0), m_curr_row_num(-1){ +} + + +SqlResultSet::~SqlResultSet(){ +} + + +const char* SqlResultSet::column(const char* col_name){ + const char* value; + if (!m_curr_row){ + g_err << "ERROR: SqlResultSet::column("<< col_name << ")" << endl + << "There is no row loaded, call next() before " + << "acessing the column values" << endl; + assert(m_curr_row); + } + if (!m_curr_row->get(col_name, &value)) + return NULL; + return value; +} + + +uint SqlResultSet::columnAsInt(const char* col_name){ + uint value; + if (!m_curr_row){ + g_err << "ERROR: SqlResultSet::columnAsInt("<< col_name << ")" << endl + << "There is no row loaded, call next() before " + << "acessing the column values" << endl; + assert(m_curr_row); + } + if (!m_curr_row->get(col_name, &value)) + return (uint)-1; + return value; +} + + +uint SqlResultSet::insertId(){ + return get_int("insert_id"); +} + + +uint SqlResultSet::affectedRows(){ + return get_int("affected_rows"); +} + + +uint SqlResultSet::numRows(void){ + return get_int("rows"); +} + + +uint SqlResultSet::mysqlErrno(void){ + return get_int("mysql_errno"); +} + + +const char* SqlResultSet::mysqlError(void){ + return get_string("mysql_error"); +} + + +const char* SqlResultSet::mysqlSqlstate(void){ + return get_string("mysql_sqlstate"); +} + + +uint SqlResultSet::get_int(const char* name){ + uint value; + get(name, &value); + return value; +} + + +const char* SqlResultSet::get_string(const char* name){ + const char* value; + get(name, &value); + return value; +} + +/* EOF */ + diff --git a/storage/ndb/test/src/Makefile.am b/storage/ndb/test/src/Makefile.am index aa486108235..1e4f30c3f39 100644 --- a/storage/ndb/test/src/Makefile.am +++ b/storage/ndb/test/src/Makefile.am @@ -23,10 +23,10 @@ libNDBT_a_SOURCES = \ HugoAsynchTransactions.cpp UtilTransactions.cpp \ NdbRestarter.cpp NdbRestarts.cpp NDBT_Output.cpp \ NdbBackup.cpp NdbConfig.cpp NdbGrep.cpp NDBT_Table.cpp \ - NdbSchemaCon.cpp NdbSchemaOp.cpp getarg.c \ - CpcClient.cpp NdbMixRestarter.cpp NDBT_Thread.cpp dbutil.cpp + NdbSchemaCon.cpp NdbSchemaOp.cpp getarg.c AtrtClient.cpp \ + CpcClient.cpp NdbMixRestarter.cpp NDBT_Thread.cpp DbUtil.cpp -INCLUDES_LOC = -I$(top_srcdir)/storage/ndb/src/common/mgmcommon -I$(top_srcdir)/storage/ndb/include/mgmcommon -I$(top_srcdir)/storage/ndb/include/kernel -I$(top_srcdir)/storage/ndb/src/mgmapi +INCLUDES_LOC = -I$(top_srcdir)/storage/ndb/src/common/mgmcommon -I$(top_srcdir)/storage/ndb/include/mgmcommon -I$(top_srcdir)/storage/ndb/include/kernel -I$(top_srcdir)/storage/ndb/src/mgmapi -I$(top_srcdir)/include include $(top_srcdir)/storage/ndb/config/common.mk.am include $(top_srcdir)/storage/ndb/config/type_ndbapitest.mk.am diff --git a/storage/ndb/test/src/NdbBackup.cpp b/storage/ndb/test/src/NdbBackup.cpp index 42b15885089..3fb4de461f0 100644 --- a/storage/ndb/test/src/NdbBackup.cpp +++ b/storage/ndb/test/src/NdbBackup.cpp @@ -350,7 +350,8 @@ FailS_codes[] = { 10025, 10027, 10033, - 10035 + 10035, + 10036 }; int diff --git a/storage/ndb/test/src/dbutil.cpp b/storage/ndb/test/src/dbutil.cpp deleted file mode 100755 index 0c936f53182..00000000000 --- a/storage/ndb/test/src/dbutil.cpp +++ /dev/null @@ -1,176 +0,0 @@ -// dbutil.cpp: implementation of the database utilities class. -// -////////////////////////////////////////////////////////////////////// - -#include "dbutil.hpp" - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// -dbutil::dbutil(const char * dbname) -{ - memset(host,' ',sizeof(host)); - memset(user,' ',sizeof(pass)); - memset(dbs,' ',sizeof(dbs)); - port = 0; - memset(socket,' ',sizeof(socket)); - this->SetDbName(dbname); -} - -dbutil::~dbutil() -{ - this->DatabaseLogout(); -} - -////////////////////////////////////////////////////////////////////// -// Database Login -////////////////////////////////////////////////////////////////////// -void dbutil::DatabaseLogin(const char* system, - const char* usr, - const char* password, - unsigned int portIn, - const char* sockIn, - bool transactional - ){ - if (!(myDbHandel = mysql_init(NULL))){ - myerror("mysql_init() failed"); - exit(1); - } - this->SetUser(usr); - this->SetHost(system); - this->SetPassword(password); - this->SetPort(portIn); - this->SetSocket(sockIn); - - if (!(mysql_real_connect(myDbHandel, host, user, pass, "test", port, socket, 0))){ - myerror("connection failed"); - mysql_close(myDbHandel); - fprintf(stdout, "\n Check the connection options using --help or -?\n"); - exit(1); - } - - myDbHandel->reconnect= 1; - - /* set AUTOCOMMIT */ - if(!transactional){ - mysql_autocommit(myDbHandel, TRUE); - } - else{ - mysql_autocommit(myDbHandel, FALSE); - } - - fprintf(stdout, "\n\tConnected to MySQL server version: %s (%lu)\n\n", - mysql_get_server_info(myDbHandel), - (unsigned long) mysql_get_server_version(myDbHandel)); -} - -////////////////////////////////////////////////////////////////////// -// Database Logout -////////////////////////////////////////////////////////////////////// -void dbutil::DatabaseLogout(){ - if (myDbHandel){ - fprintf(stdout, "\n\tClosing the MySQL database connection ...\n\n"); - mysql_close(myDbHandel); - } -} - -////////////////////////////////////////////////////////////////////// -// Prepare MySQL Statements Cont -////////////////////////////////////////////////////////////////////// -MYSQL_STMT *STDCALL dbutil::MysqlSimplePrepare(const char *query){ -#ifdef DEBUG -printf("Inside dbutil::MysqlSimplePrepare\n"); -#endif -int result = 0; - MYSQL_STMT *my_stmt= mysql_stmt_init(this->GetDbHandel()); - if (my_stmt && (result = mysql_stmt_prepare(my_stmt, query, strlen(query)))){ - printf("res = %s\n",mysql_stmt_error(my_stmt)); - mysql_stmt_close(my_stmt); - return 0; - } - return my_stmt; -} -////////////////////////////////////////////////////////////////////// -// Error Printing -////////////////////////////////////////////////////////////////////// -void dbutil::PrintError(const char *msg){ - if (this->GetDbHandel() - && mysql_errno(this->GetDbHandel())){ - if (this->GetDbHandel()->server_version){ - fprintf(stdout, "\n [MySQL-%s]", - this->GetDbHandel()->server_version); - } - else - fprintf(stdout, "\n [MySQL]"); - fprintf(stdout, "[%d] %s\n", - mysql_errno(this->GetDbHandel()), - mysql_error(this->GetDbHandel())); - } - else if (msg) - fprintf(stderr, " [MySQL] %s\n", msg); -} - -void dbutil::PrintStError(MYSQL_STMT *stmt, const char *msg) -{ - if (stmt && mysql_stmt_errno(stmt)) - { - if (this->GetDbHandel() - && this->GetDbHandel()->server_version) - fprintf(stdout, "\n [MySQL-%s]", - this->GetDbHandel()->server_version); - else - fprintf(stdout, "\n [MySQL]"); - - fprintf(stdout, "[%d] %s\n", mysql_stmt_errno(stmt), - mysql_stmt_error(stmt)); - } - else if (msg) - fprintf(stderr, " [MySQL] %s\n", msg); -} -///////////////////////////////////////////////////// -int dbutil::Select_DB() -{ - return mysql_select_db(this->GetDbHandel(), - this->GetDbName()); -} -//////////////////////////////////////////////////// -int dbutil::Do_Query(char * stm) -{ - return mysql_query(this->GetDbHandel(), stm); -} -//////////////////////////////////////////////////// -const char * dbutil::GetError() -{ - return mysql_error(this->GetDbHandel()); -} -//////////////////////////////////////////////////// -int dbutil::GetErrorNumber() -{ - return mysql_errno(this->GetDbHandel()); -} -//////////////////////////////////////////////////// -unsigned long dbutil::SelectCountTable(const char * table) -{ - unsigned long count = 0; - MYSQL_RES *result; - char query[1024]; - MYSQL_ROW row; - - sprintf(query,"select count(*) from `%s`", table); - if (mysql_query(this->GetDbHandel(),query) || !(result=mysql_store_result(this->GetDbHandel()))) - { - printf("error\n"); - return 1; - } - row= mysql_fetch_row(result); - count= (ulong) strtoull(row[0], (char**) 0, 10); - mysql_free_result(result); - - return count; -} -void dbutil::Die(const char *file, int line, const char *expr){ - fprintf(stderr, "%s:%d: check failed: '%s'\n", file, line, expr); - abort(); -} - - diff --git a/storage/ndb/test/tools/hugoPkUpdate.cpp b/storage/ndb/test/tools/hugoPkUpdate.cpp index b920a4f396a..3fa87da3145 100644 --- a/storage/ndb/test/tools/hugoPkUpdate.cpp +++ b/storage/ndb/test/tools/hugoPkUpdate.cpp @@ -106,7 +106,7 @@ int main(int argc, const char** argv){ NDBT_ThreadSet ths(_threads); // create Ndb object for each thread - if (ths.connect(&con, "TEST_DB") == -1) { + if (ths.connect(&con, db ? db : "TEST_DB") == -1) { ndbout << "connect failed: err=" << ths.get_err() << endl; return NDBT_ProgramExit(NDBT_FAILED); } diff --git a/support-files/Makefile.am b/support-files/Makefile.am index 056a61f2e2a..a6001e635e6 100644 --- a/support-files/Makefile.am +++ b/support-files/Makefile.am @@ -26,6 +26,9 @@ EXTRA_DIST = mysql.spec.sh \ mysql-log-rotate.sh \ mysql.server.sh \ mysqld_multi.server.sh \ + config.huge.ini.sh \ + config.medium.ini.sh \ + config.small.ini.sh \ binary-configure.sh \ magic mysql.m4 \ MySQL-shared-compat.spec.sh \ @@ -41,6 +44,9 @@ pkgsupp_DATA = my-small.cnf \ my-medium.cnf \ my-large.cnf \ my-huge.cnf \ + config.huge.ini \ + config.medium.ini \ + config.small.ini \ my-innodb-heavy-4G.cnf \ mysql-log-rotate \ binary-configure \ @@ -59,6 +65,9 @@ CLEANFILES = my-small.cnf \ my-medium.cnf \ my-large.cnf \ my-huge.cnf \ + config.huge.ini \ + config.medium.ini \ + config.small.ini \ my-innodb-heavy-4G.cnf \ mysql.spec \ mysql-@VERSION@.spec \ diff --git a/support-files/config.huge.ini.sh b/support-files/config.huge.ini.sh new file mode 100755 index 00000000000..938dd3209b8 --- /dev/null +++ b/support-files/config.huge.ini.sh @@ -0,0 +1,212 @@ +###################################################### +# MySQL NDB Cluster Huge Sample Configuration File # +###################################################### +# This files assumes that you are using at least 9 # +# hosts for running the cluster. Hostnames and paths # +# listed below should be changed to match your setup # +###################################################### + +[NDBD DEFAULT] +NoOfReplicas: 2 +DataDir: /add/path/here +FileSystemPath: /add/path/here + +# Data Memory, Index Memory, and String Memory # +DataMemory: 6000M +IndexMemory: 1500M +StringMemory: 5 + +# Transaction Parameters # +MaxNoOfConcurrentTransactions: 4096 +MaxNoOfConcurrentOperations: 100000 +MaxNoOfLocalOperations: 100000 + +# Transaction Temporary Storage # +MaxNoOfConcurrentIndexOperations: 8192 +MaxNoOfFiredTriggers: 4000 +TransactionBufferMemory: 1M + +# Scans and buffering # +MaxNoOfConcurrentScans: 300 +MaxNoOfLocalScans: 32 +BatchSizePerLocalScan: 64 +LongMessageBuffer: 1M + +# Logging and Checkpointing # +NoOfFragmentLogFiles: 300 +FragmentLogFileSize: 16M +MaxNoOfOpenFiles: 40 +InitialNoOfOpenFiles: 27 +MaxNoOfSavedMessages: 25 + +# Metadata Objects # +MaxNoOfAttributes: 1500 +MaxNoOfTables: 400 +MaxNoOfOrderedIndexes: 200 +MaxNoOfUniqueHashIndexes: 200 +MaxNoOfTriggers: 770 + +# Boolean Parameters # +LockPagesInMainMemory: 0 +StopOnError: 1 +Diskless: 0 +ODirect: 0 + +# Controlling Timeouts, Intervals, and Disk Paging # +TimeBetweenWatchDogCheck: 6000 +TimeBetweenWatchDogCheckInitial: 6000 +StartPartialTimeout: 30000 +StartPartitionedTimeout: 60000 +StartFailureTimeout: 1000000 +HeartbeatIntervalDbDb: 2000 +HeartbeatIntervalDbApi: 3000 +TimeBetweenLocalCheckpoints: 20 +TimeBetweenGlobalCheckpoints: 2000 +TransactionInactiveTimeout: 0 +TransactionDeadlockDetectionTimeout: 1200 +DiskSyncSize: 4M +DiskCheckpointSpeed: 10M +DiskCheckpointSpeedInRestart: 100M +ArbitrationTimeout: 10 + +# Buffering and Logging # +UndoIndexBuffer: 2M +UndoDataBuffer: 1M +RedoBuffer: 32M +LogLevelStartup: 15 +LogLevelShutdown: 3 +LogLevelStatistic: 0 +LogLevelCheckpoint: 0 +LogLevelNodeRestart: 0 +LogLevelConnection: 0 +LogLevelError: 15 +LogLevelCongestion: 0 +LogLevelInfo: 3 +MemReportFrequency: 0 + +# Backup Parameters # +BackupDataBufferSize: 2M +BackupLogBufferSize: 2M +BackupMemory: 64M +BackupWriteSize: 32K +BackupMaxWriteSize: 256K + +[MGM DEFAULT] +PortNumber: 1186 +DataDir: /add/path/here + +[TCP DEFAULT] +SendBufferMemory: 2M + +####################################### +# Change HOST1 to the name of the NDB_MGMD host +# Change HOST2 to the name of the NDB_MGMD host +# Change HOST3 to the name of the NDB_MGMD host +# Change HOST4 to the name of the NDBD host +# Change HOST5 to the name of the NDBD host +# Change HOST6 to the name of the NDBD host +# Change HOST7 to the name of the NDBD host +# Change HOST8 to the name of the NDBD host +# Change HOST9 to the name of the NDBD host +####################################### + +[NDB_MGMD] +Id: 1 +HostName: HOST1 +ArbitrationRank: 1 + +[NDB_MGMD] +Id: 2 +HostName: HOST2 +ArbitrationRank: 1 + +[NDB_MGMD] +Id: 3 +HostName: HOST3 +ArbitrationRank: 1 + +[NDBD] +Id: 4 +HostName: HOST4 + +[NDBD] +Id: 5 +HostName: HOST5 + +[NDBD] +Id: 6 +HostName: HOST6 + +[NDBD] +Id: 7 +HostName: HOST7 + +[NDBD] +Id: 8 +HostName: HOST8 + +[NDBD] +Id: 9 +HostName: HOST9 + +###################################################### +# Note: The following can be MySQLD connections or # +# NDB API application connecting to the cluster # +###################################################### + +[API] +Id: 10 +HostName: HOST1 +ArbitrationRank: 2 + +[API] +Id: 11 +HostName: HOST2 +ArbitrationRank: 2 + +[API] +Id: 12 +HostName: HOST3 + +[API] +Id: 13 +HostName: HOST4 + +[API] +Id: 14 +HostName: HOST5 + +[API] +Id: 15 +HostName: HOST6 + +[API] +Id: 16 +HostName: HOST7 + +[API] +Id: 17 +HostName: HOST8 + +[API] +Id: 19 +HostName: HOST9 + +[API] +Id: 20 + +[API] +Id: 21 + +[API] +Id: 22 + +[API] +Id: 23 + +[API] +Id: 24 + +[API] +Id: 25 + diff --git a/support-files/config.medium.ini.sh b/support-files/config.medium.ini.sh new file mode 100755 index 00000000000..e35dd35e455 --- /dev/null +++ b/support-files/config.medium.ini.sh @@ -0,0 +1,124 @@ +# +# MySQL NDB Cluster Medium Sample Configuration File +# +# This files assumes that you are using at least 6 +# hosts for running the cluster. Hostnames and paths +# listed below should be changed to match your setup +# + +[NDBD DEFAULT] +NoOfReplicas: 2 +DataDir: /add/path/here +FileSystemPath: /add/path/here + + +# Data Memory, Index Memory, and String Memory + +DataMemory: 3000M +IndexMemory: 800M +BackupMemory: 64M + +# Transaction Parameters + +MaxNoOfConcurrentOperations: 100000 +MaxNoOfLocalOperations: 100000 + +# Buffering and Logging + +RedoBuffer: 16M + +# Logging and Checkpointing + +NoOfFragmentLogFiles: 200 + +# Metadata Objects + +MaxNoOfAttributes: 500 +MaxNoOfTables: 100 + +# Scans and Buffering + +MaxNoOfConcurrentScans: 100 + + +[MGM DEFAULT] +PortNumber: 1186 +DataDir: /add/path/here + +# +# Change HOST1 to the name of the NDB_MGMD host +# Change HOST2 to the name of the NDB_MGMD host +# Change HOST3 to the name of the NDBD host +# Change HOST4 to the name of the NDBD host +# Change HOST5 to the name of the NDBD host +# Change HOST6 to the name of the NDBD host +# + +[NDB_MGMD] +Id: 1 +HostName: HOST1 +ArbitrationRank: 1 + +[NDB_MGMD] +Id: 2 +HostName: HOST2 +ArbitrationRank: 1 + +[NDBD] +Id: 3 +HostName: HOST3 + +[NDBD] +Id: 4 +HostName: HOST4 + +[NDBD] +Id: 5 +HostName: HOST5 + +[NDBD] +Id: 6 +HostName: HOST6 + +# +# Note: The following can be MySQLD connections or +# NDB API application connecting to the cluster +# + +[API] +Id: 7 +HostName: HOST1 +ArbitrationRank: 2 + +[API] +Id: 8 +HostName: HOST2 +ArbitrationRank: 2 + +[API] +Id: 9 +HostName: HOST3 +ArbitrationRank: 2 + +[API] +Id: 10 +HostName: HOST4 + +[API] +Id: 11 +HostName: HOST5 + +[API] +Id: 12 +HostName: HOST6 + +[API] +Id: 13 + +[API] +Id: 14 + +[API] +Id: 15 + + diff --git a/support-files/config.small.ini.sh b/support-files/config.small.ini.sh new file mode 100755 index 00000000000..129e2521e17 --- /dev/null +++ b/support-files/config.small.ini.sh @@ -0,0 +1,65 @@ +# +# MySQL NDB Cluster Small Sample Configuration File +# +# This files assumes that you are using 1 to 3 hosts +# for running the cluster. Hostnames and paths listed +# below should be changed to match your setup. +# +# Note: You can change localhost for a different host +# + +[NDBD DEFAULT] +NoOfReplicas: 2 +DataDir: /add/path/here +FileSystemPath: /add/path/here + +# Data Memory, Index Memory, and String Memory + +DataMemory: 600M +IndexMemory: 100M +BackupMemory: 64M + +[MGM DEFAULT] +PortNumber: 1186 +DataDir: /add/path/here + +[NDB_MGMD] +Id: 1 +HostName: localhost +ArbitrationRank: 1 + +[NDBD] +Id: 2 +HostName: localhost + +[NDBD] +Id: 3 +HostName: localhost + +# +# Note: The following can be MySQLD connections or +# NDB API application connecting to the cluster +# + +[API] +Id: 4 +HostName: localhost +ArbitrationRank: 2 + +[API] +Id: 5 +HostName: localhost + +[API] +Id: 6 +HostName: localhost + +[API] +Id: 7 + +[API] +Id: 8 + +[API] +Id: 9 +