mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-30128 remove support for 5.1- replication events
including patches from Andrei Elkin
This commit is contained in:
@ -81,7 +81,7 @@ DYNAMIC_ARRAY events_in_stmt; // Storing the events that in one statement
|
||||
String stop_event_string; // Storing the STOP_EVENT output string
|
||||
|
||||
extern "C" {
|
||||
char server_version[SERVER_VERSION_LENGTH];
|
||||
char server_version[SERVER_VERSION_LENGTH]="5.0.0";
|
||||
}
|
||||
|
||||
static char *server_id_str;
|
||||
@ -277,16 +277,10 @@ class Load_log_processor
|
||||
When we see first event corresponding to some LOAD DATA statement in
|
||||
binlog, we create temporary file to store data to be loaded.
|
||||
We add name of this file to file_names array using its file_id as index.
|
||||
If we have Create_file event (i.e. we have binary log in pre-5.0.3
|
||||
format) we also store save event object to be able which is needed to
|
||||
emit LOAD DATA statement when we will meet Exec_load_data event.
|
||||
If we have Begin_load_query event we simply store 0 in
|
||||
File_name_record::event field.
|
||||
*/
|
||||
struct File_name_record
|
||||
{
|
||||
char *fname;
|
||||
Create_file_log_event *event;
|
||||
};
|
||||
/*
|
||||
@todo Should be a map (e.g., a hash map), not an array. With the
|
||||
@ -356,7 +350,6 @@ public:
|
||||
if (ptr->fname)
|
||||
{
|
||||
my_free(ptr->fname);
|
||||
delete ptr->event;
|
||||
bzero((char *)ptr, sizeof(File_name_record));
|
||||
}
|
||||
}
|
||||
@ -364,34 +357,6 @@ public:
|
||||
delete_dynamic(&file_names);
|
||||
}
|
||||
|
||||
/**
|
||||
Obtain Create_file event for LOAD DATA statement by its file_id
|
||||
and remove it from this Load_log_processor's list of events.
|
||||
|
||||
Checks whether we have already seen a Create_file_log_event with
|
||||
the given file_id. If yes, returns a pointer to the event and
|
||||
removes the event from array describing active temporary files.
|
||||
From this moment, the caller is responsible for freeing the memory
|
||||
occupied by the event.
|
||||
|
||||
@param[in] file_id File id identifying LOAD DATA statement.
|
||||
|
||||
@return Pointer to Create_file_log_event, or NULL if we have not
|
||||
seen any Create_file_log_event with this file_id.
|
||||
*/
|
||||
Create_file_log_event *grab_event(uint file_id)
|
||||
{
|
||||
File_name_record *ptr;
|
||||
Create_file_log_event *res;
|
||||
|
||||
if (file_id >= file_names.elements)
|
||||
return 0;
|
||||
ptr= dynamic_element(&file_names, file_id, File_name_record*);
|
||||
if ((res= ptr->event))
|
||||
bzero((char *)ptr, sizeof(File_name_record));
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
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.
|
||||
@ -415,124 +380,18 @@ public:
|
||||
if (file_id >= file_names.elements)
|
||||
return 0;
|
||||
ptr= dynamic_element(&file_names, file_id, File_name_record*);
|
||||
if (!ptr->event)
|
||||
{
|
||||
res= ptr->fname;
|
||||
bzero((char *)ptr, sizeof(File_name_record));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
Exit_status process(Create_file_log_event *ce);
|
||||
Exit_status process(Begin_load_query_log_event *ce);
|
||||
Exit_status process(Begin_load_query_log_event *blqe);
|
||||
Exit_status process(Append_block_log_event *ae);
|
||||
File prepare_new_file_for_old_format(Load_log_event *le, char *filename);
|
||||
Exit_status load_old_format_file(NET* net, const char *server_fname,
|
||||
uint server_fname_len, File file);
|
||||
Exit_status process_first_event(const char *bname, size_t blen,
|
||||
const uchar *block,
|
||||
size_t block_len, uint file_id,
|
||||
Create_file_log_event *ce);
|
||||
size_t block_len, uint file_id);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Creates and opens a new temporary file in the directory specified by previous call to init_by_dir_name() or init_by_cur_dir().
|
||||
|
||||
@param[in] le The basename of the created file will start with the
|
||||
basename of the file pointed to by this Load_log_event.
|
||||
|
||||
@param[out] filename Buffer to save the filename in.
|
||||
|
||||
@return File handle >= 0 on success, -1 on error.
|
||||
*/
|
||||
File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le,
|
||||
char *filename)
|
||||
{
|
||||
size_t len;
|
||||
char *tail;
|
||||
File file;
|
||||
|
||||
fn_format(filename, le->fname, target_dir_name, "", MY_REPLACE_DIR);
|
||||
len= strlen(filename);
|
||||
tail= filename + len;
|
||||
|
||||
if ((file= create_unique_file(filename,tail)) < 0)
|
||||
{
|
||||
error("Could not construct local filename %s.",filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
le->set_fname_outside_temp_buf(filename,len+strlen(tail));
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Reads a file from a server and saves it locally.
|
||||
|
||||
@param[in,out] net The server to read from.
|
||||
|
||||
@param[in] server_fname The name of the file that the server should
|
||||
read.
|
||||
|
||||
@param[in] server_fname_len The length of server_fname.
|
||||
|
||||
@param[in,out] file The file to write to.
|
||||
|
||||
@retval ERROR_STOP An error occurred - the program should terminate.
|
||||
@retval OK_CONTINUE No error, the program should continue.
|
||||
*/
|
||||
Exit_status Load_log_processor::load_old_format_file(NET* net,
|
||||
const char*server_fname,
|
||||
uint server_fname_len,
|
||||
File file)
|
||||
{
|
||||
uchar buf[FN_REFLEN+1];
|
||||
buf[0] = 0;
|
||||
memcpy(buf + 1, server_fname, server_fname_len + 1);
|
||||
if (my_net_write(net, buf, server_fname_len +2) || net_flush(net))
|
||||
{
|
||||
error("Failed requesting the remote dump of %s.", server_fname);
|
||||
return ERROR_STOP;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
ulong packet_len = my_net_read(net);
|
||||
if (packet_len == 0)
|
||||
{
|
||||
if (my_net_write(net, (uchar*) "", 0) || net_flush(net))
|
||||
{
|
||||
error("Failed sending the ack packet.");
|
||||
return ERROR_STOP;
|
||||
}
|
||||
/*
|
||||
we just need to send something, as the server will read but
|
||||
not examine the packet - this is because mysql_load() sends
|
||||
an OK when it is done
|
||||
*/
|
||||
break;
|
||||
}
|
||||
else if (packet_len == packet_error)
|
||||
{
|
||||
error("Failed reading a packet during the dump of %s.", server_fname);
|
||||
return ERROR_STOP;
|
||||
}
|
||||
|
||||
if (packet_len > UINT_MAX)
|
||||
{
|
||||
error("Illegal length of packet read from net.");
|
||||
return ERROR_STOP;
|
||||
}
|
||||
if (my_write(file, net->read_pos, (uint) packet_len, MYF(MY_WME|MY_NABP)))
|
||||
return ERROR_STOP;
|
||||
}
|
||||
|
||||
return OK_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Process the first event in the sequence of events representing a
|
||||
LOAD DATA statement.
|
||||
@ -556,8 +415,7 @@ Exit_status Load_log_processor::process_first_event(const char *bname,
|
||||
size_t blen,
|
||||
const uchar *block,
|
||||
size_t block_len,
|
||||
uint file_id,
|
||||
Create_file_log_event *ce)
|
||||
uint file_id)
|
||||
{
|
||||
size_t full_len= target_dir_name_len + blen + 9 + 9 + 1;
|
||||
Exit_status retval= OK_CONTINUE;
|
||||
@ -569,7 +427,6 @@ Exit_status Load_log_processor::process_first_event(const char *bname,
|
||||
if (!(fname= (char*) my_malloc(PSI_NOT_INSTRUMENTED, full_len,MYF(MY_WME))))
|
||||
{
|
||||
error("Out of memory.");
|
||||
delete ce;
|
||||
DBUG_RETURN(ERROR_STOP);
|
||||
}
|
||||
|
||||
@ -584,12 +441,10 @@ Exit_status Load_log_processor::process_first_event(const char *bname,
|
||||
error("Could not construct local filename %s%s.",
|
||||
target_dir_name,bname);
|
||||
my_free(fname);
|
||||
delete ce;
|
||||
DBUG_RETURN(ERROR_STOP);
|
||||
}
|
||||
|
||||
rec.fname= fname;
|
||||
rec.event= ce;
|
||||
|
||||
/*
|
||||
fname is freed in process_event()
|
||||
@ -600,13 +455,9 @@ Exit_status Load_log_processor::process_first_event(const char *bname,
|
||||
{
|
||||
error("Out of memory.");
|
||||
my_free(fname);
|
||||
delete ce;
|
||||
DBUG_RETURN(ERROR_STOP);
|
||||
}
|
||||
|
||||
if (ce)
|
||||
ce->set_fname_outside_temp_buf(fname, strlen(fname));
|
||||
|
||||
if (my_write(file, (uchar*)block, block_len, MYF(MY_WME|MY_NABP)))
|
||||
{
|
||||
error("Failed writing to file.");
|
||||
@ -621,32 +472,12 @@ Exit_status Load_log_processor::process_first_event(const char *bname,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
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);
|
||||
size_t blen= ce->fname_len - (bname-ce->fname);
|
||||
|
||||
return process_first_event(bname, blen, ce->block, ce->block_len,
|
||||
ce->file_id, ce);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
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.
|
||||
@param blqe 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.
|
||||
@ -654,7 +485,7 @@ Exit_status Load_log_processor::process(Create_file_log_event *ce)
|
||||
Exit_status Load_log_processor::process(Begin_load_query_log_event *blqe)
|
||||
{
|
||||
return process_first_event("SQL_LOAD_MB", 11, blqe->block, blqe->block_len,
|
||||
blqe->file_id, 0);
|
||||
blqe->file_id);
|
||||
}
|
||||
|
||||
|
||||
@ -1245,41 +1076,6 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
|
||||
break;
|
||||
}
|
||||
|
||||
case CREATE_FILE_EVENT:
|
||||
{
|
||||
Create_file_log_event* ce= (Create_file_log_event*)ev;
|
||||
/*
|
||||
We test if this event has to be ignored. If yes, we don't save
|
||||
this event; this will have the good side-effect of ignoring all
|
||||
related Append_block and Exec_load.
|
||||
Note that Load event from 3.23 is not tested.
|
||||
*/
|
||||
if (shall_skip_database(ce->db))
|
||||
goto end; // Next event
|
||||
/*
|
||||
We print the event, but with a leading '#': this is just to inform
|
||||
the user of the original command; the command we want to execute
|
||||
will be a derivation of this original command (we will change the
|
||||
filename and use LOCAL), prepared in the 'case EXEC_LOAD_EVENT'
|
||||
below.
|
||||
*/
|
||||
print_skip_replication_statement(print_event_info, ev);
|
||||
if (ce->print(result_file, print_event_info, TRUE))
|
||||
goto err;
|
||||
// If this binlog is not 3.23 ; why this test??
|
||||
if (glob_description_event->binlog_version >= 3)
|
||||
{
|
||||
/*
|
||||
transfer the responsibility for destroying the event to
|
||||
load_processor
|
||||
*/
|
||||
ev= NULL;
|
||||
if ((retval= load_processor.process(ce)) != OK_CONTINUE)
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case APPEND_BLOCK_EVENT:
|
||||
/*
|
||||
Append_block_log_events can safely print themselves even if
|
||||
@ -1293,36 +1089,6 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
|
||||
goto end;
|
||||
break;
|
||||
|
||||
case EXEC_LOAD_EVENT:
|
||||
{
|
||||
if (ev->print(result_file, print_event_info))
|
||||
goto err;
|
||||
Execute_load_log_event *exv= (Execute_load_log_event*)ev;
|
||||
Create_file_log_event *ce= load_processor.grab_event(exv->file_id);
|
||||
/*
|
||||
if ce is 0, it probably means that we have not seen the Create_file
|
||||
event (a bad binlog, or most probably --start-position is after the
|
||||
Create_file event). Print a warning comment.
|
||||
*/
|
||||
if (ce)
|
||||
{
|
||||
bool error;
|
||||
/*
|
||||
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);
|
||||
error= ce->print(result_file, print_event_info, TRUE);
|
||||
my_free((void*)ce->fname);
|
||||
delete ce;
|
||||
if (error)
|
||||
goto err;
|
||||
}
|
||||
else
|
||||
warning("Ignoring Execute_load_log_event as there is no "
|
||||
"Create_file event for file_id: %u", exv->file_id);
|
||||
break;
|
||||
}
|
||||
case FORMAT_DESCRIPTION_EVENT:
|
||||
delete glob_description_event;
|
||||
glob_description_event= (Format_description_log_event*) ev;
|
||||
@ -1579,23 +1345,14 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
|
||||
destroy_evt= FALSE;
|
||||
break;
|
||||
}
|
||||
case PRE_GA_WRITE_ROWS_EVENT:
|
||||
case PRE_GA_DELETE_ROWS_EVENT:
|
||||
case PRE_GA_UPDATE_ROWS_EVENT:
|
||||
{
|
||||
Old_rows_log_event *e= (Old_rows_log_event*) ev;
|
||||
bool is_stmt_end= e->get_flags(Rows_log_event::STMT_END_F);
|
||||
if (print_row_event(print_event_info, ev, e->get_table_id(),
|
||||
e->get_flags(Old_rows_log_event::STMT_END_F)))
|
||||
goto err;
|
||||
DBUG_PRINT("info", ("is_stmt_end: %d", (int) is_stmt_end));
|
||||
if (!is_stmt_end && opt_flashback)
|
||||
destroy_evt= FALSE;
|
||||
break;
|
||||
}
|
||||
case START_ENCRYPTION_EVENT:
|
||||
glob_description_event->start_decryption((Start_encryption_log_event*)ev);
|
||||
/* fall through */
|
||||
case PRE_GA_WRITE_ROWS_EVENT:
|
||||
case PRE_GA_DELETE_ROWS_EVENT:
|
||||
case PRE_GA_UPDATE_ROWS_EVENT:
|
||||
case CREATE_FILE_EVENT:
|
||||
case EXEC_LOAD_EVENT:
|
||||
default:
|
||||
print_skip_replication_statement(print_event_info, ev);
|
||||
if (ev->print(result_file, print_event_info))
|
||||
@ -2809,22 +2566,10 @@ static Exit_status check_master_version()
|
||||
glob_description_event= NULL;
|
||||
|
||||
switch (version) {
|
||||
case 3:
|
||||
glob_description_event= new Format_description_log_event(1);
|
||||
break;
|
||||
case 4:
|
||||
glob_description_event= new Format_description_log_event(3);
|
||||
break;
|
||||
case 5:
|
||||
case 10:
|
||||
case 11:
|
||||
/*
|
||||
The server is soon going to send us its Format_description log
|
||||
event, unless it is a 5.0 server with 3.23 or 4.0 binlogs.
|
||||
So we first assume that this is 4.0 (which is enough to read the
|
||||
Format_desc event if one comes).
|
||||
*/
|
||||
glob_description_event= new Format_description_log_event(3);
|
||||
glob_description_event= new Format_description_log_event(4);
|
||||
break;
|
||||
default:
|
||||
error("Could not find server version: "
|
||||
@ -2883,8 +2628,6 @@ static Exit_status handle_event_text_mode(PRINT_EVENT_INFO *print_event_info,
|
||||
}
|
||||
|
||||
Log_event_type type= ev->get_type_code();
|
||||
if (glob_description_event->binlog_version >= 3 ||
|
||||
(type != LOAD_EVENT && type != CREATE_FILE_EVENT))
|
||||
{
|
||||
/*
|
||||
If this is a Rotate event, maybe it's the end of the requested binlog;
|
||||
@ -2943,31 +2686,6 @@ static Exit_status handle_event_text_mode(PRINT_EVENT_INFO *print_event_info,
|
||||
if (retval != OK_CONTINUE)
|
||||
DBUG_RETURN(retval);
|
||||
}
|
||||
else
|
||||
{
|
||||
Load_log_event *le= (Load_log_event*)ev;
|
||||
const char *old_fname= le->fname;
|
||||
uint old_len= le->fname_len;
|
||||
File file;
|
||||
Exit_status retval;
|
||||
char fname[FN_REFLEN+1];
|
||||
|
||||
if ((file= load_processor.prepare_new_file_for_old_format(le,fname)) < 0)
|
||||
{
|
||||
DBUG_RETURN(ERROR_STOP);
|
||||
}
|
||||
|
||||
retval= process_event(print_event_info, ev, old_off, logname);
|
||||
if (retval != OK_CONTINUE)
|
||||
{
|
||||
my_close(file,MYF(MY_WME));
|
||||
DBUG_RETURN(retval);
|
||||
}
|
||||
retval= load_processor.load_old_format_file(net,old_fname,old_len,file);
|
||||
my_close(file,MYF(MY_WME));
|
||||
if (retval != OK_CONTINUE)
|
||||
DBUG_RETURN(retval);
|
||||
}
|
||||
|
||||
DBUG_RETURN(OK_CONTINUE);
|
||||
}
|
||||
@ -3240,7 +2958,7 @@ static Exit_status check_header(IO_CACHE* file,
|
||||
MY_STAT my_file_stat;
|
||||
|
||||
delete glob_description_event;
|
||||
if (!(glob_description_event= new Format_description_log_event(3)))
|
||||
if (!(glob_description_event= new Format_description_log_event(4)))
|
||||
{
|
||||
error("Failed creating Format_description_log_event; out of memory?");
|
||||
return ERROR_STOP;
|
||||
@ -3312,25 +3030,7 @@ static Exit_status check_header(IO_CACHE* file,
|
||||
{
|
||||
DBUG_PRINT("info",("buf[EVENT_TYPE_OFFSET=%d]=%d",
|
||||
EVENT_TYPE_OFFSET, buf[EVENT_TYPE_OFFSET]));
|
||||
/* always test for a Start_v3, even if no --start-position */
|
||||
if (buf[EVENT_TYPE_OFFSET] == START_EVENT_V3)
|
||||
{
|
||||
/* This is 3.23 or 4.x */
|
||||
if (uint4korr(buf + EVENT_LEN_OFFSET) <
|
||||
(LOG_EVENT_MINIMAL_HEADER_LEN + START_V3_HEADER_LEN))
|
||||
{
|
||||
/* This is 3.23 (format 1) */
|
||||
delete glob_description_event;
|
||||
if (!(glob_description_event= new Format_description_log_event(1)))
|
||||
{
|
||||
error("Failed creating Format_description_log_event; "
|
||||
"out of memory?");
|
||||
return ERROR_STOP;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (tmp_pos >= start_position)
|
||||
if (tmp_pos >= start_position)
|
||||
break;
|
||||
else if (buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT)
|
||||
{
|
||||
@ -3803,7 +3503,6 @@ struct encryption_service_st encryption_handler=
|
||||
#include "password.c"
|
||||
#include "log_event.cc"
|
||||
#include "log_event_client.cc"
|
||||
#include "log_event_old.cc"
|
||||
#include "rpl_utility.cc"
|
||||
#include "sql_string.cc"
|
||||
#include "sql_list.cc"
|
||||
|
@ -971,17 +971,17 @@ explain extended select length('\n\t\r\b\0\_\%\\');
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
Warnings:
|
||||
Note 1003 select octet_length('\n \r\0008\0\\_\\%\\') AS `length('\n\t\r\b\0\_\%\\')`
|
||||
Note 1003 select octet_length('\n\t\r\b\0\\_\\%\\') AS `length('\n\t\r\b\0\_\%\\')`
|
||||
explain extended select bit_length('\n\t\r\b\0\_\%\\');
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
Warnings:
|
||||
Note 1003 select bit_length('\n \r\0008\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`
|
||||
Note 1003 select bit_length('\n\t\r\b\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`
|
||||
explain extended select bit_length('\n\t\r\b\0\_\%\\');
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
Warnings:
|
||||
Note 1003 select bit_length('\n \r\0008\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`
|
||||
Note 1003 select bit_length('\n\t\r\b\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`
|
||||
explain extended select concat('monty',' was here ','again');
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
|
@ -407,16 +407,26 @@ ROLLBACK /* added by mysqlbinlog */;
|
||||
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
|
||||
DELIMITER /*!*/;
|
||||
ROLLBACK/*!*/;
|
||||
SET TIMESTAMP=1108844556/*!*/;
|
||||
use `test`/*!*/;
|
||||
SET TIMESTAMP=1140641973/*!*/;
|
||||
SET @@session.pseudo_thread_id=999999999/*!*/;
|
||||
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1, @@session.system_versioning_insert_history=0/*!*/;
|
||||
SET @@session.sql_mode=#/*!*/;
|
||||
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
|
||||
/*!\C latin1 *//*!*/;
|
||||
SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=#/*!*/;
|
||||
SET @@session.lc_time_names=0/*!*/;
|
||||
SET @@session.collation_database=DEFAULT/*!*/;
|
||||
BEGIN
|
||||
CREATE TABLE t1(c INT)
|
||||
/*!*/;
|
||||
use `test`/*!*/;
|
||||
SET TIMESTAMP=1108844555/*!*/;
|
||||
insert t1 values (1)
|
||||
SET TIMESTAMP=1140641985/*!*/;
|
||||
CREATE TABLE t2(s CHAR(200))
|
||||
/*!*/;
|
||||
SET TIMESTAMP=1140642018/*!*/;
|
||||
CREATE TRIGGER trg1 AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUES(CURRENT_USER())
|
||||
/*!*/;
|
||||
SET TIMESTAMP=1140642025/*!*/;
|
||||
INSERT INTO t1 VALUES(1)
|
||||
/*!*/;
|
||||
DELIMITER ;
|
||||
# End of log file
|
||||
@ -427,16 +437,21 @@ ROLLBACK /* added by mysqlbinlog */;
|
||||
/*!40019 SET @@session.max_delayed_threads=0*/;
|
||||
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
|
||||
DELIMITER /*!*/;
|
||||
SET TIMESTAMP=1108844556/*!*/;
|
||||
ROLLBACK/*!*/;
|
||||
use `test`/*!*/;
|
||||
SET TIMESTAMP=1140642018/*!*/;
|
||||
SET @@session.pseudo_thread_id=999999999/*!*/;
|
||||
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1, @@session.system_versioning_insert_history=0/*!*/;
|
||||
SET @@session.sql_mode=#/*!*/;
|
||||
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
|
||||
/*!\C latin1 *//*!*/;
|
||||
SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=#/*!*/;
|
||||
SET @@session.lc_time_names=0/*!*/;
|
||||
SET @@session.collation_database=DEFAULT/*!*/;
|
||||
BEGIN
|
||||
CREATE TRIGGER trg1 AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUES(CURRENT_USER())
|
||||
/*!*/;
|
||||
use `test`/*!*/;
|
||||
SET TIMESTAMP=1108844555/*!*/;
|
||||
insert t1 values (1)
|
||||
SET TIMESTAMP=1140642025/*!*/;
|
||||
INSERT INTO t1 VALUES(1)
|
||||
/*!*/;
|
||||
DELIMITER ;
|
||||
# End of log file
|
||||
|
@ -123,13 +123,13 @@ select "--- reading stdin --" as "";
|
||||
--enable_query_log
|
||||
--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
|
||||
--replace_regex /SQL_LOAD_MB-[0-9a-f]+-[0-9a-f]+/SQL_LOAD_MB-#-#/ /@@session.sql_mode=\d+/@@session.sql_mode=#/ /collation_server=\d+/collation_server=#/
|
||||
--exec $MYSQL_BINLOG --short-form - < $MYSQL_TEST_DIR/std_data/trunc_binlog.000001
|
||||
--exec $MYSQL_BINLOG --short-form - < $MYSQL_TEST_DIR/std_data/bug16266.000001
|
||||
|
||||
--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
|
||||
--replace_regex /SQL_LOAD_MB-[0-9a-f]+-[0-9a-f]+/SQL_LOAD_MB-#-#/ /@@session.sql_mode=\d+/@@session.sql_mode=#/ /collation_server=\d+/collation_server=#/
|
||||
# postion is constant to correspond to an event in pre-recorded binlog
|
||||
--let $binlog_start_pos=79
|
||||
--exec $MYSQL_BINLOG --short-form --start-position=$binlog_start_pos - < $MYSQL_TEST_DIR/std_data/trunc_binlog.000001
|
||||
--let $binlog_start_pos=274
|
||||
--exec $MYSQL_BINLOG --short-form --start-position=$binlog_start_pos - < $MYSQL_TEST_DIR/std_data/bug16266.000001
|
||||
|
||||
drop table t1,t2;
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,7 +1,7 @@
|
||||
call mtr.add_suppression("BINLOG_BASE64_EVENT: According to the master's version");
|
||||
call mtr.add_suppression("BINLOG_BASE64_EVENT: Column 1 of table 'test.char128_utf8' cannot be converted");
|
||||
DROP TABLE IF EXISTS t1;
|
||||
==== Test BUG#32407 ====
|
||||
CREATE TABLE t1 (a int);
|
||||
INSERT INTO t1 VALUES (1), (1);
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
@ -49,35 +49,6 @@ a
|
||||
SELECT @binlog_fragment_0, @binlog_fragment_1 as 'NULL','NULL';
|
||||
@binlog_fragment_0 NULL NULL
|
||||
NULL NULL NULL
|
||||
==== Test --base64-output=never on a binlog with row events ====
|
||||
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
|
||||
/*!40019 SET @@session.max_delayed_threads=0*/;
|
||||
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
|
||||
DELIMITER /*!*/;
|
||||
<#>
|
||||
ROLLBACK/*!*/;
|
||||
<#>
|
||||
use `test`/*!*/;
|
||||
SET TIMESTAMP=1196959712/*!*/;
|
||||
<#>SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1, @@session.system_versioning_insert_history=0/*!*/;
|
||||
SET @@session.sql_mode=0/*!*/;
|
||||
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
|
||||
/*!\C latin1 *//*!*/;
|
||||
SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/;
|
||||
SET @@session.lc_time_names=0/*!*/;
|
||||
SET @@session.collation_database=DEFAULT/*!*/;
|
||||
create table t1 (a int) engine= myisam
|
||||
/*!*/;
|
||||
<#>
|
||||
<#>
|
||||
<#>
|
||||
<#>
|
||||
<#>
|
||||
DELIMITER ;
|
||||
# End of log file
|
||||
ROLLBACK /* added by mysqlbinlog */;
|
||||
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
|
||||
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
|
||||
==== Test non-matching FD event and Row event ====
|
||||
BINLOG '
|
||||
4CdYRw8BAAAAYgAAAGYAAAAAAAQANS4xLjE1LW5kYi02LjEuMjQtZGVidWctbG9nAAAAAAAAAAAA
|
||||
|
@ -1,70 +0,0 @@
|
||||
==== Read binlog with v2 row events ====
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a b
|
||||
0 last_insert_id
|
||||
1 one
|
||||
3 last stm in trx: next event should be xid
|
||||
4 four
|
||||
62046 random
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
a b
|
||||
3 first stm in trx
|
||||
SELECT COUNT(*) FROM t3;
|
||||
COUNT(*)
|
||||
17920
|
||||
DROP TABLE t1, t2, t3;
|
||||
==== Read modern binlog (version 5.1.23) ====
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a b
|
||||
0 last_insert_id
|
||||
1 one
|
||||
3 last stm in trx: next event should be xid
|
||||
4 four
|
||||
674568 random
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
a b
|
||||
3 first stm in trx
|
||||
SELECT COUNT(*) FROM t3;
|
||||
COUNT(*)
|
||||
17920
|
||||
DROP TABLE t1, t2, t3;
|
||||
==== Read binlog from version 5.1.17 ====
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a b
|
||||
0 last_insert_id
|
||||
1 one
|
||||
3 last stm in trx: next event should be xid
|
||||
4 four
|
||||
764247 random
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
a b
|
||||
3 first stm in trx
|
||||
SELECT COUNT(*) FROM t3;
|
||||
COUNT(*)
|
||||
17920
|
||||
DROP TABLE t1, t2, t3;
|
||||
==== Read binlog from version 4.1 ====
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a b
|
||||
0 last_insert_id
|
||||
4 four
|
||||
190243 random
|
||||
SELECT COUNT(*) FROM t3;
|
||||
COUNT(*)
|
||||
17920
|
||||
DROP TABLE t1, t3;
|
||||
==== Read binlog from telco tree (mysql-5.1-telco-6.1) ====
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a b
|
||||
0 last_insert_id
|
||||
1 one
|
||||
3 last stm in trx: next event should be xid
|
||||
4 four
|
||||
703356 random
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
a b
|
||||
3 first stm in trx
|
||||
SELECT COUNT(*) FROM t3;
|
||||
COUNT(*)
|
||||
17920
|
||||
DROP TABLE t1, t2, t3;
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -2,9 +2,6 @@
|
||||
# work as expected, and that BINLOG statements with row events fail if
|
||||
# they are not preceded by BINLOG statements with Format description
|
||||
# events.
|
||||
#
|
||||
# See also BUG#32407.
|
||||
|
||||
|
||||
# BINLOG statement does not work in embedded mode.
|
||||
source include/not_embedded.inc;
|
||||
@ -12,23 +9,10 @@ source include/not_embedded.inc;
|
||||
call mtr.add_suppression("BINLOG_BASE64_EVENT: According to the master's version");
|
||||
call mtr.add_suppression("BINLOG_BASE64_EVENT: Column 1 of table 'test.char128_utf8' cannot be converted");
|
||||
|
||||
disable_warnings;
|
||||
DROP TABLE IF EXISTS t1;
|
||||
enable_warnings;
|
||||
# Test to show BUG#32407. This reads a binlog created with the
|
||||
# mysql-5.1-telco-6.1 tree, specifically at the tag
|
||||
# mysql-5.1.15-ndb-6.1.23, and applies it to the database. The test
|
||||
# should fail before BUG#32407 was fixed and succeed afterwards.
|
||||
--echo ==== Test BUG#32407 ====
|
||||
|
||||
# The binlog contains row events equivalent to:
|
||||
# CREATE TABLE t1 (a int) engine = myisam
|
||||
# INSERT INTO t1 VALUES (1), (1)
|
||||
exec $MYSQL_BINLOG suite/binlog/std_data/bug32407.001 | $MYSQL;
|
||||
# The above line should succeed and t1 should contain two ones
|
||||
CREATE TABLE t1 (a int);
|
||||
INSERT INTO t1 VALUES (1), (1);
|
||||
select * from t1;
|
||||
|
||||
|
||||
# Test that a BINLOG statement encoding a row event fails unless a
|
||||
# Format_description_event as been supplied with an earlier BINLOG
|
||||
# statement.
|
||||
@ -92,14 +76,6 @@ select * from t1;
|
||||
# show "one-shot" feature of binlog_fragment variables
|
||||
SELECT @binlog_fragment_0, @binlog_fragment_1 as 'NULL','NULL';
|
||||
|
||||
# New mysqlbinlog supports --base64-output=never
|
||||
--echo ==== Test --base64-output=never on a binlog with row events ====
|
||||
|
||||
# mysqlbinlog should fail
|
||||
--replace_regex /#[0-9][0-9][0-9][0-9][0-9][0-9] \N*/<#>/ /SET \@\@session.pseudo_thread_id.*/<#>/
|
||||
exec $MYSQL_BINLOG --base64-output=never --print-row-count=0 --print-row-event-positions=0 suite/binlog/std_data/bug32407.001;
|
||||
|
||||
|
||||
# Test that the following fails cleanly: "First, read a
|
||||
# Format_description event which has N event types. Then, read an
|
||||
# event of type M>N"
|
||||
|
@ -1,153 +0,0 @@
|
||||
# Test that old binlog formats can be read.
|
||||
|
||||
# Some previous versions of MySQL use their own binlog format,
|
||||
# especially in row-based replication. This test uses saved binlogs
|
||||
# from those old versions to test that we can replicate from old
|
||||
# versions to the present version.
|
||||
|
||||
# Replicating from old versions to new versions is necessary in an
|
||||
# online upgrade scenario, where the .
|
||||
|
||||
# The previous versions we currently test are:
|
||||
# - version 5.1.17 and earlier trees
|
||||
# - mysql-5.1-wl2325-xxx trees (AKA alcatel trees)
|
||||
# - mysql-5.1-telco-6.1 trees
|
||||
# For completeness, we also test mysql-5.1-new_rpl, which is supposed
|
||||
# to be the "correct" version.
|
||||
|
||||
# All binlogs were generated with the same commands (listed at the end
|
||||
# of this test for reference). The binlogs contain the following
|
||||
# events: Table_map, Write_rows, Update_rows, Delete_rows Query, Xid,
|
||||
# User_var, Int_var, Rand, Begin_load, Append_file, Execute_load.
|
||||
|
||||
# Related bugs: BUG#27779, BUG#31581, BUG#31582, BUG#31583, BUG#32407
|
||||
|
||||
source include/not_embedded.inc;
|
||||
|
||||
--echo ==== Read binlog with v2 row events ====
|
||||
|
||||
# Read binlog.
|
||||
--exec $MYSQL_BINLOG --local-load=$MYSQLTEST_VARDIR/tmp/ suite/binlog/std_data/ver_trunk_row_v2.001 | $MYSQL --local-infile=1
|
||||
# Show result.
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
SELECT COUNT(*) FROM t3;
|
||||
# Reset.
|
||||
DROP TABLE t1, t2, t3;
|
||||
|
||||
|
||||
--echo ==== Read modern binlog (version 5.1.23) ====
|
||||
|
||||
# Read binlog.
|
||||
--exec $MYSQL_BINLOG --local-load=$MYSQLTEST_VARDIR/tmp/ suite/binlog/std_data/ver_5_1_23.001 | $MYSQL --local-infile=1
|
||||
# Show result.
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
SELECT COUNT(*) FROM t3;
|
||||
# Reset.
|
||||
DROP TABLE t1, t2, t3;
|
||||
|
||||
|
||||
--echo ==== Read binlog from version 5.1.17 ====
|
||||
|
||||
# Read binlog.
|
||||
--exec $MYSQL_BINLOG --local-load=$MYSQLTEST_VARDIR/tmp/ suite/binlog/std_data/ver_5_1_17.001 | $MYSQL --local-infile=1
|
||||
# Show result.
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
SELECT COUNT(*) FROM t3;
|
||||
# Reset.
|
||||
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 telco tree (mysql-5.1-telco-6.1) ====
|
||||
|
||||
# Read binlog.
|
||||
--exec $MYSQL_BINLOG --local-load=$MYSQLTEST_VARDIR/tmp/ suite/binlog/std_data/ver_5_1-telco.001 | $MYSQL --local-infile=1
|
||||
# Show resulting tablea.
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
SELECT COUNT(*) FROM t3;
|
||||
# Reset.
|
||||
DROP TABLE t1, t2, t3;
|
||||
|
||||
|
||||
#### The following commands were used to generate the binlogs ####
|
||||
#
|
||||
#source include/master-slave.inc;
|
||||
#
|
||||
## ==== initialize ====
|
||||
#USE test;
|
||||
#CREATE TABLE t1 (a int, b char(50)) ENGINE = MyISAM;
|
||||
#CREATE TABLE t2 (a int, b char(50)) ENGINE = InnoDB;
|
||||
#CREATE TABLE t3 (a char(20));
|
||||
#
|
||||
#
|
||||
## ==== row based tests ====
|
||||
#SET BINLOG_FORMAT='row';
|
||||
#
|
||||
## ---- get write, update, and delete rows events ----
|
||||
#INSERT INTO t1 VALUES (0, 'one'), (1, 'two');
|
||||
#UPDATE t1 SET a=a+1;
|
||||
#DELETE FROM t1 WHERE a=2;
|
||||
#
|
||||
#
|
||||
## ==== statement based tests ====
|
||||
#SET BINLOG_FORMAT = 'statement';
|
||||
#
|
||||
## ---- get xid events ----
|
||||
#BEGIN;
|
||||
#INSERT INTO t2 VALUES (3, 'first stm in trx');
|
||||
#INSERT INTO t1 VALUES (3, 'last stm in trx: next event should be xid');
|
||||
#COMMIT;
|
||||
#
|
||||
## ---- get user var events ----
|
||||
#SET @x = 4;
|
||||
#INSERT INTO t1 VALUES (@x, 'four');
|
||||
#
|
||||
## ---- get rand event ----
|
||||
#INSERT INTO t1 VALUES (RAND() * 1000000, 'random');
|
||||
#
|
||||
## ---- get intvar event ----
|
||||
#INSERT INTO t1 VALUES (LAST_INSERT_ID(), 'last_insert_id');
|
||||
#
|
||||
## ---- get begin, append and execute load events ----
|
||||
## double the file until we have more than 2^17 bytes, so that the
|
||||
## event has to be split and we can use Append_file_log_event.
|
||||
#
|
||||
#SET SQL_LOG_BIN=0;
|
||||
#CREATE TABLE temp (a char(20));
|
||||
#LOAD DATA INFILE '../std_data_ln/words.dat' INTO TABLE temp;
|
||||
#INSERT INTO temp SELECT * FROM temp;
|
||||
#INSERT INTO temp SELECT * FROM temp;
|
||||
#INSERT INTO temp SELECT * FROM temp;
|
||||
#INSERT INTO temp SELECT * FROM temp;
|
||||
#INSERT INTO temp SELECT * FROM temp;
|
||||
#INSERT INTO temp SELECT * FROM temp;
|
||||
#INSERT INTO temp SELECT * FROM temp;
|
||||
#INSERT INTO temp SELECT * FROM temp;
|
||||
#SELECT a FROM temp INTO OUTFILE 'big_file.dat';
|
||||
#DROP TABLE temp;
|
||||
#SET SQL_LOG_BIN=1;
|
||||
#
|
||||
#LOAD DATA INFILE 'big_file.dat' INTO TABLE t3;
|
||||
#
|
||||
#SELECT * FROM t1 ORDER BY a;
|
||||
#SELECT * FROM t2 ORDER BY a;
|
||||
#SELECT COUNT(*) FROM t3;
|
||||
#--source include/rpl_end.inc
|
@ -1,22 +0,0 @@
|
||||
include/master-slave.inc
|
||||
[connection master]
|
||||
==== Initialize ====
|
||||
connection slave;
|
||||
include/stop_slave.inc
|
||||
RESET SLAVE;
|
||||
include/setup_fake_relay_log.inc
|
||||
Setting up fake replication from MYSQL_TEST_DIR/suite/binlog/std_data/binlog_old_version_4_1.000001
|
||||
==== Test ====
|
||||
start slave sql_thread;
|
||||
include/wait_for_slave_param.inc [Exec_Master_Log_Pos]
|
||||
==== a prove that the fake has been processed successfully ====
|
||||
SELECT COUNT(*) - 17920 as zero FROM t3;
|
||||
zero
|
||||
0
|
||||
==== Clean up ====
|
||||
include/stop_slave_sql.inc
|
||||
include/cleanup_fake_relay_log.inc
|
||||
Warnings:
|
||||
Note 4190 RESET SLAVE is implicitly changing the value of 'Using_Gtid' from 'No' to 'Slave_Pos'
|
||||
drop table t1, t3;
|
||||
include/rpl_end.inc
|
@ -1 +0,0 @@
|
||||
--replicate-same-server-id --relay-log=slave-relay-bin
|
@ -1,48 +0,0 @@
|
||||
# ==== Purpose ====
|
||||
#
|
||||
# Verify cross-version replication from an old master to the up-to-date slave
|
||||
#
|
||||
# ==== Implementation ====
|
||||
#
|
||||
# Feed to the slave server a binlog recorded on an old version master
|
||||
# via setting up slave-to-slave replication. The latter is done by means of
|
||||
# the opt file and include/setup_fake_relay_log.inc.
|
||||
# The master's binlog is treated as a relay log that the SQL thread executes.
|
||||
#
|
||||
|
||||
--source include/master-slave.inc
|
||||
|
||||
#
|
||||
# Bug#31240 load data infile replication between (4.0 or 4.1) and 5.1 fails
|
||||
#
|
||||
|
||||
--echo ==== Initialize ====
|
||||
--connection slave
|
||||
|
||||
--disable_query_log
|
||||
# The binlog contains the function RAND which is unsafe.
|
||||
CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
|
||||
--enable_query_log
|
||||
|
||||
--source include/stop_slave.inc
|
||||
RESET SLAVE;
|
||||
|
||||
# the relay log contains create t1, t3 tables and load data infile
|
||||
--let $fake_relay_log = $MYSQL_TEST_DIR/suite/binlog/std_data/binlog_old_version_4_1.000001
|
||||
--source include/setup_fake_relay_log.inc
|
||||
|
||||
--echo ==== Test ====
|
||||
start slave sql_thread;
|
||||
--let $slave_param = Exec_Master_Log_Pos
|
||||
# end_log_pos of the last event of the relay log
|
||||
--let $slave_param_value = 149436
|
||||
--source include/wait_for_slave_param.inc
|
||||
--echo ==== a prove that the fake has been processed successfully ====
|
||||
SELECT COUNT(*) - 17920 as zero FROM t3;
|
||||
|
||||
--echo ==== Clean up ====
|
||||
--source include/stop_slave_sql.inc
|
||||
--source include/cleanup_fake_relay_log.inc
|
||||
drop table t1, t3;
|
||||
--let $rpl_only_running_threads= 1
|
||||
--source include/rpl_end.inc
|
@ -106,7 +106,6 @@ SET (SQL_SOURCE
|
||||
key.cc log.cc lock.cc
|
||||
log_event.cc log_event_server.cc
|
||||
rpl_record.cc rpl_reporting.cc
|
||||
log_event_old.cc rpl_record_old.cc
|
||||
mf_iocache.cc my_decimal.cc
|
||||
mysqld.cc net_serv.cc keycaches.cc
|
||||
../sql-common/client_plugin.c
|
||||
|
383
sql/log_event.cc
383
sql/log_event.cc
@ -728,40 +728,7 @@ Log_event::Log_event(const uchar *buf,
|
||||
when_sec_part= ~0UL;
|
||||
server_id= uint4korr(buf + SERVER_ID_OFFSET);
|
||||
data_written= uint4korr(buf + EVENT_LEN_OFFSET);
|
||||
if (description_event->binlog_version==1)
|
||||
{
|
||||
log_pos= 0;
|
||||
flags= 0;
|
||||
return;
|
||||
}
|
||||
/* 4.0 or newer */
|
||||
log_pos= uint4korr(buf + LOG_POS_OFFSET);
|
||||
/*
|
||||
If the log is 4.0 (so here it can only be a 4.0 relay log read by
|
||||
the SQL thread or a 4.0 master binlog read by the I/O thread),
|
||||
log_pos is the beginning of the event: we transform it into the end
|
||||
of the event, which is more useful.
|
||||
But how do you know that the log is 4.0: you know it if
|
||||
description_event is version 3 *and* you are not reading a
|
||||
Format_desc (remember that mysqlbinlog starts by assuming that 5.0
|
||||
logs are in 4.0 format, until it finds a Format_desc).
|
||||
*/
|
||||
if (description_event->binlog_version==3 &&
|
||||
(uchar)buf[EVENT_TYPE_OFFSET]<FORMAT_DESCRIPTION_EVENT && log_pos)
|
||||
{
|
||||
/*
|
||||
If log_pos=0, don't change it. log_pos==0 is a marker to mean
|
||||
"don't change rli->group_master_log_pos" (see
|
||||
inc_group_relay_log_pos()). As it is unreal log_pos, adding the
|
||||
event len's is nonsense. For example, a fake Rotate event should
|
||||
not have its log_pos (which is 0) changed or it will modify
|
||||
Exec_master_log_pos in SHOW SLAVE STATUS, displaying a nonsense
|
||||
value of (a non-zero offset which does not exist in the master's
|
||||
binlog, so which will cause problems if the user uses this value
|
||||
in CHANGE MASTER).
|
||||
*/
|
||||
log_pos+= data_written; /* purecov: inspected */
|
||||
}
|
||||
DBUG_PRINT("info", ("log_pos: %llu", log_pos));
|
||||
|
||||
flags= uint2korr(buf + FLAGS_OFFSET);
|
||||
@ -966,7 +933,7 @@ err:
|
||||
if (force_opt)
|
||||
DBUG_RETURN(new Unknown_log_event());
|
||||
#endif
|
||||
if (event.length() >= OLD_HEADER_LEN)
|
||||
if (event.length() >= LOG_EVENT_MINIMAL_HEADER_LEN)
|
||||
sql_print_error("Error in Log_event::read_log_event(): '%s',"
|
||||
" data_len: %lu, event_type: %u", error,
|
||||
(ulong) uint4korr(&event[EVENT_LEN_OFFSET]),
|
||||
@ -1128,12 +1095,6 @@ Log_event* Log_event::read_log_event(const uchar *buf, uint event_len,
|
||||
ev= new Query_compressed_log_event(buf, event_len, fdle,
|
||||
QUERY_COMPRESSED_EVENT);
|
||||
break;
|
||||
case LOAD_EVENT:
|
||||
ev= new Load_log_event(buf, event_len, fdle);
|
||||
break;
|
||||
case NEW_LOAD_EVENT:
|
||||
ev= new Load_log_event(buf, event_len, fdle);
|
||||
break;
|
||||
case ROTATE_EVENT:
|
||||
ev= new Rotate_log_event(buf, event_len, fdle);
|
||||
break;
|
||||
@ -1146,21 +1107,12 @@ Log_event* Log_event::read_log_event(const uchar *buf, uint event_len,
|
||||
case GTID_LIST_EVENT:
|
||||
ev= new Gtid_list_log_event(buf, event_len, fdle);
|
||||
break;
|
||||
case CREATE_FILE_EVENT:
|
||||
ev= new Create_file_log_event(buf, event_len, fdle);
|
||||
break;
|
||||
case APPEND_BLOCK_EVENT:
|
||||
ev= new Append_block_log_event(buf, event_len, fdle);
|
||||
break;
|
||||
case DELETE_FILE_EVENT:
|
||||
ev= new Delete_file_log_event(buf, event_len, fdle);
|
||||
break;
|
||||
case EXEC_LOAD_EVENT:
|
||||
ev= new Execute_load_log_event(buf, event_len, fdle);
|
||||
break;
|
||||
case START_EVENT_V3: /* this is sent only by MySQL <=4.x */
|
||||
ev= new Start_log_event_v3(buf, event_len, fdle);
|
||||
break;
|
||||
case STOP_EVENT:
|
||||
ev= new Stop_log_event(buf, fdle);
|
||||
break;
|
||||
@ -1183,15 +1135,6 @@ Log_event* Log_event::read_log_event(const uchar *buf, uint event_len,
|
||||
ev= new Format_description_log_event(buf, event_len, fdle);
|
||||
break;
|
||||
#if defined(HAVE_REPLICATION)
|
||||
case PRE_GA_WRITE_ROWS_EVENT:
|
||||
ev= new Write_rows_log_event_old(buf, event_len, fdle);
|
||||
break;
|
||||
case PRE_GA_UPDATE_ROWS_EVENT:
|
||||
ev= new Update_rows_log_event_old(buf, event_len, fdle);
|
||||
break;
|
||||
case PRE_GA_DELETE_ROWS_EVENT:
|
||||
ev= new Delete_rows_log_event_old(buf, event_len, fdle);
|
||||
break;
|
||||
case WRITE_ROWS_EVENT_V1:
|
||||
case WRITE_ROWS_EVENT:
|
||||
ev= new Write_rows_log_event(buf, event_len, fdle);
|
||||
@ -1247,6 +1190,14 @@ Log_event* Log_event::read_log_event(const uchar *buf, uint event_len,
|
||||
case START_ENCRYPTION_EVENT:
|
||||
ev= new Start_encryption_log_event(buf, event_len, fdle);
|
||||
break;
|
||||
case PRE_GA_WRITE_ROWS_EVENT:
|
||||
case PRE_GA_UPDATE_ROWS_EVENT:
|
||||
case PRE_GA_DELETE_ROWS_EVENT:
|
||||
case START_EVENT_V3: /* this is sent only by MySQL <=4.x */
|
||||
case CREATE_FILE_EVENT:
|
||||
case EXEC_LOAD_EVENT:
|
||||
case LOAD_EVENT:
|
||||
case NEW_LOAD_EVENT:
|
||||
default:
|
||||
DBUG_PRINT("error",("Unknown event code: %d",
|
||||
(uchar) buf[EVENT_TYPE_OFFSET]));
|
||||
@ -1427,11 +1378,10 @@ Query_log_event::Query_log_event(const uchar *buf, uint event_len,
|
||||
flags2_inited(0), sql_mode_inited(0), charset_inited(0), flags2(0),
|
||||
auto_increment_increment(1), auto_increment_offset(1),
|
||||
time_zone_len(0), lc_time_names_number(0), charset_database_number(0),
|
||||
table_map_for_update(0), xid(0), master_data_written(0), gtid_flags_extra(0),
|
||||
table_map_for_update(0), xid(0), gtid_flags_extra(0),
|
||||
sa_seq_no(0)
|
||||
{
|
||||
ulong data_len;
|
||||
uint32 tmp;
|
||||
uint8 common_header_len, post_header_len;
|
||||
Log_event::Byte *start;
|
||||
const Log_event::Byte *end;
|
||||
@ -1460,14 +1410,6 @@ Query_log_event::Query_log_event(const uchar *buf, uint event_len,
|
||||
db_len = (uchar)buf[Q_DB_LEN_OFFSET]; // TODO: add a check of all *_len vars
|
||||
error_code = uint2korr(buf + Q_ERR_CODE_OFFSET);
|
||||
|
||||
/*
|
||||
5.0 format starts here.
|
||||
Depending on the format, we may or not have affected/warnings etc
|
||||
The remnent post-header to be parsed has length:
|
||||
*/
|
||||
tmp= post_header_len - QUERY_HEADER_MINIMAL_LEN;
|
||||
if (tmp)
|
||||
{
|
||||
status_vars_len= uint2korr(buf + Q_STATUS_VARS_LEN_OFFSET);
|
||||
/*
|
||||
Check if status variable length is corrupt and will lead to very
|
||||
@ -1485,20 +1427,6 @@ Query_log_event::Query_log_event(const uchar *buf, uint event_len,
|
||||
data_len-= status_vars_len;
|
||||
DBUG_PRINT("info", ("Query_log_event has status_vars_len: %u",
|
||||
(uint) status_vars_len));
|
||||
tmp-= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
server version < 5.0 / binlog_version < 4 master's event is
|
||||
relay-logged with storing the original size of the event in
|
||||
Q_MASTER_DATA_WRITTEN_CODE status variable.
|
||||
The size is to be restored at reading Q_MASTER_DATA_WRITTEN_CODE-marked
|
||||
event from the relay log.
|
||||
*/
|
||||
DBUG_ASSERT(description_event->binlog_version < 4);
|
||||
master_data_written= (uint32)data_written;
|
||||
}
|
||||
/*
|
||||
We have parsed everything we know in the post header for QUERY_EVENT,
|
||||
the rest of post header is either comes from older version MySQL or
|
||||
@ -1585,9 +1513,9 @@ Query_log_event::Query_log_event(const uchar *buf, uint event_len,
|
||||
table_map_for_update= uint8korr(pos);
|
||||
pos+= 8;
|
||||
break;
|
||||
case Q_MASTER_DATA_WRITTEN_CODE:
|
||||
case Q_MASTER_DATA_WRITTEN_CODE: // impossible
|
||||
CHECK_SPACE(pos, end, 4);
|
||||
data_written= master_data_written= uint4korr(pos);
|
||||
data_written= uint4korr(pos);
|
||||
pos+= 4;
|
||||
break;
|
||||
case Q_INVOKER:
|
||||
@ -1991,32 +1919,6 @@ Query_log_event::begin_event(String *packet, ulong ev_offset,
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
Start_log_event_v3 methods
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
Start_log_event_v3::Start_log_event_v3(const uchar *buf, uint event_len,
|
||||
const Format_description_log_event
|
||||
*description_event)
|
||||
:Log_event(buf, description_event), binlog_version(BINLOG_VERSION)
|
||||
{
|
||||
if (event_len < LOG_EVENT_MINIMAL_HEADER_LEN + ST_COMMON_HEADER_LEN_OFFSET)
|
||||
{
|
||||
server_version[0]= 0;
|
||||
return;
|
||||
}
|
||||
buf+= LOG_EVENT_MINIMAL_HEADER_LEN;
|
||||
binlog_version= uint2korr(buf+ST_BINLOG_VER_OFFSET);
|
||||
memcpy(server_version, buf+ST_SERVER_VER_OFFSET,
|
||||
ST_SERVER_VER_LEN);
|
||||
// prevent overrun if log is corrupted on disk
|
||||
server_version[ST_SERVER_VER_LEN-1]= 0;
|
||||
created= uint4korr(buf+ST_CREATED_OFFSET);
|
||||
dont_set_created= 1;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Format_description_log_event methods
|
||||
****************************************************************************/
|
||||
@ -2040,10 +1942,10 @@ Start_log_event_v3::Start_log_event_v3(const uchar *buf, uint event_len,
|
||||
|
||||
Format_description_log_event::
|
||||
Format_description_log_event(uint8 binlog_ver, const char* server_ver)
|
||||
:Start_log_event_v3(), event_type_permutation(0)
|
||||
:Log_event(), created(0), binlog_version(binlog_ver),
|
||||
dont_set_created(0), event_type_permutation(0)
|
||||
{
|
||||
binlog_version= binlog_ver;
|
||||
switch (binlog_ver) {
|
||||
switch (binlog_version) {
|
||||
case 4: /* MySQL 5.0 */
|
||||
memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
|
||||
DBUG_EXECUTE_IF("pretend_version_50034_in_binlog",
|
||||
@ -2161,44 +2063,6 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
|
||||
|
||||
case 1: /* 3.23 */
|
||||
case 3: /* 4.0.x x>=2 */
|
||||
/*
|
||||
We build an artificial (i.e. not sent by the master) event, which
|
||||
describes what those old master versions send.
|
||||
*/
|
||||
if (binlog_ver==1)
|
||||
strmov(server_version, server_ver ? server_ver : "3.23");
|
||||
else
|
||||
strmov(server_version, server_ver ? server_ver : "4.0");
|
||||
common_header_len= binlog_ver==1 ? OLD_HEADER_LEN :
|
||||
LOG_EVENT_MINIMAL_HEADER_LEN;
|
||||
/*
|
||||
The first new event in binlog version 4 is Format_desc. So any event type
|
||||
after that does not exist in older versions. We use the events known by
|
||||
version 3, even if version 1 had only a subset of them (this is not a
|
||||
problem: it uses a few bytes for nothing but unifies code; it does not
|
||||
make the slave detect less corruptions).
|
||||
*/
|
||||
number_of_event_types= FORMAT_DESCRIPTION_EVENT - 1;
|
||||
post_header_len=(uint8*) my_malloc(PSI_INSTRUMENT_ME,
|
||||
number_of_event_types*sizeof(uint8), MYF(0));
|
||||
if (post_header_len)
|
||||
{
|
||||
post_header_len[START_EVENT_V3-1]= START_V3_HEADER_LEN;
|
||||
post_header_len[QUERY_EVENT-1]= QUERY_HEADER_MINIMAL_LEN;
|
||||
post_header_len[STOP_EVENT-1]= 0;
|
||||
post_header_len[ROTATE_EVENT-1]= (binlog_ver==1) ? 0 : ROTATE_HEADER_LEN;
|
||||
post_header_len[INTVAR_EVENT-1]= 0;
|
||||
post_header_len[LOAD_EVENT-1]= LOAD_HEADER_LEN;
|
||||
post_header_len[SLAVE_EVENT-1]= 0;
|
||||
post_header_len[CREATE_FILE_EVENT-1]= CREATE_FILE_HEADER_LEN;
|
||||
post_header_len[APPEND_BLOCK_EVENT-1]= APPEND_BLOCK_HEADER_LEN;
|
||||
post_header_len[EXEC_LOAD_EVENT-1]= EXEC_LOAD_HEADER_LEN;
|
||||
post_header_len[DELETE_FILE_EVENT-1]= DELETE_FILE_HEADER_LEN;
|
||||
post_header_len[NEW_LOAD_EVENT-1]= post_header_len[LOAD_EVENT-1];
|
||||
post_header_len[RAND_EVENT-1]= 0;
|
||||
post_header_len[USER_VAR_EVENT-1]= 0;
|
||||
}
|
||||
break;
|
||||
default: /* Includes binlog version 2 i.e. 4.0.x x<=1 */
|
||||
post_header_len= 0; /* will make is_valid() fail */
|
||||
break;
|
||||
@ -2232,14 +2096,26 @@ Format_description_log_event::
|
||||
Format_description_log_event(const uchar *buf, uint event_len,
|
||||
const Format_description_log_event*
|
||||
description_event)
|
||||
:Start_log_event_v3(buf, event_len, description_event),
|
||||
:Log_event(buf, description_event), binlog_version(BINLOG_VERSION),
|
||||
common_header_len(0), post_header_len(NULL), event_type_permutation(0)
|
||||
{
|
||||
DBUG_ENTER("Format_description_log_event::Format_description_log_event(char*,...)");
|
||||
if (!Start_log_event_v3::is_valid())
|
||||
DBUG_VOID_RETURN; /* sanity check */
|
||||
if (event_len < LOG_EVENT_MINIMAL_HEADER_LEN + ST_COMMON_HEADER_LEN_OFFSET)
|
||||
{
|
||||
server_version[0]= 0;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
buf+= LOG_EVENT_MINIMAL_HEADER_LEN;
|
||||
if ((common_header_len=buf[ST_COMMON_HEADER_LEN_OFFSET]) < OLD_HEADER_LEN)
|
||||
binlog_version= uint2korr(buf+ST_BINLOG_VER_OFFSET);
|
||||
memcpy(server_version, buf+ST_SERVER_VER_OFFSET, ST_SERVER_VER_LEN);
|
||||
// prevent overrun if log is corrupted on disk
|
||||
server_version[ST_SERVER_VER_LEN-1]= 0;
|
||||
created= uint4korr(buf+ST_CREATED_OFFSET);
|
||||
dont_set_created= 1;
|
||||
|
||||
if (server_version[0] == 0)
|
||||
DBUG_VOID_RETURN; /* sanity check */
|
||||
if ((common_header_len=buf[ST_COMMON_HEADER_LEN_OFFSET]) < LOG_EVENT_MINIMAL_HEADER_LEN)
|
||||
DBUG_VOID_RETURN; /* sanity check */
|
||||
number_of_event_types=
|
||||
event_len - (LOG_EVENT_MINIMAL_HEADER_LEN + ST_COMMON_HEADER_LEN_OFFSET + 1);
|
||||
@ -2427,120 +2303,6 @@ Start_encryption_log_event(const uchar *buf, uint event_len,
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
Load_log_event methods
|
||||
General note about Load_log_event: the binlogging of LOAD DATA INFILE is
|
||||
going to be changed in 5.0 (or maybe in 5.1; not decided yet).
|
||||
However, the 5.0 slave could still have to read such events (from a 4.x
|
||||
master), convert them (which just means maybe expand the header, when 5.0
|
||||
servers have a UID in events) (remember that whatever is after the header
|
||||
will be like in 4.x, as this event's format is not modified in 5.0 as we
|
||||
will use new types of events to log the new LOAD DATA INFILE features).
|
||||
To be able to read/convert, we just need to not assume that the common
|
||||
header is of length LOG_EVENT_HEADER_LEN (we must use the description
|
||||
event).
|
||||
Note that I (Guilhem) manually tested replication of a big LOAD DATA INFILE
|
||||
between 3.23 and 5.0, and between 4.0 and 5.0, and it works fine (and the
|
||||
positions displayed in SHOW SLAVE STATUS then are fine too).
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
/**
|
||||
@note
|
||||
The caller must do buf[event_len]= 0 before he starts using the
|
||||
constructed event.
|
||||
*/
|
||||
|
||||
Load_log_event::Load_log_event(const uchar *buf, uint event_len,
|
||||
const Format_description_log_event
|
||||
*description_event)
|
||||
:Log_event(buf, description_event), num_fields(0), fields(0),
|
||||
field_lens(0),field_block_len(0),
|
||||
table_name(0), db(0), fname(0), local_fname(FALSE),
|
||||
/*
|
||||
Load_log_event which comes from the binary log does not contain
|
||||
information about the type of insert which was used on the master.
|
||||
Assume that it was an ordinary, non-concurrent LOAD DATA.
|
||||
*/
|
||||
is_concurrent(FALSE)
|
||||
{
|
||||
DBUG_ENTER("Load_log_event");
|
||||
/*
|
||||
I (Guilhem) manually tested replication of LOAD DATA INFILE for 3.23->5.0,
|
||||
4.0->5.0 and 5.0->5.0 and it works.
|
||||
*/
|
||||
if (event_len)
|
||||
copy_log_event(buf, event_len,
|
||||
(((uchar)buf[EVENT_TYPE_OFFSET] == LOAD_EVENT) ?
|
||||
LOAD_HEADER_LEN +
|
||||
description_event->common_header_len :
|
||||
LOAD_HEADER_LEN + LOG_EVENT_HEADER_LEN),
|
||||
description_event);
|
||||
/* otherwise it's a derived class, will call copy_log_event() itself */
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Load_log_event::copy_log_event()
|
||||
*/
|
||||
|
||||
int Load_log_event::copy_log_event(const uchar *buf, ulong event_len,
|
||||
int body_offset,
|
||||
const Format_description_log_event
|
||||
*description_event)
|
||||
{
|
||||
DBUG_ENTER("Load_log_event::copy_log_event");
|
||||
uint data_len;
|
||||
if ((int) event_len <= body_offset)
|
||||
DBUG_RETURN(1);
|
||||
const uchar *buf_end= buf + event_len;
|
||||
/* this is the beginning of the post-header */
|
||||
const uchar *data_head= buf + description_event->common_header_len;
|
||||
thread_id= slave_proxy_id= uint4korr(data_head + L_THREAD_ID_OFFSET);
|
||||
exec_time= uint4korr(data_head + L_EXEC_TIME_OFFSET);
|
||||
skip_lines= uint4korr(data_head + L_SKIP_LINES_OFFSET);
|
||||
table_name_len= (uint)data_head[L_TBL_LEN_OFFSET];
|
||||
db_len= (uint)data_head[L_DB_LEN_OFFSET];
|
||||
num_fields= uint4korr(data_head + L_NUM_FIELDS_OFFSET);
|
||||
|
||||
/*
|
||||
Sql_ex.init() on success returns the pointer to the first byte after
|
||||
the sql_ex structure, which is the start of field lengths array.
|
||||
*/
|
||||
if (!(field_lens= (uchar*) sql_ex.init(buf + body_offset, buf_end,
|
||||
buf[EVENT_TYPE_OFFSET] != LOAD_EVENT)))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
data_len= event_len - body_offset;
|
||||
if (num_fields > data_len) // simple sanity check against corruption
|
||||
DBUG_RETURN(1);
|
||||
for (uint i= 0; i < num_fields; i++)
|
||||
field_block_len+= (uint)field_lens[i] + 1;
|
||||
|
||||
fields= (char*) field_lens + num_fields;
|
||||
table_name= fields + field_block_len;
|
||||
if (strlen(table_name) > NAME_LEN)
|
||||
goto err;
|
||||
|
||||
db= table_name + table_name_len + 1;
|
||||
DBUG_EXECUTE_IF("simulate_invalid_address", db_len= data_len;);
|
||||
fname= db + db_len + 1;
|
||||
if ((db_len > data_len) || (fname > (char*) buf_end))
|
||||
goto err;
|
||||
fname_len= (uint) strlen(fname);
|
||||
if ((fname_len > data_len) || (fname + fname_len > (char*) buf_end))
|
||||
goto err;
|
||||
// null termination is accomplished by the caller doing buf[event_len]=0
|
||||
|
||||
DBUG_RETURN(0);
|
||||
|
||||
err:
|
||||
// Invalid event.
|
||||
table_name= 0;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
Rotate_log_event methods
|
||||
@ -3020,68 +2782,6 @@ err:
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
Create_file_log_event methods
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
Create_file_log_event ctor
|
||||
*/
|
||||
|
||||
Create_file_log_event::
|
||||
Create_file_log_event(const uchar *buf, uint len,
|
||||
const Format_description_log_event* description_event)
|
||||
:Load_log_event(buf,0,description_event),fake_base(0),block(0),
|
||||
inited_from_old(0)
|
||||
{
|
||||
DBUG_ENTER("Create_file_log_event::Create_file_log_event(char*,...)");
|
||||
uint block_offset;
|
||||
uint header_len= description_event->common_header_len;
|
||||
uint8 load_header_len= description_event->post_header_len[LOAD_EVENT-1];
|
||||
uint8 create_file_header_len= description_event->post_header_len[CREATE_FILE_EVENT-1];
|
||||
if (!(event_buf= (uchar*) my_memdup(PSI_INSTRUMENT_ME, buf, len,
|
||||
MYF(MY_WME))) ||
|
||||
copy_log_event(event_buf,len,
|
||||
(((uchar)buf[EVENT_TYPE_OFFSET] == LOAD_EVENT) ?
|
||||
load_header_len + header_len :
|
||||
(fake_base ? (header_len+load_header_len) :
|
||||
(header_len+load_header_len) +
|
||||
create_file_header_len)),
|
||||
description_event))
|
||||
DBUG_VOID_RETURN;
|
||||
if (description_event->binlog_version!=1)
|
||||
{
|
||||
file_id= uint4korr(buf +
|
||||
header_len +
|
||||
load_header_len + CF_FILE_ID_OFFSET);
|
||||
/*
|
||||
Note that it's ok to use get_data_size() below, because it is computed
|
||||
with values we have already read from this event (because we called
|
||||
copy_log_event()); we are not using slave's format info to decode
|
||||
master's format, we are really using master's format info.
|
||||
Anyway, both formats should be identical (except the common_header_len)
|
||||
as these Load events are not changed between 4.0 and 5.0 (as logging of
|
||||
LOAD DATA INFILE does not use Load_log_event in 5.0).
|
||||
|
||||
The + 1 is for \0 terminating fname
|
||||
*/
|
||||
block_offset= (description_event->common_header_len +
|
||||
Load_log_event::get_data_size() +
|
||||
create_file_header_len + 1);
|
||||
if (len < block_offset)
|
||||
DBUG_VOID_RETURN;
|
||||
block= const_cast<uchar*>(buf) + block_offset;
|
||||
block_len= len - block_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
sql_ex.force_new_format();
|
||||
inited_from_old= 1;
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
Append_block_log_event methods
|
||||
**************************************************************************/
|
||||
@ -3130,27 +2830,6 @@ Delete_file_log_event(const uchar *buf, uint len,
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
Execute_load_log_event methods
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
Execute_load_log_event ctor
|
||||
*/
|
||||
|
||||
Execute_load_log_event::
|
||||
Execute_load_log_event(const uchar *buf, uint len,
|
||||
const Format_description_log_event* description_event)
|
||||
:Log_event(buf, description_event), file_id(0)
|
||||
{
|
||||
uint8 common_header_len= description_event->common_header_len;
|
||||
uint8 exec_load_header_len= description_event->post_header_len[EXEC_LOAD_EVENT-1];
|
||||
if (len < (uint)(common_header_len+exec_load_header_len))
|
||||
return;
|
||||
file_id= uint4korr(buf + common_header_len + EL_FILE_ID_OFFSET);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
Begin_load_query_log_event methods
|
||||
**************************************************************************/
|
||||
|
619
sql/log_event.h
619
sql/log_event.h
@ -169,21 +169,17 @@ class String;
|
||||
See the #defines below for the format specifics.
|
||||
|
||||
The events which really update data are Query_log_event,
|
||||
Execute_load_query_log_event and old Load_log_event and
|
||||
Execute_load_log_event events (Execute_load_query is used together with
|
||||
Begin_load_query and Append_block events to replicate LOAD DATA INFILE.
|
||||
Create_file/Append_block/Execute_load (which includes Load_log_event)
|
||||
were used to replicate LOAD DATA before the 5.0.3).
|
||||
Execute_load_query_log_event and Execute_load_log_event events
|
||||
(Execute_load_query is used together with Begin_load_query and Append_block
|
||||
events to replicate LOAD DATA INFILE.
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#define LOG_EVENT_HEADER_LEN 19 /* the fixed header length */
|
||||
#define OLD_HEADER_LEN 13 /* the fixed header length in 3.23 */
|
||||
/*
|
||||
Fixed header length, where 4.x and 5.0 agree. That is, 5.0 may have a longer
|
||||
header (it will for sure when we have the unique event's ID), but at least
|
||||
the first 19 bytes are the same in 4.x and 5.0. So when we have the unique
|
||||
event's ID, LOG_EVENT_HEADER_LEN will be something like 26, but
|
||||
Fixed header length. That is, some future version may have a longer
|
||||
header, but at least the first 19 bytes will be the same. So
|
||||
LOG_EVENT_HEADER_LEN will be something like 26, but
|
||||
LOG_EVENT_MINIMAL_HEADER_LEN will remain 19.
|
||||
*/
|
||||
#define LOG_EVENT_MINIMAL_HEADER_LEN 19
|
||||
@ -604,11 +600,6 @@ enum Log_event_type
|
||||
APPEND_BLOCK_EVENT= 9,
|
||||
EXEC_LOAD_EVENT= 10,
|
||||
DELETE_FILE_EVENT= 11,
|
||||
/*
|
||||
NEW_LOAD_EVENT is like LOAD_EVENT except that it has a longer
|
||||
sql_ex, allowing multibyte TERMINATED BY etc; both types share the
|
||||
same class (Load_log_event)
|
||||
*/
|
||||
NEW_LOAD_EVENT= 12,
|
||||
RAND_EVENT= 13,
|
||||
USER_VAR_EVENT= 14,
|
||||
@ -2098,10 +2089,9 @@ public:
|
||||
uint16 error_code;
|
||||
my_thread_id thread_id;
|
||||
/*
|
||||
For events created by Query_log_event::do_apply_event (and
|
||||
Load_log_event::do_apply_event()) we need the *original* thread
|
||||
id, to be able to log the event with the original (=master's)
|
||||
thread id (fix for BUG#1686).
|
||||
For events created by Query_log_event::do_apply_event we need the
|
||||
*original* thread id, to be able to log the event with the original
|
||||
(=master's) thread id (fix for BUG#1686).
|
||||
*/
|
||||
ulong slave_proxy_id;
|
||||
|
||||
@ -2125,12 +2115,6 @@ public:
|
||||
'sql_mode', 'affected' etc. Sometimes 'value' must be a short string, so
|
||||
its first byte is its length. For now the order of status vars is:
|
||||
flags2 - sql_mode - catalog - autoinc - charset
|
||||
We should add the same thing to Load_log_event, but in fact
|
||||
LOAD DATA INFILE is going to be logged with a new type of event (logging of
|
||||
the plain text query), so Load_log_event would be frozen, so no need. The
|
||||
new way of logging LOAD DATA INFILE would use a derived class of
|
||||
Query_log_event, so automatically benefit from the work already done for
|
||||
status variables in Query_log_event.
|
||||
*/
|
||||
uint16 status_vars_len;
|
||||
|
||||
@ -2162,16 +2146,6 @@ public:
|
||||
ulonglong table_map_for_update;
|
||||
/* Xid for the event, if such exists */
|
||||
ulonglong xid;
|
||||
/*
|
||||
Holds the original length of a Query_log_event that comes from a
|
||||
master of version < 5.0 (i.e., binlog_version < 4). When the IO
|
||||
thread writes the relay log, it augments the Query_log_event with a
|
||||
Q_MASTER_DATA_WRITTEN_CODE status_var that holds the original event
|
||||
length. This field is initialized to non-zero in the SQL thread when
|
||||
it reads this augmented event. SQL thread does not write
|
||||
Q_MASTER_DATA_WRITTEN_CODE to the slave's server binlog.
|
||||
*/
|
||||
uint32 master_data_written;
|
||||
/*
|
||||
A copy of Gtid event's extra flags that is relevant for two-phase
|
||||
logged ALTER.
|
||||
@ -2330,413 +2304,6 @@ struct sql_ex_info
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@class Load_log_event
|
||||
|
||||
This log event corresponds to a "LOAD DATA INFILE" SQL query on the
|
||||
following form:
|
||||
|
||||
@verbatim
|
||||
(1) USE db;
|
||||
(2) LOAD DATA [CONCURRENT] [LOCAL] INFILE 'file_name'
|
||||
(3) [REPLACE | IGNORE]
|
||||
(4) INTO TABLE 'table_name'
|
||||
(5) [FIELDS
|
||||
(6) [TERMINATED BY 'field_term']
|
||||
(7) [[OPTIONALLY] ENCLOSED BY 'enclosed']
|
||||
(8) [ESCAPED BY 'escaped']
|
||||
(9) ]
|
||||
(10) [LINES
|
||||
(11) [TERMINATED BY 'line_term']
|
||||
(12) [LINES STARTING BY 'line_start']
|
||||
(13) ]
|
||||
(14) [IGNORE skip_lines LINES]
|
||||
(15) (field_1, field_2, ..., field_n)@endverbatim
|
||||
|
||||
@section Load_log_event_binary_format Binary Format
|
||||
|
||||
The Post-Header consists of the following six components.
|
||||
|
||||
<table>
|
||||
<caption>Post-Header for Load_log_event</caption>
|
||||
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Format</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>slave_proxy_id</td>
|
||||
<td>4 byte unsigned integer</td>
|
||||
<td>An integer identifying the client thread that issued the
|
||||
query. The id is unique per server. (Note, however, that two
|
||||
threads on different servers may have the same slave_proxy_id.)
|
||||
This is used when a client thread creates a temporary table local
|
||||
to the client. The slave_proxy_id is used to distinguish
|
||||
temporary tables that belong to different clients.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>exec_time</td>
|
||||
<td>4 byte unsigned integer</td>
|
||||
<td>The time from when the query started to when it was logged in
|
||||
the binlog, in seconds.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>skip_lines</td>
|
||||
<td>4 byte unsigned integer</td>
|
||||
<td>The number on line (14) above, if present, or 0 if line (14)
|
||||
is left out.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>table_name_len</td>
|
||||
<td>1 byte unsigned integer</td>
|
||||
<td>The length of 'table_name' on line (4) above.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>db_len</td>
|
||||
<td>1 byte unsigned integer</td>
|
||||
<td>The length of 'db' on line (1) above.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>num_fields</td>
|
||||
<td>4 byte unsigned integer</td>
|
||||
<td>The number n of fields on line (15) above.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
The Body contains the following components.
|
||||
|
||||
<table>
|
||||
<caption>Body of Load_log_event</caption>
|
||||
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Format</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>sql_ex</td>
|
||||
<td>variable length</td>
|
||||
|
||||
<td>Describes the part of the query on lines (3) and
|
||||
(5)–(13) above. More precisely, it stores the five strings
|
||||
(on lines) field_term (6), enclosed (7), escaped (8), line_term
|
||||
(11), and line_start (12); as well as a bitfield indicating the
|
||||
presence of the keywords REPLACE (3), IGNORE (3), and OPTIONALLY
|
||||
(7).
|
||||
|
||||
The data is stored in one of two formats, called "old" and "new".
|
||||
The type field of Common-Header determines which of these two
|
||||
formats is used: type LOAD_EVENT means that the old format is
|
||||
used, and type NEW_LOAD_EVENT means that the new format is used.
|
||||
When MySQL writes a Load_log_event, it uses the new format if at
|
||||
least one of the five strings is two or more bytes long.
|
||||
Otherwise (i.e., if all strings are 0 or 1 bytes long), the old
|
||||
format is used.
|
||||
|
||||
The new and old format differ in the way the five strings are
|
||||
stored.
|
||||
|
||||
<ul>
|
||||
<li> In the new format, the strings are stored in the order
|
||||
field_term, enclosed, escaped, line_term, line_start. Each string
|
||||
consists of a length (1 byte), followed by a sequence of
|
||||
characters (0-255 bytes). Finally, a boolean combination of the
|
||||
following flags is stored in 1 byte: REPLACE_FLAG==0x4,
|
||||
IGNORE_FLAG==0x8, and OPT_ENCLOSED_FLAG==0x2. If a flag is set,
|
||||
it indicates the presence of the corresponding keyword in the SQL
|
||||
query.
|
||||
|
||||
<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
|
||||
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
|
||||
format. Finally, a 1 byte bitfield called empty_flags is stored.
|
||||
The low 5 bits of empty_flags indicate which of the five strings
|
||||
have length 0. For each of the following flags that is set, the
|
||||
corresponding string has length 0; for the flags that are not set,
|
||||
the string has length 1: FIELD_TERM_EMPTY==0x1,
|
||||
ENCLOSED_EMPTY==0x2, LINE_TERM_EMPTY==0x4, LINE_START_EMPTY==0x8,
|
||||
ESCAPED_EMPTY==0x10.
|
||||
</ul>
|
||||
|
||||
Thus, the size of the new format is 6 bytes + the sum of the sizes
|
||||
of the five strings. The size of the old format is always 7
|
||||
bytes.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>field_lens</td>
|
||||
<td>num_fields 1 byte unsigned integers</td>
|
||||
<td>An array of num_fields integers representing the length of
|
||||
each field in the query. (num_fields is from the Post-Header).
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>fields</td>
|
||||
<td>num_fields null-terminated strings</td>
|
||||
<td>An array of num_fields null-terminated strings, each
|
||||
representing a field in the query. (The trailing zero is
|
||||
redundant, since the length are stored in the num_fields array.)
|
||||
The total length of all strings equals to the sum of all
|
||||
field_lens, plus num_fields bytes for all the trailing zeros.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>table_name</td>
|
||||
<td>null-terminated string of length table_len+1 bytes</td>
|
||||
<td>The 'table_name' from the query, as a null-terminated string.
|
||||
(The trailing zero is actually redundant since the table_len is
|
||||
known from Post-Header.)
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>db</td>
|
||||
<td>null-terminated string of length db_len+1 bytes</td>
|
||||
<td>The 'db' from the query, as a null-terminated string.
|
||||
(The trailing zero is actually redundant since the db_len is known
|
||||
from Post-Header.)
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>file_name</td>
|
||||
<td>variable length string without trailing zero, extending to the
|
||||
end of the event (determined by the length field of the
|
||||
Common-Header)
|
||||
</td>
|
||||
<td>The 'file_name' from the query.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
@subsection Load_log_event_notes_on_previous_versions Notes on Previous Versions
|
||||
|
||||
This event type is understood by current versions, but only
|
||||
generated by MySQL 3.23 and earlier.
|
||||
*/
|
||||
class Load_log_event: public Log_event
|
||||
{
|
||||
private:
|
||||
protected:
|
||||
int copy_log_event(const uchar *buf, ulong event_len,
|
||||
int body_offset,
|
||||
const Format_description_log_event* description_event);
|
||||
|
||||
public:
|
||||
bool print_query(THD *thd, bool need_db, const char *cs, String *buf,
|
||||
my_off_t *fn_start, my_off_t *fn_end,
|
||||
const char *qualify_db);
|
||||
my_thread_id thread_id;
|
||||
ulong slave_proxy_id;
|
||||
uint32 table_name_len;
|
||||
/*
|
||||
No need to have a catalog, as these events can only come from 4.x.
|
||||
TODO: this may become false if Dmitri pushes his new LOAD DATA INFILE in
|
||||
5.0 only (not in 4.x).
|
||||
*/
|
||||
uint32 db_len;
|
||||
uint32 fname_len;
|
||||
uint32 num_fields;
|
||||
const char* fields;
|
||||
const uchar* field_lens;
|
||||
uint32 field_block_len;
|
||||
|
||||
const char* table_name;
|
||||
const char* db;
|
||||
const char* fname;
|
||||
uint32 skip_lines;
|
||||
sql_ex_info sql_ex;
|
||||
bool local_fname;
|
||||
/**
|
||||
Indicates that this event corresponds to LOAD DATA CONCURRENT,
|
||||
|
||||
@note Since Load_log_event event coming from the binary log
|
||||
lacks information whether LOAD DATA on master was concurrent
|
||||
or not, this flag is only set to TRUE for an auxiliary
|
||||
Load_log_event object which is used in mysql_load() to
|
||||
re-construct LOAD DATA statement from function parameters,
|
||||
for logging.
|
||||
*/
|
||||
bool is_concurrent;
|
||||
|
||||
/* fname doesn't point to memory inside Log_event::temp_buf */
|
||||
void set_fname_outside_temp_buf(const char *afname, size_t alen)
|
||||
{
|
||||
fname= afname;
|
||||
fname_len= (uint)alen;
|
||||
local_fname= TRUE;
|
||||
}
|
||||
/* fname doesn't point to memory inside Log_event::temp_buf */
|
||||
int check_fname_outside_temp_buf()
|
||||
{
|
||||
return local_fname;
|
||||
}
|
||||
|
||||
#ifdef MYSQL_SERVER
|
||||
String field_lens_buf;
|
||||
String fields_buf;
|
||||
|
||||
Load_log_event(THD* thd, const sql_exchange* ex, const char* db_arg,
|
||||
const char* table_name_arg,
|
||||
List<Item>& fields_arg,
|
||||
bool is_concurrent_arg,
|
||||
enum enum_duplicates handle_dup, bool ignore,
|
||||
bool using_trans);
|
||||
void set_fields(const char* db, List<Item> &fields_arg,
|
||||
Name_resolution_context *context);
|
||||
const char* get_db() { return db; }
|
||||
#ifdef HAVE_REPLICATION
|
||||
void pack_info(Protocol* protocol);
|
||||
#endif /* HAVE_REPLICATION */
|
||||
#else
|
||||
bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
|
||||
bool print(FILE* file, PRINT_EVENT_INFO* print_event_info, bool commented);
|
||||
#endif
|
||||
|
||||
/*
|
||||
Note that for all the events related to LOAD DATA (Load_log_event,
|
||||
Create_file/Append/Exec/Delete, we pass description_event; however as
|
||||
logging of LOAD DATA is going to be changed in 4.1 or 5.0, this is only used
|
||||
for the common_header_len (post_header_len will not be changed).
|
||||
*/
|
||||
Load_log_event(const uchar *buf, uint event_len,
|
||||
const Format_description_log_event* description_event);
|
||||
~Load_log_event()
|
||||
{}
|
||||
Log_event_type get_type_code()
|
||||
{
|
||||
return sql_ex.new_format() ? NEW_LOAD_EVENT: LOAD_EVENT;
|
||||
}
|
||||
#ifdef MYSQL_SERVER
|
||||
bool write_data_header();
|
||||
bool write_data_body();
|
||||
#endif
|
||||
bool is_valid() const { return table_name != 0; }
|
||||
int get_data_size()
|
||||
{
|
||||
return (table_name_len + db_len + 2 + fname_len
|
||||
+ LOAD_HEADER_LEN
|
||||
+ sql_ex.data_size() + field_block_len + num_fields);
|
||||
}
|
||||
|
||||
public: /* !!! Public in this patch to allow old usage */
|
||||
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
|
||||
virtual int do_apply_event(rpl_group_info *rgi)
|
||||
{
|
||||
return do_apply_event(thd->slave_net,rgi,0);
|
||||
}
|
||||
|
||||
int do_apply_event(NET *net, rpl_group_info *rgi,
|
||||
bool use_rli_only_for_errors);
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
@class Start_log_event_v3
|
||||
|
||||
Start_log_event_v3 is the Start_log_event of binlog format 3 (MySQL 3.23 and
|
||||
4.x).
|
||||
|
||||
Format_description_log_event derives from Start_log_event_v3; it is
|
||||
the Start_log_event of binlog format 4 (MySQL 5.0), that is, the
|
||||
event that describes the other events' Common-Header/Post-Header
|
||||
lengths. This event is sent by MySQL 5.0 whenever it starts sending
|
||||
a new binlog if the requested position is >4 (otherwise if ==4 the
|
||||
event will be sent naturally).
|
||||
|
||||
@section Start_log_event_v3_binary_format Binary Format
|
||||
*/
|
||||
class Start_log_event_v3: public Log_event
|
||||
{
|
||||
public:
|
||||
/*
|
||||
If this event is at the start of the first binary log since server
|
||||
startup 'created' should be the timestamp when the event (and the
|
||||
binary log) was created. In the other case (i.e. this event is at
|
||||
the start of a binary log created by FLUSH LOGS or automatic
|
||||
rotation), 'created' should be 0. This "trick" is used by MySQL
|
||||
>=4.0.14 slaves to know whether they must drop stale temporary
|
||||
tables and whether they should abort unfinished transaction.
|
||||
|
||||
Note that when 'created'!=0, it is always equal to the event's
|
||||
timestamp; indeed Start_log_event is written only in log.cc where
|
||||
the first constructor below is called, in which 'created' is set
|
||||
to 'when'. So in fact 'created' is a useless variable. When it is
|
||||
0 we can read the actual value from timestamp ('when') and when it
|
||||
is non-zero we can read the same value from timestamp
|
||||
('when'). Conclusion:
|
||||
- we use timestamp to print when the binlog was created.
|
||||
- we use 'created' only to know if this is a first binlog or not.
|
||||
In 3.23.57 we did not pay attention to this identity, so mysqlbinlog in
|
||||
3.23.57 does not print 'created the_date' if created was zero. This is now
|
||||
fixed.
|
||||
*/
|
||||
time_t created;
|
||||
uint16 binlog_version;
|
||||
char server_version[ST_SERVER_VER_LEN];
|
||||
/*
|
||||
We set this to 1 if we don't want to have the created time in the log,
|
||||
which is the case when we rollover to a new log.
|
||||
*/
|
||||
bool dont_set_created;
|
||||
|
||||
#ifdef MYSQL_SERVER
|
||||
Start_log_event_v3();
|
||||
#ifdef HAVE_REPLICATION
|
||||
void pack_info(Protocol* protocol);
|
||||
#endif /* HAVE_REPLICATION */
|
||||
#else
|
||||
Start_log_event_v3() {}
|
||||
bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
|
||||
#endif
|
||||
|
||||
Start_log_event_v3(const uchar *buf, uint event_len,
|
||||
const Format_description_log_event* description_event);
|
||||
~Start_log_event_v3() {}
|
||||
Log_event_type get_type_code() { return START_EVENT_V3;}
|
||||
my_off_t get_header_len(my_off_t l __attribute__((unused)))
|
||||
{ return LOG_EVENT_MINIMAL_HEADER_LEN; }
|
||||
#ifdef MYSQL_SERVER
|
||||
bool write();
|
||||
#endif
|
||||
bool is_valid() const { return server_version[0] != 0; }
|
||||
int get_data_size()
|
||||
{
|
||||
return START_V3_HEADER_LEN; //no variable-sized part
|
||||
}
|
||||
|
||||
protected:
|
||||
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
|
||||
virtual int do_apply_event(rpl_group_info *rgi);
|
||||
virtual enum_skip_reason do_shall_skip(rpl_group_info*)
|
||||
{
|
||||
/*
|
||||
Events from ourself should be skipped, but they should not
|
||||
decrease the slave skip counter.
|
||||
*/
|
||||
if (this->server_id == global_system_variables.server_id)
|
||||
return Log_event::EVENT_SKIP_IGNORE;
|
||||
else
|
||||
return Log_event::EVENT_SKIP_NOT;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
@class Start_encryption_log_event
|
||||
|
||||
@ -2847,9 +2414,40 @@ public:
|
||||
@section Format_description_log_event_binary_format Binary Format
|
||||
*/
|
||||
|
||||
class Format_description_log_event: public Start_log_event_v3
|
||||
class Format_description_log_event: public Log_event
|
||||
{
|
||||
public:
|
||||
/*
|
||||
If this event is at the start of the first binary log since server
|
||||
startup 'created' should be the timestamp when the event (and the
|
||||
binary log) was created. In the other case (i.e. this event is at
|
||||
the start of a binary log created by FLUSH LOGS or automatic
|
||||
rotation), 'created' should be 0. This "trick" is used by MySQL
|
||||
>=4.0.14 slaves to know whether they must drop stale temporary
|
||||
tables and whether they should abort unfinished transaction.
|
||||
|
||||
Note that when 'created'!=0, it is always equal to the event's
|
||||
timestamp; indeed Start_log_event is written only in log.cc where
|
||||
the first constructor below is called, in which 'created' is set
|
||||
to 'when'. So in fact 'created' is a useless variable. When it is
|
||||
0 we can read the actual value from timestamp ('when') and when it
|
||||
is non-zero we can read the same value from timestamp
|
||||
('when'). Conclusion:
|
||||
- we use timestamp to print when the binlog was created.
|
||||
- we use 'created' only to know if this is a first binlog or not.
|
||||
In 3.23.57 we did not pay attention to this identity, so mysqlbinlog in
|
||||
3.23.57 does not print 'created the_date' if created was zero. This is now
|
||||
fixed.
|
||||
*/
|
||||
time_t created;
|
||||
uint16 binlog_version;
|
||||
char server_version[ST_SERVER_VER_LEN];
|
||||
/*
|
||||
We set this to 1 if we don't want to have the created time in the log,
|
||||
which is the case when we rollover to a new log.
|
||||
*/
|
||||
bool dont_set_created;
|
||||
|
||||
/*
|
||||
The size of the fixed header which _all_ events have
|
||||
(for binlogs written by this version, this is equal to
|
||||
@ -2888,14 +2486,18 @@ public:
|
||||
my_free(post_header_len);
|
||||
}
|
||||
Log_event_type get_type_code() { return FORMAT_DESCRIPTION_EVENT;}
|
||||
my_off_t get_header_len(my_off_t) { return LOG_EVENT_MINIMAL_HEADER_LEN; }
|
||||
#ifdef MYSQL_SERVER
|
||||
bool write();
|
||||
#ifdef HAVE_REPLICATION
|
||||
void pack_info(Protocol* protocol);
|
||||
#endif /* HAVE_REPLICATION */
|
||||
#else
|
||||
bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
|
||||
#endif
|
||||
bool header_is_valid() const
|
||||
{
|
||||
return ((common_header_len >= ((binlog_version==1) ? OLD_HEADER_LEN :
|
||||
LOG_EVENT_MINIMAL_HEADER_LEN)) &&
|
||||
(post_header_len != NULL));
|
||||
return common_header_len >= LOG_EVENT_MINIMAL_HEADER_LEN && post_header_len;
|
||||
}
|
||||
|
||||
bool is_valid() const
|
||||
@ -3861,82 +3463,6 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/* the classes below are for the new LOAD DATA INFILE logging */
|
||||
|
||||
/**
|
||||
@class Create_file_log_event
|
||||
|
||||
@section Create_file_log_event_binary_format Binary Format
|
||||
*/
|
||||
|
||||
class Create_file_log_event: public Load_log_event
|
||||
{
|
||||
protected:
|
||||
/*
|
||||
Pretend we are Load event, so we can write out just
|
||||
our Load part - used on the slave when writing event out to
|
||||
SQL_LOAD-*.info file
|
||||
*/
|
||||
bool fake_base;
|
||||
public:
|
||||
uchar *block;
|
||||
const uchar *event_buf;
|
||||
uint block_len;
|
||||
uint file_id;
|
||||
bool inited_from_old;
|
||||
|
||||
#ifdef MYSQL_SERVER
|
||||
Create_file_log_event(THD* thd, sql_exchange* ex, const char* db_arg,
|
||||
const char* table_name_arg,
|
||||
List<Item>& fields_arg,
|
||||
bool is_concurrent_arg,
|
||||
enum enum_duplicates handle_dup, bool ignore,
|
||||
uchar* block_arg, uint block_len_arg,
|
||||
bool using_trans);
|
||||
#ifdef HAVE_REPLICATION
|
||||
void pack_info(Protocol* protocol);
|
||||
#endif /* HAVE_REPLICATION */
|
||||
#else
|
||||
bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
|
||||
bool print(FILE* file, PRINT_EVENT_INFO* print_event_info,
|
||||
bool enable_local);
|
||||
#endif
|
||||
|
||||
Create_file_log_event(const uchar *buf, uint event_len,
|
||||
const Format_description_log_event* description_event);
|
||||
~Create_file_log_event()
|
||||
{
|
||||
my_free((void*) event_buf);
|
||||
}
|
||||
|
||||
Log_event_type get_type_code()
|
||||
{
|
||||
return fake_base ? Load_log_event::get_type_code() : CREATE_FILE_EVENT;
|
||||
}
|
||||
int get_data_size()
|
||||
{
|
||||
return (fake_base ? Load_log_event::get_data_size() :
|
||||
Load_log_event::get_data_size() +
|
||||
4 + 1 + block_len);
|
||||
}
|
||||
bool is_valid() const { return inited_from_old || block != 0; }
|
||||
#ifdef MYSQL_SERVER
|
||||
bool write_data_header();
|
||||
bool write_data_body();
|
||||
/*
|
||||
Cut out Create_file extensions and
|
||||
write it as Load event - used on the slave
|
||||
*/
|
||||
bool write_base();
|
||||
#endif
|
||||
|
||||
private:
|
||||
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
|
||||
virtual int do_apply_event(rpl_group_info *rgi);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@class Append_block_log_event
|
||||
|
||||
@ -3956,9 +3482,7 @@ public:
|
||||
used by Append_block_log_event::write()), so it can't be read in
|
||||
the Append_block_log_event(const uchar *buf, int event_len)
|
||||
constructor. In other words, 'db' is used only for filtering by
|
||||
binlog-*-db rules. Create_file_log_event is different: it's 'db'
|
||||
(which is inherited from Load_log_event) is written to the binlog
|
||||
and can be re-read.
|
||||
binlog-*-db rules.
|
||||
*/
|
||||
const char* db;
|
||||
|
||||
@ -4033,46 +3557,6 @@ private:
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@class Execute_load_log_event
|
||||
|
||||
@section Delete_file_log_event_binary_format Binary Format
|
||||
*/
|
||||
|
||||
class Execute_load_log_event: public Log_event
|
||||
{
|
||||
public:
|
||||
uint file_id;
|
||||
const char* db; /* see comment in Append_block_log_event */
|
||||
|
||||
#ifdef MYSQL_SERVER
|
||||
Execute_load_log_event(THD* thd, const char* db_arg, bool using_trans);
|
||||
#ifdef HAVE_REPLICATION
|
||||
void pack_info(Protocol* protocol);
|
||||
#endif /* HAVE_REPLICATION */
|
||||
#else
|
||||
bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
|
||||
#endif
|
||||
|
||||
Execute_load_log_event(const uchar *buf, uint event_len,
|
||||
const Format_description_log_event
|
||||
*description_event);
|
||||
~Execute_load_log_event() {}
|
||||
Log_event_type get_type_code() { return EXEC_LOAD_EVENT;}
|
||||
int get_data_size() { return EXEC_LOAD_HEADER_LEN ;}
|
||||
bool is_valid() const { return file_id != 0; }
|
||||
#ifdef MYSQL_SERVER
|
||||
bool write();
|
||||
const char* get_db() { return db; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
|
||||
virtual int do_apply_event(rpl_group_info *rgi);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@class Begin_load_query_log_event
|
||||
|
||||
@ -5358,8 +4842,6 @@ private:
|
||||
*/
|
||||
virtual int do_exec_row(rpl_group_info *rli) = 0;
|
||||
#endif /* defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) */
|
||||
|
||||
friend class Old_rows_log_event;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -5608,9 +5090,6 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#include "log_event_old.h"
|
||||
|
||||
/**
|
||||
@class Incident_log_event
|
||||
|
||||
|
@ -2104,9 +2104,9 @@ err:
|
||||
}
|
||||
|
||||
|
||||
bool Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
|
||||
bool Format_description_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
|
||||
{
|
||||
DBUG_ENTER("Start_log_event_v3::print");
|
||||
DBUG_ENTER("Format_description_log_event::print");
|
||||
|
||||
Write_on_release_cache cache(&print_event_info->head_cache, file,
|
||||
Write_on_release_cache::FLUSH_F);
|
||||
@ -2188,122 +2188,6 @@ bool Start_encryption_log_event::print(FILE* file,
|
||||
}
|
||||
|
||||
|
||||
bool Load_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
|
||||
{
|
||||
return print(file, print_event_info, 0);
|
||||
}
|
||||
|
||||
|
||||
bool Load_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info,
|
||||
bool commented)
|
||||
{
|
||||
Write_on_release_cache cache(&print_event_info->head_cache, file_arg);
|
||||
bool different_db= 1;
|
||||
DBUG_ENTER("Load_log_event::print");
|
||||
|
||||
if (!print_event_info->short_form)
|
||||
{
|
||||
if (print_header(&cache, print_event_info, FALSE) ||
|
||||
my_b_printf(&cache, "\tQuery\tthread_id=%ld\texec_time=%ld\n",
|
||||
thread_id, exec_time))
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (db)
|
||||
{
|
||||
/*
|
||||
If the database is different from the one of the previous statement, we
|
||||
need to print the "use" command, and we update the last_db.
|
||||
But if commented, the "use" is going to be commented so we should not
|
||||
update the last_db.
|
||||
*/
|
||||
if ((different_db= memcmp(print_event_info->db, db, db_len + 1)) &&
|
||||
!commented)
|
||||
memcpy(print_event_info->db, db, db_len + 1);
|
||||
}
|
||||
|
||||
if (db && db[0] && different_db)
|
||||
if (my_b_printf(&cache, "%suse %`s%s\n",
|
||||
commented ? "# " : "",
|
||||
db, print_event_info->delimiter))
|
||||
goto err;
|
||||
|
||||
if (flags & LOG_EVENT_THREAD_SPECIFIC_F)
|
||||
if (my_b_printf(&cache,"%sSET @@session.pseudo_thread_id=%lu%s\n",
|
||||
commented ? "# " : "", (ulong)thread_id,
|
||||
print_event_info->delimiter))
|
||||
goto err;
|
||||
if (my_b_printf(&cache, "%sLOAD DATA ",
|
||||
commented ? "# " : ""))
|
||||
goto err;
|
||||
if (check_fname_outside_temp_buf())
|
||||
if (my_b_write_string(&cache, "LOCAL "))
|
||||
goto err;
|
||||
if (my_b_printf(&cache, "INFILE '%-*s' ", fname_len, fname))
|
||||
goto err;
|
||||
|
||||
if (sql_ex.opt_flags & REPLACE_FLAG)
|
||||
{
|
||||
if (my_b_write_string(&cache, "REPLACE "))
|
||||
goto err;
|
||||
}
|
||||
else if (sql_ex.opt_flags & IGNORE_FLAG)
|
||||
if (my_b_write_string(&cache, "IGNORE "))
|
||||
goto err;
|
||||
|
||||
if (my_b_printf(&cache, "INTO TABLE `%s`", table_name) ||
|
||||
my_b_write_string(&cache, " FIELDS TERMINATED BY ") ||
|
||||
pretty_print_str(&cache, sql_ex.field_term, sql_ex.field_term_len))
|
||||
goto err;
|
||||
|
||||
if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG)
|
||||
if (my_b_write_string(&cache, " OPTIONALLY "))
|
||||
goto err;
|
||||
if (my_b_write_string(&cache, " ENCLOSED BY ") ||
|
||||
pretty_print_str(&cache, sql_ex.enclosed, sql_ex.enclosed_len) ||
|
||||
my_b_write_string(&cache, " ESCAPED BY ") ||
|
||||
pretty_print_str(&cache, sql_ex.escaped, sql_ex.escaped_len) ||
|
||||
my_b_write_string(&cache, " LINES TERMINATED BY ") ||
|
||||
pretty_print_str(&cache, sql_ex.line_term, sql_ex.line_term_len))
|
||||
goto err;
|
||||
|
||||
if (sql_ex.line_start)
|
||||
{
|
||||
if (my_b_write_string(&cache," STARTING BY ") ||
|
||||
pretty_print_str(&cache, sql_ex.line_start, sql_ex.line_start_len))
|
||||
goto err;
|
||||
}
|
||||
if ((long) skip_lines > 0)
|
||||
if (my_b_printf(&cache, " IGNORE %ld LINES", (long) skip_lines))
|
||||
goto err;
|
||||
|
||||
if (num_fields)
|
||||
{
|
||||
uint i;
|
||||
const char* field = fields;
|
||||
if (my_b_write_string(&cache, " ("))
|
||||
goto err;
|
||||
for (i = 0; i < num_fields; i++)
|
||||
{
|
||||
if (i)
|
||||
if (my_b_write_byte(&cache, ','))
|
||||
goto err;
|
||||
if (my_b_printf(&cache, "%`s", field))
|
||||
goto err;
|
||||
field += field_lens[i] + 1;
|
||||
}
|
||||
if (my_b_write_byte(&cache, ')'))
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (my_b_printf(&cache, "%s\n", print_event_info->delimiter))
|
||||
goto err;
|
||||
DBUG_RETURN(cache.flush_data());
|
||||
err:
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
|
||||
bool Rotate_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
|
||||
{
|
||||
if (print_event_info->short_form)
|
||||
@ -2626,61 +2510,6 @@ bool Stop_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
|
||||
#endif
|
||||
|
||||
|
||||
bool Create_file_log_event::print(FILE* file,
|
||||
PRINT_EVENT_INFO* print_event_info,
|
||||
bool enable_local)
|
||||
{
|
||||
if (print_event_info->short_form)
|
||||
{
|
||||
if (enable_local && check_fname_outside_temp_buf())
|
||||
return Load_log_event::print(file, print_event_info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Write_on_release_cache cache(&print_event_info->head_cache, file);
|
||||
|
||||
if (enable_local)
|
||||
{
|
||||
if (Load_log_event::print(file, print_event_info,
|
||||
!check_fname_outside_temp_buf()))
|
||||
goto err;
|
||||
|
||||
/**
|
||||
reduce the size of io cache so that the write function is called
|
||||
for every call to my_b_printf().
|
||||
*/
|
||||
DBUG_EXECUTE_IF ("simulate_create_event_write_error",
|
||||
{(&cache)->write_pos= (&cache)->write_end;
|
||||
DBUG_SET("+d,simulate_file_write_error");});
|
||||
/*
|
||||
That one is for "file_id: etc" below: in mysqlbinlog we want the #, in
|
||||
SHOW BINLOG EVENTS we don't.
|
||||
*/
|
||||
if (my_b_write_byte(&cache, '#'))
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (my_b_printf(&cache, " file_id: %d block_len: %d\n", file_id, block_len))
|
||||
goto err;
|
||||
|
||||
return cache.flush_data();
|
||||
err:
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool Create_file_log_event::print(FILE* file,
|
||||
PRINT_EVENT_INFO* print_event_info)
|
||||
{
|
||||
return print(file, print_event_info, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Append_block_log_event::print()
|
||||
*/
|
||||
|
||||
bool Append_block_log_event::print(FILE* file,
|
||||
PRINT_EVENT_INFO* print_event_info)
|
||||
{
|
||||
@ -2700,10 +2529,6 @@ err:
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Delete_file_log_event::print()
|
||||
*/
|
||||
|
||||
bool Delete_file_log_event::print(FILE* file,
|
||||
PRINT_EVENT_INFO* print_event_info)
|
||||
{
|
||||
@ -2719,25 +2544,6 @@ bool Delete_file_log_event::print(FILE* file,
|
||||
return cache.flush_data();
|
||||
}
|
||||
|
||||
/*
|
||||
Execute_load_log_event::print()
|
||||
*/
|
||||
|
||||
bool Execute_load_log_event::print(FILE* file,
|
||||
PRINT_EVENT_INFO* print_event_info)
|
||||
{
|
||||
if (print_event_info->short_form)
|
||||
return 0;
|
||||
|
||||
Write_on_release_cache cache(&print_event_info->head_cache, file);
|
||||
|
||||
if (print_header(&cache, print_event_info, FALSE) ||
|
||||
my_b_printf(&cache, "\n#Exec_load: file_id=%d\n",
|
||||
file_id))
|
||||
return 1;
|
||||
|
||||
return cache.flush_data();
|
||||
}
|
||||
|
||||
bool Execute_load_query_log_event::print(FILE* file,
|
||||
PRINT_EVENT_INFO* print_event_info)
|
||||
@ -2995,10 +2801,6 @@ err:
|
||||
where fragments are represented by a pair of indexed user
|
||||
"one shot" variables.
|
||||
|
||||
@note
|
||||
If any changes made don't forget to duplicate them to
|
||||
Old_rows_log_event as long as it's supported.
|
||||
|
||||
@param file pointer to IO_CACHE
|
||||
@param print_event_info pointer to print_event_info specializing
|
||||
what out of and how to print the event
|
||||
|
2749
sql/log_event_old.cc
2749
sql/log_event_old.cc
File diff suppressed because it is too large
Load Diff
@ -1,569 +0,0 @@
|
||||
/* Copyright (c) 2007, 2013, Oracle and/or its affiliates.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
|
||||
|
||||
#ifndef LOG_EVENT_OLD_H
|
||||
#define LOG_EVENT_OLD_H
|
||||
|
||||
/*
|
||||
Need to include this file at the proper position of log_event.h
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
@file
|
||||
|
||||
@brief This file contains classes handling old formats of row-based
|
||||
binlog events.
|
||||
*/
|
||||
/*
|
||||
Around 2007-10-31, I made these classes completely separated from
|
||||
the new classes (before, there was a complex class hierarchy
|
||||
involving multiple inheritance; see BUG#31581), by simply copying
|
||||
and pasting the entire contents of Rows_log_event into
|
||||
Old_rows_log_event and the entire contents of
|
||||
{Write|Update|Delete}_rows_log_event into
|
||||
{Write|Update|Delete}_rows_log_event_old. For clarity, I will keep
|
||||
the comments marking which code was cut-and-pasted for some time.
|
||||
With the classes collapsed into one, there is probably some
|
||||
redundancy (maybe some methods can be simplified and/or removed),
|
||||
but we keep them this way for now. /Sven
|
||||
*/
|
||||
|
||||
/* These classes are based on the v1 RowsHeaderLen */
|
||||
#undef ROWS_HEADER_LEN
|
||||
#define ROWS_HEADER_LEN ROWS_HEADER_LEN_V1
|
||||
|
||||
/**
|
||||
@class Old_rows_log_event
|
||||
|
||||
Base class for the three types of row-based events
|
||||
{Write|Update|Delete}_row_log_event_old, with event type codes
|
||||
PRE_GA_{WRITE|UPDATE|DELETE}_ROWS_EVENT. These events are never
|
||||
created any more, except when reading a relay log created by an old
|
||||
server.
|
||||
*/
|
||||
class Old_rows_log_event : public Log_event
|
||||
{
|
||||
/********** BEGIN CUT & PASTE FROM Rows_log_event **********/
|
||||
public:
|
||||
/**
|
||||
Enumeration of the errors that can be returned.
|
||||
*/
|
||||
enum enum_error
|
||||
{
|
||||
ERR_OPEN_FAILURE = -1, /**< Failure to open table */
|
||||
ERR_OK = 0, /**< No error */
|
||||
ERR_TABLE_LIMIT_EXCEEDED = 1, /**< No more room for tables */
|
||||
ERR_OUT_OF_MEM = 2, /**< Out of memory */
|
||||
ERR_BAD_TABLE_DEF = 3, /**< Table definition does not match */
|
||||
ERR_RBR_TO_SBR = 4 /**< daisy-chanining RBR to SBR not allowed */
|
||||
};
|
||||
|
||||
/*
|
||||
These definitions allow you to combine the flags into an
|
||||
appropriate flag set using the normal bitwise operators. The
|
||||
implicit conversion from an enum-constant to an integer is
|
||||
accepted by the compiler, which is then used to set the real set
|
||||
of flags.
|
||||
*/
|
||||
enum enum_flag
|
||||
{
|
||||
/* Last event of a statement */
|
||||
STMT_END_F = (1U << 0),
|
||||
|
||||
/* Value of the OPTION_NO_FOREIGN_KEY_CHECKS flag in thd->options */
|
||||
NO_FOREIGN_KEY_CHECKS_F = (1U << 1),
|
||||
|
||||
/* Value of the OPTION_RELAXED_UNIQUE_CHECKS flag in thd->options */
|
||||
RELAXED_UNIQUE_CHECKS_F = (1U << 2),
|
||||
|
||||
/**
|
||||
Indicates that rows in this event are complete, that is contain
|
||||
values for all columns of the table.
|
||||
*/
|
||||
COMPLETE_ROWS_F = (1U << 3)
|
||||
};
|
||||
|
||||
typedef uint16 flag_set;
|
||||
|
||||
/* Special constants representing sets of flags */
|
||||
enum
|
||||
{
|
||||
RLE_NO_FLAGS = 0U
|
||||
};
|
||||
|
||||
virtual ~Old_rows_log_event();
|
||||
|
||||
void set_flags(flag_set flags_arg) { m_flags |= flags_arg; }
|
||||
void clear_flags(flag_set flags_arg) { m_flags &= ~flags_arg; }
|
||||
flag_set get_flags(flag_set flags_arg) const { return m_flags & flags_arg; }
|
||||
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
virtual void pack_info(Protocol *protocol);
|
||||
#endif
|
||||
|
||||
#ifdef MYSQL_CLIENT
|
||||
/* not for direct call, each derived has its own ::print() */
|
||||
virtual bool print(FILE *file, PRINT_EVENT_INFO *print_event_info)= 0;
|
||||
#endif
|
||||
|
||||
#ifndef MYSQL_CLIENT
|
||||
int add_row_data(uchar *data, size_t length)
|
||||
{
|
||||
return do_add_row_data(data,length);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Member functions to implement superclass interface */
|
||||
virtual int get_data_size();
|
||||
|
||||
MY_BITMAP const *get_cols() const { return &m_cols; }
|
||||
size_t get_width() const { return m_width; }
|
||||
ulong get_table_id() const { return m_table_id; }
|
||||
|
||||
#ifndef MYSQL_CLIENT
|
||||
virtual bool write_data_header();
|
||||
virtual bool write_data_body();
|
||||
virtual const char *get_db() { return m_table->s->db.str; }
|
||||
#endif
|
||||
/*
|
||||
Check that malloc() succeeded in allocating memory for the rows
|
||||
buffer and the COLS vector. Checking that an Update_rows_log_event_old
|
||||
is valid is done in the Update_rows_log_event_old::is_valid()
|
||||
function.
|
||||
*/
|
||||
virtual bool is_valid() const
|
||||
{
|
||||
return m_rows_buf && m_cols.bitmap;
|
||||
}
|
||||
bool is_part_of_group() { return 1; }
|
||||
|
||||
uint m_row_count; /* The number of rows added to the event */
|
||||
|
||||
protected:
|
||||
/*
|
||||
The constructors are protected since you're supposed to inherit
|
||||
this class, not create instances of this class.
|
||||
*/
|
||||
#ifndef MYSQL_CLIENT
|
||||
Old_rows_log_event(THD*, TABLE*, ulong table_id,
|
||||
MY_BITMAP const *cols, bool is_transactional);
|
||||
#endif
|
||||
Old_rows_log_event(const uchar *row_data, uint event_len,
|
||||
Log_event_type event_type,
|
||||
const Format_description_log_event *description_event);
|
||||
|
||||
#ifdef MYSQL_CLIENT
|
||||
bool print_helper(FILE *, PRINT_EVENT_INFO *, char const *const name);
|
||||
#endif
|
||||
|
||||
#ifndef MYSQL_CLIENT
|
||||
virtual int do_add_row_data(uchar *data, size_t length);
|
||||
#endif
|
||||
|
||||
#ifndef MYSQL_CLIENT
|
||||
TABLE *m_table; /* The table the rows belong to */
|
||||
#endif
|
||||
ulong m_table_id; /* Table ID */
|
||||
MY_BITMAP m_cols; /* Bitmap denoting columns available */
|
||||
ulong m_width; /* The width of the columns bitmap */
|
||||
|
||||
ulong m_master_reclength; /* Length of record on master side */
|
||||
|
||||
/* Bit buffers in the same memory as the class */
|
||||
uint32 m_bitbuf[128/(sizeof(uint32)*8)];
|
||||
uint32 m_bitbuf_ai[128/(sizeof(uint32)*8)];
|
||||
|
||||
uchar *m_rows_buf; /* The rows in packed format */
|
||||
uchar *m_rows_cur; /* One-after the end of the data */
|
||||
uchar *m_rows_end; /* One-after the end of the allocated space */
|
||||
|
||||
flag_set m_flags; /* Flags for row-level events */
|
||||
|
||||
/* helper functions */
|
||||
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
const uchar *m_curr_row; /* Start of the row being processed */
|
||||
const uchar *m_curr_row_end; /* One-after the end of the current row */
|
||||
uchar *m_key; /* Buffer to keep key value during searches */
|
||||
|
||||
int find_row(rpl_group_info *);
|
||||
int write_row(rpl_group_info *, const bool);
|
||||
|
||||
// Unpack the current row into m_table->record[0]
|
||||
int unpack_current_row(rpl_group_info *rgi)
|
||||
{
|
||||
DBUG_ASSERT(m_table);
|
||||
ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT);
|
||||
return ::unpack_row(rgi, m_table, m_width, m_curr_row, &m_cols,
|
||||
&m_curr_row_end, &m_master_reclength, m_rows_end);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
virtual int do_apply_event(rpl_group_info *rgi);
|
||||
virtual int do_update_pos(rpl_group_info *rgi);
|
||||
virtual enum_skip_reason do_shall_skip(rpl_group_info *rgi);
|
||||
|
||||
/*
|
||||
Primitive to prepare for a sequence of row executions.
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
Before doing a sequence of do_prepare_row() and do_exec_row()
|
||||
calls, this member function should be called to prepare for the
|
||||
entire sequence. Typically, this member function will allocate
|
||||
space for any buffers that are needed for the two member
|
||||
functions mentioned above.
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
The member function will return 0 if all went OK, or a non-zero
|
||||
error code otherwise.
|
||||
*/
|
||||
virtual
|
||||
int do_before_row_operations(const Slave_reporting_capability *const log) = 0;
|
||||
|
||||
/*
|
||||
Primitive to clean up after a sequence of row executions.
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
After doing a sequence of do_prepare_row() and do_exec_row(),
|
||||
this member function should be called to clean up and release
|
||||
any allocated buffers.
|
||||
|
||||
The error argument, if non-zero, indicates an error which happened during
|
||||
row processing before this function was called. In this case, even if
|
||||
function is successful, it should return the error code given in the argument.
|
||||
*/
|
||||
virtual
|
||||
int do_after_row_operations(const Slave_reporting_capability *const log,
|
||||
int error) = 0;
|
||||
|
||||
/*
|
||||
Primitive to do the actual execution necessary for a row.
|
||||
|
||||
DESCRIPTION
|
||||
The member function will do the actual execution needed to handle a row.
|
||||
The row is located at m_curr_row. When the function returns,
|
||||
m_curr_row_end should point at the next row (one byte after the end
|
||||
of the current row).
|
||||
|
||||
RETURN VALUE
|
||||
0 if execution succeeded, 1 if execution failed.
|
||||
|
||||
*/
|
||||
virtual int do_exec_row(rpl_group_info *rgi) = 0;
|
||||
#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
|
||||
|
||||
/********** END OF CUT & PASTE FROM Rows_log_event **********/
|
||||
protected:
|
||||
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
|
||||
int do_apply_event(Old_rows_log_event*, rpl_group_info *rgi);
|
||||
|
||||
/*
|
||||
Primitive to prepare for a sequence of row executions.
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
Before doing a sequence of do_prepare_row() and do_exec_row()
|
||||
calls, this member function should be called to prepare for the
|
||||
entire sequence. Typically, this member function will allocate
|
||||
space for any buffers that are needed for the two member
|
||||
functions mentioned above.
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
The member function will return 0 if all went OK, or a non-zero
|
||||
error code otherwise.
|
||||
*/
|
||||
virtual int do_before_row_operations(TABLE *table) = 0;
|
||||
|
||||
/*
|
||||
Primitive to clean up after a sequence of row executions.
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
After doing a sequence of do_prepare_row() and do_exec_row(),
|
||||
this member function should be called to clean up and release
|
||||
any allocated buffers.
|
||||
*/
|
||||
virtual int do_after_row_operations(TABLE *table, int error) = 0;
|
||||
|
||||
/*
|
||||
Primitive to prepare for handling one row in a row-level event.
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
The member function prepares for execution of operations needed for one
|
||||
row in a row-level event by reading up data from the buffer containing
|
||||
the row. No specific interpretation of the data is normally done here,
|
||||
since SQL thread specific data is not available: that data is made
|
||||
available for the do_exec function.
|
||||
|
||||
A pointer to the start of the next row, or NULL if the preparation
|
||||
failed. Currently, preparation cannot fail, but don't rely on this
|
||||
behavior.
|
||||
|
||||
RETURN VALUE
|
||||
Error code, if something went wrong, 0 otherwise.
|
||||
*/
|
||||
virtual int do_prepare_row(THD*, rpl_group_info*, TABLE*,
|
||||
uchar const *row_start,
|
||||
uchar const **row_end) = 0;
|
||||
|
||||
/*
|
||||
Primitive to do the actual execution necessary for a row.
|
||||
|
||||
DESCRIPTION
|
||||
The member function will do the actual execution needed to handle a row.
|
||||
|
||||
RETURN VALUE
|
||||
0 if execution succeeded, 1 if execution failed.
|
||||
|
||||
*/
|
||||
virtual int do_exec_row(TABLE *table) = 0;
|
||||
|
||||
#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@class Write_rows_log_event_old
|
||||
|
||||
Old class for binlog events that write new rows to a table (event
|
||||
type code PRE_GA_WRITE_ROWS_EVENT). Such events are never produced
|
||||
by this version of the server, but they may be read from a relay log
|
||||
created by an old server. New servers create events of class
|
||||
Write_rows_log_event (event type code WRITE_ROWS_EVENT) instead.
|
||||
*/
|
||||
class Write_rows_log_event_old : public Old_rows_log_event
|
||||
{
|
||||
/********** BEGIN CUT & PASTE FROM Write_rows_log_event **********/
|
||||
public:
|
||||
#if !defined(MYSQL_CLIENT)
|
||||
Write_rows_log_event_old(THD*, TABLE*, ulong table_id,
|
||||
MY_BITMAP const *cols, bool is_transactional);
|
||||
#endif
|
||||
#ifdef HAVE_REPLICATION
|
||||
Write_rows_log_event_old(const uchar *buf, uint event_len,
|
||||
const Format_description_log_event *description_event);
|
||||
#endif
|
||||
#if !defined(MYSQL_CLIENT)
|
||||
static bool binlog_row_logging_function(THD *thd, TABLE *table,
|
||||
bool is_transactional,
|
||||
const uchar *before_record
|
||||
__attribute__((unused)),
|
||||
const uchar *after_record)
|
||||
{
|
||||
return thd->binlog_write_row(table, is_transactional, after_record);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifdef MYSQL_CLIENT
|
||||
bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
|
||||
#endif
|
||||
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
virtual int do_before_row_operations(const Slave_reporting_capability *const);
|
||||
virtual int do_after_row_operations(const Slave_reporting_capability *const,int);
|
||||
virtual int do_exec_row(rpl_group_info *);
|
||||
#endif
|
||||
/********** END OF CUT & PASTE FROM Write_rows_log_event **********/
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
/* Support interface to THD::binlog_prepare_pending_rows_event */
|
||||
TYPE_CODE = PRE_GA_WRITE_ROWS_EVENT
|
||||
};
|
||||
|
||||
private:
|
||||
virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
|
||||
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
// use old definition of do_apply_event()
|
||||
virtual int do_apply_event(rpl_group_info *rgi)
|
||||
{ return Old_rows_log_event::do_apply_event(this, rgi); }
|
||||
|
||||
// primitives for old version of do_apply_event()
|
||||
virtual int do_before_row_operations(TABLE *table);
|
||||
virtual int do_after_row_operations(TABLE *table, int error);
|
||||
virtual int do_prepare_row(THD*, rpl_group_info*, TABLE*,
|
||||
uchar const *row_start, uchar const **row_end);
|
||||
virtual int do_exec_row(TABLE *table);
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@class Update_rows_log_event_old
|
||||
|
||||
Old class for binlog events that modify existing rows to a table
|
||||
(event type code PRE_GA_UPDATE_ROWS_EVENT). Such events are never
|
||||
produced by this version of the server, but they may be read from a
|
||||
relay log created by an old server. New servers create events of
|
||||
class Update_rows_log_event (event type code UPDATE_ROWS_EVENT)
|
||||
instead.
|
||||
*/
|
||||
class Update_rows_log_event_old : public Old_rows_log_event
|
||||
{
|
||||
/********** BEGIN CUT & PASTE FROM Update_rows_log_event **********/
|
||||
public:
|
||||
#ifndef MYSQL_CLIENT
|
||||
Update_rows_log_event_old(THD*, TABLE*, ulong table_id,
|
||||
MY_BITMAP const *cols,
|
||||
bool is_transactional);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_REPLICATION
|
||||
Update_rows_log_event_old(const uchar *buf, uint event_len,
|
||||
const Format_description_log_event *description_event);
|
||||
#endif
|
||||
|
||||
#if !defined(MYSQL_CLIENT)
|
||||
static bool binlog_row_logging_function(THD *thd, TABLE *table,
|
||||
bool is_transactional,
|
||||
MY_BITMAP *cols,
|
||||
uint fields,
|
||||
const uchar *before_record,
|
||||
const uchar *after_record)
|
||||
{
|
||||
return thd->binlog_update_row(table, is_transactional,
|
||||
before_record, after_record);
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
#ifdef MYSQL_CLIENT
|
||||
bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
|
||||
#endif
|
||||
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
virtual int do_before_row_operations(const Slave_reporting_capability *const);
|
||||
virtual int do_after_row_operations(const Slave_reporting_capability *const,int);
|
||||
virtual int do_exec_row(rpl_group_info *);
|
||||
#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
|
||||
/********** END OF CUT & PASTE FROM Update_rows_log_event **********/
|
||||
|
||||
uchar *m_after_image, *m_memory;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
/* Support interface to THD::binlog_prepare_pending_rows_event */
|
||||
TYPE_CODE = PRE_GA_UPDATE_ROWS_EVENT
|
||||
};
|
||||
|
||||
private:
|
||||
virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
|
||||
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
// use old definition of do_apply_event()
|
||||
virtual int do_apply_event(rpl_group_info *rgi)
|
||||
{ return Old_rows_log_event::do_apply_event(this, rgi); }
|
||||
|
||||
// primitives for old version of do_apply_event()
|
||||
virtual int do_before_row_operations(TABLE *table);
|
||||
virtual int do_after_row_operations(TABLE *table, int error);
|
||||
virtual int do_prepare_row(THD*, rpl_group_info*, TABLE*,
|
||||
uchar const *row_start, uchar const **row_end);
|
||||
virtual int do_exec_row(TABLE *table);
|
||||
#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@class Delete_rows_log_event_old
|
||||
|
||||
Old class for binlog events that delete existing rows from a table
|
||||
(event type code PRE_GA_DELETE_ROWS_EVENT). Such events are never
|
||||
produced by this version of the server, but they may be read from a
|
||||
relay log created by an old server. New servers create events of
|
||||
class Delete_rows_log_event (event type code DELETE_ROWS_EVENT)
|
||||
instead.
|
||||
*/
|
||||
class Delete_rows_log_event_old : public Old_rows_log_event
|
||||
{
|
||||
/********** BEGIN CUT & PASTE FROM Update_rows_log_event **********/
|
||||
public:
|
||||
#ifndef MYSQL_CLIENT
|
||||
Delete_rows_log_event_old(THD*, TABLE*, ulong,
|
||||
MY_BITMAP const *cols, bool is_transactional);
|
||||
#endif
|
||||
#ifdef HAVE_REPLICATION
|
||||
Delete_rows_log_event_old(const uchar *buf, uint event_len,
|
||||
const Format_description_log_event *description_event);
|
||||
#endif
|
||||
#if !defined(MYSQL_CLIENT)
|
||||
static bool binlog_row_logging_function(THD *thd, TABLE *table,
|
||||
bool is_transactional,
|
||||
MY_BITMAP *cols,
|
||||
uint fields,
|
||||
const uchar *before_record,
|
||||
const uchar *after_record
|
||||
__attribute__((unused)))
|
||||
{
|
||||
return thd->binlog_delete_row(table, is_transactional, before_record);
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
#ifdef MYSQL_CLIENT
|
||||
bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
|
||||
#endif
|
||||
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
virtual int do_before_row_operations(const Slave_reporting_capability *const);
|
||||
virtual int do_after_row_operations(const Slave_reporting_capability *const,int);
|
||||
virtual int do_exec_row(rpl_group_info *);
|
||||
#endif
|
||||
/********** END CUT & PASTE FROM Delete_rows_log_event **********/
|
||||
|
||||
uchar *m_after_image, *m_memory;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
/* Support interface to THD::binlog_prepare_pending_rows_event */
|
||||
TYPE_CODE = PRE_GA_DELETE_ROWS_EVENT
|
||||
};
|
||||
|
||||
private:
|
||||
virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
|
||||
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
// use old definition of do_apply_event()
|
||||
virtual int do_apply_event(rpl_group_info *rgi)
|
||||
{ return Old_rows_log_event::do_apply_event(this, rgi); }
|
||||
|
||||
// primitives for old version of do_apply_event()
|
||||
virtual int do_before_row_operations(TABLE *table);
|
||||
virtual int do_after_row_operations(TABLE *table, int error);
|
||||
virtual int do_prepare_row(THD*, rpl_group_info*, TABLE*,
|
||||
uchar const *row_start, uchar const **row_end);
|
||||
virtual int do_exec_row(TABLE *table);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,199 +0,0 @@
|
||||
/* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
|
||||
|
||||
#include "mariadb.h"
|
||||
#include "sql_priv.h"
|
||||
#include "rpl_rli.h"
|
||||
#include "rpl_record_old.h"
|
||||
#include "log_event.h" // Log_event_type
|
||||
|
||||
size_t
|
||||
pack_row_old(TABLE *table, MY_BITMAP const* cols,
|
||||
uchar *row_data, const uchar *record)
|
||||
{
|
||||
Field **p_field= table->field, *field;
|
||||
int n_null_bytes= table->s->null_bytes;
|
||||
uchar *ptr;
|
||||
uint i;
|
||||
my_ptrdiff_t const rec_offset= record - table->record[0];
|
||||
my_ptrdiff_t const def_offset= table->s->default_values - table->record[0];
|
||||
memcpy(row_data, record, n_null_bytes);
|
||||
ptr= row_data+n_null_bytes;
|
||||
|
||||
for (i= 0 ; (field= *p_field) ; i++, p_field++)
|
||||
{
|
||||
if (bitmap_is_set(cols,i))
|
||||
{
|
||||
my_ptrdiff_t const offset=
|
||||
field->is_null(rec_offset) ? def_offset : rec_offset;
|
||||
field->move_field_offset(offset);
|
||||
ptr= field->pack(ptr, field->ptr);
|
||||
field->move_field_offset(-offset);
|
||||
}
|
||||
}
|
||||
return (static_cast<size_t>(ptr - row_data));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Unpack a row into a record.
|
||||
|
||||
SYNOPSIS
|
||||
unpack_row()
|
||||
rli Relay log info
|
||||
table Table to unpack into
|
||||
colcnt Number of columns to read from record
|
||||
record Record where the data should be unpacked
|
||||
row Packed row data
|
||||
cols Pointer to columns data to fill in
|
||||
row_end Pointer to variable that will hold the value of the
|
||||
one-after-end position for the row
|
||||
master_reclength
|
||||
Pointer to variable that will be set to the length of the
|
||||
record on the master side
|
||||
rw_set Pointer to bitmap that holds either the read_set or the
|
||||
write_set of the table
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
The row is assumed to only consist of the fields for which the
|
||||
bitset represented by 'arr' and 'bits'; the other parts of the
|
||||
record are left alone.
|
||||
|
||||
At most 'colcnt' columns are read: if the table is larger than
|
||||
that, the remaining fields are not filled in.
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
Error code, or zero if no error. The following error codes can
|
||||
be returned:
|
||||
|
||||
ER_NO_DEFAULT_FOR_FIELD
|
||||
Returned if one of the fields existing on the slave but not on
|
||||
the master does not have a default value (and isn't nullable)
|
||||
ER_SLAVE_CORRUPT_EVENT
|
||||
Wrong data for field found.
|
||||
*/
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
int
|
||||
unpack_row_old(rpl_group_info *rgi,
|
||||
TABLE *table, uint const colcnt, uchar *record,
|
||||
uchar const *row, const uchar *row_buffer_end,
|
||||
MY_BITMAP const *cols,
|
||||
uchar const **row_end, ulong *master_reclength,
|
||||
MY_BITMAP* const rw_set, Log_event_type const event_type)
|
||||
{
|
||||
DBUG_ASSERT(record && row);
|
||||
my_ptrdiff_t const offset= record - (uchar*) table->record[0];
|
||||
size_t master_null_bytes= table->s->null_bytes;
|
||||
|
||||
if (colcnt != table->s->fields)
|
||||
{
|
||||
Field **fptr= &table->field[colcnt-1];
|
||||
do
|
||||
master_null_bytes= (*fptr)->last_null_byte();
|
||||
while (master_null_bytes == Field::LAST_NULL_BYTE_UNDEF &&
|
||||
fptr-- > table->field);
|
||||
|
||||
/*
|
||||
If master_null_bytes is LAST_NULL_BYTE_UNDEF (0) at this time,
|
||||
there were no nullable fields nor BIT fields at all in the
|
||||
columns that are common to the master and the slave. In that
|
||||
case, there is only one null byte holding the X bit.
|
||||
|
||||
OBSERVE! There might still be nullable columns following the
|
||||
common columns, so table->s->null_bytes might be greater than 1.
|
||||
*/
|
||||
if (master_null_bytes == Field::LAST_NULL_BYTE_UNDEF)
|
||||
master_null_bytes= 1;
|
||||
}
|
||||
|
||||
DBUG_ASSERT(master_null_bytes <= table->s->null_bytes);
|
||||
memcpy(record, row, master_null_bytes); // [1]
|
||||
int error= 0;
|
||||
|
||||
bitmap_set_all(rw_set);
|
||||
|
||||
Field **const begin_ptr = table->field;
|
||||
Field **field_ptr;
|
||||
uchar const *ptr= row + master_null_bytes;
|
||||
Field **const end_ptr= begin_ptr + colcnt;
|
||||
for (field_ptr= begin_ptr ; field_ptr < end_ptr ; ++field_ptr)
|
||||
{
|
||||
Field *const f= *field_ptr;
|
||||
|
||||
if (bitmap_is_set(cols, (uint)(field_ptr - begin_ptr)))
|
||||
{
|
||||
f->move_field_offset(offset);
|
||||
ptr= f->unpack(f->ptr, ptr, row_buffer_end, 0);
|
||||
f->move_field_offset(-offset);
|
||||
if (!ptr)
|
||||
{
|
||||
rgi->rli->report(ERROR_LEVEL, ER_SLAVE_CORRUPT_EVENT, NULL,
|
||||
"Could not read field `%s` of table `%s`.`%s`",
|
||||
f->field_name.str, table->s->db.str,
|
||||
table->s->table_name.str);
|
||||
return(ER_SLAVE_CORRUPT_EVENT);
|
||||
}
|
||||
}
|
||||
else
|
||||
bitmap_clear_bit(rw_set, (uint)(field_ptr - begin_ptr));
|
||||
}
|
||||
|
||||
*row_end = ptr;
|
||||
if (master_reclength)
|
||||
{
|
||||
if (*field_ptr)
|
||||
*master_reclength = (ulong)((*field_ptr)->ptr - table->record[0]);
|
||||
else
|
||||
*master_reclength = table->s->reclength;
|
||||
}
|
||||
|
||||
/*
|
||||
Set properties for remaining columns, if there are any. We let the
|
||||
corresponding bit in the write_set be set, to write the value if
|
||||
it was not there already. We iterate over all remaining columns,
|
||||
even if there were an error, to get as many error messages as
|
||||
possible. We are still able to return a pointer to the next row,
|
||||
so redo that.
|
||||
|
||||
This generation of error messages is only relevant when inserting
|
||||
new rows.
|
||||
*/
|
||||
for ( ; *field_ptr ; ++field_ptr)
|
||||
{
|
||||
uint32 const mask= NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG;
|
||||
|
||||
DBUG_PRINT("debug", ("flags = 0x%x, mask = 0x%x, flags & mask = 0x%x",
|
||||
(*field_ptr)->flags, mask,
|
||||
(*field_ptr)->flags & mask));
|
||||
|
||||
if (event_type == WRITE_ROWS_EVENT &&
|
||||
((*field_ptr)->flags & mask) == mask)
|
||||
{
|
||||
rgi->rli->report(ERROR_LEVEL, ER_NO_DEFAULT_FOR_FIELD, NULL,
|
||||
"Field `%s` of table `%s`.`%s` "
|
||||
"has no default value and cannot be NULL",
|
||||
(*field_ptr)->field_name.str, table->s->db.str,
|
||||
table->s->table_name.str);
|
||||
error = ER_NO_DEFAULT_FOR_FIELD;
|
||||
}
|
||||
else
|
||||
(*field_ptr)->set_default();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
#endif
|
@ -1,35 +0,0 @@
|
||||
/* Copyright (c) 2007, 2010, Oracle and/or its affiliates.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
|
||||
|
||||
#ifndef RPL_RECORD_OLD_H
|
||||
#define RPL_RECORD_OLD_H
|
||||
|
||||
#include "log_event.h" /* Log_event_type */
|
||||
|
||||
#ifndef MYSQL_CLIENT
|
||||
size_t pack_row_old(TABLE *table, MY_BITMAP const* cols,
|
||||
uchar *row_data, const uchar *record);
|
||||
|
||||
#ifdef HAVE_REPLICATION
|
||||
int unpack_row_old(rpl_group_info *rgi,
|
||||
TABLE *table, uint const colcnt, uchar *record,
|
||||
uchar const *row, uchar const *row_buffer_end,
|
||||
MY_BITMAP const *cols,
|
||||
uchar const **row_end, ulong *master_reclength,
|
||||
MY_BITMAP* const rw_set,
|
||||
Log_event_type const event_type);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
@ -525,13 +525,7 @@ read_relay_log_description_event(IO_CACHE *cur_log, ulonglong start_pos,
|
||||
Format_description_log_event *fdev;
|
||||
bool found= false;
|
||||
|
||||
/*
|
||||
By default the relay log is in binlog format 3 (4.0).
|
||||
Even if format is 4, this will work enough to read the first event
|
||||
(Format_desc) (remember that format 4 is just lenghtened compared to format
|
||||
3; format 3 is a prefix of format 4).
|
||||
*/
|
||||
fdev= new Format_description_log_event(3);
|
||||
fdev= new Format_description_log_event(4);
|
||||
|
||||
while (!found)
|
||||
{
|
||||
@ -666,14 +660,7 @@ int init_relay_log_pos(Relay_log_info* rli,const char* log,
|
||||
running, say, CHANGE MASTER.
|
||||
*/
|
||||
delete rli->relay_log.description_event_for_exec;
|
||||
/*
|
||||
By default the relay log is in binlog format 3 (4.0).
|
||||
Even if format is 4, this will work enough to read the first event
|
||||
(Format_desc) (remember that format 4 is just lenghtened compared to format
|
||||
3; format 3 is a prefix of format 4).
|
||||
*/
|
||||
rli->relay_log.description_event_for_exec= new
|
||||
Format_description_log_event(3);
|
||||
rli->relay_log.description_event_for_exec= new Format_description_log_event(4);
|
||||
|
||||
mysql_mutex_lock(log_lock);
|
||||
|
||||
|
369
sql/slave.cc
369
sql/slave.cc
@ -160,7 +160,6 @@ failed read"
|
||||
typedef enum { SLAVE_THD_IO, SLAVE_THD_SQL} SLAVE_THD_TYPE;
|
||||
|
||||
static int process_io_rotate(Master_info* mi, Rotate_log_event* rev);
|
||||
static int process_io_create_file(Master_info* mi, Create_file_log_event* cev);
|
||||
static bool wait_for_relay_log_space(Relay_log_info* rli);
|
||||
static bool io_slave_killed(Master_info* mi);
|
||||
static bool sql_slave_killed(rpl_group_info *rgi);
|
||||
@ -1487,20 +1486,6 @@ bool net_request_file(NET* net, const char* fname)
|
||||
(uchar*) "", 0));
|
||||
}
|
||||
|
||||
/*
|
||||
From other comments and tests in code, it looks like
|
||||
sometimes Query_log_event and Load_log_event can have db == 0
|
||||
(see rewrite_db() above for example)
|
||||
(cases where this happens are unclear; it may be when the master is 3.23).
|
||||
*/
|
||||
|
||||
const char *print_slave_db_safe(const char* db)
|
||||
{
|
||||
DBUG_ENTER("*print_slave_db_safe");
|
||||
|
||||
DBUG_RETURN((db ? db : ""));
|
||||
}
|
||||
|
||||
#endif /* HAVE_REPLICATION */
|
||||
|
||||
bool Sql_cmd_show_slave_status::execute(THD *thd)
|
||||
@ -1785,6 +1770,8 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi)
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
errmsg= err_buff2;
|
||||
snprintf(err_buff2, sizeof(err_buff2),
|
||||
"Master reported unrecognized MariaDB version: %s",
|
||||
@ -1792,14 +1779,6 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi)
|
||||
err_code= ER_SLAVE_FATAL_ERROR;
|
||||
sprintf(err_buff, ER_DEFAULT(err_code), err_buff2);
|
||||
break;
|
||||
case 3:
|
||||
mi->rli.relay_log.description_event_for_queue= new
|
||||
Format_description_log_event(1, mysql->server_version);
|
||||
break;
|
||||
case 4:
|
||||
mi->rli.relay_log.description_event_for_queue= new
|
||||
Format_description_log_event(3, mysql->server_version);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
Master is MySQL >=5.0. Give a default Format_desc event, so that we can
|
||||
@ -4850,8 +4829,6 @@ connected:
|
||||
goto connected;
|
||||
}
|
||||
|
||||
if (mi->rli.relay_log.description_event_for_queue->binlog_version > 1)
|
||||
{
|
||||
/*
|
||||
Register ourselves with the master.
|
||||
*/
|
||||
@ -4871,7 +4848,6 @@ connected:
|
||||
goto connected;
|
||||
}
|
||||
DBUG_EXECUTE_IF("fail_com_register_slave", goto err;);
|
||||
}
|
||||
|
||||
DBUG_PRINT("info",("Starting reading binary log from master"));
|
||||
thd->set_command(COM_SLAVE_IO);
|
||||
@ -5846,115 +5822,6 @@ err_during_init:
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
process_io_create_file()
|
||||
*/
|
||||
|
||||
static int process_io_create_file(Master_info* mi, Create_file_log_event* cev)
|
||||
{
|
||||
int error = 1;
|
||||
ulong num_bytes;
|
||||
bool cev_not_written;
|
||||
THD *thd = mi->io_thd;
|
||||
NET *net = &mi->mysql->net;
|
||||
DBUG_ENTER("process_io_create_file");
|
||||
|
||||
if (unlikely(!cev->is_valid()))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (!mi->rpl_filter->db_ok(cev->db))
|
||||
{
|
||||
skip_load_data_infile(net);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
DBUG_ASSERT(cev->inited_from_old);
|
||||
thd->file_id = cev->file_id = mi->file_id++;
|
||||
thd->variables.server_id = cev->server_id;
|
||||
cev_not_written = 1;
|
||||
|
||||
if (unlikely(net_request_file(net,cev->fname)))
|
||||
{
|
||||
sql_print_error("Slave I/O: failed requesting download of '%s'",
|
||||
cev->fname);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
This dummy block is so we could instantiate Append_block_log_event
|
||||
once and then modify it slightly instead of doing it multiple times
|
||||
in the loop
|
||||
*/
|
||||
{
|
||||
Append_block_log_event aev(thd,0,0,0,0);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (unlikely((num_bytes=my_net_read(net)) == packet_error))
|
||||
{
|
||||
sql_print_error("Network read error downloading '%s' from master",
|
||||
cev->fname);
|
||||
goto err;
|
||||
}
|
||||
if (unlikely(!num_bytes)) /* eof */
|
||||
{
|
||||
/* 3.23 master wants it */
|
||||
net_write_command(net, 0, (uchar*) "", 0, (uchar*) "", 0);
|
||||
/*
|
||||
If we wrote Create_file_log_event, then we need to write
|
||||
Execute_load_log_event. If we did not write Create_file_log_event,
|
||||
then this is an empty file and we can just do as if the LOAD DATA
|
||||
INFILE had not existed, i.e. write nothing.
|
||||
*/
|
||||
if (unlikely(cev_not_written))
|
||||
break;
|
||||
Execute_load_log_event xev(thd,0,0);
|
||||
xev.log_pos = cev->log_pos;
|
||||
if (unlikely(mi->rli.relay_log.append(&xev)))
|
||||
{
|
||||
mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, NULL,
|
||||
ER_THD(thd, ER_SLAVE_RELAY_LOG_WRITE_FAILURE),
|
||||
"error writing Exec_load event to relay log");
|
||||
goto err;
|
||||
}
|
||||
mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total);
|
||||
break;
|
||||
}
|
||||
if (unlikely(cev_not_written))
|
||||
{
|
||||
cev->block = net->read_pos;
|
||||
cev->block_len = num_bytes;
|
||||
if (unlikely(mi->rli.relay_log.append(cev)))
|
||||
{
|
||||
mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, NULL,
|
||||
ER_THD(thd, ER_SLAVE_RELAY_LOG_WRITE_FAILURE),
|
||||
"error writing Create_file event to relay log");
|
||||
goto err;
|
||||
}
|
||||
cev_not_written=0;
|
||||
mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total);
|
||||
}
|
||||
else
|
||||
{
|
||||
aev.block = net->read_pos;
|
||||
aev.block_len = num_bytes;
|
||||
aev.log_pos = cev->log_pos;
|
||||
if (unlikely(mi->rli.relay_log.append(&aev)))
|
||||
{
|
||||
mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, NULL,
|
||||
ER_THD(thd, ER_SLAVE_RELAY_LOG_WRITE_FAILURE),
|
||||
"error writing Append_block event to relay log");
|
||||
goto err;
|
||||
}
|
||||
mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
error=0;
|
||||
err:
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Start using a new binary log on the master
|
||||
|
||||
@ -5999,25 +5866,10 @@ static int process_io_rotate(Master_info *mi, Rotate_log_event *rev)
|
||||
mi->events_till_disconnect++;
|
||||
#endif
|
||||
|
||||
/*
|
||||
If description_event_for_queue is format <4, there is conversion in the
|
||||
relay log to the slave's format (4). And Rotate can mean upgrade or
|
||||
nothing. If upgrade, it's to 5.0 or newer, so we will get a Format_desc, so
|
||||
no need to reset description_event_for_queue now. And if it's nothing (same
|
||||
master version as before), no need (still using the slave's format).
|
||||
*/
|
||||
/* this prevents a redundant FDLE in the relay log */
|
||||
if (mi->rli.relay_log.description_event_for_queue->binlog_version >= 4)
|
||||
{
|
||||
DBUG_ASSERT(mi->rli.relay_log.description_event_for_queue->checksum_alg ==
|
||||
mi->rli.relay_log.relay_log_checksum_alg);
|
||||
mi->rli.relay_log.description_event_for_queue->binlog_version= 3;
|
||||
|
||||
delete mi->rli.relay_log.description_event_for_queue;
|
||||
/* start from format 3 (MySQL 4.0) again */
|
||||
mi->rli.relay_log.description_event_for_queue= new
|
||||
Format_description_log_event(3);
|
||||
mi->rli.relay_log.description_event_for_queue->checksum_alg=
|
||||
mi->rli.relay_log.relay_log_checksum_alg;
|
||||
}
|
||||
/*
|
||||
Rotate the relay log makes binlog format detection easier (at next slave
|
||||
start or mysqlbinlog)
|
||||
@ -6025,217 +5877,10 @@ static int process_io_rotate(Master_info *mi, Rotate_log_event *rev)
|
||||
DBUG_RETURN(rotate_relay_log(mi) /* will take the right mutexes */);
|
||||
}
|
||||
|
||||
/*
|
||||
Reads a 3.23 event and converts it to the slave's format. This code was
|
||||
copied from MySQL 4.0.
|
||||
*/
|
||||
static int queue_binlog_ver_1_event(Master_info *mi, const uchar *buf,
|
||||
ulong event_len)
|
||||
{
|
||||
const char *errmsg = 0;
|
||||
ulong inc_pos;
|
||||
bool ignore_event= 0;
|
||||
uchar *tmp_buf = 0;
|
||||
Relay_log_info *rli= &mi->rli;
|
||||
DBUG_ENTER("queue_binlog_ver_1_event");
|
||||
|
||||
/*
|
||||
If we get Load event, we need to pass a non-reusable buffer
|
||||
to read_log_event, so we do a trick
|
||||
*/
|
||||
if ((uchar)buf[EVENT_TYPE_OFFSET] == LOAD_EVENT)
|
||||
{
|
||||
if (unlikely(!(tmp_buf= (uchar*) my_malloc(key_memory_binlog_ver_1_event,
|
||||
event_len+1, MYF(MY_WME)))))
|
||||
{
|
||||
mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, NULL,
|
||||
ER(ER_SLAVE_FATAL_ERROR), "Memory allocation failed");
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
memcpy(tmp_buf,buf,event_len);
|
||||
/*
|
||||
Create_file constructor wants a 0 as last char of buffer, this 0 will
|
||||
serve as the string-termination char for the file's name (which is at the
|
||||
end of the buffer)
|
||||
We must increment event_len, otherwise the event constructor will not see
|
||||
this end 0, which leads to segfault.
|
||||
*/
|
||||
tmp_buf[event_len++]=0;
|
||||
int4store(tmp_buf+EVENT_LEN_OFFSET, event_len);
|
||||
buf= tmp_buf;
|
||||
}
|
||||
/*
|
||||
This will transform LOAD_EVENT into CREATE_FILE_EVENT, ask the master to
|
||||
send the loaded file, and write it to the relay log in the form of
|
||||
Append_block/Exec_load (the SQL thread needs the data, as that thread is not
|
||||
connected to the master).
|
||||
*/
|
||||
Log_event *ev=
|
||||
Log_event::read_log_event(buf, event_len, &errmsg,
|
||||
mi->rli.relay_log.description_event_for_queue, 0);
|
||||
if (unlikely(!ev))
|
||||
{
|
||||
sql_print_error("Read invalid event from master: '%s',\
|
||||
master could be corrupt but a more likely cause of this is a bug",
|
||||
errmsg);
|
||||
my_free(tmp_buf);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
mysql_mutex_lock(&mi->data_lock);
|
||||
ev->log_pos= mi->master_log_pos; /* 3.23 events don't contain log_pos */
|
||||
switch (ev->get_type_code()) {
|
||||
case STOP_EVENT:
|
||||
ignore_event= 1;
|
||||
inc_pos= event_len;
|
||||
break;
|
||||
case ROTATE_EVENT:
|
||||
if (unlikely(process_io_rotate(mi,(Rotate_log_event*)ev)))
|
||||
{
|
||||
delete ev;
|
||||
mysql_mutex_unlock(&mi->data_lock);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
inc_pos= 0;
|
||||
break;
|
||||
case CREATE_FILE_EVENT:
|
||||
/*
|
||||
Yes it's possible to have CREATE_FILE_EVENT here, even if we're in
|
||||
queue_old_event() which is for 3.23 events which don't comprise
|
||||
CREATE_FILE_EVENT. This is because read_log_event() above has just
|
||||
transformed LOAD_EVENT into CREATE_FILE_EVENT.
|
||||
*/
|
||||
{
|
||||
/* We come here when and only when tmp_buf != 0 */
|
||||
DBUG_ASSERT(tmp_buf != 0);
|
||||
inc_pos=event_len;
|
||||
ev->log_pos+= inc_pos;
|
||||
int error = process_io_create_file(mi,(Create_file_log_event*)ev);
|
||||
delete ev;
|
||||
mi->master_log_pos += inc_pos;
|
||||
DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
|
||||
mysql_mutex_unlock(&mi->data_lock);
|
||||
my_free(tmp_buf);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
default:
|
||||
inc_pos= event_len;
|
||||
break;
|
||||
}
|
||||
if (likely(!ignore_event))
|
||||
{
|
||||
if (ev->log_pos)
|
||||
/*
|
||||
Don't do it for fake Rotate events (see comment in
|
||||
Log_event::Log_event(const char* buf...) in log_event.cc).
|
||||
*/
|
||||
ev->log_pos+= event_len; /* make log_pos be the pos of the end of the event */
|
||||
if (unlikely(rli->relay_log.append(ev)))
|
||||
{
|
||||
delete ev;
|
||||
mysql_mutex_unlock(&mi->data_lock);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
rli->relay_log.harvest_bytes_written(&rli->log_space_total);
|
||||
}
|
||||
delete ev;
|
||||
mi->master_log_pos+= inc_pos;
|
||||
DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
|
||||
mysql_mutex_unlock(&mi->data_lock);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*
|
||||
Reads a 4.0 event and converts it to the slave's format. This code was copied
|
||||
from queue_binlog_ver_1_event(), with some affordable simplifications.
|
||||
*/
|
||||
static int queue_binlog_ver_3_event(Master_info *mi, const uchar *buf,
|
||||
ulong event_len)
|
||||
{
|
||||
const char *errmsg = 0;
|
||||
ulong inc_pos;
|
||||
char *tmp_buf = 0;
|
||||
Relay_log_info *rli= &mi->rli;
|
||||
DBUG_ENTER("queue_binlog_ver_3_event");
|
||||
|
||||
/* read_log_event() will adjust log_pos to be end_log_pos */
|
||||
Log_event *ev=
|
||||
Log_event::read_log_event(buf, event_len, &errmsg,
|
||||
mi->rli.relay_log.description_event_for_queue, 0);
|
||||
if (unlikely(!ev))
|
||||
{
|
||||
sql_print_error("Read invalid event from master: '%s',\
|
||||
master could be corrupt but a more likely cause of this is a bug",
|
||||
errmsg);
|
||||
my_free(tmp_buf);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
mysql_mutex_lock(&mi->data_lock);
|
||||
switch (ev->get_type_code()) {
|
||||
case STOP_EVENT:
|
||||
goto err;
|
||||
case ROTATE_EVENT:
|
||||
if (unlikely(process_io_rotate(mi,(Rotate_log_event*)ev)))
|
||||
{
|
||||
delete ev;
|
||||
mysql_mutex_unlock(&mi->data_lock);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
inc_pos= 0;
|
||||
break;
|
||||
default:
|
||||
inc_pos= event_len;
|
||||
break;
|
||||
}
|
||||
|
||||
if (unlikely(rli->relay_log.append(ev)))
|
||||
{
|
||||
delete ev;
|
||||
mysql_mutex_unlock(&mi->data_lock);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
rli->relay_log.harvest_bytes_written(&rli->log_space_total);
|
||||
delete ev;
|
||||
mi->master_log_pos+= inc_pos;
|
||||
err:
|
||||
DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
|
||||
mysql_mutex_unlock(&mi->data_lock);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*
|
||||
queue_old_event()
|
||||
|
||||
Writes a 3.23 or 4.0 event to the relay log, after converting it to the 5.0
|
||||
(exactly, slave's) format. To do the conversion, we create a 5.0 event from
|
||||
the 3.23/4.0 bytes, then write this event to the relay log.
|
||||
|
||||
TODO:
|
||||
Test this code before release - it has to be tested on a separate
|
||||
setup with 3.23 master or 4.0 master
|
||||
*/
|
||||
|
||||
static int queue_old_event(Master_info *mi, const uchar *buf, ulong event_len)
|
||||
{
|
||||
DBUG_ENTER("queue_old_event");
|
||||
|
||||
switch (mi->rli.relay_log.description_event_for_queue->binlog_version) {
|
||||
case 1:
|
||||
DBUG_RETURN(queue_binlog_ver_1_event(mi,buf,event_len));
|
||||
case 3:
|
||||
DBUG_RETURN(queue_binlog_ver_3_event(mi,buf,event_len));
|
||||
default: /* unsupported format; eg version 2 */
|
||||
DBUG_PRINT("info",("unsupported binlog format %d in queue_old_event()",
|
||||
mi->rli.relay_log.description_event_for_queue->binlog_version));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
queue_event()
|
||||
|
||||
If the event is 3.23/4.0, passes it to queue_old_event() which will convert
|
||||
it. Otherwise, writes a 5.0 (or newer) event to the relay log. Then there is
|
||||
Writes a 5.0 (or newer) event to the relay log. Then there is
|
||||
no format conversion, it's pure read/write of bytes.
|
||||
So a 5.0.0 slave's relay log can contain events in the slave's format or in
|
||||
any >=5.0.0 format.
|
||||
@ -6323,10 +5968,6 @@ static int queue_event(Master_info* mi, const uchar *buf, ulong event_len)
|
||||
}
|
||||
DBUG_ASSERT(((uchar) buf[FLAGS_OFFSET] & LOG_EVENT_ACCEPT_OWN_F) == 0);
|
||||
|
||||
if (mi->rli.relay_log.description_event_for_queue->binlog_version<4 &&
|
||||
buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT /* a way to escape */)
|
||||
DBUG_RETURN(queue_old_event(mi,buf,event_len));
|
||||
|
||||
#ifdef ENABLED_DEBUG_SYNC
|
||||
/*
|
||||
A (+d,dbug.rows_events_to_delay_relay_logging)-test is supposed to
|
||||
|
@ -90,7 +90,6 @@ struct rpl_group_info;
|
||||
struct rpl_parallel_thread;
|
||||
class Rpl_filter;
|
||||
class Query_log_event;
|
||||
class Load_log_event;
|
||||
class Log_event_writer;
|
||||
class sp_rcontext;
|
||||
class sp_cache;
|
||||
|
@ -836,8 +836,6 @@ err:
|
||||
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
|
||||
/* Not a very useful function; just to avoid duplication of code */
|
||||
static bool write_execute_load_query_log_event(THD *thd, const sql_exchange* ex,
|
||||
const char* db_arg, /* table's database */
|
||||
const char* table_name_arg,
|
||||
@ -848,27 +846,34 @@ static bool write_execute_load_query_log_event(THD *thd, const sql_exchange* ex,
|
||||
int errcode)
|
||||
{
|
||||
char *load_data_query;
|
||||
my_off_t fname_start,
|
||||
fname_end;
|
||||
List<Item> fv;
|
||||
my_off_t fname_start, fname_end;
|
||||
Item *item, *val;
|
||||
int n;
|
||||
const char *tdb= (thd->db.str != NULL ? thd->db.str : db_arg);
|
||||
const char *qualify_db= NULL;
|
||||
char command_buffer[1024];
|
||||
String query_str(command_buffer, sizeof(command_buffer),
|
||||
system_charset_info);
|
||||
StringBuffer<1024> query_str(system_charset_info);
|
||||
|
||||
Load_log_event lle(thd, ex, tdb, table_name_arg, fv, is_concurrent,
|
||||
duplicates, ignore, transactional_table);
|
||||
query_str.append(STRING_WITH_LEN("LOAD DATA "));
|
||||
|
||||
if (is_concurrent)
|
||||
query_str.append(STRING_WITH_LEN("CONCURRENT "));
|
||||
|
||||
fname_start= query_str.length();
|
||||
|
||||
/*
|
||||
force in a LOCAL if there was one in the original.
|
||||
*/
|
||||
if (thd->lex->local_file)
|
||||
lle.set_fname_outside_temp_buf(ex->file_name, strlen(ex->file_name));
|
||||
query_str.append(STRING_WITH_LEN("LOCAL "));
|
||||
query_str.append(STRING_WITH_LEN("INFILE '"));
|
||||
query_str.append_for_single_quote(ex->file_name, strlen(ex->file_name));
|
||||
query_str.append(STRING_WITH_LEN("' "));
|
||||
|
||||
query_str.length(0);
|
||||
if (duplicates == DUP_REPLACE)
|
||||
query_str.append(STRING_WITH_LEN("REPLACE "));
|
||||
else if (ignore)
|
||||
query_str.append(STRING_WITH_LEN("IGNORE "));
|
||||
|
||||
query_str.append(STRING_WITH_LEN("INTO"));
|
||||
|
||||
fname_end= query_str.length();
|
||||
|
||||
query_str.append(STRING_WITH_LEN(" TABLE "));
|
||||
if (!thd->db.str || strcmp(db_arg, thd->db.str))
|
||||
{
|
||||
/*
|
||||
@ -876,10 +881,47 @@ static bool write_execute_load_query_log_event(THD *thd, const sql_exchange* ex,
|
||||
prefix table name with database name so that it
|
||||
becomes a FQ name.
|
||||
*/
|
||||
qualify_db= db_arg;
|
||||
append_identifier(thd, &query_str, db_arg, strlen(db_arg));
|
||||
query_str.append(STRING_WITH_LEN("."));
|
||||
}
|
||||
append_identifier(thd, &query_str, table_name_arg, strlen(table_name_arg));
|
||||
|
||||
if (ex->cs)
|
||||
{
|
||||
query_str.append(STRING_WITH_LEN(" CHARACTER SET "));
|
||||
query_str.append(ex->cs->cs_name);
|
||||
}
|
||||
|
||||
/* We have to create all optional fields as the default is not empty */
|
||||
query_str.append(STRING_WITH_LEN(" FIELDS TERMINATED BY '"));
|
||||
query_str.append_for_single_quote(ex->field_term);
|
||||
query_str.append(STRING_WITH_LEN("'"));
|
||||
if (ex->opt_enclosed)
|
||||
query_str.append(STRING_WITH_LEN(" OPTIONALLY"));
|
||||
query_str.append(STRING_WITH_LEN(" ENCLOSED BY '"));
|
||||
query_str.append_for_single_quote(ex->enclosed);
|
||||
query_str.append(STRING_WITH_LEN("'"));
|
||||
|
||||
query_str.append(STRING_WITH_LEN(" ESCAPED BY '"));
|
||||
query_str.append_for_single_quote(ex->escaped);
|
||||
query_str.append(STRING_WITH_LEN("'"));
|
||||
|
||||
query_str.append(STRING_WITH_LEN(" LINES TERMINATED BY '"));
|
||||
query_str.append_for_single_quote(ex->line_term);
|
||||
query_str.append(STRING_WITH_LEN("'"));
|
||||
if (ex->line_start->length())
|
||||
{
|
||||
query_str.append(STRING_WITH_LEN(" STARTING BY '"));
|
||||
query_str.append_for_single_quote(ex->line_start);
|
||||
query_str.append(STRING_WITH_LEN("'"));
|
||||
}
|
||||
|
||||
if (ex->skip_lines)
|
||||
{
|
||||
query_str.append(STRING_WITH_LEN(" IGNORE "));
|
||||
query_str.append_ulonglong(ex->skip_lines);
|
||||
query_str.append(STRING_WITH_LEN(" LINES "));
|
||||
}
|
||||
lle.print_query(thd, FALSE, (const char*) ex->cs ? ex->cs->cs_name.str : NULL,
|
||||
&query_str, &fname_start, &fname_end, qualify_db);
|
||||
|
||||
/*
|
||||
prepare fields-list and SET if needed; print_query won't do that for us.
|
||||
|
@ -1467,7 +1467,7 @@ gtid_state_from_pos(const char *name, uint32 offset,
|
||||
if (unlikely((file= open_binlog(&cache, name, &errormsg)) == (File)-1))
|
||||
return errormsg;
|
||||
|
||||
if (!(fdev= new Format_description_log_event(3)))
|
||||
if (!(fdev= new Format_description_log_event(4)))
|
||||
{
|
||||
errormsg= "Out of memory initializing format_description event "
|
||||
"while scanning binlog to find start position";
|
||||
@ -2273,7 +2273,7 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log,
|
||||
if (info->fdev != NULL)
|
||||
delete info->fdev;
|
||||
|
||||
if (!(info->fdev= new Format_description_log_event(3)))
|
||||
if (!(info->fdev= new Format_description_log_event(4)))
|
||||
{
|
||||
info->errmsg= "Out of memory initializing format_description event";
|
||||
info->error= ER_MASTER_FATAL_ERROR_READING_BINLOG;
|
||||
@ -4163,7 +4163,7 @@ bool mysql_show_binlog_events(THD* thd)
|
||||
}
|
||||
|
||||
Format_description_log_event *description_event= new
|
||||
Format_description_log_event(3); /* MySQL 4.0 by default */
|
||||
Format_description_log_event(4);
|
||||
|
||||
if (binary_log->is_open())
|
||||
{
|
||||
|
@ -1146,7 +1146,6 @@ String_copier::well_formed_copy(CHARSET_INFO *to_cs,
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Append characters to a single-quoted string '...', escaping special
|
||||
characters with backslashes as necessary.
|
||||
@ -1164,6 +1163,8 @@ bool String::append_for_single_quote(const char *st, size_t len)
|
||||
case '\\': APPEND(STRING_WITH_LEN("\\\\"));
|
||||
case '\0': APPEND(STRING_WITH_LEN("\\0"));
|
||||
case '\'': APPEND(STRING_WITH_LEN("\\'"));
|
||||
case '\b': APPEND(STRING_WITH_LEN("\\b"));
|
||||
case '\t': APPEND(STRING_WITH_LEN("\\t"));
|
||||
case '\n': APPEND(STRING_WITH_LEN("\\n"));
|
||||
case '\r': APPEND(STRING_WITH_LEN("\\r"));
|
||||
case '\032': APPEND(STRING_WITH_LEN("\\Z"));
|
||||
|
@ -3413,7 +3413,7 @@ ignore_error:
|
||||
WSREP_WARN("Ignoring error '%s' on query. "
|
||||
"Default database: '%s'. Query: '%s', Error_code: %d",
|
||||
thd->get_stmt_da()->message(),
|
||||
print_slave_db_safe(thd->db.str),
|
||||
safe_str(thd->db.str),
|
||||
thd->query(),
|
||||
error);
|
||||
return 1;
|
||||
|
Reference in New Issue
Block a user