summaryrefslogtreecommitdiff
path: root/sql/log_event.h
diff options
context:
space:
mode:
Diffstat (limited to 'sql/log_event.h')
-rw-r--r--sql/log_event.h1012
1 files changed, 761 insertions, 251 deletions
diff --git a/sql/log_event.h b/sql/log_event.h
index 5c81d0c92f0..29580589a34 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
@@ -35,12 +35,42 @@
#define LOG_EVENT_OFFSET 4
-#define BINLOG_VERSION 3
+/*
+ 3 is MySQL 4.x; 4 is MySQL 5.0.0.
+ Compared to version 3, version 4 has:
+ - a different Start_log_event, which includes info about the binary log
+ (sizes of headers); this info is included for better compatibility if the
+ master's MySQL version is different from the slave's.
+ - all events have a unique ID (the triplet (server_id, timestamp at server
+ start, other) to be sure an event is not executed more than once in a
+ multimaster setup, example:
+ M1
+ / \
+ v v
+ M2 M3
+ \ /
+ v v
+ S
+ if a query is run on M1, it will arrive twice on S, so we need that S
+ remembers the last unique ID it has processed, to compare and know if the
+ event should be skipped or not. Example of ID: we already have the server id
+ (4 bytes), plus:
+ timestamp_when_the_master_started (4 bytes), a counter (a sequence number
+ which increments every time we write an event to the binlog) (3 bytes).
+ Q: how do we handle when the counter is overflowed and restarts from 0 ?
+
+ - Query and Load (Create or Execute) events may have a more precise timestamp
+ (with microseconds), number of matched/affected/warnings rows
+ and fields of session variables: SQL_MODE,
+ FOREIGN_KEY_CHECKS, UNIQUE_CHECKS, SQL_AUTO_IS_NULL, the collations and
+ charsets, the PASSWORD() version (old/new/...).
+*/
+#define BINLOG_VERSION 4
/*
We could have used SERVER_VERSION_LENGTH, but this introduces an
obscure dependency - if somebody decided to change SERVER_VERSION_LENGTH
- this would have broken the replication protocol
+ this would break the replication protocol
*/
#define ST_SERVER_VER_LEN 50
@@ -49,6 +79,12 @@
TERMINATED etc).
*/
+/*
+ These are flags and structs to handle all the LOAD DATA INFILE options (LINES
+ TERMINATED etc).
+ DUMPFILE_FLAG is probably useless (DUMPFILE is a clause of SELECT, not of LOAD
+ DATA).
+*/
#define DUMPFILE_FLAG 0x1
#define OPT_ENCLOSED_FLAG 0x2
#define REPLACE_FLAG 0x4
@@ -92,18 +128,18 @@ struct sql_ex_info
char* escaped;
int cached_new_format;
uint8 field_term_len,enclosed_len,line_term_len,line_start_len, escaped_len;
- char opt_flags;
+ char opt_flags;
char empty_flags;
-
+
// store in new format even if old is possible
- void force_new_format() { cached_new_format = 1;}
+ void force_new_format() { cached_new_format = 1;}
int data_size()
{
return (new_format() ?
field_term_len + enclosed_len + line_term_len +
line_start_len + escaped_len + 6 : 7);
}
- int write_data(IO_CACHE* file);
+ bool write_data(IO_CACHE* file);
char* init(char* buf,char* buf_end,bool use_new_format);
bool new_format()
{
@@ -127,28 +163,44 @@ struct sql_ex_info
See the #defines below for the format specifics.
- The events which really update data are Query_log_event and
- Load_log_event/Create_file_log_event/Execute_load_log_event (these 3 act
- together to replicate LOAD DATA INFILE, with the help of
- Append_block_log_event which prepares temporary files to load into the table).
+ 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).
****************************************************************************/
#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
+ LOG_EVENT_MINIMAL_HEADER_LEN will remain 19.
+*/
+#define LOG_EVENT_MINIMAL_HEADER_LEN 19
/* event-specific post-header sizes */
-#define QUERY_HEADER_LEN (4 + 4 + 1 + 2)
+// where 3.23, 4.x and 5.0 agree
+#define QUERY_HEADER_MINIMAL_LEN (4 + 4 + 1 + 2)
+// where 5.0 differs: 2 for len of N-bytes vars.
+#define QUERY_HEADER_LEN (QUERY_HEADER_MINIMAL_LEN + 2)
#define LOAD_HEADER_LEN (4 + 4 + 4 + 1 +1 + 4)
-#define START_HEADER_LEN (2 + ST_SERVER_VER_LEN + 4)
-#define ROTATE_HEADER_LEN 8
+#define START_V3_HEADER_LEN (2 + ST_SERVER_VER_LEN + 4)
+#define ROTATE_HEADER_LEN 8 // this is FROZEN (the Rotate post-header is frozen)
#define CREATE_FILE_HEADER_LEN 4
#define APPEND_BLOCK_HEADER_LEN 4
#define EXEC_LOAD_HEADER_LEN 4
#define DELETE_FILE_HEADER_LEN 4
+#define FORMAT_DESCRIPTION_HEADER_LEN (START_V3_HEADER_LEN+1+LOG_EVENT_TYPES)
+#define EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN (4 + 4 + 4 + 1)
+#define EXECUTE_LOAD_QUERY_HEADER_LEN (QUERY_HEADER_LEN + EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN)
-/*
- Event header offsets;
+/*
+ Event header offsets;
these point to places inside the fixed header.
*/
@@ -158,11 +210,12 @@ struct sql_ex_info
#define LOG_POS_OFFSET 13
#define FLAGS_OFFSET 17
-/* start event post-header */
+/* start event post-header (for v3 and v4) */
#define ST_BINLOG_VER_OFFSET 0
#define ST_SERVER_VER_OFFSET 2
#define ST_CREATED_OFFSET (ST_SERVER_VER_OFFSET + ST_SERVER_VER_LEN)
+#define ST_COMMON_HEADER_LEN_OFFSET (ST_CREATED_OFFSET + 4)
/* slave event post-header (this event is never written) */
@@ -176,7 +229,28 @@ struct sql_ex_info
#define Q_EXEC_TIME_OFFSET 4
#define Q_DB_LEN_OFFSET 8
#define Q_ERR_CODE_OFFSET 9
+#define Q_STATUS_VARS_LEN_OFFSET 11
#define Q_DATA_OFFSET QUERY_HEADER_LEN
+/* these are codes, not offsets; not more than 256 values (1 byte). */
+#define Q_FLAGS2_CODE 0
+#define Q_SQL_MODE_CODE 1
+/*
+ Q_CATALOG_CODE is catalog with end zero stored; it is used only by MySQL
+ 5.0.x where 0<=x<=3. We have to keep it to be able to replicate these
+ old masters.
+*/
+#define Q_CATALOG_CODE 2
+#define Q_AUTO_INCREMENT 3
+#define Q_CHARSET_CODE 4
+#define Q_TIME_ZONE_CODE 5
+/*
+ Q_CATALOG_NZ_CODE is catalog withOUT end zero stored; it is used by MySQL
+ 5.0.x where x>=4. Saves one byte in every Query_log_event in binlog,
+ compared to Q_CATALOG_CODE. The reason we didn't simply re-use
+ Q_CATALOG_CODE is that then a 5.0.3 slave of this 5.0.x (x>=4) master would
+ crash (segfault etc) because it would expect a 0 when there is none.
+*/
+#define Q_CATALOG_NZ_CODE 6
/* Intvar event post-header */
@@ -228,15 +302,11 @@ struct sql_ex_info
/* DF = "Delete File" */
#define DF_FILE_ID_OFFSET 0
-#define QUERY_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+QUERY_HEADER_LEN)
-#define QUERY_DATA_OFFSET (LOG_EVENT_HEADER_LEN+QUERY_HEADER_LEN)
-#define ROTATE_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+ROTATE_HEADER_LEN)
-#define LOAD_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+LOAD_HEADER_LEN)
-#define CREATE_FILE_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+\
- +LOAD_HEADER_LEN+CREATE_FILE_HEADER_LEN)
-#define DELETE_FILE_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+DELETE_FILE_HEADER_LEN)
-#define EXEC_LOAD_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+EXEC_LOAD_HEADER_LEN)
-#define APPEND_BLOCK_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+APPEND_BLOCK_HEADER_LEN)
+/* ELQ = "Execute Load Query" */
+#define ELQ_FILE_ID_OFFSET QUERY_HEADER_LEN
+#define ELQ_FN_POS_START_OFFSET ELQ_FILE_ID_OFFSET + 4
+#define ELQ_FN_POS_END_OFFSET ELQ_FILE_ID_OFFSET + 8
+#define ELQ_DUP_HANDLING_OFFSET ELQ_FILE_ID_OFFSET + 12
/* 4 bytes which all binlogs should begin with */
#define BINLOG_MAGIC "\xfe\x62\x69\x6e"
@@ -249,20 +319,45 @@ struct sql_ex_info
So they are now removed and their place may later be reused for other
flags. Then one must remember that Rotate events in 4.x have
LOG_EVENT_FORCED_ROTATE_F set, so one should not rely on the value of the
- replacing flag when reading a Rotate event.
+ replacing flag when reading a Rotate event.
I keep the defines here just to remember what they were.
*/
#ifdef TO_BE_REMOVED
#define LOG_EVENT_TIME_F 0x1
-#define LOG_EVENT_FORCED_ROTATE_F 0x2
+#define LOG_EVENT_FORCED_ROTATE_F 0x2
#endif
-/*
+
+/*
+ This flag only makes sense for Format_description_log_event. It is set
+ when the event is written, and *reset* when a binlog file is
+ closed (yes, it's the only case when MySQL modifies already written
+ part of binlog). Thus it is a reliable indicator that binlog was
+ closed correctly. (Stop_log_event is not enough, there's always a
+ small chance that mysqld crashes in the middle of insert and end of
+ the binlog would look like a Stop_log_event).
+
+ This flag is used to detect a restart after a crash, and to provide
+ "unbreakable" binlog. The problem is that on a crash storage engines
+ rollback automatically, while binlog does not. To solve this we use this
+ flag and automatically append ROLLBACK to every non-closed binlog (append
+ virtually, on reading, file itself is not changed). If this flag is found,
+ mysqlbinlog simply prints "ROLLBACK" Replication master does not abort on
+ binlog corruption, but takes it as EOF, and replication slave forces a
+ rollback in this case.
+
+ Note, that old binlogs does not have this flag set, so we get a
+ a backward-compatible behaviour.
+*/
+
+#define LOG_EVENT_BINLOG_IN_USE_F 0x1
+
+/*
If the query depends on the thread (for example: TEMPORARY TABLE).
Currently this is used by mysqlbinlog to know it must print
SET @@PSEUDO_THREAD_ID=xx; before the query (it would not hurt to print it
for every query but this would be slow).
*/
-#define LOG_EVENT_THREAD_SPECIFIC_F 0x4
+#define LOG_EVENT_THREAD_SPECIFIC_F 0x4
/*
Suppress the generation of 'USE' statements before the actual
@@ -277,15 +372,67 @@ struct sql_ex_info
*/
#define LOG_EVENT_SUPPRESS_USE_F 0x8
+/*
+ OPTIONS_WRITTEN_TO_BIN_LOG are the bits of thd->options which must be
+ written to the binlog. OPTIONS_WRITTEN_TO_BINLOG could be written
+ into the Format_description_log_event, so that if later we don't want
+ to replicate a variable we did replicate, or the contrary, it's
+ doable. But it should not be too hard to decide once for all of what
+ we replicate and what we don't, among the fixed 32 bits of
+ thd->options.
+ I (Guilhem) have read through every option's usage, and it looks like
+ OPTION_AUTO_IS_NULL and OPTION_NO_FOREIGN_KEYS are the only ones
+ which alter how the query modifies the table. It's good to replicate
+ OPTION_RELAXED_UNIQUE_CHECKS too because otherwise, the slave may
+ insert data slower than the master, in InnoDB.
+ OPTION_BIG_SELECTS is not needed (the slave thread runs with
+ max_join_size=HA_POS_ERROR) and OPTION_BIG_TABLES is not needed
+ either, as the manual says (because a too big in-memory temp table is
+ automatically written to disk).
+*/
+#define OPTIONS_WRITTEN_TO_BIN_LOG (OPTION_AUTO_IS_NULL | \
+OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_RELAXED_UNIQUE_CHECKS)
+
+#if OPTIONS_WRITTEN_TO_BIN_LOG != ((1L << 14) | (1L << 26) | (1L << 27))
+#error OPTIONS_WRITTEN_TO_BIN_LOG must NOT change their values!
+#endif
+
enum Log_event_type
{
- UNKNOWN_EVENT= 0, START_EVENT= 1, QUERY_EVENT= 2, STOP_EVENT= 3,
- ROTATE_EVENT= 4, INTVAR_EVENT= 5, LOAD_EVENT=6, SLAVE_EVENT= 7,
- CREATE_FILE_EVENT= 8, APPEND_BLOCK_EVENT= 9, EXEC_LOAD_EVENT= 10,
- DELETE_FILE_EVENT= 11, NEW_LOAD_EVENT= 12, RAND_EVENT= 13,
- USER_VAR_EVENT= 14
+ /*
+ Every time you update this enum (when you add a type), you have to
+ fix Format_description_log_event::Format_description_log_event().
+ */
+ UNKNOWN_EVENT= 0, START_EVENT_V3, QUERY_EVENT, STOP_EVENT, ROTATE_EVENT,
+ INTVAR_EVENT, LOAD_EVENT, SLAVE_EVENT, CREATE_FILE_EVENT,
+ APPEND_BLOCK_EVENT, EXEC_LOAD_EVENT, DELETE_FILE_EVENT,
+ /*
+ 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,
+ RAND_EVENT, USER_VAR_EVENT,
+ FORMAT_DESCRIPTION_EVENT,
+ XID_EVENT,
+ BEGIN_LOAD_QUERY_EVENT,
+ EXECUTE_LOAD_QUERY_EVENT,
+
+ /*
+ add new events here - right above this comment!
+ existing events should never change their numbers
+ */
+
+ ENUM_END_EVENT /* end marker */
};
+/*
+ The number of types we handle in Format_description_log_event (UNKNOWN_EVENT
+ is not to be handled, it does not exist in binlogs, it does not have a
+ format).
+*/
+#define LOG_EVENT_TYPES (ENUM_END_EVENT-1)
+
enum Int_event_type
{
INVALID_INT_EVENT = 0, LAST_INSERT_ID_EVENT = 1, INSERT_ID_EVENT = 2
@@ -298,8 +445,45 @@ class MYSQL_LOG;
class THD;
#endif
+class Format_description_log_event;
+
struct st_relay_log_info;
+#ifdef MYSQL_CLIENT
+/*
+ A structure for mysqlbinlog to remember the last db, flags2, sql_mode etc; it
+ is passed to events' print() methods, so that they print only the necessary
+ USE and SET commands.
+*/
+typedef struct st_last_event_info
+{
+ // TODO: have the last catalog here ??
+ char db[FN_REFLEN+1]; // TODO: make this a LEX_STRING when thd->db is
+ bool flags2_inited;
+ uint32 flags2;
+ bool sql_mode_inited;
+ ulong sql_mode; /* must be same as THD.variables.sql_mode */
+ ulong auto_increment_increment, auto_increment_offset;
+ bool charset_inited;
+ char charset[6]; // 3 variables, each of them storable in 2 bytes
+ char time_zone_str[MAX_TIME_ZONE_NAME_LENGTH];
+ st_last_event_info()
+ :flags2_inited(0), sql_mode_inited(0),
+ auto_increment_increment(1),auto_increment_offset(1), charset_inited(0)
+ {
+ /*
+ Currently we only use static LAST_EVENT_INFO objects, so zeroed at
+ program's startup, but these explicit bzero() is for the day someone
+ creates dynamic instances.
+ */
+ bzero(db, sizeof(db));
+ bzero(charset, sizeof(charset));
+ bzero(time_zone_str, sizeof(time_zone_str));
+ }
+} LAST_EVENT_INFO;
+#endif
+
+
/*****************************************************************************
Log_event class
@@ -310,69 +494,76 @@ struct st_relay_log_info;
class Log_event
{
public:
- /*
- The offset in the log where this event originally appeared (it is preserved
- in relay logs, making SHOW SLAVE STATUS able to print coordinates of the
- event in the master's binlog). Note: when a transaction is written by the
- master to its binlog (wrapped in BEGIN/COMMIT) the log_pos of all the
- queries it contains is the one of the BEGIN (this way, when one does SHOW
- SLAVE STATUS it sees the offset of the BEGIN, which is logical as rollback
- may occur), except the COMMIT query which has its real offset.
+ /*
+ The offset in the log where this event originally appeared (it is
+ preserved in relay logs, making SHOW SLAVE STATUS able to print
+ coordinates of the event in the master's binlog). Note: when a
+ transaction is written by the master to its binlog (wrapped in
+ BEGIN/COMMIT) the log_pos of all the queries it contains is the
+ one of the BEGIN (this way, when one does SHOW SLAVE STATUS it
+ sees the offset of the BEGIN, which is logical as rollback may
+ occur), except the COMMIT query which has its real offset.
*/
my_off_t log_pos;
- /*
+ /*
A temp buffer for read_log_event; it is later analysed according to the
event's type, and its content is distributed in the event-specific fields.
*/
- char *temp_buf;
+ char *temp_buf;
/*
- Timestamp on the master(for debugging and replication of NOW()/TIMESTAMP).
- It is important for queries and LOAD DATA INFILE. This is set at the event's
- creation time, except for Query and Load (et al.) events where this is set
- at the query's execution time, which guarantees good replication (otherwise,
- we could have a query and its event with different timestamps).
+ Timestamp on the master(for debugging and replication of
+ NOW()/TIMESTAMP). It is important for queries and LOAD DATA
+ INFILE. This is set at the event's creation time, except for Query
+ and Load (et al.) events where this is set at the query's
+ execution time, which guarantees good replication (otherwise, we
+ could have a query and its event with different timestamps).
*/
time_t when;
/* The number of seconds the query took to run on the master. */
ulong exec_time;
- /*
- The master's server id (is preserved in the relay log; used to prevent from
- infinite loops in circular replication).
+ /* Number of bytes written by write() function */
+ ulong data_written;
+
+ /*
+ The master's server id (is preserved in the relay log; used to
+ prevent from infinite loops in circular replication).
*/
uint32 server_id;
- uint cached_event_len;
/*
- Some 16 flags. Only one is really used now; look above for
- LOG_EVENT_TIME_F, LOG_EVENT_FORCED_ROTATE_F,
- LOG_EVENT_THREAD_SPECIFIC_F, and LOG_EVENT_SUPPRESS_USE_F for
- notes.
+ Some 16 flags. Look above for LOG_EVENT_TIME_F,
+ LOG_EVENT_FORCED_ROTATE_F, LOG_EVENT_THREAD_SPECIFIC_F, and
+ LOG_EVENT_SUPPRESS_USE_F for notes.
*/
uint16 flags;
bool cache_stmt;
+
#ifndef MYSQL_CLIENT
THD* thd;
- Log_event(THD* thd_arg, uint16 flags_arg, bool cache_stmt);
Log_event();
+ Log_event(THD* thd_arg, uint16 flags_arg, bool cache_stmt);
/*
- read_log_event() functions read an event from a binlog or relay log; used by
- SHOW BINLOG EVENTS, the binlog_dump thread on the master (reads master's
- binlog), the slave IO thread (reads the event sent by binlog_dump), the
- slave SQL thread (reads the event from the relay log).
+ read_log_event() functions read an event from a binlog or relay
+ log; used by SHOW BINLOG EVENTS, the binlog_dump thread on the
+ master (reads master's binlog), the slave IO thread (reads the
+ event sent by binlog_dump), the slave SQL thread (reads the event
+ from the relay log). If mutex is 0, the read will proceed without
+ mutex. We need the description_event to be able to parse the
+ event (to know the post-header's size); in fact in read_log_event
+ we detect the event's type, then call the specific event's
+ constructor and pass description_event as an argument.
*/
- // if mutex is 0, the read will proceed without mutex
static Log_event* read_log_event(IO_CACHE* file,
pthread_mutex_t* log_lock,
- bool old_format);
+ const Format_description_log_event *description_event);
static int read_log_event(IO_CACHE* file, String* packet,
pthread_mutex_t* log_lock);
- /* set_log_pos() is used to fill log_pos with tell(log). */
- void set_log_pos(MYSQL_LOG* log);
/*
- init_show_field_list() prepares the column names and types for the output of
- SHOW BINLOG EVENTS; it is used only by SHOW BINLOG EVENTS.
+ init_show_field_list() prepares the column names and types for the
+ output of SHOW BINLOG EVENTS; it is used only by SHOW BINLOG
+ EVENTS.
*/
static void init_show_field_list(List<Item>* field_list);
#ifdef HAVE_REPLICATION
@@ -393,13 +584,15 @@ public:
return thd ? thd->db : 0;
}
#else
- // avoid having to link mysqlbinlog against libpthread
- static Log_event* read_log_event(IO_CACHE* file, bool old_format);
+ Log_event() : temp_buf(0) {}
+ /* avoid having to link mysqlbinlog against libpthread */
+ static Log_event* read_log_event(IO_CACHE* file,
+ const Format_description_log_event *description_event);
/* print*() functions are used by mysqlbinlog */
- virtual void print(FILE* file, bool short_form = 0, char* last_db = 0) = 0;
+ virtual void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0) = 0;
void print_timestamp(FILE* file, time_t *ts = 0);
void print_header(FILE* file);
-#endif
+#endif
static void *operator new(size_t size)
{
@@ -409,19 +602,25 @@ public:
{
my_free((gptr) ptr, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
}
-
- int write(IO_CACHE* file);
- int write_header(IO_CACHE* file);
- virtual int write_data(IO_CACHE* file)
- { return write_data_header(file) || write_data_body(file); }
- virtual int write_data_header(IO_CACHE* file __attribute__((unused)))
+
+#ifndef MYSQL_CLIENT
+ bool write_header(IO_CACHE* file, ulong data_length);
+ virtual bool write(IO_CACHE* file)
+ {
+ return (write_header(file, get_data_size()) ||
+ write_data_header(file) ||
+ write_data_body(file));
+ }
+ virtual bool write_data_header(IO_CACHE* file)
{ return 0; }
- virtual int write_data_body(IO_CACHE* file __attribute__((unused)))
+ virtual bool write_data_body(IO_CACHE* file __attribute__((unused)))
{ return 0; }
+#endif
virtual Log_event_type get_type_code() = 0;
- virtual bool is_valid() = 0;
+ virtual bool is_valid() const = 0;
+ virtual bool is_artificial_event() { return 0; }
inline bool get_cache_stmt() { return cache_stmt; }
- Log_event(const char* buf, bool old_format);
+ Log_event(const char* buf, const Format_description_log_event* description_event);
virtual ~Log_event() { free_temp_buf();}
void register_temp_buf(char* buf) { temp_buf = buf; }
void free_temp_buf()
@@ -432,19 +631,31 @@ public:
temp_buf = 0;
}
}
+ /*
+ Get event length for simple events. For complicated events the length
+ is calculated during write()
+ */
virtual int get_data_size() { return 0;}
- virtual int get_data_body_offset() { return 0; }
- int get_event_len()
- {
- return (cached_event_len ? cached_event_len :
- (cached_event_len = LOG_EVENT_HEADER_LEN + get_data_size()));
- }
- static Log_event* read_log_event(const char* buf, int event_len,
- const char **error, bool old_format);
+ static Log_event* read_log_event(const char* buf, uint event_len,
+ const char **error,
+ const Format_description_log_event
+ *description_event);
/* returns the human readable name of the event's type */
const char* get_type_str();
};
+/*
+ One class for each type of event.
+ Two constructors for each class:
+ - one to create the event for logging (when the server acts as a master),
+ called after an update to the database is done,
+ which accepts parameters like the query, the database, the options for LOAD
+ DATA INFILE...
+ - one to create the event from a packet (when the server acts as a slave),
+ called before reproducing the update, which accepts parameters (like a
+ buffer). Used to read from the master, from the relay log, and in
+ mysqlbinlog. This constructor must be format-tolerant.
+*/
/*****************************************************************************
@@ -459,6 +670,7 @@ protected:
char* data_buf;
public:
const char* query;
+ const char* catalog;
const char* db;
/*
If we already know the length of the query string
@@ -469,13 +681,64 @@ public:
uint32 db_len;
uint16 error_code;
ulong thread_id;
- /*
- For events created by Query_log_event::exec_event (and
- Load_log_event::exec_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::exec_event (and
+ Load_log_event::exec_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;
+
+ /*
+ Binlog format 3 and 4 start to differ (as far as class members are
+ concerned) from here.
+ */
+
+ uint catalog_len; // <= 255 char; 0 means uninited
+
+ /*
+ We want to be able to store a variable number of N-bit status vars:
+ (generally N=32; but N=64 for SQL_MODE) a user may want to log the number
+ of affected rows (for debugging) while another does not want to lose 4
+ bytes in this.
+ The storage on disk is the following:
+ status_vars_len is part of the post-header,
+ status_vars are in the variable-length part, after the post-header, before
+ the db & query.
+ status_vars on disk is a sequence of pairs (code, value) where 'code' means
+ '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;
+
+ /*
+ 'flags2' is a second set of flags (on top of those in Log_event), for
+ session variables. These are thd->options which is & against a mask
+ (OPTIONS_WRITTEN_TO_BINLOG).
+ flags2_inited helps make a difference between flags2==0 (3.23 or 4.x
+ master, we don't know flags2, so use the slave server's global options) and
+ flags2==0 (5.0 master, we know this has a meaning of flags all down which
+ must influence the query).
+ */
+ bool flags2_inited;
+ bool sql_mode_inited;
+ bool charset_inited;
+
+ uint32 flags2;
+ /* In connections sql_mode is 32 bits now but will be 64 bits soon */
+ ulong sql_mode;
+ ulong auto_increment_increment, auto_increment_offset;
+ char charset[6];
+ uint time_zone_len; /* 0 means uninited */
+ const char *time_zone_str;
+
#ifndef MYSQL_CLIENT
Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length,
@@ -484,31 +747,35 @@ public:
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
+ int exec_event(struct st_relay_log_info* rli, const char *query_arg,
+ uint32 q_len_arg);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
+ void print_query_header(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
#endif
- Query_log_event(const char* buf, int event_len, bool old_format);
+ Query_log_event(const char* buf, uint event_len,
+ const Format_description_log_event *description_event,
+ Log_event_type event_type);
~Query_log_event()
{
if (data_buf)
- {
my_free((gptr) data_buf, MYF(0));
- }
}
Log_event_type get_type_code() { return QUERY_EVENT; }
- int write(IO_CACHE* file);
- int write_data(IO_CACHE* file); // returns 0 on success, -1 on error
- bool is_valid() { return query != 0; }
- int get_data_size()
- {
- return (q_len + db_len + 2
- + 4 // thread_id
- + 4 // exec_time
- + 2 // error_code
- );
- }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+ virtual bool write_post_header_for_derived(IO_CACHE* file) { return FALSE; }
+#endif
+ bool is_valid() const { return query != 0; }
+
+ /*
+ Returns number of bytes additionaly written to post header by derived
+ events (so far it is only Execute_load_query event).
+ */
+ virtual ulong get_post_header_size_for_derived() { return 0; }
+ /* Writes derived event-specific part of post header. */
};
#ifdef HAVE_REPLICATION
@@ -518,6 +785,7 @@ public:
Slave Log Event class
Note that this class is currently not used at all; no code writes a
Slave_log_event (though some code in repl_failsafe.cc reads Slave_log_event).
+ So it's not a problem if this code is not maintained.
****************************************************************************/
class Slave_log_event: public Log_event
@@ -533,20 +801,22 @@ public:
int master_log_len;
uint16 master_port;
-#ifndef MYSQL_CLIENT
+#ifndef MYSQL_CLIENT
Slave_log_event(THD* thd_arg, struct st_relay_log_info* rli);
void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
-#endif
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+#endif
- Slave_log_event(const char* buf, int event_len);
+ Slave_log_event(const char* buf, uint event_len);
~Slave_log_event();
int get_data_size();
- bool is_valid() { return master_host != 0; }
+ bool is_valid() const { return master_host != 0; }
Log_event_type get_type_code() { return SLAVE_EVENT; }
- int write_data(IO_CACHE* file );
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
};
#endif /* HAVE_REPLICATION */
@@ -559,13 +829,23 @@ public:
****************************************************************************/
class Load_log_event: public Log_event
{
+private:
+ uint get_query_buffer_length();
+ void print_query(bool need_db, char *buf, char **end,
+ char **fn_start, char **fn_end);
protected:
- int copy_log_event(const char *buf, ulong event_len, bool old_format);
+ int copy_log_event(const char *buf, ulong event_len,
+ int body_offset, const Format_description_log_event* description_event);
public:
ulong 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;
@@ -596,12 +876,13 @@ public:
#ifndef MYSQL_CLIENT
String field_lens_buf;
String fields_buf;
-
+
Load_log_event(THD* thd, sql_exchange* ex, const char* db_arg,
const char* table_name_arg,
List<Item>& fields_arg, enum enum_duplicates handle_dup, bool ignore,
bool using_trans);
- void set_fields(const char* db, List<Item> &fields_arg);
+ 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);
@@ -609,60 +890,76 @@ public:
{
return exec_event(thd->slave_net,rli,0);
}
- int exec_event(NET* net, struct st_relay_log_info* rli,
+ int exec_event(NET* net, struct st_relay_log_info* rli,
bool use_rli_only_for_errors);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
- void print(FILE* file, bool short_form, char* last_db, bool commented);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info = 0);
+ void print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info, bool commented);
#endif
- Load_log_event(const char* buf, int event_len, bool old_format);
+ /*
+ 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 char* 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;
}
- int write_data_header(IO_CACHE* file);
- int write_data_body(IO_CACHE* file);
- bool is_valid() { return table_name != 0; }
+#ifndef MYSQL_CLIENT
+ bool write_data_header(IO_CACHE* file);
+ bool write_data_body(IO_CACHE* file);
+#endif
+ bool is_valid() const { return table_name != 0; }
int get_data_size()
{
- return (table_name_len + 2 + db_len + 2 + fname_len
- + 4 // thread_id
- + 4 // exec_time
- + 4 // skip_lines
- + 4 // field block len
+ return (table_name_len + db_len + 2 + fname_len
+ + LOAD_HEADER_LEN
+ sql_ex.data_size() + field_block_len + num_fields);
}
- int get_data_body_offset() { return LOAD_EVENT_OVERHEAD; }
};
extern char server_version[SERVER_VERSION_LENGTH];
/*****************************************************************************
- Start Log Event class
+ Start Log Event_v3 class
+
+ Start_log_event_v3 is the Start_log_event of binlog format 3 (MySQL 3.23 and
+ 4.x).
+ Format_description_log_event derives from Start_log_event_v3; it is the
+ Start_log_event of binlog format 4 (MySQL 5.0), that is, the event that
+ describes the other events' header/postheader lengths. This event is sent by
+ MySQL 5.0 whenever it starts sending a new binlog if the requested position
+ is >4 (otherwise if ==4 the event will be sent naturally).
****************************************************************************/
-class Start_log_event: public Log_event
+
+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 if they must drop the
- stale temporary tables or not.
- 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:
+ /*
+ 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
@@ -672,29 +969,89 @@ public:
time_t created;
uint16 binlog_version;
char server_version[ST_SERVER_VER_LEN];
+ /*
+ artifical_event is 1 in the case where this is a generated event that
+ should not case any cleanup actions. We handle this in the log by
+ setting log_event == 0 (for now).
+ */
+ bool artificial_event;
#ifndef MYSQL_CLIENT
- Start_log_event() :Log_event(), binlog_version(BINLOG_VERSION)
- {
- created = (time_t) when;
- memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
- }
+ Start_log_event_v3();
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
-#endif
-
- Start_log_event(const char* buf, bool old_format);
- ~Start_log_event() {}
- Log_event_type get_type_code() { return START_EVENT;}
- int write_data(IO_CACHE* file);
- bool is_valid() { return 1; }
+ Start_log_event_v3() {}
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+#endif
+
+ Start_log_event_v3(const char* buf,
+ const Format_description_log_event* description_event);
+ ~Start_log_event_v3() {}
+ Log_event_type get_type_code() { return START_EVENT_V3;}
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
+ bool is_valid() const { return 1; }
+ int get_data_size()
+ {
+ return START_V3_HEADER_LEN; //no variable-sized part
+ }
+ virtual bool is_artificial_event() { return artificial_event; }
+};
+
+
+/*
+ For binlog version 4.
+ This event is saved by threads which read it, as they need it for future
+ use (to decode the ordinary events).
+*/
+
+class Format_description_log_event: public Start_log_event_v3
+{
+public:
+ /*
+ The size of the fixed header which _all_ events have
+ (for binlogs written by this version, this is equal to
+ LOG_EVENT_HEADER_LEN), except FORMAT_DESCRIPTION_EVENT and ROTATE_EVENT
+ (those have a header of size LOG_EVENT_MINIMAL_HEADER_LEN).
+ */
+ uint8 common_header_len;
+ uint8 number_of_event_types;
+ /* The list of post-headers' lengthes */
+ uint8 *post_header_len;
+
+ Format_description_log_event(uint8 binlog_ver, const char* server_ver=0);
+
+#ifndef MYSQL_CLIENT
+#ifdef HAVE_REPLICATION
+ int exec_event(struct st_relay_log_info* rli);
+#endif /* HAVE_REPLICATION */
+#endif
+
+ Format_description_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event);
+ ~Format_description_log_event() { my_free((gptr)post_header_len, MYF(0)); }
+ Log_event_type get_type_code() { return FORMAT_DESCRIPTION_EVENT;}
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
+ bool is_valid() const
+ {
+ return ((common_header_len >= ((binlog_version==1) ? OLD_HEADER_LEN :
+ LOG_EVENT_MINIMAL_HEADER_LEN)) &&
+ (post_header_len != NULL));
+ }
int get_data_size()
{
- return START_HEADER_LEN;
+ /*
+ The vector of post-header lengths is considered as part of the
+ post-header, because in a given version it never changes (contrary to the
+ query in a Query_log_event).
+ */
+ return FORMAT_DESCRIPTION_HEADER_LEN;
}
};
@@ -706,13 +1063,14 @@ public:
Logs special variables such as auto_increment values
****************************************************************************/
+
class Intvar_log_event: public Log_event
{
public:
ulonglong val;
uchar type;
-#ifndef MYSQL_CLIENT
+#ifndef MYSQL_CLIENT
Intvar_log_event(THD* thd_arg,uchar type_arg, ulonglong val_arg)
:Log_event(thd_arg,0,0),val(val_arg),type(type_arg)
{}
@@ -721,25 +1079,32 @@ public:
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
-#endif
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+#endif
- Intvar_log_event(const char* buf, bool old_format);
+ Intvar_log_event(const char* buf, const Format_description_log_event* description_event);
~Intvar_log_event() {}
Log_event_type get_type_code() { return INTVAR_EVENT;}
const char* get_var_type_name();
int get_data_size() { return 9; /* sizeof(type) + sizeof(val) */;}
- int write_data(IO_CACHE* file);
- bool is_valid() { return 1; }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
+ bool is_valid() const { return 1; }
};
+
/*****************************************************************************
Rand Log Event class
- Logs random seed used by the next RAND(), and by PASSWORD() in 4.1.
+ Logs random seed used by the next RAND(), and by PASSWORD() in 4.1.0.
+ 4.1.1 does not need it (it's repeatable again) so this event needn't be
+ written in 4.1.1 for PASSWORD() (but the fact that it is written is just a
+ waste, it does not cause bugs).
****************************************************************************/
+
class Rand_log_event: public Log_event
{
public:
@@ -755,15 +1120,54 @@ class Rand_log_event: public Log_event
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
#endif
- Rand_log_event(const char* buf, bool old_format);
+ Rand_log_event(const char* buf, const Format_description_log_event* description_event);
~Rand_log_event() {}
Log_event_type get_type_code() { return RAND_EVENT;}
int get_data_size() { return 16; /* sizeof(ulonglong) * 2*/ }
- int write_data(IO_CACHE* file);
- bool is_valid() { return 1; }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
+ bool is_valid() const { return 1; }
+};
+
+/*****************************************************************************
+
+ Xid Log Event class
+
+ Logs xid of the transaction-to-be-committed in the 2pc protocol.
+ Has no meaning in replication, slaves ignore it.
+
+ ****************************************************************************/
+#ifdef MYSQL_CLIENT
+typedef ulonglong my_xid; // this line is the same as in handler.h
+#endif
+
+class Xid_log_event: public Log_event
+{
+ public:
+ my_xid xid;
+
+#ifndef MYSQL_CLIENT
+ Xid_log_event(THD* thd_arg, my_xid x): Log_event(thd_arg,0,0), xid(x) {}
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol* protocol);
+ int exec_event(struct st_relay_log_info* rli);
+#endif /* HAVE_REPLICATION */
+#else
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+#endif
+
+ Xid_log_event(const char* buf, const Format_description_log_event* description_event);
+ ~Xid_log_event() {}
+ Log_event_type get_type_code() { return XID_EVENT;}
+ int get_data_size() { return sizeof(xid); }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
+ bool is_valid() const { return 1; }
};
/*****************************************************************************
@@ -774,6 +1178,7 @@ class Rand_log_event: public Log_event
written before the Query_log_event, to set the user variable.
****************************************************************************/
+
class User_var_log_event: public Log_event
{
public:
@@ -794,29 +1199,24 @@ public:
void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
#endif
- User_var_log_event(const char* buf, bool old_format);
+ User_var_log_event(const char* buf, const Format_description_log_event* description_event);
~User_var_log_event() {}
Log_event_type get_type_code() { return USER_VAR_EVENT;}
- int get_data_size()
- {
- return (is_null ? UV_NAME_LEN_SIZE + name_len + UV_VAL_IS_NULL :
- UV_NAME_LEN_SIZE + name_len + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
- UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE + val_len);
- }
- int write_data(IO_CACHE* file);
- bool is_valid() { return 1; }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
+ bool is_valid() const { return 1; }
};
+
/*****************************************************************************
Stop Log Event class
****************************************************************************/
-#ifdef HAVE_REPLICATION
-
class Stop_log_event: public Log_event
{
public:
@@ -825,27 +1225,25 @@ public:
{}
int exec_event(struct st_relay_log_info* rli);
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
-#endif
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+#endif
- Stop_log_event(const char* buf, bool old_format):
- Log_event(buf, old_format)
+ Stop_log_event(const char* buf, const Format_description_log_event* description_event):
+ Log_event(buf, description_event)
{}
~Stop_log_event() {}
Log_event_type get_type_code() { return STOP_EVENT;}
- bool is_valid() { return 1; }
+ bool is_valid() const { return 1; }
};
-#endif /* HAVE_REPLICATION */
-
-
/*****************************************************************************
Rotate Log Event class
- This will be depricated when we move to using sequence ids.
+ This will be deprecated when we move to using sequence ids.
****************************************************************************/
+
class Rotate_log_event: public Log_event
{
public:
@@ -853,7 +1251,7 @@ public:
ulonglong pos;
uint ident_len;
bool alloced;
-#ifndef MYSQL_CLIENT
+#ifndef MYSQL_CLIENT
Rotate_log_event(THD* thd_arg, const char* new_log_ident_arg,
uint ident_len_arg = 0,
ulonglong pos_arg = LOG_EVENT_OFFSET)
@@ -866,10 +1264,11 @@ public:
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
#endif
- Rotate_log_event(const char* buf, int event_len, bool old_format);
+ Rotate_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event);
~Rotate_log_event()
{
if (alloced)
@@ -877,17 +1276,19 @@ public:
}
Log_event_type get_type_code() { return ROTATE_EVENT;}
int get_data_size() { return ident_len + ROTATE_HEADER_LEN;}
- bool is_valid() { return new_log_ident != 0; }
- int write_data(IO_CACHE* file);
+ bool is_valid() const { return new_log_ident != 0; }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
};
+
/* the classes below are for the new LOAD DATA INFILE logging */
/*****************************************************************************
-
Create File Log Event class
-
****************************************************************************/
+
class Create_file_log_event: public Load_log_event
{
protected:
@@ -896,7 +1297,7 @@ protected:
our Load part - used on the slave when writing event out to
SQL_LOAD-*.info file
*/
- bool fake_base;
+ bool fake_base;
public:
char* block;
const char *event_buf;
@@ -916,11 +1317,12 @@ public:
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
- void print(FILE* file, bool short_form, char* last_db, bool enable_local);
-#endif
-
- Create_file_log_event(const char* buf, int event_len, bool old_format);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info, bool enable_local);
+#endif
+
+ Create_file_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event);
~Create_file_log_event()
{
my_free((char*) event_buf, MYF(MY_ALLOW_ZERO_PTR));
@@ -936,19 +1338,16 @@ public:
Load_log_event::get_data_size() +
4 + 1 + block_len);
}
- int get_data_body_offset()
- {
- return (fake_base ? LOAD_EVENT_OVERHEAD:
- LOAD_EVENT_OVERHEAD + CREATE_FILE_HEADER_LEN);
- }
- bool is_valid() { return inited_from_old || block != 0; }
- int write_data_header(IO_CACHE* file);
- int write_data_body(IO_CACHE* file);
+ bool is_valid() const { return inited_from_old || block != 0; }
+#ifndef MYSQL_CLIENT
+ bool write_data_header(IO_CACHE* file);
+ bool write_data_body(IO_CACHE* file);
/*
Cut out Create_file extentions and
write it as Load event - used on the slave
*/
- int write_base(IO_CACHE* file);
+ bool write_base(IO_CACHE* file);
+#endif
};
@@ -957,6 +1356,7 @@ public:
Append Block Log Event class
****************************************************************************/
+
class Append_block_log_event: public Log_event
{
public:
@@ -964,14 +1364,15 @@ public:
uint block_len;
uint file_id;
/*
- 'db' is filled when the event is created in mysql_load() (the event needs to
- have a 'db' member to be well filtered by binlog-*-db rules). 'db' is not
- written to the binlog (it's not used by Append_block_log_event::write()), so
- it can't be read in the Append_block_log_event(const char* buf, int
- event_len) constructor.
- In other words, 'db' is used only for filtering by binlog-*-db rules.
- Create_file_log_event is different: its 'db' (which is inherited from
- Load_log_event) is written to the binlog and can be re-read.
+ 'db' is filled when the event is created in mysql_load() (the
+ event needs to have a 'db' member to be well filtered by
+ binlog-*-db rules). 'db' is not written to the binlog (it's not
+ used by Append_block_log_event::write()), so it can't be read in
+ the Append_block_log_event(const char* 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.
*/
const char* db;
@@ -981,31 +1382,37 @@ public:
#ifdef HAVE_REPLICATION
int exec_event(struct st_relay_log_info* rli);
void pack_info(Protocol* protocol);
+ virtual int get_create_or_append() const;
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
#endif
-
- Append_block_log_event(const char* buf, int event_len);
+
+ Append_block_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event);
~Append_block_log_event() {}
Log_event_type get_type_code() { return APPEND_BLOCK_EVENT;}
int get_data_size() { return block_len + APPEND_BLOCK_HEADER_LEN ;}
- bool is_valid() { return block != 0; }
- int write_data(IO_CACHE* file);
+ bool is_valid() const { return block != 0; }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
const char* get_db() { return db; }
};
+
/*****************************************************************************
Delete File Log Event class
****************************************************************************/
+
class Delete_file_log_event: public Log_event
{
public:
uint file_id;
const char* db; /* see comment in Append_block_log_event */
-
+
#ifndef MYSQL_CLIENT
Delete_file_log_event(THD* thd, const char* db_arg, bool using_trans);
#ifdef HAVE_REPLICATION
@@ -1013,29 +1420,34 @@ public:
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
- void print(FILE* file, bool short_form, char* last_db, bool enable_local);
-#endif
-
- Delete_file_log_event(const char* buf, int event_len);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info, bool enable_local);
+#endif
+
+ Delete_file_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event);
~Delete_file_log_event() {}
Log_event_type get_type_code() { return DELETE_FILE_EVENT;}
int get_data_size() { return DELETE_FILE_HEADER_LEN ;}
- bool is_valid() { return file_id != 0; }
- int write_data(IO_CACHE* file);
+ bool is_valid() const { return file_id != 0; }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
const char* get_db() { return db; }
};
+
/*****************************************************************************
Execute Load Log Event class
****************************************************************************/
+
class Execute_load_log_event: public Log_event
{
public:
uint file_id;
- const char* db; /* see comment in Append_block_log_event */
+ const char* db; /* see comment in Append_block_log_event */
#ifndef MYSQL_CLIENT
Execute_load_log_event(THD* thd, const char* db_arg, bool using_trans);
@@ -1044,30 +1456,128 @@ public:
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
-#endif
-
- Execute_load_log_event(const char* buf, int event_len);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+#endif
+
+ Execute_load_log_event(const char* 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() { return file_id != 0; }
- int write_data(IO_CACHE* file);
+ bool is_valid() const { return file_id != 0; }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
const char* get_db() { return db; }
};
+
+/***************************************************************************
+
+ Begin load query Log Event class
+
+ Event for the first block of file to be loaded, its only difference from
+ Append_block event is that this event creates or truncates existing file
+ before writing data.
+
+****************************************************************************/
+class Begin_load_query_log_event: public Append_block_log_event
+{
+public:
+#ifndef MYSQL_CLIENT
+ Begin_load_query_log_event(THD* thd_arg, const char *db_arg,
+ char* block_arg, uint block_len_arg,
+ bool using_trans);
+#ifdef HAVE_REPLICATION
+ Begin_load_query_log_event(THD* thd);
+ int get_create_or_append() const;
+#endif /* HAVE_REPLICATION */
+#endif
+ Begin_load_query_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event);
+ ~Begin_load_query_log_event() {}
+ Log_event_type get_type_code() { return BEGIN_LOAD_QUERY_EVENT; }
+};
+
+
+/*
+ Elements of this enum describe how LOAD DATA handles duplicates.
+*/
+enum enum_load_dup_handling { LOAD_DUP_ERROR= 0, LOAD_DUP_IGNORE,
+ LOAD_DUP_REPLACE };
+
+/****************************************************************************
+
+ Execute load query Log Event class
+
+ Event responsible for LOAD DATA execution, it similar to Query_log_event
+ but before executing the query it substitutes original filename in LOAD DATA
+ query with name of temporary file.
+
+****************************************************************************/
+class Execute_load_query_log_event: public Query_log_event
+{
+public:
+ uint file_id; // file_id of temporary file
+ uint fn_pos_start; // pointer to the part of the query that should
+ // be substituted
+ uint fn_pos_end; // pointer to the end of this part of query
+ /*
+ We have to store type of duplicate handling explicitly, because
+ for LOAD DATA it also depends on LOCAL option. And this part
+ of query will be rewritten during replication so this information
+ may be lost...
+ */
+ enum_load_dup_handling dup_handling;
+
+#ifndef MYSQL_CLIENT
+ Execute_load_query_log_event(THD* thd, const char* query_arg,
+ ulong query_length, uint fn_pos_start_arg,
+ uint fn_pos_end_arg,
+ enum_load_dup_handling dup_handling_arg,
+ bool using_trans, bool suppress_use);
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol* protocol);
+ int exec_event(struct st_relay_log_info* rli);
+#endif /* HAVE_REPLICATION */
+#else
+ void print(FILE* file, bool short_form = 0,
+ LAST_EVENT_INFO* last_event_info= 0);
+ /* Prints the query as LOAD DATA LOCAL and with rewritten filename */
+ void print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info,
+ const char *local_fname);
+#endif
+ Execute_load_query_log_event(const char* buf, uint event_len,
+ const Format_description_log_event *description_event);
+ ~Execute_load_query_log_event() {}
+
+ Log_event_type get_type_code() { return EXECUTE_LOAD_QUERY_EVENT; }
+ bool is_valid() const { return Query_log_event::is_valid() && file_id != 0; }
+
+ ulong get_post_header_size_for_derived();
+#ifndef MYSQL_CLIENT
+ bool write_post_header_for_derived(IO_CACHE* file);
+#endif
+ };
+
+
#ifdef MYSQL_CLIENT
class Unknown_log_event: public Log_event
{
public:
- Unknown_log_event(const char* buf, bool old_format):
- Log_event(buf, old_format)
+ /*
+ Even if this is an unknown event, we still pass description_event to
+ Log_event's ctor, this way we can extract maximum information from the
+ event's header (the unique ID for example).
+ */
+ Unknown_log_event(const char* buf, const Format_description_log_event* description_event):
+ Log_event(buf, description_event)
{}
~Unknown_log_event() {}
- void print(FILE* file, bool short_form= 0, char* last_db= 0);
+ void print(FILE* file, bool short_form= 0, LAST_EVENT_INFO* last_event_info= 0);
Log_event_type get_type_code() { return UNKNOWN_EVENT;}
- bool is_valid() { return 1; }
+ bool is_valid() const { return 1; }
};
-#endif
+#endif
char *str_to_hex(char *to, const char *from, uint len);
#endif /* _log_event_h */