Commit 2944f4b0 authored by unknown's avatar unknown

Merge bk-internal.mysql.com:/home/bk/mysql-5.1-new-rpl

into  janus.mylan:/usr/home/serg/Abk/mysql-maria


mysql-test/mysql-test-run.pl:
  Auto merged
sql/log_event.cc:
  Auto merged
sql/slave.cc:
  Auto merged
sql/slave.h:
  Auto merged
sql/share/errmsg.txt:
  Auto merged
include/my_base.h:
  merged
parents 5fa560e9 2942c1ea
...@@ -59,7 +59,8 @@ static const char* default_dbug_option = "d:t:o,/tmp/mysqlbinlog.trace"; ...@@ -59,7 +59,8 @@ static const char* default_dbug_option = "d:t:o,/tmp/mysqlbinlog.trace";
#endif #endif
static const char *load_default_groups[]= { "mysqlbinlog","client",0 }; 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 one_database=0, to_last_remote_log= 0, disable_log_bin= 0;
static bool opt_hexdump= 0; static bool opt_hexdump= 0;
...@@ -92,24 +93,33 @@ static ulonglong rec_count= 0; ...@@ -92,24 +93,33 @@ static ulonglong rec_count= 0;
static short binlog_flags = 0; static short binlog_flags = 0;
static MYSQL* mysql = NULL; static MYSQL* mysql = NULL;
static const char* dirname_for_local_load= 0; 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. Pointer to the Format_description_log_event of the currently active binlog.
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() This will be changed each time a new Format_description_log_event is
(which returns a pointer) in check_header(). 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, /**
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); const char* logname);
static int dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info, static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
const char* logname); const char* logname);
static int dump_log_entries(const char* logname); static Exit_status dump_log_entries(const char* logname);
static void die(const char* fmt, ...) __attribute__ ((__noreturn__)); static Exit_status safe_connect();
static MYSQL* safe_connect();
class Load_log_processor class Load_log_processor
...@@ -132,22 +142,29 @@ class Load_log_processor ...@@ -132,22 +142,29 @@ class Load_log_processor
char *fname; char *fname;
Create_file_log_event *event; 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; DYNAMIC_ARRAY file_names;
/* /**
Looking for new uniquie filename that doesn't exist yet by Looks for a non-existing filename by adding a numerical suffix to
adding postfix -%x the given base name, creates the generated file, and returns the
filename by modifying the filename argument.
SYNOPSIS @param[in,out] filename Base filename
create_unique_file()
filename buffer for filename @param[in,out] file_name_end Pointer to last character of
file_name_end tail of buffer that should be changed filename. The numerical suffix will be written to this position.
should point to a memory enough to printf("-%x",..) Note that there must be a least five bytes of allocated memory
after file_name_end.
RETURN VALUES @retval -1 Error (can't find new filename).
values less than 0 - can't find new filename @retval >=0 Found file.
values great or equal 0 - created file with found filename
*/ */
File create_unique_file(char *filename, char *file_name_end) File create_unique_file(char *filename, char *file_name_end)
{ {
...@@ -201,22 +218,20 @@ public: ...@@ -201,22 +218,20 @@ public:
delete_dynamic(&file_names); 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 Checks whether we have already seen a Create_file_log_event with
grab_event() the given file_id. If yes, returns a pointer to the event and
file_id - file_id identifiying LOAD DATA statement 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 @param[in] file_id File id identifying LOAD DATA statement.
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.
RETURN VALUES @return Pointer to Create_file_log_event, or NULL if we have not
Pointer to Create_file event or 0 if there was no such event seen any Create_file_log_event with this file_id.
with this file_id.
*/ */
Create_file_log_event *grab_event(uint file_id) Create_file_log_event *grab_event(uint file_id)
{ {
...@@ -231,23 +246,20 @@ public: ...@@ -231,23 +246,20 @@ public:
return res; 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() @param[in] file_id Identifier for the LOAD DATA statement.
file_id - file_id identifiying LOAD DATA statement
Checks whether we have already seen Begin_load_query event for
DESCRIPTION this file_id. If yes, returns the file name of the corresponding
Checks whenever we have already seen Begin_load_query event for this temporary file and removes the filename from the array of active
file_id. If yes then returns file name of corresponding temporary file. temporary files. From this moment, the caller is responsible for
Removes record about this file from the array of active temporary files. freeing the memory occupied by this name.
Since this moment caller is responsible for freeing memory occupied by
this name. @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.
RETURN VALUES
String with name of temporary file or 0 if we have not seen Begin_load_query
event with this file_id.
*/ */
char *grab_fname(uint file_id) char *grab_fname(uint file_id)
{ {
...@@ -264,19 +276,29 @@ public: ...@@ -264,19 +276,29 @@ public:
} }
return res; return res;
} }
int process(Create_file_log_event *ce); Exit_status process(Create_file_log_event *ce);
int process(Begin_load_query_log_event *ce); Exit_status process(Begin_load_query_log_event *ce);
int process(Append_block_log_event *ae); Exit_status process(Append_block_log_event *ae);
File prepare_new_file_for_old_format(Load_log_event *le, char *filename); File prepare_new_file_for_old_format(Load_log_event *le, char *filename);
int load_old_format_file(NET* net, const char *server_fname, Exit_status load_old_format_file(NET* net, const char *server_fname,
uint server_fname_len, File file); uint server_fname_len, File file);
int process_first_event(const char *bname, uint blen, const uchar *block, Exit_status process_first_event(const char *bname, uint blen,
const uchar *block,
uint block_len, uint file_id, uint block_len, uint file_id,
Create_file_log_event *ce); 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, File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le,
char *filename) char *filename)
{ {
...@@ -284,13 +306,13 @@ File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le, ...@@ -284,13 +306,13 @@ File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le,
char *tail; char *tail;
File file; 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); len= strlen(filename);
tail= filename + len; tail= filename + len;
if ((file= create_unique_file(filename,tail)) < 0) 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; return -1;
} }
...@@ -300,16 +322,33 @@ File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le, ...@@ -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]; uchar buf[FN_REFLEN+1];
buf[0] = 0; buf[0] = 0;
memcpy(buf + 1, server_fname, server_fname_len + 1); memcpy(buf + 1, server_fname, server_fname_len + 1);
if (my_net_write(net, buf, server_fname_len +2) || net_flush(net)) 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); error("Failed requesting the remote dump of %s.", server_fname);
return -1; return ERROR_STOP;
} }
for (;;) for (;;)
...@@ -319,8 +358,8 @@ int Load_log_processor::load_old_format_file(NET* net, const char*server_fname, ...@@ -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)) if (my_net_write(net, (uchar*) "", 0) || net_flush(net))
{ {
sql_print_error("Failed sending the ack packet"); error("Failed sending the ack packet.");
return -1; return ERROR_STOP;
} }
/* /*
we just need to send something, as the server will read but 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, ...@@ -331,63 +370,63 @@ int Load_log_processor::load_old_format_file(NET* net, const char*server_fname,
} }
else if (packet_len == packet_error) else if (packet_len == packet_error)
{ {
sql_print_error("Failed reading a packet during the dump of %s ", error("Failed reading a packet during the dump of %s.", server_fname);
server_fname); return ERROR_STOP;
return -1;
} }
if (packet_len > UINT_MAX) if (packet_len > UINT_MAX)
{ {
sql_print_error("Illegal length of packet read from net"); error("Illegal length of packet read from net.");
return -1; return ERROR_STOP;
} }
if (my_write(file, (uchar*) net->read_pos, if (my_write(file, (uchar*) net->read_pos,
(uint) packet_len, MYF(MY_WME|MY_NABP))) (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 Process the first event in the sequence of events representing a
statement. LOAD DATA statement.
SYNOPSIS Creates a temporary file to be used in LOAD DATA and writes first
process_first_event() block of data to it. Registers its file name (and optional
bname - base name for temporary file to be created Create_file event) in the array of active temporary files.
blen - base name length
block - first block of data to be loaded @param bname Base name for temporary file to be created.
block_len - first block length @param blen Base name length.
file_id - identifies LOAD DATA statement @param block First block of data to be loaded.
ce - pointer to Create_file event object if we are processing @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. this type of event.
DESCRIPTION @retval ERROR_STOP An error occurred - the program should terminate.
Creates temporary file to be used in LOAD DATA and writes first block of @retval OK_CONTINUE No error, the program should continue.
data to it. Registers its file name (and optional Create_file event)
in the array of active temporary files.
RETURN VALUES
0 - success
non-0 - error
*/ */
Exit_status Load_log_processor::process_first_event(const char *bname,
int Load_log_processor::process_first_event(const char *bname, uint blen, uint blen,
const uchar *block, uint block_len, const uchar *block,
uint block_len,
uint file_id, uint file_id,
Create_file_log_event *ce) Create_file_log_event *ce)
{ {
uint full_len= target_dir_name_len + blen + 9 + 9 + 1; uint full_len= target_dir_name_len + blen + 9 + 9 + 1;
int error= 0; Exit_status retval= OK_CONTINUE;
char *fname, *ptr; char *fname, *ptr;
File file; File file;
File_name_record rec; File_name_record rec;
DBUG_ENTER("Load_log_processor::process_first_event"); DBUG_ENTER("Load_log_processor::process_first_event");
if (!(fname= (char*) my_malloc(full_len,MYF(MY_WME)))) 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); memcpy(fname, target_dir_name, target_dir_name_len);
ptr= fname + 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, ...@@ -397,9 +436,10 @@ int Load_log_processor::process_first_event(const char *bname, uint blen,
if ((file= create_unique_file(fname,ptr)) < 0) if ((file= create_unique_file(fname,ptr)) < 0)
{ {
sql_print_error("Could not construct local filename %s%s", error("Could not construct local filename %s%s.",
target_dir_name,bname); target_dir_name,bname);
DBUG_RETURN(-1); delete ce;
DBUG_RETURN(ERROR_STOP);
} }
rec.fname= fname; rec.fname= fname;
...@@ -407,23 +447,39 @@ int Load_log_processor::process_first_event(const char *bname, uint blen, ...@@ -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)) if (set_dynamic(&file_names, (uchar*)&rec, file_id))
{ {
sql_print_error("Could not construct local filename %s%s", error("Out of memory.");
target_dir_name, bname); delete ce;
DBUG_RETURN(-1); DBUG_RETURN(ERROR_STOP);
} }
if (ce) if (ce)
ce->set_fname_outside_temp_buf(fname, strlen(fname)); ce->set_fname_outside_temp_buf(fname, strlen(fname));
if (my_write(file, (uchar*)block, block_len, MYF(MY_WME|MY_NABP))) 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))) 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); const char *bname= ce->fname + dirname_length(ce->fname);
uint blen= ce->fname_len - (bname-ce->fname); uint blen= ce->fname_len - (bname-ce->fname);
...@@ -433,14 +489,46 @@ int Load_log_processor::process(Create_file_log_event *ce) ...@@ -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, return process_first_event("SQL_LOAD_MB", 11, blqe->block, blqe->block_len,
blqe->file_id, 0); 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"); DBUG_ENTER("Load_log_processor::process");
const char* fname= ((ae->file_id < file_names.elements) ? const char* fname= ((ae->file_id < file_names.elements) ?
...@@ -450,15 +538,24 @@ int Load_log_processor::process(Append_block_log_event *ae) ...@@ -450,15 +538,24 @@ int Load_log_processor::process(Append_block_log_event *ae)
if (fname) if (fname)
{ {
File file; File file;
int error= 0; Exit_status retval= OK_CONTINUE;
if (((file= my_open(fname, if (((file= my_open(fname,
O_APPEND|O_BINARY|O_WRONLY,MYF(MY_WME))) < 0)) 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))) 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))) 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) ...@@ -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 --start-position). Assuming it's a big --start-position, we just do
nothing and print a warning. nothing and print a warning.
*/ */
fprintf(stderr,"Warning: ignoring Append_block as there is no \ warning("Ignoring Append_block as there is no "
Create_file event for file_id: %u\n",ae->file_id); "Create_file event for file_id: %u", ae->file_id);
DBUG_RETURN(-1); DBUG_RETURN(OK_CONTINUE);
}
static Load_log_processor load_processor;
/**
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++;
}
} }
Load_log_processor load_processor; /**
Indicates whether the given database should be filtered out,
according to the --database=X option.
@param log_dbname Name of database.
static bool check_database(const char *log_dbname) @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 && return one_database &&
(log_dbname != NULL) && (log_dbname != NULL) &&
...@@ -483,8 +614,23 @@ static bool check_database(const char *log_dbname) ...@@ -483,8 +614,23 @@ static bool check_database(const char *log_dbname)
} }
/**
Prints the given event in base64 format.
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.
static int @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, write_event_header_and_base64(Log_event *ev, FILE *result_file,
PRINT_EVENT_INFO *print_event_info) PRINT_EVENT_INFO *print_event_info)
{ {
...@@ -497,35 +643,44 @@ write_event_header_and_base64(Log_event *ev, FILE *result_file, ...@@ -497,35 +643,44 @@ write_event_header_and_base64(Log_event *ev, FILE *result_file,
ev->print_base64(body, print_event_info, FALSE); ev->print_base64(body, print_event_info, FALSE);
/* Read data from cache and write to result file */ /* Read data from cache and write to result file */
DBUG_RETURN(copy_event_cache_to_file_and_reinit(head, result_file) || if (copy_event_cache_to_file_and_reinit(head, result_file) ||
copy_event_cache_to_file_and_reinit(body, 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
RETURN glob_description_event; (2) the event is a Create_file_log_event,
0 ok and continue and is saved in load_processor.
1 error and terminate
-1 ok and terminate @param[in,out] print_event_info Parameters and context state
determining how to print.
TODO @param[in] ev Log_event to process.
This function returns 0 even in some error cases. This should be changed. @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.
*/ */
Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
my_off_t pos, const char *logname)
int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
my_off_t pos)
{ {
char ll_buff[21]; char ll_buff[21];
Log_event_type ev_type= ev->get_type_code(); Log_event_type ev_type= ev->get_type_code();
DBUG_ENTER("process_event"); DBUG_ENTER("process_event");
print_event_info->short_form= short_form; 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 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, ...@@ -545,14 +700,15 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
start_datetime= 0; start_datetime= 0;
offset= 0; // print everything and protect against cycling rec_count offset= 0; // print everything and protect against cycling rec_count
} }
if (server_id && (server_id != ev->server_id)) { if (server_id && (server_id != ev->server_id))
DBUG_RETURN(0); /* skip just this event, continue processing the log. */
} goto end;
if (((my_time_t)(ev->when) >= stop_datetime) if (((my_time_t)(ev->when) >= stop_datetime)
|| (pos >= stop_position_mot)) || (pos >= stop_position_mot))
{ {
stop_passed= 1; // skip all next binlogs /* end the program */
DBUG_RETURN(-1); retval= OK_STOP;
goto end;
} }
if (!short_form) if (!short_form)
fprintf(result_file, "# at %s\n",llstr(pos,ll_buff)); 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, ...@@ -568,10 +724,15 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
switch (ev_type) { switch (ev_type) {
case QUERY_EVENT: case QUERY_EVENT:
if (check_database(((Query_log_event*)ev)->db)) if (shall_skip_database(((Query_log_event*)ev)->db))
goto end; goto end;
if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS) 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 else
ev->print(result_file, print_event_info); ev->print(result_file, print_event_info);
break; break;
...@@ -585,7 +746,7 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, ...@@ -585,7 +746,7 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
related Append_block and Exec_load. related Append_block and Exec_load.
Note that Load event from 3.23 is not tested. 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 goto end; // Next event
/* /*
We print the event, but with a leading '#': this is just to inform 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, ...@@ -596,7 +757,10 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
*/ */
if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS) 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 else
ce->print(result_file, print_event_info, TRUE); ce->print(result_file, print_event_info, TRUE);
...@@ -604,17 +768,29 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, ...@@ -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 this binlog is not 3.23 ; why this test??
if (glob_description_event->binlog_version >= 3) if (glob_description_event->binlog_version >= 3)
{ {
if (load_processor.process(ce)) /*
break; // Error transfer the responsibility for destroying the event to
ev= 0; load_processor
*/
ev= NULL;
if ((retval= load_processor.process(ce)) != OK_CONTINUE)
goto end;
} }
break; break;
} }
case APPEND_BLOCK_EVENT: 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); ev->print(result_file, print_event_info);
if (load_processor.process((Append_block_log_event*) ev)) if ((retval= load_processor.process((Append_block_log_event*) ev)) !=
break; // Error OK_CONTINUE)
goto end;
break; break;
case EXEC_LOAD_EVENT: case EXEC_LOAD_EVENT:
{ {
ev->print(result_file, print_event_info); ev->print(result_file, print_event_info);
...@@ -627,13 +803,18 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, ...@@ -627,13 +803,18 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
*/ */
if (ce) 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); ce->print(result_file, print_event_info, TRUE);
my_free((char*)ce->fname,MYF(MY_WME)); my_free((char*)ce->fname,MYF(MY_WME));
delete ce; delete ce;
} }
else else
fprintf(stderr,"Warning: ignoring Exec_load as there is no \ warning("Ignoring Execute_load_log_event as there is no "
Create_file event for file_id: %u\n",exv->file_id); "Create_file event for file_id: %u", exv->file_id);
break; break;
} }
case FORMAT_DESCRIPTION_EVENT: case FORMAT_DESCRIPTION_EVENT:
...@@ -653,41 +834,37 @@ Create_file event for file_id: %u\n",exv->file_id); ...@@ -653,41 +834,37 @@ Create_file event for file_id: %u\n",exv->file_id);
if (!force_if_open_opt && if (!force_if_open_opt &&
(glob_description_event->flags & LOG_EVENT_BINLOG_IN_USE_F)) (glob_description_event->flags & LOG_EVENT_BINLOG_IN_USE_F))
{ {
file_not_closed_error= 1; error("Attempting to dump binlog '%s', which was not closed properly. "
DBUG_RETURN(1); "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; break;
case BEGIN_LOAD_QUERY_EVENT: case BEGIN_LOAD_QUERY_EVENT:
ev->print(result_file, print_event_info); 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; break;
case EXECUTE_LOAD_QUERY_EVENT: case EXECUTE_LOAD_QUERY_EVENT:
{ {
Execute_load_query_log_event *exlq= (Execute_load_query_log_event*)ev; Execute_load_query_log_event *exlq= (Execute_load_query_log_event*)ev;
char *fname= load_processor.grab_fname(exlq->file_id); 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;
}
if (fname) if (fname)
{ {
/* convert_path_to_forward_slashes(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); exlq->print(result_file, print_event_info, fname);
my_free(fname, MYF(MY_WME));
} }
else else
fprintf(stderr,"Warning: ignoring Execute_load_query as there is no \ warning("Ignoring Execute_load_query since there is no "
Begin_load_query event for file_id: %u\n", exlq->file_id); "Begin_load_query event for file_id: %u", exlq->file_id);
}
if (fname)
my_free(fname, MYF(MY_WME));
break; break;
} }
case TABLE_MAP_EVENT: case TABLE_MAP_EVENT:
...@@ -706,20 +883,18 @@ Begin_load_query event for file_id: %u\n", exlq->file_id); ...@@ -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) if (!print_event_info->printed_fd_event && !short_form)
{ {
/*
todo: a lot to clean up here
*/
const char* type_str= ev->get_type_str(); const char* type_str= ev->get_type_str();
delete ev;
if (opt_base64_output_mode == BASE64_OUTPUT_NEVER) if (opt_base64_output_mode == BASE64_OUTPUT_NEVER)
die("--base64-output=never specified, but binlog contains a " error("--base64-output=never specified, but binlog contains a "
"%s event which must be printed in base64.", "%s event which must be printed in base64.",
type_str); type_str);
else else
die("malformed binlog: it does not contain any " error("malformed binlog: it does not contain any "
"Format_description_log_event. I now found a %s event, which is " "Format_description_log_event. I now found a %s event, which "
"not safe to process without a Format_description_log_event.", "is not safe to process without a "
"Format_description_log_event.",
type_str); type_str);
goto err;
} }
/* FALL THROUGH */ /* FALL THROUGH */
default: default:
...@@ -727,6 +902,10 @@ Begin_load_query event for file_id: %u\n", exlq->file_id); ...@@ -727,6 +902,10 @@ Begin_load_query event for file_id: %u\n", exlq->file_id);
} }
} }
goto end;
err:
retval= ERROR_STOP;
end: end:
rec_count++; rec_count++;
/* /*
...@@ -739,7 +918,7 @@ end: ...@@ -739,7 +918,7 @@ end:
ev->temp_buf= 0; ev->temp_buf= 0;
delete ev; delete ev;
} }
DBUG_RETURN(0); DBUG_RETURN(retval);
} }
...@@ -894,16 +1073,71 @@ that may lead to an endless loop.", ...@@ -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)
{ {
va_list args; fprintf(stderr, "%s: ", msg);
va_start(args, format);
fprintf(stderr, "ERROR: ");
vfprintf(stderr, format, args); vfprintf(stderr, format, args);
fprintf(stderr, "\n"); 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);
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); va_end(args);
} }
/**
Frees memory for global variables in this file.
*/
static void cleanup() static void cleanup()
{ {
my_free(pass,MYF(MY_ALLOW_ZERO_PTR)); my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
...@@ -911,20 +1145,10 @@ static void cleanup() ...@@ -911,20 +1145,10 @@ static void cleanup()
my_free((char*) host, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) host, MYF(MY_ALLOW_ZERO_PTR));
my_free((char*) user, 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)); my_free((char*) dirname_for_local_load, MYF(MY_ALLOW_ZERO_PTR));
}
static void die(const char* fmt, ...) delete glob_description_event;
{ if (mysql)
va_list args; mysql_close(mysql);
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);
} }
#include <help_start.h> #include <help_start.h>
...@@ -962,7 +1186,7 @@ static my_time_t convert_str_to_timestamp(const char* str) ...@@ -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) != if (str_to_datetime(str, strlen(str), &l_time, 0, &was_cut) !=
MYSQL_TIMESTAMP_DATETIME || 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); exit(1);
} }
/* /*
...@@ -1063,34 +1287,56 @@ static int parse_args(int *argc, char*** argv) ...@@ -1063,34 +1287,56 @@ static int parse_args(int *argc, char*** argv)
return 0; return 0;
} }
static MYSQL* safe_connect()
/**
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 *local_mysql= mysql_init(NULL); mysql= mysql_init(NULL);
if (!local_mysql) if (!mysql)
die("Failed on mysql_init"); {
error("Failed on mysql_init.");
return ERROR_STOP;
}
if (opt_protocol) if (opt_protocol)
mysql_options(local_mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol); mysql_options(mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol);
if (!mysql_real_connect(local_mysql, host, user, pass, 0, port, sock, 0)) if (!mysql_real_connect(mysql, host, user, pass, 0, port, sock, 0))
{ {
char errmsg[256]; error("Failed on connect: %s", mysql_error(mysql));
strmake(errmsg, mysql_error(local_mysql), sizeof(errmsg)-1); return ERROR_STOP;
mysql_close(local_mysql);
die("failed on connect: %s", errmsg);
} }
local_mysql->reconnect= 1; mysql->reconnect= 1;
return local_mysql; 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; PRINT_EVENT_INFO print_event_info;
if (!print_event_info.init_ok()) if (!print_event_info.init_ok())
return 1; return ERROR_STOP;
/* /*
Set safe delimiter, to dump things Set safe delimiter, to dump things
like CREATE PROCEDURE safely like CREATE PROCEDURE safely
...@@ -1108,51 +1354,50 @@ static int dump_log_entries(const char* logname) ...@@ -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 When reading a remote binlog, this function is used to grab the
for a binlog which mixes format. TODO: fix this. 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, static Exit_status check_master_version()
Format_description_log_event
**description_event)
{ {
MYSQL_RES* res = 0; MYSQL_RES* res = 0;
MYSQL_ROW row; MYSQL_ROW row;
const char* version; const char* version;
if (mysql_query(mysql_arg, "SELECT VERSION()") || if (mysql_query(mysql, "SELECT VERSION()") ||
!(res = mysql_store_result(mysql_arg))) !(res = mysql_store_result(mysql)))
{ {
/* purecov: begin inspected */ error("Could not find server version: "
char errmsg[256]; "Query failed when checking master version: %s", mysql_error(mysql));
strmake(errmsg, mysql_error(mysql_arg), sizeof(errmsg)-1); return ERROR_STOP;
mysql_close(mysql_arg);
die("Error checking master version: %s", errmsg);
/* purecov: end */
} }
if (!(row = mysql_fetch_row(res))) if (!(row = mysql_fetch_row(res)))
{ {
/* purecov: begin inspected */ error("Could not find server version: "
mysql_free_result(res); "Master returned no rows for SELECT VERSION().");
mysql_close(mysql); goto err;
die("Master returned no rows for SELECT VERSION()");
/* purecov: end */
} }
if (!(version = row[0])) if (!(version = row[0]))
{ {
/* purecov: begin inspected */ error("Could not find server version: "
mysql_free_result(res); "Master reported NULL for the version.");
mysql_close(mysql_arg); goto err;
die("Master reported NULL for the version");
/* purecov: end */
} }
delete glob_description_event;
switch (*version) { switch (*version) {
case '3': case '3':
*description_event= new Format_description_log_event(1); glob_description_event= new Format_description_log_event(1);
break; break;
case '4': case '4':
*description_event= new Format_description_log_event(3); glob_description_event= new Format_description_log_event(3);
break; break;
case '5': case '5':
/* /*
...@@ -1161,21 +1406,43 @@ static int check_master_version(MYSQL *mysql_arg, ...@@ -1161,21 +1406,43 @@ static int check_master_version(MYSQL *mysql_arg,
So we first assume that this is 4.0 (which is enough to read the So we first assume that this is 4.0 (which is enough to read the
Format_desc event if one comes). Format_desc event if one comes).
*/ */
*description_event= new Format_description_log_event(3); glob_description_event= new Format_description_log_event(3);
break; break;
default: default:
/* purecov: begin inspected */ glob_description_event= NULL;
mysql_free_result(res); error("Could not find server version: "
mysql_close(mysql_arg); "Master reported unrecognized MySQL version '%s'.", version);
die("Master reported unrecognized MySQL version '%s'", version); goto err;
/* purecov: end */ }
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); 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, /**
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) const char* logname)
{ {
...@@ -1183,9 +1450,9 @@ static int dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info, ...@@ -1183,9 +1450,9 @@ static int dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
ulong len; ulong len;
uint logname_len; uint logname_len;
NET* net; NET* net;
int error= 0;
my_off_t old_off= start_position_mot; my_off_t old_off= start_position_mot;
char fname[FN_REFLEN+1]; char fname[FN_REFLEN+1];
Exit_status retval= OK_CONTINUE;
DBUG_ENTER("dump_remote_log_entries"); DBUG_ENTER("dump_remote_log_entries");
/* /*
...@@ -1193,20 +1460,12 @@ static int dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info, ...@@ -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 we cannot re-use the same connection as before, because it is now dead
(COM_BINLOG_DUMP kills the thread when it finishes). (COM_BINLOG_DUMP kills the thread when it finishes).
*/ */
mysql= safe_connect(); if ((retval= safe_connect()) != OK_CONTINUE)
DBUG_RETURN(retval);
net= &mysql->net; net= &mysql->net;
if (check_master_version(mysql, &glob_description_event)) if ((retval= check_master_version()) != OK_CONTINUE)
{ DBUG_RETURN(retval);
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);
}
/* /*
COM_BINLOG_DUMP accepts only 4 bytes for the position, so we are forced to COM_BINLOG_DUMP accepts only 4 bytes for the position, so we are forced to
...@@ -1218,18 +1477,16 @@ could be out of memory"); ...@@ -1218,18 +1477,16 @@ could be out of memory");
size_t tlen = strlen(logname); size_t tlen = strlen(logname);
if (tlen > UINT_MAX) if (tlen > UINT_MAX)
{ {
fprintf(stderr,"Log name too long\n"); error("Log name too long.");
error= 1; DBUG_RETURN(ERROR_STOP);
goto err;
} }
logname_len = (uint) tlen; logname_len = (uint) tlen;
int4store(buf + 6, 0); int4store(buf + 6, 0);
memcpy(buf + 10, logname, logname_len); memcpy(buf + 10, logname, logname_len);
if (simple_command(mysql, COM_BINLOG_DUMP, buf, logname_len + 10, 1)) if (simple_command(mysql, COM_BINLOG_DUMP, buf, logname_len + 10, 1))
{ {
fprintf(stderr,"Got fatal error sending the log dump command\n"); error("Got fatal error sending the log dump command.");
error= 1; DBUG_RETURN(ERROR_STOP);
goto err;
} }
for (;;) for (;;)
...@@ -1240,10 +1497,8 @@ could be out of memory"); ...@@ -1240,10 +1497,8 @@ could be out of memory");
len= cli_safe_read(mysql); len= cli_safe_read(mysql);
if (len == packet_error) if (len == packet_error)
{ {
fprintf(stderr, "Got error reading packet from server: %s\n", error("Got error reading packet from server: %s", mysql_error(mysql));
mysql_error(mysql)); DBUG_RETURN(ERROR_STOP);
error= 1;
goto err;
} }
if (len < 8 && net->read_pos[0] == 254) if (len < 8 && net->read_pos[0] == 254)
break; // end of data break; // end of data
...@@ -1253,9 +1508,8 @@ could be out of memory"); ...@@ -1253,9 +1508,8 @@ could be out of memory");
len - 1, &error_msg, len - 1, &error_msg,
glob_description_event))) glob_description_event)))
{ {
fprintf(stderr, "Could not construct log event object\n"); error("Could not construct log event object: %s", error_msg);
error= 1; DBUG_RETURN(ERROR_STOP);
goto err;
} }
/* /*
If reading from a remote host, ensure the temp_buf for the If reading from a remote host, ensure the temp_buf for the
...@@ -1294,8 +1548,7 @@ could be out of memory"); ...@@ -1294,8 +1548,7 @@ could be out of memory");
if ((rev->ident_len != logname_len) || if ((rev->ident_len != logname_len) ||
memcmp(rev->new_log_ident, logname, logname_len)) memcmp(rev->new_log_ident, logname, logname_len))
{ {
error= 0; DBUG_RETURN(OK_CONTINUE);
goto err;
} }
/* /*
Otherwise, this is a fake Rotate for our log, at the very Otherwise, this is a fake Rotate for our log, at the very
...@@ -1320,11 +1573,9 @@ could be out of memory"); ...@@ -1320,11 +1573,9 @@ could be out of memory");
if (old_off != BIN_LOG_HEADER_SIZE) if (old_off != BIN_LOG_HEADER_SIZE)
len= 1; // fake event, don't increment old_off len= 1; // fake event, don't increment old_off
} }
if ((error= process_event(print_event_info, ev, old_off))) Exit_status retval= process_event(print_event_info, ev, old_off, logname);
{ if (retval != OK_CONTINUE)
error= ((error < 0) ? 0 : 1); DBUG_RETURN(retval);
goto err;
}
} }
else else
{ {
...@@ -1332,26 +1583,21 @@ could be out of memory"); ...@@ -1332,26 +1583,21 @@ could be out of memory");
const char *old_fname= le->fname; const char *old_fname= le->fname;
uint old_len= le->fname_len; uint old_len= le->fname_len;
File file; File file;
Exit_status retval;
if ((file= load_processor.prepare_new_file_for_old_format(le,fname)) < 0) if ((file= load_processor.prepare_new_file_for_old_format(le,fname)) < 0)
{ DBUG_RETURN(ERROR_STOP);
error= 1;
goto err;
}
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)); my_close(file,MYF(MY_WME));
error= ((error < 0) ? 0 : 1); DBUG_RETURN(retval);
goto err;
} }
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)); my_close(file,MYF(MY_WME));
if (error) if (retval != OK_CONTINUE)
{ DBUG_RETURN(retval);
error= 1;
goto err;
}
} }
/* /*
Let's adjust offset for remote log as for local log to produce Let's adjust offset for remote log as for local log to produce
...@@ -1360,15 +1606,13 @@ could be out of memory"); ...@@ -1360,15 +1606,13 @@ could be out of memory");
old_off+= len-1; old_off+= len-1;
} }
err: DBUG_RETURN(OK_CONTINUE);
mysql_close(mysql);
DBUG_RETURN(error);
} }
/** /**
Reads the @c Format_description_log_event from the beginning of the Reads the @c Format_description_log_event from the beginning of a
input file. local input file.
The @c Format_description_log_event is only read if it is outside The @c Format_description_log_event is only read if it is outside
the range specified with @c --start-position; otherwise, it will be the range specified with @c --start-position; otherwise, it will be
...@@ -1382,32 +1626,42 @@ err: ...@@ -1382,32 +1626,42 @@ err:
@param file The file to which a @c Format_description_log_event will @param file The file to which a @c Format_description_log_event will
be printed. be printed.
@param description_event Pointer to the global @c @param[in,out] print_event_info Parameters and context state
Format_description_log_event pointer. This will be updated if a new determining how to print.
Format_description_log_event is found.
@param[in] logname Name of input binlog.
@param print_event_info Context state needed to print events. @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, static Exit_status check_header(IO_CACHE* file,
Format_description_log_event **description_event, PRINT_EVENT_INFO *print_event_info,
PRINT_EVENT_INFO *print_event_info) const char* logname)
{ {
uchar header[BIN_LOG_HEADER_SIZE]; uchar header[BIN_LOG_HEADER_SIZE];
uchar buf[PROBE_HEADER_LEN]; uchar buf[PROBE_HEADER_LEN];
my_off_t tmp_pos, pos; 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); pos= my_b_tell(file);
my_b_seek(file, (my_off_t)0); my_b_seek(file, (my_off_t)0);
if (my_b_read(file, header, sizeof(header))) if (my_b_read(file, header, sizeof(header)))
{ {
delete *description_event; error("Failed reading header; probably an empty file.");
die("Failed reading header; Probably an empty file"); return ERROR_STOP;
} }
if (memcmp(header, BINLOG_MAGIC, sizeof(header))) if (memcmp(header, BINLOG_MAGIC, sizeof(header)))
{ {
delete *description_event; error("File is not a binary log file.");
die("File is not a binary log file"); return ERROR_STOP;
} }
/* /*
...@@ -1430,10 +1684,9 @@ static void check_header(IO_CACHE* file, ...@@ -1430,10 +1684,9 @@ static void check_header(IO_CACHE* file,
{ {
if (file->error) if (file->error)
{ {
delete *description_event; error("Could not read entry at offset %llu: "
die("\ "Error in log format or read error.", (ulonglong)tmp_pos);
Could not read entry at offset %lu : Error in log format or read error", return ERROR_STOP;
tmp_pos);
} }
/* /*
Otherwise this is just EOF : this log currently contains 0-2 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", ...@@ -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)) (LOG_EVENT_MINIMAL_HEADER_LEN + START_V3_HEADER_LEN))
{ {
/* This is 3.23 (format 1) */ /* This is 3.23 (format 1) */
delete *description_event; delete glob_description_event;
*description_event= new Format_description_log_event(1); if (!(glob_description_event= new Format_description_log_event(1)))
{
error("Failed creating Format_description_log_event; "
"out of memory?");
return ERROR_STOP;
}
} }
break; break;
} }
...@@ -1476,26 +1734,32 @@ Could not read entry at offset %lu : Error in log format or read error", ...@@ -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; Format_description_log_event *new_description_event;
my_b_seek(file, tmp_pos); /* seek back to event's start */ my_b_seek(file, tmp_pos); /* seek back to event's start */
if (!(new_description_event= (Format_description_log_event*) 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 */ /* EOF can't be hit here normally, so it's a real error */
{ {
delete *description_event; error("Could not read a Format_description_log_event event at "
die("Could not read a Format_description_log_event event \ "offset %llu; this could be a log format error or read error.",
at offset %lu ; this could be a log format error or read error", (ulonglong)tmp_pos);
tmp_pos); return ERROR_STOP;
} }
if (opt_base64_output_mode == BASE64_OUTPUT_AUTO if (opt_base64_output_mode == BASE64_OUTPUT_AUTO
|| opt_base64_output_mode == BASE64_OUTPUT_ALWAYS) || opt_base64_output_mode == BASE64_OUTPUT_ALWAYS)
{
/* /*
process_event will delete *description_event and set it to process_event will delete *description_event and set it to
the new one, so we should not do it ourselves in this the new one, so we should not do it ourselves in this
case. 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 else
{ {
delete *description_event; delete glob_description_event;
*description_event= new_description_event; glob_description_event= new_description_event;
} }
DBUG_PRINT("info",("Setting 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", ...@@ -1503,12 +1767,13 @@ at offset %lu ; this could be a log format error or read error",
{ {
Log_event *ev; Log_event *ev;
my_b_seek(file, tmp_pos); /* seek back to event's start */ my_b_seek(file, tmp_pos); /* seek back to event's start */
if (!(ev= Log_event::read_log_event(file, *description_event))) if (!(ev= 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; /* EOF can't be hit here normally, so it's a real error */
die("Could not read a Rotate_log_event event at offset %lu ;" error("Could not read a Rotate_log_event event at offset %llu;"
" this could be a log format error or read error", tmp_pos); " this could be a log format error or read error.",
(ulonglong)tmp_pos);
return ERROR_STOP;
} }
delete ev; delete ev;
} }
...@@ -1517,31 +1782,48 @@ at offset %lu ; this could be a log format error or read error", ...@@ -1517,31 +1782,48 @@ at offset %lu ; this could be a log format error or read error",
} }
} }
my_b_seek(file, pos); my_b_seek(file, pos);
return OK_CONTINUE;
} }
static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, /**
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) const char* logname)
{ {
File fd = -1; File fd = -1;
IO_CACHE cache,*file= &cache; IO_CACHE cache,*file= &cache;
uchar tmp_buff[BIN_LOG_HEADER_SIZE]; uchar tmp_buff[BIN_LOG_HEADER_SIZE];
int error= 0; Exit_status retval= OK_CONTINUE;
if (logname && strcmp(logname, "-") != 0) if (logname && strcmp(logname, "-") != 0)
{ {
/* read from normal file */
if ((fd = my_open(logname, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0) 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, if (init_io_cache(file, fd, 0, READ_CACHE, start_position_mot, 0,
MYF(MY_WME | MY_NABP))) MYF(MY_WME | MY_NABP)))
{ {
my_close(fd, MYF(MY_WME)); 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 Windows opens stdin in text mode by default. Certain characters
such as CTRL-Z are interpeted as events and the read() method 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, ...@@ -1553,14 +1835,18 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
#if defined (__WIN__) || (_WIN64) #if defined (__WIN__) || (_WIN64)
if (_setmode(fileno(stdin), O_BINARY) == -1) if (_setmode(fileno(stdin), O_BINARY) == -1)
{ {
fprintf(stderr, "Could not set binary mode on stdin.\n"); error("Could not set binary mode on stdin.");
return 1; return ERROR_STOP;
} }
#endif #endif
if (init_io_cache(file, fileno(stdin), 0, READ_CACHE, (my_off_t) 0, if (init_io_cache(file, fileno(stdin), 0, READ_CACHE, (my_off_t) 0,
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE))) 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) if (start_position)
{ {
/* skip 'start_position' characters from stdin */ /* skip 'start_position' characters from stdin */
...@@ -1571,8 +1857,8 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, ...@@ -1571,8 +1857,8 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
tmp=min(length,sizeof(buff)); tmp=min(length,sizeof(buff));
if (my_b_read(file, buff, (uint) tmp)) if (my_b_read(file, buff, (uint) tmp))
{ {
error= 1; error("Failed reading from file.");
goto end; goto err;
} }
} }
} }
...@@ -1580,14 +1866,14 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, ...@@ -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()) if (!glob_description_event || !glob_description_event->is_valid())
{ {
delete glob_description_event; error("Invalid Format_description log event; could be out of memory.");
die("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)) if (!start_position && my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE))
{ {
error= 1; error("Failed reading from file.");
goto end; goto err;
} }
for (;;) for (;;)
{ {
...@@ -1605,36 +1891,36 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, ...@@ -1605,36 +1891,36 @@ static int dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
file->error= 0; file->error= 0;
else if (file->error) else if (file->error)
{ {
fprintf(stderr, error("Could not read entry at offset %s: "
"Could not read entry at offset %s:" "Error in log format or read error.",
"Error in log format or read error\n",
llstr(old_off,llbuff)); llstr(old_off,llbuff));
error= 1; goto err;
} }
// file->error == 0 means EOF, that's OK, we break in this case // file->error == 0 means EOF, that's OK, we break in this case
break; goto end;
}
if ((error= process_event(print_event_info, ev, old_off)))
{
if (error < 0)
error= 0;
break;
} }
if ((retval= process_event(print_event_info, ev, old_off, logname)) !=
OK_CONTINUE)
goto end;
} }
/* NOTREACHED */
err:
retval= ERROR_STOP;
end: end:
if (fd >= 0) if (fd >= 0)
my_close(fd, MYF(MY_WME)); my_close(fd, MYF(MY_WME));
end_io_cache(file); end_io_cache(file);
delete glob_description_event; return retval;
return error;
} }
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
char **defaults_argv; char **defaults_argv;
int exit_value= 0; Exit_status retval= OK_CONTINUE;
ulonglong save_stop_position; ulonglong save_stop_position;
MY_INIT(argv[0]); MY_INIT(argv[0]);
DBUG_ENTER("main"); DBUG_ENTER("main");
...@@ -1696,15 +1982,13 @@ int main(int argc, char** argv) ...@@ -1696,15 +1982,13 @@ int main(int argc, char** argv)
"\n/*!40101 SET NAMES %s */;\n", charset); "\n/*!40101 SET NAMES %s */;\n", charset);
for (save_stop_position= stop_position, stop_position= ~(my_off_t)0 ; 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 if (argc == 0) // last log, --stop-position applies
stop_position= save_stop_position; stop_position= save_stop_position;
if (dump_log_entries(*(argv++))) if ((retval= dump_log_entries(*argv++)) != OK_CONTINUE)
{
exit_value=1;
break; break;
}
// For next log, --start-position does not apply // For next log, --start-position does not apply
start_position= BIN_LOG_HEADER_SIZE; start_position= BIN_LOG_HEADER_SIZE;
} }
...@@ -1736,17 +2020,9 @@ int main(int argc, char** argv) ...@@ -1736,17 +2020,9 @@ int main(int argc, char** argv)
/* We cannot free DBUG, it is used in global destructors after exit(). */ /* We cannot free DBUG, it is used in global destructors after exit(). */
my_end(my_end_arg | MY_DONT_FREE_DBUG); my_end(my_end_arg | MY_DONT_FREE_DBUG);
if (file_not_closed_error) exit(retval == ERROR_STOP ? 1 : 0);
{ /* Keep compilers happy. */
fprintf(stderr, DBUG_RETURN(retval == ERROR_STOP ? 1 : 0);
"\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
} }
/* /*
......
...@@ -434,13 +434,15 @@ enum ha_base_keytype { ...@@ -434,13 +434,15 @@ enum ha_base_keytype {
#define HA_ERR_RECORD_IS_THE_SAME 169 #define HA_ERR_RECORD_IS_THE_SAME 169
/* It is not possible to log this statement */ /* It is not possible to log this statement */
#define HA_ERR_LOGGING_IMPOSSIBLE 170 #define HA_ERR_LOGGING_IMPOSSIBLE 170
#define HA_ERR_CORRUPT_EVENT 171 /* The event was corrupt, leading to #define HA_ERR_CORRUPT_EVENT 171 /* The event was corrupt, leading to */
illegal data being read */ /* illegal data being read */
#define HA_ERR_NEW_FILE 172 /* New file format */ #define HA_ERR_NEW_FILE 172 /* New file format */
#define HA_ERR_INITIALIZATION 173 /* Error during initialization */ #define HA_ERR_INITIALIZATION 173 /* Error during initialization */
#define HA_ERR_FILE_TOO_SHORT 174 /* File too short */ #define HA_ERR_FILE_TOO_SHORT 174 /* File too short */
#define HA_ERR_WRONG_CRC 175 /* Wrong CRC on page */ #define HA_ERR_WRONG_CRC 175 /* Wrong CRC on page */
#define HA_ERR_LAST 175 /* Copy of last error nr */ #define HA_ERR_ROWS_EVENT_APPLY 176 /* The event could not be processed */
/* no other hanlder error happened */
#define HA_ERR_LAST 176 /* Copy of last error nr */
/* Number of different errors */ /* Number of different errors */
#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1) #define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1)
......
...@@ -342,5 +342,6 @@ SHOW CREATE TABLE t1; ...@@ -342,5 +342,6 @@ SHOW CREATE TABLE t1;
--echo --- Do Cleanup --- --echo --- Do Cleanup ---
DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t1;
sync_slave_with_master;
# End of 5.1 test case # End of 5.1 test case
...@@ -46,7 +46,7 @@ ALTER TABLE t1_bit ...@@ -46,7 +46,7 @@ ALTER TABLE t1_bit
ALTER TABLE t1_char ADD x CHAR(20) DEFAULT 'Just a test'; ALTER TABLE t1_char ADD x CHAR(20) DEFAULT 'Just a test';
# ... and add one non-nullable INT column last in table 't1_text' # ... and add one non-nullable INT column last in table 't1_text'
# with no default, # 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 # ... and remove the last column in t2
ALTER TABLE t2 DROP b; ALTER TABLE t2 DROP b;
# ... change the type of the single column in table 't4' # ... change the type of the single column in table 't4'
...@@ -222,8 +222,8 @@ sync_slave_with_master; ...@@ -222,8 +222,8 @@ sync_slave_with_master;
--echo **** On Slave **** --echo **** On Slave ****
connection slave; connection slave;
INSERT INTO t1_nodef VALUES (1,2,3); INSERT INTO t1_nodef VALUES (1,2,3,4,5);
INSERT INTO t1_nodef VALUES (2,4,6); INSERT INTO t1_nodef VALUES (2,4,6,8,10);
--echo **** On Master **** --echo **** On Master ****
connection master; connection master;
......
...@@ -3898,14 +3898,6 @@ sub mysqld_arguments ($$$$) { ...@@ -3898,14 +3898,6 @@ sub mysqld_arguments ($$$$) {
mtr_add_arg($args, "%s--user=root"); mtr_add_arg($args, "%s--user=root");
} }
# When mysqld is run by a root user(euid is 0), it will fail
# to start unless we specify what user to run as, see BUG#30630
my $euid= $>;
if (!$glob_win32 and $euid == 0 and
(grep(/^--user/, @$extra_opt, @opt_extra_mysqld_opt)) == 0) {
mtr_add_arg($args, "%s--user=root", $prefix);
}
if ( $opt_valgrind_mysqld ) if ( $opt_valgrind_mysqld )
{ {
mtr_add_arg($args, "%s--skip-safemalloc", $prefix); mtr_add_arg($args, "%s--skip-safemalloc", $prefix);
......
...@@ -40,8 +40,13 @@ SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.uniq ...@@ -40,8 +40,13 @@ SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.uniq
SET @@session.sql_mode=0/*!*/; SET @@session.sql_mode=0/*!*/;
/*!\C latin1 *//*!*/; /*!\C latin1 *//*!*/;
SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/; 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 # 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 ==== ==== Test non-matching FD event and Row event ====
BINLOG ' BINLOG '
4CdYRw8BAAAAYgAAAGYAAAAAAAQANS4xLjE1LW5kYi02LjEuMjQtZGVidWctbG9nAAAAAAAAAAAA 4CdYRw8BAAAAYgAAAGYAAAAAAAQANS4xLjE1LW5kYi02LjEuMjQtZGVidWctbG9nAAAAAAAAAAAA
......
...@@ -29,6 +29,16 @@ SELECT COUNT(*) FROM t3; ...@@ -29,6 +29,16 @@ SELECT COUNT(*) FROM t3;
COUNT(*) COUNT(*)
17920 17920
DROP TABLE t1, t2, t3; 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) ==== ==== Read binlog from alcatel tree (mysql-5.1-wl2325-5.0-drop6) ====
SELECT * FROM t1 ORDER BY a; SELECT * FROM t1 ORDER BY a;
a b a b
......
...@@ -6,6 +6,10 @@ ...@@ -6,6 +6,10 @@
# See also BUG#32407. # 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 # 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-telco-6.1 tree, specifically at the tag
# mysql-5.1.15-ndb-6.1.23, and applies it to the database. The test # mysql-5.1.15-ndb-6.1.23, and applies it to the database. The test
...@@ -15,7 +19,7 @@ ...@@ -15,7 +19,7 @@
# The binlog contains row events equivalent to: # The binlog contains row events equivalent to:
# CREATE TABLE t1 (a int) engine = myisam # CREATE TABLE t1 (a int) engine = myisam
# INSERT INTO t1 VALUES (1), (1) # 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 # The above line should succeed and t1 should contain two ones
select * from t1; select * from t1;
...@@ -68,7 +72,7 @@ select * from t1; ...@@ -68,7 +72,7 @@ select * from t1;
# mysqlbinlog should fail # mysqlbinlog should fail
--replace_regex /#[0-9][0-9][0-9][0-9][0-9][0-9] .*/#/ --replace_regex /#[0-9][0-9][0-9][0-9][0-9][0-9] .*/#/
error 1; 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 # 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 ...@@ -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 ==== --echo ==== Test non-matching FD event and Row event ====
# This is the Format_description_log_event from # 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) # row events (number of event types is 22)
BINLOG ' BINLOG '
4CdYRw8BAAAAYgAAAGYAAAAAAAQANS4xLjE1LW5kYi02LjEuMjQtZGVidWctbG9nAAAAAAAAAAAA 4CdYRw8BAAAAYgAAAGYAAAAAAAQANS4xLjE1LW5kYi02LjEuMjQtZGVidWctbG9nAAAAAAAAAAAA
......
...@@ -39,7 +39,7 @@ connection con2; ...@@ -39,7 +39,7 @@ connection con2;
reap; reap;
let $rows= `select count(*) from t2 /* must be 2 or 0 */`; 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 --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval select eval select
(@a:=load_file("$MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog")) (@a:=load_file("$MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog"))
...@@ -250,7 +250,7 @@ source include/show_binlog_events.inc; ...@@ -250,7 +250,7 @@ source include/show_binlog_events.inc;
# a proof the query is binlogged with an error # 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 --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval select eval select
(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) (@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
...@@ -296,7 +296,7 @@ source include/show_binlog_events.inc; ...@@ -296,7 +296,7 @@ source include/show_binlog_events.inc;
# a proof the query is binlogged with an error # 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 --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval select eval select
(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) (@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
......
...@@ -23,7 +23,7 @@ update t1 set a=2 /* will be "killed" after work has been done */; ...@@ -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 #todo: introduce a suite private macro that provides numeric values
# for some constants like the offset of the first real event # for some constants like the offset of the first real event
# that is different between severs versions. # 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 --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval select eval select
(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) (@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 ...@@ -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; 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 --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval select eval select
(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) (@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
......
...@@ -31,7 +31,7 @@ DROP TABLE IF EXISTS t1, t2, t3; ...@@ -31,7 +31,7 @@ DROP TABLE IF EXISTS t1, t2, t3;
--echo ==== Read modern binlog (version 5.1.23) ==== --echo ==== Read modern binlog (version 5.1.23) ====
# Read binlog. # 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. # Show result.
SELECT * FROM t1 ORDER BY a; SELECT * FROM t1 ORDER BY a;
SELECT * FROM t2 ORDER BY a; SELECT * FROM t2 ORDER BY a;
...@@ -43,7 +43,7 @@ DROP TABLE t1, t2, t3; ...@@ -43,7 +43,7 @@ DROP TABLE t1, t2, t3;
--echo ==== Read binlog from version 5.1.17 ==== --echo ==== Read binlog from version 5.1.17 ====
# Read binlog. # 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. # Show result.
SELECT * FROM t1 ORDER BY a; SELECT * FROM t1 ORDER BY a;
SELECT * FROM t2 ORDER BY a; SELECT * FROM t2 ORDER BY a;
...@@ -52,6 +52,21 @@ SELECT COUNT(*) FROM t3; ...@@ -52,6 +52,21 @@ SELECT COUNT(*) FROM t3;
DROP TABLE t1, t2, 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) ==== --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 # In this version, it was not possible to switch between row-based and
...@@ -60,9 +75,9 @@ DROP TABLE t1, t2, t3; ...@@ -60,9 +75,9 @@ DROP TABLE t1, t2, t3;
# replication. # replication.
# Read rbr binlog. # 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. # 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. # Show result.
SELECT * FROM t1 ORDER BY a; SELECT * FROM t1 ORDER BY a;
SELECT * FROM t2 ORDER BY a; SELECT * FROM t2 ORDER BY a;
...@@ -74,7 +89,7 @@ DROP TABLE t1, t2, t3; ...@@ -74,7 +89,7 @@ DROP TABLE t1, t2, t3;
--echo ==== Read binlog from ndb tree (mysql-5.1-telco-6.1) ==== --echo ==== Read binlog from ndb tree (mysql-5.1-telco-6.1) ====
# Read binlog. # 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. # Show resulting tablea.
SELECT * FROM t1 ORDER BY a; SELECT * FROM t1 ORDER BY a;
SELECT * FROM t2 ORDER BY a; SELECT * FROM t2 ORDER BY a;
......
...@@ -10,4 +10,3 @@ ...@@ -10,4 +10,3 @@
# #
############################################################################## ##############################################################################
binlog_multi_engine : Bug#32663 binlog_multi_engine.test fails randomly 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.
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;
# Bug#12691: Exec_master_log_pos corrupted with SQL_SLAVE_SKIP_COUNTER
# Date: 01/31/2008
# Added: Serge Kozlov <skozlov@mysql.com>
--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
...@@ -12,13 +12,13 @@ load data infile 'MYSQLTEST_VARDIR/tmp/bug30435_5k.txt' into table t2; ...@@ -12,13 +12,13 @@ load data infile 'MYSQLTEST_VARDIR/tmp/bug30435_5k.txt' into table t2;
select count(*) from t2 /* 5 000 */; select count(*) from t2 /* 5 000 */;
count(*) count(*)
5000 5000
show binlog events in 'master-bin.000002' from 106; show binlog events in 'master-bin.000002' from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info 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 # Query # # 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 # Begin_load_query # # ;file_id=#;block_len=#
master-bin.000002 8444 Append_block 1 # ;file_id=#;block_len=8192 master-bin.000002 # Append_block # # ;file_id=#;block_len=#
master-bin.000002 16659 Append_block 1 # ;file_id=#;block_len=7509 master-bin.000002 # Append_block # # ;file_id=#;block_len=#
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 # 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 */; select count(*) from t2 /* 5 000 */;
count(*) count(*)
5000 5000
......
...@@ -26,7 +26,7 @@ ADD x BIT(3) DEFAULT b'011', ...@@ -26,7 +26,7 @@ ADD x BIT(3) DEFAULT b'011',
ADD y BIT(5) DEFAULT b'10101', ADD y BIT(5) DEFAULT b'10101',
ADD z BIT(2) DEFAULT b'10'; ADD z BIT(2) DEFAULT b'10';
ALTER TABLE t1_char ADD x CHAR(20) DEFAULT 'Just a test'; 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 t2 DROP b;
ALTER TABLE t4 MODIFY a FLOAT; ALTER TABLE t4 MODIFY a FLOAT;
ALTER TABLE t5 MODIFY b FLOAT; ALTER TABLE t5 MODIFY b FLOAT;
...@@ -393,8 +393,8 @@ INSERT INTO t1_nodef VALUES (1,2); ...@@ -393,8 +393,8 @@ INSERT INTO t1_nodef VALUES (1,2);
INSERT INTO t1_nodef VALUES (2,4); INSERT INTO t1_nodef VALUES (2,4);
SET SQL_LOG_BIN=1; SET SQL_LOG_BIN=1;
**** On Slave **** **** On Slave ****
INSERT INTO t1_nodef VALUES (1,2,3); INSERT INTO t1_nodef VALUES (1,2,3,4,5);
INSERT INTO t1_nodef VALUES (2,4,6); INSERT INTO t1_nodef VALUES (2,4,6,8,10);
**** On Master **** **** On Master ****
UPDATE t1_nodef SET b=2*b WHERE a=1; UPDATE t1_nodef SET b=2*b WHERE a=1;
SELECT * FROM t1_nodef ORDER BY a; SELECT * FROM t1_nodef ORDER BY a;
...@@ -403,9 +403,9 @@ a b ...@@ -403,9 +403,9 @@ a b
2 4 2 4
**** On Slave **** **** On Slave ****
SELECT * FROM t1_nodef ORDER BY a; SELECT * FROM t1_nodef ORDER BY a;
a b x a b x y z
1 4 3 1 4 3 4 5
2 4 6 2 4 6 8 10
**** On Master **** **** On Master ****
DELETE FROM t1_nodef WHERE a=2; DELETE FROM t1_nodef WHERE a=2;
SELECT * FROM t1_nodef ORDER BY a; SELECT * FROM t1_nodef ORDER BY a;
...@@ -413,8 +413,8 @@ a b ...@@ -413,8 +413,8 @@ a b
1 4 1 4
**** On Slave **** **** On Slave ****
SELECT * FROM t1_nodef ORDER BY a; SELECT * FROM t1_nodef ORDER BY a;
a b x a b x y z
1 4 3 1 4 3 4 5
**** Cleanup **** **** Cleanup ****
DROP TABLE IF EXISTS t1_int,t1_bit,t1_char,t1_nodef; DROP TABLE IF EXISTS t1_int,t1_bit,t1_char,t1_nodef;
DROP TABLE IF EXISTS t2,t3,t4,t5,t6,t7,t8,t9; DROP TABLE IF EXISTS t2,t3,t4,t5,t6,t7,t8,t9;
......
...@@ -26,7 +26,7 @@ ADD x BIT(3) DEFAULT b'011', ...@@ -26,7 +26,7 @@ ADD x BIT(3) DEFAULT b'011',
ADD y BIT(5) DEFAULT b'10101', ADD y BIT(5) DEFAULT b'10101',
ADD z BIT(2) DEFAULT b'10'; ADD z BIT(2) DEFAULT b'10';
ALTER TABLE t1_char ADD x CHAR(20) DEFAULT 'Just a test'; 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 t2 DROP b;
ALTER TABLE t4 MODIFY a FLOAT; ALTER TABLE t4 MODIFY a FLOAT;
ALTER TABLE t5 MODIFY b FLOAT; ALTER TABLE t5 MODIFY b FLOAT;
...@@ -393,8 +393,8 @@ INSERT INTO t1_nodef VALUES (1,2); ...@@ -393,8 +393,8 @@ INSERT INTO t1_nodef VALUES (1,2);
INSERT INTO t1_nodef VALUES (2,4); INSERT INTO t1_nodef VALUES (2,4);
SET SQL_LOG_BIN=1; SET SQL_LOG_BIN=1;
**** On Slave **** **** On Slave ****
INSERT INTO t1_nodef VALUES (1,2,3); INSERT INTO t1_nodef VALUES (1,2,3,4,5);
INSERT INTO t1_nodef VALUES (2,4,6); INSERT INTO t1_nodef VALUES (2,4,6,8,10);
**** On Master **** **** On Master ****
UPDATE t1_nodef SET b=2*b WHERE a=1; UPDATE t1_nodef SET b=2*b WHERE a=1;
SELECT * FROM t1_nodef ORDER BY a; SELECT * FROM t1_nodef ORDER BY a;
...@@ -403,9 +403,9 @@ a b ...@@ -403,9 +403,9 @@ a b
2 4 2 4
**** On Slave **** **** On Slave ****
SELECT * FROM t1_nodef ORDER BY a; SELECT * FROM t1_nodef ORDER BY a;
a b x a b x y z
1 4 3 1 4 3 4 5
2 4 6 2 4 6 8 10
**** On Master **** **** On Master ****
DELETE FROM t1_nodef WHERE a=2; DELETE FROM t1_nodef WHERE a=2;
SELECT * FROM t1_nodef ORDER BY a; SELECT * FROM t1_nodef ORDER BY a;
...@@ -413,8 +413,8 @@ a b ...@@ -413,8 +413,8 @@ a b
1 4 1 4
**** On Slave **** **** On Slave ****
SELECT * FROM t1_nodef ORDER BY a; SELECT * FROM t1_nodef ORDER BY a;
a b x a b x y z
1 4 3 1 4 3 4 5
**** Cleanup **** **** Cleanup ****
DROP TABLE IF EXISTS t1_int,t1_bit,t1_char,t1_nodef; DROP TABLE IF EXISTS t1_int,t1_bit,t1_char,t1_nodef;
DROP TABLE IF EXISTS t2,t3,t4,t5,t6,t7,t8,t9; DROP TABLE IF EXISTS t2,t3,t4,t5,t6,t7,t8,t9;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
# BUG#33413 show binlog events fails if binlog has event size of close # BUG#33413 show binlog events fails if binlog has event size of close
# to max_allowed_packet # to max_allowed_packet
source include/have_binlog_format_mixed_or_statement.inc;
source include/master-slave.inc; source include/master-slave.inc;
source include/have_innodb.inc; source include/have_innodb.inc;
source include/have_binlog_format_mixed_or_statement.inc; source include/have_binlog_format_mixed_or_statement.inc;
...@@ -35,9 +36,9 @@ select count(*) from t2 /* 5 000 */; ...@@ -35,9 +36,9 @@ select count(*) from t2 /* 5 000 */;
# the binglog will show fragmented Append_block events # the binglog will show fragmented Append_block events
--let $binlog_start=106 --let $binlog_start=106
--replace_column 5 # --replace_column 2 # 4 # 5 #
--replace_regex /\/\* xid=.* \*\//\/* XID *\// /file_id=[0-9]+/file_id=#/ --replace_regex /\/\* xid=.* \*\//\/* XID *\// /file_id=[0-9]+/file_id=#/ /block_len=[0-9]+/block_len=#/
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR $binlog_start <binlog_start>
--eval show binlog events in 'master-bin.000002' from $binlog_start --eval show binlog events in 'master-bin.000002' from $binlog_start
......
...@@ -99,12 +99,23 @@ static const char *HA_ERR(int i) ...@@ -99,12 +99,23 @@ static const char *HA_ERR(int i)
case HA_ERR_RECORD_IS_THE_SAME: return "HA_ERR_RECORD_IS_THE_SAME"; 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_LOGGING_IMPOSSIBLE: return "HA_ERR_LOGGING_IMPOSSIBLE";
case HA_ERR_CORRUPT_EVENT: return "HA_ERR_CORRUPT_EVENT"; case HA_ERR_CORRUPT_EVENT: return "HA_ERR_CORRUPT_EVENT";
case HA_ERR_ROWS_EVENT_APPLY : return "HA_ERR_ROWS_EVENT_APPLY";
} }
return 0; 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, static void inline slave_rows_error_report(enum loglevel level, int ha_error,
Relay_log_info const *rli, THD *thd, Relay_log_info const *rli, THD *thd,
...@@ -112,14 +123,27 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error, ...@@ -112,14 +123,27 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error,
const char *log_name, ulong pos) 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<MYSQL_ERROR> 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, rli->report(level, thd->net.client_last_errno,
"Could not execute %s event on table %s.%s;" "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", "the event's master log %s, end_log_pos %lu",
type, table->s->db.str, type, table->s->db.str,
table->s->table_name.str, table->s->table_name.str,
thd->net.client_last_error[0] != 0 ? thd->net.client_last_error : "", buff,
thd->net.client_last_error[0] != 0 ? ";" : "",
handler_error == NULL? "<unknown>" : handler_error, handler_error == NULL? "<unknown>" : handler_error,
log_name, pos); log_name, pos);
} }
...@@ -212,9 +236,9 @@ uint debug_not_change_ts_if_art_event= 1; // bug#29309 simulation ...@@ -212,9 +236,9 @@ uint debug_not_change_ts_if_art_event= 1; // bug#29309 simulation
*/ */
#ifdef MYSQL_CLIENT #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, "\'"); my_b_printf(cache, "\'");
while (str < end) while (str < end)
{ {
...@@ -277,9 +301,9 @@ inline int ignored_error_code(int err_code) ...@@ -277,9 +301,9 @@ inline int ignored_error_code(int err_code)
*/ */
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) #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; char *pos= packet;
*pos++= '\''; *pos++= '\'';
while (str < end) while (str < end)
...@@ -385,7 +409,7 @@ static void cleanup_load_tmpdir() ...@@ -385,7 +409,7 @@ static void cleanup_load_tmpdir()
write_str() 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]; uchar tmp[1];
tmp[0]= (uchar) length; tmp[0]= (uchar) length;
...@@ -2957,18 +2981,63 @@ Format_description_log_event(const char* buf, ...@@ -2957,18 +2981,63 @@ Format_description_log_event(const char* buf,
If post_header_len is null, it means malloc failed, and is_valid If post_header_len is null, it means malloc failed, and is_valid
will fail, so there is no need to do anything. will fail, so there is no need to do anything.
The trees which have wrong event id's are: The trees in which events have wrong 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 mysql-5.1-wl1012.old mysql-5.1-wl2325-5.0-drop6p13-alpha
BEGIN_LOAD_QUERY_EVENT /home/bk/ * /sql/log_event.h`). The mysql-5.1-wl2325-5.0-drop6 mysql-5.1-wl2325-5.0
corresponding version (`grep mysql, configure.in` in those trees) mysql-5.1-wl2325-no-dd
strings are 5.2.2-a_drop6p13-alpha, 5.2.2-a_drop6p13c,
5.1.5-a_drop5p20, 5.1.2-a_drop5p5. (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 && if (post_header_len &&
(strncmp(server_version, "5.1.2-a_drop5", 13) == 0 || server_version[0] == '5' && server_version[1] == '.' &&
strncmp(server_version, "5.1.5-a_drop5", 13) == 0 || server_version[3] == '.' &&
strncmp(server_version, "5.2.2-a_drop6", 13) == 0)) 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) if (number_of_event_types != 22)
{ {
...@@ -6026,7 +6095,8 @@ bool sql_ex_info::write_data(IO_CACHE* file) ...@@ -6026,7 +6095,8 @@ bool sql_ex_info::write_data(IO_CACHE* file)
sql_ex_info::init() 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; cached_new_format = use_new_format;
if (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) ...@@ -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 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. to read the actual file before we write out the Create_file event.
*/ */
const char *ptr= buf; if (read_str(&buf, buf_end, &field_term, &field_term_len) ||
if (read_str(&ptr, buf_end, (const char **) &field_term, &field_term_len) || read_str(&buf, buf_end, &enclosed, &enclosed_len) ||
read_str(&ptr, buf_end, (const char **) &enclosed, &enclosed_len) || read_str(&buf, buf_end, &line_term, &line_term_len) ||
read_str(&ptr, buf_end, (const char **) &line_term, &line_term_len) || read_str(&buf, buf_end, &line_start, &line_start_len) ||
read_str(&ptr, buf_end, (const char **) &line_start, &line_start_len) || read_str(&buf, buf_end, &escaped, &escaped_len))
read_str(&ptr, buf_end, (const char **) &escaped, &escaped_len))
return 0; return 0;
opt_flags = *buf++; opt_flags = *buf++;
} }
...@@ -7646,7 +7715,7 @@ Rows_log_event::write_row(const Relay_log_info *const rli, ...@@ -7646,7 +7715,7 @@ Rows_log_event::write_row(const Relay_log_info *const rli,
/* fill table->record[0] with default values */ /* 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 */))) TRUE /* check if columns have def. values */)))
DBUG_RETURN(error); DBUG_RETURN(error);
...@@ -7964,12 +8033,16 @@ int Rows_log_event::find_row(const Relay_log_info *rli) ...@@ -7964,12 +8033,16 @@ int Rows_log_event::find_row(const Relay_log_info *rli)
DBUG_ASSERT(m_table && m_table->in_use != NULL); DBUG_ASSERT(m_table && m_table->in_use != NULL);
TABLE *table= m_table; TABLE *table= m_table;
int error; int error= 0;
/* unpack row - missing fields get default values */ /*
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
*/
// TODO: shall we check and report errors here? prepare_record(table, m_width, FALSE);
prepare_record(NULL,table,m_width,FALSE /* don't check errors */);
error= unpack_current_row(rli); error= unpack_current_row(rli);
#ifndef DBUG_OFF #ifndef DBUG_OFF
......
...@@ -152,11 +152,11 @@ struct old_sql_ex ...@@ -152,11 +152,11 @@ struct old_sql_ex
struct sql_ex_info struct sql_ex_info
{ {
sql_ex_info() {} /* Remove gcc warning */ sql_ex_info() {} /* Remove gcc warning */
char* field_term; const char* field_term;
char* enclosed; const char* enclosed;
char* line_term; const char* line_term;
char* line_start; const char* line_start;
char* escaped; const char* escaped;
int cached_new_format; int cached_new_format;
uint8 field_term_len,enclosed_len,line_term_len,line_start_len, escaped_len; uint8 field_term_len,enclosed_len,line_term_len,line_start_len, escaped_len;
char opt_flags; char opt_flags;
...@@ -171,7 +171,7 @@ struct sql_ex_info ...@@ -171,7 +171,7 @@ struct sql_ex_info
line_start_len + escaped_len + 6 : 7); line_start_len + escaped_len + 6 : 7);
} }
bool write_data(IO_CACHE* file); 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() bool new_format()
{ {
return ((cached_new_format != -1) ? cached_new_format : return ((cached_new_format != -1) ? cached_new_format :
...@@ -667,34 +667,35 @@ typedef struct st_print_event_info ...@@ -667,34 +667,35 @@ typedef struct st_print_event_info
@section Log_event_binary_format Binary Format @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. components.
@li Common-Header * Common-Header
@li Post-Header * Post-Header
@li Body * Body
The Common-Header, documented below, always has the same form and The Common-Header, documented in the table @ref Table_common_header
length within one version of MySQL. Each event type specifies a "below", always has the same form and length within one version of
form and length of the Post-Header common to all events of the type. MySQL. Each event type specifies a form and length of the
The Body may be of different form and length even for different Post-Header common to all events of the type. The Body may be of
events of the same type. The binary formats of Post-Header and Body different form and length even for different events of the same
are documented separately in each subclass. The binary format of type. The binary formats of Post-Header and Body are documented
Common-Header is as follows. separately in each subclass. The binary format of Common-Header is
as follows.
<table> <table>
<caption>Common-Header</caption> <caption>Common-Header</caption>
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Format<br/></th> <th>Format</th>
<th>Description</th> <th>Description</th>
</tr> </tr>
<tr> <tr>
<td>timestamp</td> <td>timestamp</td>
<td>4 byte unsigned integer</td> <td>4 byte unsigned integer</td>
<td>The number of seconds since 1970. <td>The time when the query started, in seconds since 1970.
</td> </td>
</tr> </tr>
...@@ -705,14 +706,14 @@ typedef struct st_print_event_info ...@@ -705,14 +706,14 @@ typedef struct st_print_event_info
</tr> </tr>
<tr> <tr>
<td>master_id</td> <td>server_id</td>
<td>4 byte integer</td> <td>4 byte unsigned integer</td>
<td>Server ID of the server that created the event.</td> <td>Server ID of the server that created the event.</td>
</tr> </tr>
<tr> <tr>
<td>total_size</td> <td>total_size</td>
<td>4 byte integer</td> <td>4 byte unsigned integer</td>
<td>The total size of this event, in bytes. In other words, this <td>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. is the sum of the sizes of Common-Header, Post-Header, and Body.
</td> </td>
...@@ -720,9 +721,12 @@ typedef struct st_print_event_info ...@@ -720,9 +721,12 @@ typedef struct st_print_event_info
<tr> <tr>
<td>master_position</td> <td>master_position</td>
<td>4 byte integer</td> <td>4 byte unsigned integer</td>
<td>The position of the next event in the master binary log, in <td>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.
</td> </td>
</tr> </tr>
...@@ -736,13 +740,55 @@ 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 Summing up the numbers above, we see that the total size of the
common header is 19 bytes. 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-, 24-, 32-, or 64-bit numbers,
are stored in little endian, i.e., the least significant byte first,
unless otherwise specified.
@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:
<table>
<caption>Format of Packed Integer</caption>
<tr>
<th>First byte</th>
<th>Format</th>
</tr>
<tr>
<td>0-250</td>
<td>The first byte is the number (in range 0-250), and no more
bytes are used.</td>
</tr>
<tr>
<td>252</td>
<td>Two more bytes are used. The number is in the range
251-0xffff.</td>
</tr>
All numbers, whether they are 16-, 32-, or 64-bit, are stored in <tr>
little endian, i.e., the least significant byte first. <td>253</td>
<td>Three more bytes are used. The number is in the range
0xffff-0xffffff.</td>
</tr>
Strings are stored in various formats. The format of each string is <tr>
documented separately. <td>254</td>
<td>Eight more bytes are used. The number is in the range
0xffffff-0xffffffffffffffff.</td>
</tr>
</table>
- Strings are stored in various formats. The format of each string
is documented separately.
*/ */
class Log_event class Log_event
{ {
...@@ -1123,7 +1169,8 @@ protected: ...@@ -1123,7 +1169,8 @@ protected:
/** /**
@class Query_log_event @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 @section Query_log_event_binary_format Binary format
...@@ -1134,60 +1181,49 @@ protected: ...@@ -1134,60 +1181,49 @@ protected:
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Size<br/></th> <th>Format</th>
<th>Description</th> <th>Description</th>
</tr> </tr>
<tr> <tr>
<td>slave_proxy_id</td> <td>slave_proxy_id</td>
<td>4 byte unsigned integer</td> <td>4 byte unsigned integer</td>
<td>An integer identifying the client thread, which is unique on <td>An integer identifying the client thread that issued the
the server. (Note, however, that two threads on different servers query. The id is unique per server. (Note, however, that two
may have the same slave_proxy_id.) This is used when a client threads on different servers may have the same slave_proxy_id.)
thread creates a temporary table. Temporary tables are local to This is used when a client thread creates a temporary table local
the client, and the slave_proxy_id is used to distinguish to the client. The slave_proxy_id is used to distinguish
temporary tables belonging to different clients. temporary tables that belong to different clients.
</td> </td>
</tr> </tr>
<tr> <tr>
<td>exec_time</td> <td>exec_time</td>
<td>4 byte integer</td> <td>4 byte unsigned integer</td>
<td>???TODO</td> <td>The time from when the query started to when it was logged in
the binlog, in seconds.</td>
</tr> </tr>
<tr> <tr>
<td>db_len</td> <td>db_len</td>
<td>1 byte integer</td> <td>1 byte integer</td>
<td>The length of the name of the currently selected <td>The length of the name of the currently selected database.</td>
database.
</td>
</tr> </tr>
<tr> <tr>
<td>error_code</td> <td>error_code</td>
<td>2 byte integer</td> <td>2 byte unsigned integer</td>
<td>Error code generated by the master. If the master fails, the <td>Error code generated by the master. If the master fails, the
slave will fail with the same error code, except for the error 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.
</td> </td>
</tr> </tr>
<tr> <tr>
<td>status_vars_len</td> <td>status_vars_len</td>
<td>2 byte integer</td> <td>2 byte unsigned integer</td>
<td>The length of the status_vars block of the Body, in bytes. See <td>The length of the status_vars block of the Body, in bytes. See
<a href="#query_log_event_status_vars">below</a>. @ref query_log_event_status_vars "below".
</td>
</tr>
<tr>
<td>Post-Header-For-Derived</td>
<td>0 bytes</td>
<td>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.
</td> </td>
</tr> </tr>
</table> </table>
...@@ -1199,19 +1235,19 @@ protected: ...@@ -1199,19 +1235,19 @@ protected:
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Size<br/></th> <th>Format</th>
<th>Description</th> <th>Description</th>
</tr> </tr>
<tr> <tr>
<td><a name="query_log_event_status_vars" /> status_vars</td> <td>@anchor query_log_event_status_vars status_vars</td>
<td>variable length</td> <td>status_vars_len bytes</td>
<td>Zero or more status variables. Each status variable consists <td>Zero or more status variables. Each status variable consists
of one byte identifying the variable stored, followed by the value of one byte identifying the variable stored, followed by the value
of the variable. The possible variables are listed separately in of the variable. The possible variables are listed separately in
the table below. MySQL always writes events in the order defined the table @ref Table_query_log_event_status_vars "below". MySQL
below; however, it is capable of reading them in any order. always writes events in the order defined below; however, it is
</td> capable of reading them in any order. </td>
</tr> </tr>
<tr> <tr>
...@@ -1237,13 +1273,14 @@ protected: ...@@ -1237,13 +1273,14 @@ protected:
The following table lists the status variables that may appear in The following table lists the status variables that may appear in
the status_vars field. the status_vars field.
@anchor Table_query_log_event_status_vars
<table> <table>
<caption>Status variables for Query_log_event</caption> <caption>Status variables for Query_log_event</caption>
<tr> <tr>
<th>Status variable</th> <th>Status variable</th>
<th>1-byte identifier</th> <th>1 byte identifier</th>
<th>Size<br/></th> <th>Format</th>
<th>Description</th> <th>Description</th>
</tr> </tr>
...@@ -1251,13 +1288,13 @@ protected: ...@@ -1251,13 +1288,13 @@ protected:
<td>flags2</td> <td>flags2</td>
<td>Q_FLAGS2_CODE == 0</td> <td>Q_FLAGS2_CODE == 0</td>
<td>4 byte bitfield</td> <td>4 byte bitfield</td>
<td>The flags in thd->options, binary AND-ed with <td>The flags in @c thd->options, binary AND-ed with @c
OPTIONS_WRITTEN_TO_BIN_LOG. The thd->options bitfield contains OPTIONS_WRITTEN_TO_BIN_LOG. The @c thd->options bitfield contains
options for SELECT. OPTIONS_WRITTEN identifies those options that options for "SELECT". @c OPTIONS_WRITTEN identifies those options
need to be written to the binlog (not all do). Specifically, that need to be written to the binlog (not all do). Specifically,
OPTIONS_WRITTEN_TO_BIN_LOG equals (OPTION_AUTO_IS_NULL | @c OPTIONS_WRITTEN_TO_BIN_LOG equals (@c OPTION_AUTO_IS_NULL | @c
OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_RELAXED_UNIQUE_CHECKS | OPTION_NO_FOREIGN_KEY_CHECKS | @c OPTION_RELAXED_UNIQUE_CHECKS |
OPTION_NOT_AUTOCOMMIT), or 0x0c084000 in hex. @c OPTION_NOT_AUTOCOMMIT), or 0x0c084000 in hex.
These flags correspond to the SQL variables SQL_AUTO_IS_NULL, These flags correspond to the SQL variables SQL_AUTO_IS_NULL,
FOREIGN_KEY_CHECKS, UNIQUE_CHECKS, and AUTOCOMMIT, documented in FOREIGN_KEY_CHECKS, UNIQUE_CHECKS, and AUTOCOMMIT, documented in
...@@ -1271,8 +1308,8 @@ protected: ...@@ -1271,8 +1308,8 @@ protected:
<tr> <tr>
<td>sql_mode</td> <td>sql_mode</td>
<td>Q_SQL_MODE_CODE == 1</td> <td>Q_SQL_MODE_CODE == 1</td>
<td>8 byte integer</td> <td>8 byte bitfield</td>
<td>The sql_mode variable. See the section "SQL Modes" in the <td>The @c sql_mode variable. See the section "SQL Modes" in the
MySQL manual, and see mysql_priv.h for a list of the possible MySQL manual, and see mysql_priv.h for a list of the possible
flags. Currently (2007-10-04), the following flags are available: flags. Currently (2007-10-04), the following flags are available:
<pre> <pre>
...@@ -1310,10 +1347,10 @@ protected: ...@@ -1310,10 +1347,10 @@ protected:
MODE_PAD_CHAR_TO_FULL_LENGTH==0x80000000 MODE_PAD_CHAR_TO_FULL_LENGTH==0x80000000
</pre> </pre>
All these flags are replicated from the server. However, all All these flags are replicated from the server. However, all
flags except MODE_NO_DIR_IN_CREATE are honored by the slave; the flags except @c MODE_NO_DIR_IN_CREATE are honored by the slave;
slave always preserves its old value of MODE_NO_DIR_IN_CREATE. the slave always preserves its old value of @c
For a rationale, see comment in Query_log_event::do_apply_event in MODE_NO_DIR_IN_CREATE. For a rationale, see comment in
log_event.cc. @c Query_log_event::do_apply_event in @c log_event.cc.
This field is always written to the binlog. This field is always written to the binlog.
</td> </td>
...@@ -1327,7 +1364,7 @@ protected: ...@@ -1327,7 +1364,7 @@ protected:
</td> </td>
<td>Stores the client's current catalog. Every database belongs <td>Stores the client's current catalog. Every database belongs
to a catalog, the same way that every table belongs to a 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; This field is written if the length of the catalog is > 0;
otherwise it is not written. otherwise it is not written.
...@@ -1343,7 +1380,7 @@ protected: ...@@ -1343,7 +1380,7 @@ protected:
auto_increment_offset, in that order. For more information, see auto_increment_offset, in that order. For more information, see
"System variables" in the MySQL manual. "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. written.
</td> </td>
</tr> </tr>
...@@ -1351,14 +1388,14 @@ protected: ...@@ -1351,14 +1388,14 @@ protected:
<tr> <tr>
<td>charset</td> <td>charset</td>
<td>Q_CHARSET_CODE == 4</td> <td>Q_CHARSET_CODE == 4</td>
<td>three 2-byte unsigned integers (i.e., 6 bytes)</td> <td>three 2 byte unsigned integers, totally 2+2+2=6 bytes</td>
<td>The three variables character_set_client, <td>The three variables character_set_client,
collation_connection, and collation_server, in that order. 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 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 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 default character set and collation used when a new database is
created. created.
...@@ -1396,9 +1433,9 @@ protected: ...@@ -1396,9 +1433,9 @@ protected:
<td>Q_LC_TIME_NAMES_CODE == 7</td> <td>Q_LC_TIME_NAMES_CODE == 7</td>
<td>2 byte integer</td> <td>2 byte integer</td>
<td>A code identifying a table of month and day names. The <td>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. en_US.
</td> </td>
</tr> </tr>
...@@ -1409,14 +1446,14 @@ protected: ...@@ -1409,14 +1446,14 @@ protected:
<td>2 byte integer</td> <td>2 byte integer</td>
<td>The value of the collation_database system variable (in the <td>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 holds the code for a (character set, collation) pair as described
above (see Q_CHARSET_CODE). above (see Q_CHARSET_CODE).
`collation_database' was used in old versions (???WHEN). Its collation_database was used in old versions (???WHEN). Its value
value was loaded when issuing a "use db" command and could be was loaded when issuing a "use db" query and could be changed by
changed by issuing a "SET collation_database=xxx" command. It issuing a "SET collation_database=xxx" query. It used to affect
used to affect the "LOAD DATA INFILE" and "CREATE TABLE" commands. the "LOAD DATA INFILE" and "CREATE TABLE" commands.
In newer versions, "CREATE TABLE" has been changed to take the In newer versions, "CREATE TABLE" has been changed to take the
character set from the database of the created table, rather than character set from the database of the created table, rather than
...@@ -1433,17 +1470,17 @@ protected: ...@@ -1433,17 +1470,17 @@ protected:
@subsection Query_log_event_notes_on_previous_versions Notes on Previous Versions @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. 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 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 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 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 Q_CATALOG_CODE will never be written by a new master, but can still
be understood by a new slave. 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 class Query_log_event: public Log_event
...@@ -1576,7 +1613,8 @@ public: /* !!! Public in this patch to allow old usage */ ...@@ -1576,7 +1613,8 @@ public: /* !!! Public in this patch to allow old usage */
/** /**
@class Muted_query_log_event @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 @section Muted_query_log_event_binary_format Binary Format
...@@ -1603,7 +1641,7 @@ public: ...@@ -1603,7 +1641,7 @@ public:
@class Slave_log_event @class Slave_log_event
Note that this class is currently not used at all; no code writes a 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 Slave_log_event). So it's not a problem if this code is not
maintained. maintained.
...@@ -1617,7 +1655,7 @@ public: ...@@ -1617,7 +1655,7 @@ public:
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Size<br/></th> <th>Format</th>
<th>Description</th> <th>Description</th>
</tr> </tr>
...@@ -1717,26 +1755,27 @@ private: ...@@ -1717,26 +1755,27 @@ private:
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Size<br/></th> <th>Format</th>
<th>Description</th> <th>Description</th>
</tr> </tr>
<tr> <tr>
<td>slave_proxy_id</td> <td>slave_proxy_id</td>
<td>4 byte unsigned integer</td> <td>4 byte unsigned integer</td>
<td>An integer identifying the client thread, which is unique on <td>An integer identifying the client thread that issued the
the server. (Note, however, that the same slave_proxy_id may query. The id is unique per server. (Note, however, that two
appear on different servers.) This is used when a client thread threads on different servers may have the same slave_proxy_id.)
creates a temporary table. Temporary tables are local to the This is used when a client thread creates a temporary table local
client, and the slave_proxy_id is used to distinguish temporary to the client. The slave_proxy_id is used to distinguish
tables belonging to different clients. temporary tables that belong to different clients.
</td> </td>
</tr> </tr>
<tr> <tr>
<td>exec_time</td> <td>exec_time</td>
<td>4 byte unsigned integer</td> <td>4 byte unsigned integer</td>
<td>???TODO</td> <td>The time from when the query started to when it was logged in
the binlog, in seconds.</td>
</tr> </tr>
<tr> <tr>
...@@ -1773,7 +1812,7 @@ private: ...@@ -1773,7 +1812,7 @@ private:
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Size<br/></th> <th>Format</th>
<th>Description</th> <th>Description</th>
</tr> </tr>
...@@ -1813,7 +1852,7 @@ private: ...@@ -1813,7 +1852,7 @@ private:
<li> In the old format, we know that each string has length 0 or <li> 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 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 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. format. Finally, a 1 byte bitfield called empty_flags is stored.
The low 5 bits of empty_flags indicate which of the five strings 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 have length 0. For each of the following flags that is set, the
...@@ -1831,7 +1870,7 @@ private: ...@@ -1831,7 +1870,7 @@ private:
<tr> <tr>
<td>field_lens</td> <td>field_lens</td>
<td>num_fields 1-byte unsigned integers</td> <td>num_fields 1 byte unsigned integers</td>
<td>An array of num_fields integers representing the length of <td>An array of num_fields integers representing the length of
each field in the query. (num_fields is from the Post-Header). each field in the query. (num_fields is from the Post-Header).
</td> </td>
...@@ -1992,11 +2031,13 @@ extern char server_version[SERVER_VERSION_LENGTH]; ...@@ -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 Start_log_event_v3 is the Start_log_event of binlog format 3 (MySQL 3.23 and
4.x). 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 Format_description_log_event derives from Start_log_event_v3; it is
describes the other events' header/postheader lengths. This event is sent by the Start_log_event of binlog format 4 (MySQL 5.0), that is, the
MySQL 5.0 whenever it starts sending a new binlog if the requested position event that describes the other events' Common-Header/Post-Header
is >4 (otherwise if ==4 the event will be sent naturally). 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 @section Start_log_event_v3_binary_format Binary Format
*/ */
...@@ -2150,7 +2191,9 @@ protected: ...@@ -2150,7 +2191,9 @@ protected:
/** /**
@class Intvar_log_event @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 @section Intvar_log_event_binary_format Binary Format
...@@ -2161,12 +2204,12 @@ protected: ...@@ -2161,12 +2204,12 @@ protected:
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Size<br/></th> <th>Format</th>
<th>Description</th> <th>Description</th>
</tr> </tr>
<tr> <tr>
<td>Type</td> <td>type</td>
<td>1 byte enumeration</td> <td>1 byte enumeration</td>
<td>One byte identifying the type of variable stored. Currently, <td>One byte identifying the type of variable stored. Currently,
two identifiers are supported: LAST_INSERT_ID_EVENT==1 and two identifiers are supported: LAST_INSERT_ID_EVENT==1 and
...@@ -2182,7 +2225,6 @@ protected: ...@@ -2182,7 +2225,6 @@ protected:
</table> </table>
*/ */
class Intvar_log_event: public Log_event class Intvar_log_event: public Log_event
{ {
public: public:
...@@ -2228,15 +2270,34 @@ private: ...@@ -2228,15 +2270,34 @@ private:
written in 4.1.1 for PASSWORD() (but the fact that it is written is just a written in 4.1.1 for PASSWORD() (but the fact that it is written is just a
waste, it does not cause bugs). 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 @section Rand_log_event_binary_format Binary Format
This event type has no Post-Header. The Body of this event type has This event type has no Post-Header. The Body of this event type has
two components: two components:
@li seed1 (8 bytes): 64 bit random seed1. <table>
@li seed2 (8 bytes): 64 bit random seed2. <caption>Post-Header for Intvar_log_event</caption>
The state of the random number generation consists of 128 bits, <tr>
which are stored internally as two 64-bit numbers. <th>Name</th>
<th>Format</th>
<th>Description</th>
</tr>
<tr>
<td>seed1</td>
<td>8 byte unsigned integer</td>
<td>64 bit random seed1.</td>
</tr>
<tr>
<td>seed2</td>
<td>8 byte unsigned integer</td>
<td>64 bit random seed2.</td>
</tr>
</table>
*/ */
class Rand_log_event: public Log_event class Rand_log_event: public Log_event
...@@ -2423,14 +2484,14 @@ private: ...@@ -2423,14 +2484,14 @@ private:
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Size<br/></th> <th>Format</th>
<th>Description</th> <th>Description</th>
</tr> </tr>
<tr> <tr>
<td>pos</td> <td>position</td>
<td>8 byte integer</td> <td>8 byte integer</td>
<td>???TODO</td> <td>The position within the binlog to rotate to.</td>
</tr> </tr>
</table> </table>
...@@ -2442,17 +2503,17 @@ private: ...@@ -2442,17 +2503,17 @@ private:
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Size<br/></th> <th>Format</th>
<th>Description</th> <th>Description</th>
</tr> </tr>
<tr> <tr>
<td>new_log_ident</td> <td>new_log</td>
<td>variable length string without trailing zero, extending to the <td>variable length string without trailing zero, extending to the
end of the event (determined by the length field of the end of the event (determined by the length field of the
Common-Header) Common-Header)
</td> </td>
<td>???TODO</td> <td>Name of the binlog to rotate to.</td>
</tr> </tr>
</table> </table>
...@@ -2841,10 +2902,316 @@ char *str_to_hex(char *to, const char *from, uint len); ...@@ -2841,10 +2902,316 @@ char *str_to_hex(char *to, const char *from, uint len);
/** /**
@class Table_map_log_event @class Table_map_log_event
Create a mapping from a (database name, table name) couple to a table In row-based mode, every row operation event is preceded by a
identifier (an integer number). 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 @section Table_map_log_event_binary_format Binary Format
The Post-Header has the following components:
<table>
<caption>Post-Header for Table_map_log_event</caption>
<tr>
<th>Name</th>
<th>Format</th>
<th>Description</th>
</tr>
<tr>
<td>table_id</td>
<td>6 bytes unsigned integer</td>
<td>The number that identifies the table.</td>
</tr>
<tr>
<td>flags</td>
<td>2 byte bitfield</td>
<td>Reserved for future use; currently always 0.</td>
</tr>
</table>
The Body has the following components:
<table>
<caption>Body for Table_map_log_event</caption>
<tr>
<th>Name</th>
<th>Format</th>
<th>Description</th>
</tr>
<tr>
<td>database_name</td>
<td>one byte string length, followed by null-terminated string</td>
<td>The 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.) </td>
</tr>
<tr>
<td>table_name</td>
<td>one byte string length, followed by null-terminated string</td>
<td>The name of the table, encoded the same way as the database
name above.</td>
</tr>
<tr>
<td>column_count</td>
<td>@ref packed_integer "Packed Integer"</td>
<td>The number of columns in the table, represented as a packed
variable-length integer.</td>
</tr>
<tr>
<td>column_type</td>
<td>List of column_count 1 byte enumeration values</td>
<td>The 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). </td>
</tr>
<tr>
<td>metadata_length</td>
<td>@ref packed_integer "Packed Integer"</td>
<td>The length of the following metadata block</td>
</tr>
<tr>
<td>metadata</td>
<td>list of metadata for each column</td>
<td>For 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".</td>
</tr>
<tr>
<td>null_bits</td>
<td>column_count bits, rounded up to nearest byte</td>
<td>For 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. </td>
</tr>
</table>
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>
<caption>Table_map_log_event column types: numerical identifier and
metadata</caption>
<tr>
<th>Name</th>
<th>Identifier</th>
<th>Size of metadata in bytes</th>
<th>Description of metadata</th>
</tr>
<tr>
<td>MYSQL_TYPE_DECIMAL</td><td>0</td>
<td>0</td>
<td>No column metadata.</td>
</tr>
<tr>
<td>MYSQL_TYPE_TINY</td><td>1</td>
<td>0</td>
<td>No column metadata.</td>
</tr>
<tr>
<td>MYSQL_TYPE_SHORT</td><td>2</td>
<td>0</td>
<td>No column metadata.</td>
</tr>
<tr>
<td>MYSQL_TYPE_LONG</td><td>3</td>
<td>0</td>
<td>No column metadata.</td>
</tr>
<tr>
<td>MYSQL_TYPE_FLOAT</td><td>4</td>
<td>1 byte</td>
<td>1 byte unsigned integer, representing the "pack_length", which
is equal to sizeof(float) on the server from which the event
originates.</td>
</tr>
<tr>
<td>MYSQL_TYPE_DOUBLE</td><td>5</td>
<td>1 byte</td>
<td>1 byte unsigned integer, representing the "pack_length", which
is equal to sizeof(double) on the server from which the event
originates.</td>
</tr>
<tr>
<td>MYSQL_TYPE_NULL</td><td>6</td>
<td>0</td>
<td>No column metadata.</td>
</tr>
<tr>
<td>MYSQL_TYPE_TIMESTAMP</td><td>7</td>
<td>0</td>
<td>No column metadata.</td>
</tr>
<tr>
<td>MYSQL_TYPE_LONGLONG</td><td>8</td>
<td>0</td>
<td>No column metadata.</td>
</tr>
<tr>
<td>MYSQL_TYPE_INT24</td><td>9</td>
<td>0</td>
<td>No column metadata.</td>
</tr>
<tr>
<td>MYSQL_TYPE_DATE</td><td>10</td>
<td>0</td>
<td>No column metadata.</td>
</tr>
<tr>
<td>MYSQL_TYPE_TIME</td><td>11</td>
<td>0</td>
<td>No column metadata.</td>
</tr>
<tr>
<td>MYSQL_TYPE_DATETIME</td><td>12</td>
<td>0</td>
<td>No column metadata.</td>
</tr>
<tr>
<td>MYSQL_TYPE_YEAR</td><td>13</td>
<td>0</td>
<td>No column metadata.</td>
</tr>
<tr>
<td><i>MYSQL_TYPE_NEWDATE</i></td><td><i>14</i></td>
<td>&ndash;</td>
<td><i>This enumeration value is only used internally and cannot
exist in a binlog.</i></td>
</tr>
<tr>
<td>MYSQL_TYPE_VARCHAR</td><td>15</td>
<td>2 bytes</td>
<td>2 byte unsigned integer representing the maximum length of
the string.</td>
</tr>
<tr>
<td>MYSQL_TYPE_BIT</td><td>16</td>
<td>2 bytes</td>
<td>A 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).</td>
</tr>
<tr>
<td>MYSQL_TYPE_NEWDECIMAL</td><td>246</td>
<td>2 bytes</td>
<td>A 1 byte unsigned int representing the precision, followed
by a 1 byte unsigned int representing the number of decimals.</td>
</tr>
<tr>
<td><i>MYSQL_TYPE_ENUM</i></td><td><i>247</i></td>
<td>&ndash;</td>
<td><i>This enumeration value is only used internally and cannot
exist in a binlog.</i></td>
</tr>
<tr>
<td><i>MYSQL_TYPE_SET</i></td><td><i>248</i></td>
<td>&ndash;</td>
<td><i>This enumeration value is only used internally and cannot
exist in a binlog.</i></td>
</tr>
<tr>
<td>MYSQL_TYPE_TINY_BLOB</td><td>249</td>
<td>&ndash;</td>
<td><i>This enumeration value is only used internally and cannot
exist in a binlog.</i></td>
</tr>
<tr>
<td><i>MYSQL_TYPE_MEDIUM_BLOB</i></td><td><i>250</i></td>
<td>&ndash;</td>
<td><i>This enumeration value is only used internally and cannot
exist in a binlog.</i></td>
</tr>
<tr>
<td><i>MYSQL_TYPE_LONG_BLOB</i></td><td><i>251</i></td>
<td>&ndash;</td>
<td><i>This enumeration value is only used internally and cannot
exist in a binlog.</i></td>
</tr>
<tr>
<td>MYSQL_TYPE_BLOB</td><td>252</td>
<td>1 byte</td>
<td>The pack length, i.e., the number of bytes needed to represent
the length of the blob: 1, 2, 3, or 4.</td>
</tr>
<tr>
<td>MYSQL_TYPE_VAR_STRING</td><td>253</td>
<td>2 bytes</td>
<td>This is used to store both strings and enumeration values.
The first byte is a enumeration value storing the <i>real
type</i>, 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.</td>
</tr>
<tr>
<td>MYSQL_TYPE_STRING</td><td>254</td>
<td>2 bytes</td>
<td>The 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.</td>
</tr>
<tr>
<td>MYSQL_TYPE_GEOMETRY</td><td>255</td>
<td>1 byte</td>
<td>The pack length, i.e., the number of bytes needed to represent
the length of the geometry: 1, 2, 3, or 4.</td>
</tr>
</table>
*/ */
class Table_map_log_event : public Log_event class Table_map_log_event : public Log_event
{ {
...@@ -3131,6 +3498,8 @@ protected: ...@@ -3131,6 +3498,8 @@ protected:
ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT); 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, int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols,
&m_curr_row_end, &m_master_reclength); &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); ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT);
return result; return result;
} }
...@@ -3408,7 +3777,7 @@ protected: ...@@ -3408,7 +3777,7 @@ protected:
<caption>Incident event format</caption> <caption>Incident event format</caption>
<tr> <tr>
<th>Symbol</th> <th>Symbol</th>
<th>Size<br/>(bytes)</th> <th>Format</th>
<th>Description</th> <th>Description</th>
</tr> </tr>
<tr> <tr>
......
...@@ -2078,7 +2078,7 @@ Old_rows_log_event::write_row(const Relay_log_info *const rli, ...@@ -2078,7 +2078,7 @@ Old_rows_log_event::write_row(const Relay_log_info *const rli,
/* fill table->record[0] with default values */ /* 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 */))) TRUE /* check if columns have def. values */)))
DBUG_RETURN(error); DBUG_RETURN(error);
...@@ -2289,7 +2289,7 @@ int Old_rows_log_event::find_row(const Relay_log_info *rli) ...@@ -2289,7 +2289,7 @@ int Old_rows_log_event::find_row(const Relay_log_info *rli)
/* unpack row - missing fields get default values */ /* unpack row - missing fields get default values */
// TODO: shall we check and report errors here? // 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); error= unpack_current_row(rli);
#ifndef DBUG_OFF #ifndef DBUG_OFF
......
...@@ -307,17 +307,15 @@ unpack_row(Relay_log_info const *rli, ...@@ -307,17 +307,15 @@ unpack_row(Relay_log_info const *rli,
If @c check is true, fields are explicitly initialized only if they have If @c check is true, fields are explicitly initialized only if they have
default value or can be NULL. Otherwise error is reported. 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 table Table whose record[0] buffer is prepared.
@param skip Number of columns for which default value initialization @param skip Number of columns for which default value initialization
should be skipped. should be skipped.
@param check Indicates if errors should be checked when setting default @param check Indicates if errors should be checked when setting default
values. values.
@returns 0 on success. @returns 0 on success or a handler level error code
*/ */
int prepare_record(const Slave_reporting_capability *const log, int prepare_record(TABLE *const table,
TABLE *const table,
const uint skip, const bool check) const uint skip, const bool check)
{ {
DBUG_ENTER("prepare_record"); DBUG_ENTER("prepare_record");
...@@ -337,14 +335,8 @@ int prepare_record(const Slave_reporting_capability *const log, ...@@ -337,14 +335,8 @@ int prepare_record(const Slave_reporting_capability *const log,
if (check && ((f->flags & mask) == mask)) if (check && ((f->flags & mask) == mask))
{ {
DBUG_ASSERT(log); my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), f->field_name);
error= ER_NO_DEFAULT_FOR_FIELD; error = HA_ERR_ROWS_EVENT_APPLY;
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);
} }
else else
f->set_default(); f->set_default();
......
...@@ -30,8 +30,7 @@ int unpack_row(Relay_log_info const *rli, ...@@ -30,8 +30,7 @@ int unpack_row(Relay_log_info const *rli,
uchar const **const row_end, ulong *const master_reclength); uchar const **const row_end, ulong *const master_reclength);
// Fill table's record[0] with default values. // Fill table's record[0] with default values.
int prepare_record(const Slave_reporting_capability *const, TABLE *const, int prepare_record(TABLE *const, const uint =0, const bool =FALSE);
const uint =0, const bool =FALSE);
#endif #endif
#endif #endif
...@@ -33,7 +33,10 @@ Relay_log_info::Relay_log_info() ...@@ -33,7 +33,10 @@ Relay_log_info::Relay_log_info()
:Slave_reporting_capability("SQL"), :Slave_reporting_capability("SQL"),
no_storage(FALSE), replicate_same_server_id(::replicate_same_server_id), no_storage(FALSE), replicate_same_server_id(::replicate_same_server_id),
info_fd(-1), cur_log_fd(-1), save_temporary_tables(0), info_fd(-1), cur_log_fd(-1), save_temporary_tables(0),
group_relay_log_pos(0), group_relay_log_pos(0), event_relay_log_pos(0),
#if HAVE_purify
is_fake(FALSE),
#endif
cur_log_old_open_count(0), group_master_log_pos(0), log_space_total(0), cur_log_old_open_count(0), group_master_log_pos(0), log_space_total(0),
ignore_log_space_limit(0), last_master_timestamp(0), slave_skip_counter(0), ignore_log_space_limit(0), last_master_timestamp(0), slave_skip_counter(0),
abort_pos_wait(0), slave_run_id(0), sql_thd(0), abort_pos_wait(0), slave_run_id(0), sql_thd(0),
......
...@@ -154,6 +154,10 @@ public: ...@@ -154,6 +154,10 @@ public:
ulonglong event_relay_log_pos; ulonglong event_relay_log_pos;
ulonglong future_event_relay_log_pos; ulonglong future_event_relay_log_pos;
#ifdef HAVE_purify
bool is_fake; /* Mark that this is a fake relay log info structure */
#endif
/* /*
Original log name and position of the group we're currently executing Original log name and position of the group we're currently executing
(whose coordinates are group_relay_log_name/pos in the relay log) (whose coordinates are group_relay_log_name/pos in the relay log)
......
...@@ -6119,3 +6119,5 @@ ER_SLAVE_AMBIGOUS_EXEC_MODE ...@@ -6119,3 +6119,5 @@ ER_SLAVE_AMBIGOUS_EXEC_MODE
ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT
eng "The BINLOG statement of type `%s` was not preceded by a format description 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"
...@@ -1337,14 +1337,15 @@ bool show_master_info(THD* thd, Master_info* mi) ...@@ -1337,14 +1337,15 @@ bool show_master_info(THD* thd, Master_info* mi)
protocol->prepare_for_resend(); protocol->prepare_for_resend();
/* /*
TODO: we read slave_running without run_lock, whereas these variables slave_running can be accessed without run_lock but not other
are updated under run_lock and not data_lock. In 5.0 we should lock non-volotile members like mi->io_thd, which is guarded by the mutex.
run_lock on top of data_lock (with good order).
*/ */
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->data_lock);
pthread_mutex_lock(&mi->rli.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->host, &my_charset_bin);
protocol->store(mi->user, &my_charset_bin); protocol->store(mi->user, &my_charset_bin);
protocol->store((uint32) mi->port); protocol->store((uint32) mi->port);
...@@ -1892,7 +1893,13 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli, ...@@ -1892,7 +1893,13 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli,
if (exec_res == 0) if (exec_res == 0)
{ {
int error= ev->update_pos(rli); int error= ev->update_pos(rli);
#ifdef HAVE_purify
if (!rli->is_fake)
#endif
{
#ifndef DBUG_OFF
char buf[22]; char buf[22];
#endif
DBUG_PRINT("info", ("update_pos error = %d", error)); DBUG_PRINT("info", ("update_pos error = %d", error));
DBUG_PRINT("info", ("group %s %s", DBUG_PRINT("info", ("group %s %s",
llstr(rli->group_relay_log_pos, buf), llstr(rli->group_relay_log_pos, buf),
...@@ -1900,6 +1907,7 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli, ...@@ -1900,6 +1907,7 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli,
DBUG_PRINT("info", ("event %s %s", DBUG_PRINT("info", ("event %s %s",
llstr(rli->event_relay_log_pos, buf), llstr(rli->event_relay_log_pos, buf),
rli->event_relay_log_name)); rli->event_relay_log_name));
}
/* /*
The update should not fail, so print an error message and The update should not fail, so print an error message and
return an error code. return an error code.
...@@ -1909,6 +1917,7 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli, ...@@ -1909,6 +1917,7 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli,
*/ */
if (error) if (error)
{ {
char buf[22];
rli->report(ERROR_LEVEL, ER_UNKNOWN_ERROR, rli->report(ERROR_LEVEL, ER_UNKNOWN_ERROR,
"It was not possible to update the positions" "It was not possible to update the positions"
" of the relay log information: the slave may" " of the relay log information: the slave may"
......
...@@ -80,8 +80,8 @@ class Master_info; ...@@ -80,8 +80,8 @@ class Master_info;
mi->rli does not either. mi->rli does not either.
In Master_info: run_lock, data_lock In Master_info: run_lock, data_lock
run_lock protects all information about the run state: slave_running, and the run_lock protects all information about the run state: slave_running, thd
existence of the I/O thread (to stop/start it, you need this mutex). 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, data_lock protects some moving members of the struct: counters (log name,
position) and relay log (MYSQL_BIN_LOG object). position) and relay log (MYSQL_BIN_LOG object).
......
...@@ -56,6 +56,9 @@ void mysql_client_binlog_statement(THD* thd) ...@@ -56,6 +56,9 @@ void mysql_client_binlog_statement(THD* thd)
if (!thd->rli_fake) if (!thd->rli_fake)
{ {
thd->rli_fake= new Relay_log_info; thd->rli_fake= new Relay_log_info;
#ifdef HAVE_purify
thd->rli_fake->is_fake= TRUE;
#endif
have_fd_event= FALSE; have_fd_event= FALSE;
} }
if (thd->rli_fake && !thd->rli_fake->relay_log.description_event_for_exec) if (thd->rli_fake && !thd->rli_fake->relay_log.description_event_for_exec)
...@@ -152,14 +155,13 @@ void mysql_client_binlog_statement(THD* thd) ...@@ -152,14 +155,13 @@ void mysql_client_binlog_statement(THD* thd)
*/ */
if (!have_fd_event) 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; have_fd_event= TRUE;
else else
{ {
my_error(ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT, my_error(ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT,
MYF(0), MYF(0), Log_event::get_type_str((Log_event_type)type));
Log_event::get_type_str(
(Log_event_type)bufptr[EVENT_TYPE_OFFSET]));
goto end; goto end;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment