mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 19:06:14 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			5976 lines
		
	
	
	
		
			184 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
	
	
			
		
		
	
	
			5976 lines
		
	
	
	
		
			184 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
	
	
| /* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
 | |
|    Copyright (c) 2009, 2020, MariaDB Corporation.
 | |
| 
 | |
|    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 */
 | |
| 
 | |
| /**
 | |
|   @addtogroup Replication
 | |
|   @{
 | |
| 
 | |
|   @file
 | |
|   
 | |
|   @brief Binary log event definitions.  This includes generic code
 | |
|   common to all types of log events, as well as specific code for each
 | |
|   type of log event.
 | |
| */
 | |
| 
 | |
| 
 | |
| #ifndef _log_event_h
 | |
| #define _log_event_h
 | |
| 
 | |
| #if defined(USE_PRAGMA_INTERFACE) && defined(MYSQL_SERVER)
 | |
| #pragma interface			/* gcc class implementation */
 | |
| #endif
 | |
| 
 | |
| #include <my_bitmap.h>
 | |
| #include "rpl_constants.h"
 | |
| #include <vector>
 | |
| #include <string>
 | |
| #include <functional>
 | |
| #include <memory>
 | |
| #include <map>
 | |
| 
 | |
| #ifdef MYSQL_CLIENT
 | |
| #include "sql_const.h"
 | |
| #include "rpl_utility.h"
 | |
| #include "hash.h"
 | |
| #include "rpl_tblmap.h"
 | |
| #include "sql_string.h"
 | |
| #endif
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
| #include "rpl_record.h"
 | |
| #include "rpl_reporting.h"
 | |
| #include "sql_class.h"                          /* THD */
 | |
| #endif
 | |
| 
 | |
| #include "rpl_gtid.h"
 | |
| 
 | |
| #include "log_event_data_type.h"
 | |
| 
 | |
| /* Forward declarations */
 | |
| #ifndef MYSQL_CLIENT
 | |
| class String;
 | |
| #endif
 | |
| 
 | |
| #define PREFIX_SQL_LOAD "SQL_LOAD-"
 | |
| #define LONG_FIND_ROW_THRESHOLD 60 /* seconds */
 | |
| 
 | |
| /**
 | |
|    Either assert or return an error.
 | |
| 
 | |
|    In debug build, the condition will be checked, but in non-debug
 | |
|    builds, the error code given will be returned instead.
 | |
| 
 | |
|    @param COND   Condition to check
 | |
|    @param ERRNO  Error number to return in non-debug builds
 | |
| */
 | |
| #ifdef DBUG_OFF
 | |
| #define ASSERT_OR_RETURN_ERROR(COND, ERRNO) \
 | |
|   do { if (!(COND)) return ERRNO; } while (0)
 | |
| #else
 | |
| #define ASSERT_OR_RETURN_ERROR(COND, ERRNO) \
 | |
|   DBUG_ASSERT(COND)
 | |
| #endif
 | |
| 
 | |
| #define LOG_READ_EOF    -1
 | |
| #define LOG_READ_BOGUS  -2
 | |
| #define LOG_READ_IO     -3
 | |
| #define LOG_READ_MEM    -5
 | |
| #define LOG_READ_TRUNC  -6
 | |
| #define LOG_READ_TOO_LARGE -7
 | |
| #define LOG_READ_CHECKSUM_FAILURE -8
 | |
| #define LOG_READ_DECRYPT -9
 | |
| 
 | |
| #define LOG_EVENT_OFFSET 4
 | |
| 
 | |
| /*
 | |
|    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 break the replication protocol
 | |
| */
 | |
| #define ST_SERVER_VER_LEN 50
 | |
| 
 | |
| /*
 | |
|   These are flags and structs to handle all the LOAD DATA INFILE options (LINES
 | |
|   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
 | |
| #define IGNORE_FLAG		0x8
 | |
| 
 | |
| #define FIELD_TERM_EMPTY	0x1
 | |
| #define ENCLOSED_EMPTY		0x2
 | |
| #define LINE_TERM_EMPTY		0x4
 | |
| #define LINE_START_EMPTY	0x8
 | |
| #define ESCAPED_EMPTY		0x10
 | |
| 
 | |
| #define NUM_LOAD_DELIM_STRS 5
 | |
| 
 | |
| /*
 | |
|   The following is the max table_map_id. This is limited by that we
 | |
|   are using 6 bytes for it in replication
 | |
| */
 | |
| #define MAX_TABLE_MAP_ID ((1ULL << (6*8)) -1)
 | |
| 
 | |
| /*****************************************************************************
 | |
| 
 | |
|   MySQL Binary Log
 | |
| 
 | |
|   This log consists of events.  Each event has a fixed-length header,
 | |
|   possibly followed by a variable length data body.
 | |
| 
 | |
|   The data body consists of an optional fixed length segment (post-header)
 | |
|   and  an optional variable length segment.
 | |
| 
 | |
|   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).
 | |
| 
 | |
|  ****************************************************************************/
 | |
| 
 | |
| #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 */
 | |
| // 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 STOP_HEADER_LEN      0
 | |
| #define LOAD_HEADER_LEN      (4 + 4 + 4 + 1 +1 + 4)
 | |
| #define SLAVE_HEADER_LEN     0
 | |
| #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 INTVAR_HEADER_LEN      0
 | |
| #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 NEW_LOAD_HEADER_LEN    LOAD_HEADER_LEN
 | |
| #define RAND_HEADER_LEN        0
 | |
| #define USER_VAR_HEADER_LEN    0
 | |
| #define FORMAT_DESCRIPTION_HEADER_LEN (START_V3_HEADER_LEN+1+LOG_EVENT_TYPES)
 | |
| #define XID_HEADER_LEN         0
 | |
| #define BEGIN_LOAD_QUERY_HEADER_LEN APPEND_BLOCK_HEADER_LEN
 | |
| #define ROWS_HEADER_LEN_V1     8
 | |
| #define TABLE_MAP_HEADER_LEN   8
 | |
| #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)
 | |
| #define INCIDENT_HEADER_LEN    2
 | |
| #define HEARTBEAT_HEADER_LEN   0
 | |
| #define IGNORABLE_HEADER_LEN   0
 | |
| #define ROWS_HEADER_LEN_V2    10
 | |
| #define ANNOTATE_ROWS_HEADER_LEN  0
 | |
| #define BINLOG_CHECKPOINT_HEADER_LEN 4
 | |
| #define GTID_HEADER_LEN       19
 | |
| #define GTID_LIST_HEADER_LEN   4
 | |
| #define START_ENCRYPTION_HEADER_LEN 0
 | |
| #define XA_PREPARE_HEADER_LEN 0
 | |
| 
 | |
| /* 
 | |
|   Max number of possible extra bytes in a replication event compared to a
 | |
|   packet (i.e. a query) sent from client to master;
 | |
|   First, an auxiliary log_event status vars estimation:
 | |
| */
 | |
| #define MAX_SIZE_LOG_EVENT_STATUS (1 + 4          /* type, flags2 */   + \
 | |
|                                    1 + 8          /* type, sql_mode */ + \
 | |
|                                    1 + 1 + 255    /* type, length, catalog */ + \
 | |
|                                    1 + 4          /* type, auto_increment */ + \
 | |
|                                    1 + 6          /* type, charset */ + \
 | |
|                                    1 + 1 + 255    /* type, length, time_zone */ + \
 | |
|                                    1 + 2          /* type, lc_time_names_number */ + \
 | |
|                                    1 + 2          /* type, charset_database_number */ + \
 | |
|                                    1 + 8          /* type, table_map_for_update */ + \
 | |
|                                    1 + 4          /* type, master_data_written */ + \
 | |
|                                    1 + 3          /* type, sec_part of NOW() */ + \
 | |
|                                    1 + 16 + 1 + 60/* type, user_len, user, host_len, host */ + \
 | |
|                                    1 + 2 + 8      /* type, flags3, seq_no */)
 | |
| #define MAX_LOG_EVENT_HEADER   ( /* in order of Query_log_event::write */ \
 | |
|   LOG_EVENT_HEADER_LEN + /* write_header */ \
 | |
|   QUERY_HEADER_LEN     + /* write_data */   \
 | |
|   EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN + /*write_post_header_for_derived */ \
 | |
|   MAX_SIZE_LOG_EVENT_STATUS + /* status */ \
 | |
|   NAME_LEN + 1)
 | |
| 
 | |
| /*
 | |
|   The new option is added to handle large packets that are sent from the master 
 | |
|   to the slave. It is used to increase the thd(max_allowed) for both the
 | |
|   DUMP thread on the master and the SQL/IO thread on the slave. 
 | |
| */
 | |
| #define MAX_MAX_ALLOWED_PACKET (1024*1024*1024)
 | |
| 
 | |
| /* 
 | |
|    Event header offsets; 
 | |
|    these point to places inside the fixed header.
 | |
| */
 | |
| 
 | |
| #define EVENT_TYPE_OFFSET    4
 | |
| #define SERVER_ID_OFFSET     5
 | |
| #define EVENT_LEN_OFFSET     9
 | |
| #define LOG_POS_OFFSET       13
 | |
| #define FLAGS_OFFSET         17
 | |
| 
 | |
| /* 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) */
 | |
| 
 | |
| #define SL_MASTER_PORT_OFFSET   8
 | |
| #define SL_MASTER_POS_OFFSET    0
 | |
| #define SL_MASTER_HOST_OFFSET   10
 | |
| 
 | |
| /* query event post-header */
 | |
| 
 | |
| #define Q_THREAD_ID_OFFSET	0
 | |
| #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
 | |
| 
 | |
| #define Q_LC_TIME_NAMES_CODE    7
 | |
| 
 | |
| #define Q_CHARSET_DATABASE_CODE 8
 | |
| 
 | |
| #define Q_TABLE_MAP_FOR_UPDATE_CODE 9
 | |
| 
 | |
| #define Q_MASTER_DATA_WRITTEN_CODE 10
 | |
| 
 | |
| #define Q_INVOKER 11
 | |
| 
 | |
| #define Q_HRNOW 128
 | |
| #define Q_XID   129
 | |
| 
 | |
| #define Q_GTID_FLAGS3 130
 | |
| /* Intvar event post-header */
 | |
| 
 | |
| /* Intvar event data */
 | |
| #define I_TYPE_OFFSET        0
 | |
| #define I_VAL_OFFSET         1
 | |
| 
 | |
| /* Rand event data */
 | |
| #define RAND_SEED1_OFFSET 0
 | |
| #define RAND_SEED2_OFFSET 8
 | |
| 
 | |
| /* User_var event data */
 | |
| #define UV_VAL_LEN_SIZE        4
 | |
| #define UV_VAL_IS_NULL         1
 | |
| #define UV_VAL_TYPE_SIZE       1
 | |
| #define UV_NAME_LEN_SIZE       4
 | |
| #define UV_CHARSET_NUMBER_SIZE 4
 | |
| 
 | |
| /* Load event post-header */
 | |
| #define L_THREAD_ID_OFFSET   0
 | |
| #define L_EXEC_TIME_OFFSET   4
 | |
| #define L_SKIP_LINES_OFFSET  8
 | |
| #define L_TBL_LEN_OFFSET     12
 | |
| #define L_DB_LEN_OFFSET      13
 | |
| #define L_NUM_FIELDS_OFFSET  14
 | |
| #define L_SQL_EX_OFFSET      18
 | |
| #define L_DATA_OFFSET        LOAD_HEADER_LEN
 | |
| 
 | |
| /* Rotate event post-header */
 | |
| #define R_POS_OFFSET       0
 | |
| #define R_IDENT_OFFSET     8
 | |
| 
 | |
| /* CF to DF handle LOAD DATA INFILE */
 | |
| 
 | |
| /* CF = "Create File" */
 | |
| #define CF_FILE_ID_OFFSET  0
 | |
| #define CF_DATA_OFFSET     CREATE_FILE_HEADER_LEN
 | |
| 
 | |
| /* AB = "Append Block" */
 | |
| #define AB_FILE_ID_OFFSET  0
 | |
| #define AB_DATA_OFFSET     APPEND_BLOCK_HEADER_LEN
 | |
| 
 | |
| /* EL = "Execute Load" */
 | |
| #define EL_FILE_ID_OFFSET  0
 | |
| 
 | |
| /* DF = "Delete File" */
 | |
| #define DF_FILE_ID_OFFSET  0
 | |
| 
 | |
| /* TM = "Table Map" */
 | |
| #define TM_MAPID_OFFSET    0
 | |
| #define TM_FLAGS_OFFSET    6
 | |
| 
 | |
| /* RW = "RoWs" */
 | |
| #define RW_MAPID_OFFSET    0
 | |
| #define RW_FLAGS_OFFSET    6
 | |
| #define RW_VHLEN_OFFSET    8
 | |
| #define RW_V_TAG_LEN       1
 | |
| #define RW_V_EXTRAINFO_TAG 0
 | |
| 
 | |
| /* 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        (const uchar*) "\xfe\x62\x69\x6e"
 | |
| 
 | |
| /*
 | |
|   The 2 flags below were useless :
 | |
|   - the first one was never set
 | |
|   - the second one was set in all Rotate events on the master, but not used for
 | |
|   anything useful.
 | |
|   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.
 | |
|   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
 | |
| #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
 | |
| 
 | |
| /**
 | |
|   @def LOG_EVENT_THREAD_SPECIFIC_F
 | |
| 
 | |
|   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
 | |
| 
 | |
| /**
 | |
|   @def LOG_EVENT_SUPPRESS_USE_F
 | |
| 
 | |
|   Suppress the generation of 'USE' statements before the actual
 | |
|   statement. This flag should be set for any events that does not need
 | |
|   the current database set to function correctly. Most notable cases
 | |
|   are 'CREATE DATABASE' and 'DROP DATABASE'.
 | |
| 
 | |
|   This flags should only be used in exceptional circumstances, since
 | |
|   it introduce a significant change in behaviour regarding the
 | |
|   replication logic together with the flags --binlog-do-db and
 | |
|   --replicated-do-db.
 | |
|  */
 | |
| #define LOG_EVENT_SUPPRESS_USE_F    0x8
 | |
| 
 | |
| /*
 | |
|   Note: this is a place holder for the flag
 | |
|   LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F (0x10), which is not used any
 | |
|   more, please do not reused this value for other flags.
 | |
|  */
 | |
| 
 | |
| /**
 | |
|    @def LOG_EVENT_ARTIFICIAL_F
 | |
|    
 | |
|    Artificial events are created arbitrarily and not written to binary
 | |
|    log
 | |
| 
 | |
|    These events should not update the master log position when slave
 | |
|    SQL thread executes them.
 | |
| */
 | |
| #define LOG_EVENT_ARTIFICIAL_F 0x20
 | |
| 
 | |
| /**
 | |
|    @def LOG_EVENT_RELAY_LOG_F
 | |
|    
 | |
|    Events with this flag set are created by slave IO thread and written
 | |
|    to relay log
 | |
| */
 | |
| #define LOG_EVENT_RELAY_LOG_F 0x40
 | |
| 
 | |
| /**
 | |
|    @def LOG_EVENT_IGNORABLE_F
 | |
| 
 | |
|    For an event, 'e', carrying a type code, that a slave,
 | |
|    's', does not recognize, 's' will check 'e' for
 | |
|    LOG_EVENT_IGNORABLE_F, and if the flag is set, then 'e'
 | |
|    is ignored. Otherwise, 's' acknowledges that it has
 | |
|    found an unknown event in the relay log.
 | |
| */
 | |
| #define LOG_EVENT_IGNORABLE_F 0x80
 | |
| 
 | |
| /**
 | |
|    @def LOG_EVENT_ACCEPT_OWN_F
 | |
| 
 | |
|    Flag sets by the semisync slave for accepting
 | |
|    the same server_id ("own") events which the slave must not have
 | |
|    in its state. Typically such events were never committed by
 | |
|    their originator (this server) and discared at its semisync-slave recovery.
 | |
| */
 | |
| #define LOG_EVENT_ACCEPT_OWN_F 0x4000
 | |
| 
 | |
| /**
 | |
|    @def LOG_EVENT_SKIP_REPLICATION_F
 | |
| 
 | |
|    Flag set by application creating the event (with @@skip_replication); the
 | |
|    slave will skip replication of such events if
 | |
|    --replicate-events-marked-for-skip is not set to REPLICATE.
 | |
| 
 | |
|    This is a MariaDB flag; we allocate it from the end of the available
 | |
|    values to reduce risk of conflict with new MySQL flags.
 | |
| */
 | |
| #define LOG_EVENT_SKIP_REPLICATION_F 0x8000
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @def OPTIONS_WRITTEN_TO_BIN_LOG
 | |
| 
 | |
|   OPTIONS_WRITTEN_TO_BIN_LOG are the bits of thd->options which must
 | |
|   be written to the binlog. OPTIONS_WRITTEN_TO_BIN_LOG 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 deduct
 | |
|   the value of OPTIONS_WRITTEN_TO_BIN_LOG from the master's version.
 | |
| 
 | |
|   This is done in deduct_options_written_to_bin_log().
 | |
|   You *must* update it, when changing the definition below.
 | |
| */
 | |
| #define OPTIONS_WRITTEN_TO_BIN_LOG (OPTION_EXPLICIT_DEF_TIMESTAMP |\
 | |
|    OPTION_AUTO_IS_NULL | OPTION_NO_FOREIGN_KEY_CHECKS |  \
 | |
|    OPTION_RELAXED_UNIQUE_CHECKS | OPTION_NOT_AUTOCOMMIT | OPTION_IF_EXISTS |\
 | |
|    OPTION_INSERT_HISTORY)
 | |
| 
 | |
| #define CHECKSUM_CRC32_SIGNATURE_LEN 4
 | |
| /**
 | |
|    defined statically while there is just one alg implemented
 | |
| */
 | |
| #define BINLOG_CHECKSUM_LEN CHECKSUM_CRC32_SIGNATURE_LEN
 | |
| #define BINLOG_CHECKSUM_ALG_DESC_LEN 1  /* 1 byte checksum alg descriptor */
 | |
| 
 | |
| /*
 | |
|   These are capability numbers for MariaDB slave servers.
 | |
| 
 | |
|   Newer MariaDB slaves set this to inform the master about their capabilities.
 | |
|   This allows the master to decide which events it can send to the slave
 | |
|   without breaking replication on old slaves that maybe do not understand
 | |
|   all events from newer masters.
 | |
| 
 | |
|   As new releases are backwards compatible, a given capability implies also
 | |
|   all capabilities with smaller number.
 | |
| 
 | |
|   Older MariaDB slaves and other MySQL slave servers do not set this, so they
 | |
|   are recorded with capability 0.
 | |
| */
 | |
| 
 | |
| /* MySQL or old MariaDB slave with no announced capability. */
 | |
| #define MARIA_SLAVE_CAPABILITY_UNKNOWN 0
 | |
| /* MariaDB >= 5.3, which understands ANNOTATE_ROWS_EVENT. */
 | |
| #define MARIA_SLAVE_CAPABILITY_ANNOTATE 1
 | |
| /*
 | |
|   MariaDB >= 5.5. This version has the capability to tolerate events omitted
 | |
|   from the binlog stream without breaking replication (MySQL slaves fail
 | |
|   because they mis-compute the offsets into the master's binlog).
 | |
| */
 | |
| #define MARIA_SLAVE_CAPABILITY_TOLERATE_HOLES 2
 | |
| /* MariaDB >= 10.0, which knows about binlog_checkpoint_log_event. */
 | |
| #define MARIA_SLAVE_CAPABILITY_BINLOG_CHECKPOINT 3
 | |
| /* MariaDB >= 10.0.1, which knows about global transaction id events. */
 | |
| #define MARIA_SLAVE_CAPABILITY_GTID 4
 | |
| 
 | |
| /* Our capability. */
 | |
| #define MARIA_SLAVE_CAPABILITY_MINE MARIA_SLAVE_CAPABILITY_GTID
 | |
| 
 | |
| 
 | |
| /*
 | |
|   When the size of 'log_pos' within Heartbeat_log_event exceeds UINT32_MAX it
 | |
|   cannot be accommodated in common_header, as 'log_pos' is of 4 bytes size. In
 | |
|   such cases, sub_header, of size 8 bytes will hold larger 'log_pos' value.
 | |
| */
 | |
| #define HB_SUB_HEADER_LEN 8
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @enum Log_event_type
 | |
| 
 | |
|   Enumeration type for the different types of log events.
 | |
| */
 | |
| enum Log_event_type
 | |
| {
 | |
|   /*
 | |
|     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= 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 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,
 | |
|   FORMAT_DESCRIPTION_EVENT= 15,
 | |
|   XID_EVENT= 16,
 | |
|   BEGIN_LOAD_QUERY_EVENT= 17,
 | |
|   EXECUTE_LOAD_QUERY_EVENT= 18,
 | |
| 
 | |
|   TABLE_MAP_EVENT = 19,
 | |
| 
 | |
|   /*
 | |
|     These event numbers were used for 5.1.0 to 5.1.15 and are
 | |
|     therefore obsolete.
 | |
|    */
 | |
|   PRE_GA_WRITE_ROWS_EVENT = 20,
 | |
|   PRE_GA_UPDATE_ROWS_EVENT = 21,
 | |
|   PRE_GA_DELETE_ROWS_EVENT = 22,
 | |
| 
 | |
|   /*
 | |
|     These event numbers are used from 5.1.16 until mysql-5.6.6,
 | |
|     and in MariaDB
 | |
|    */
 | |
|   WRITE_ROWS_EVENT_V1 = 23,
 | |
|   UPDATE_ROWS_EVENT_V1 = 24,
 | |
|   DELETE_ROWS_EVENT_V1 = 25,
 | |
| 
 | |
|   /*
 | |
|     Something out of the ordinary happened on the master
 | |
|    */
 | |
|   INCIDENT_EVENT= 26,
 | |
| 
 | |
|   /*
 | |
|     Heartbeat event to be send by master at its idle time 
 | |
|     to ensure master's online status to slave 
 | |
|   */
 | |
|   HEARTBEAT_LOG_EVENT= 27,
 | |
|   
 | |
|   /*
 | |
|     In some situations, it is necessary to send over ignorable
 | |
|     data to the slave: data that a slave can handle in case there
 | |
|     is code for handling it, but which can be ignored if it is not
 | |
|     recognized.
 | |
| 
 | |
|     These mysql-5.6 events are not recognized (and ignored) by MariaDB
 | |
|   */
 | |
|   IGNORABLE_LOG_EVENT= 28,
 | |
|   ROWS_QUERY_LOG_EVENT= 29,
 | |
|  
 | |
|   /* Version 2 of the Row events, generated only by mysql-5.6.6+ */
 | |
|   WRITE_ROWS_EVENT = 30,
 | |
|   UPDATE_ROWS_EVENT = 31,
 | |
|   DELETE_ROWS_EVENT = 32,
 | |
|  
 | |
|   /* MySQL 5.6 GTID events, ignored by MariaDB */
 | |
|   GTID_LOG_EVENT= 33,
 | |
|   ANONYMOUS_GTID_LOG_EVENT= 34,
 | |
|   PREVIOUS_GTIDS_LOG_EVENT= 35,
 | |
| 
 | |
|   /* MySQL 5.7 events, ignored by MariaDB */
 | |
|   TRANSACTION_CONTEXT_EVENT= 36,
 | |
|   VIEW_CHANGE_EVENT= 37,
 | |
|   /* not ignored */
 | |
|   XA_PREPARE_LOG_EVENT= 38,
 | |
| 
 | |
|   /**
 | |
|     Extension of UPDATE_ROWS_EVENT, allowing partial values according
 | |
|     to binlog_row_value_options.
 | |
|   */
 | |
|   PARTIAL_UPDATE_ROWS_EVENT = 39,
 | |
|   TRANSACTION_PAYLOAD_EVENT = 40,
 | |
|   HEARTBEAT_LOG_EVENT_V2 = 41,
 | |
| 
 | |
|   /*
 | |
|     Add new events here - right above this comment!
 | |
|     Existing events (except ENUM_END_EVENT) should never change their numbers
 | |
|   */
 | |
| 
 | |
|   /* New MySQL/Sun events are to be added right above this comment */
 | |
|   MYSQL_EVENTS_END,
 | |
| 
 | |
|   MARIA_EVENTS_BEGIN= 160,
 | |
|   /* New Maria event numbers start from here */
 | |
|   ANNOTATE_ROWS_EVENT= 160,
 | |
|   /*
 | |
|     Binlog checkpoint event. Used for XA crash recovery on the master, not used
 | |
|     in replication.
 | |
|     A binlog checkpoint event specifies a binlog file such that XA crash
 | |
|     recovery can start from that file - and it is guaranteed to find all XIDs
 | |
|     that are prepared in storage engines but not yet committed.
 | |
|   */
 | |
|   BINLOG_CHECKPOINT_EVENT= 161,
 | |
|   /*
 | |
|     Gtid event. For global transaction ID, used to start a new event group,
 | |
|     instead of the old BEGIN query event, and also to mark stand-alone
 | |
|     events.
 | |
|   */
 | |
|   GTID_EVENT= 162,
 | |
|   /*
 | |
|     Gtid list event. Logged at the start of every binlog, to record the
 | |
|     current replication state. This consists of the last GTID seen for
 | |
|     each replication domain.
 | |
|   */
 | |
|   GTID_LIST_EVENT= 163,
 | |
| 
 | |
|   START_ENCRYPTION_EVENT= 164,
 | |
| 
 | |
|   /*
 | |
|     Compressed binlog event.
 | |
| 
 | |
|     Note that the order between WRITE/UPDATE/DELETE events is significant;
 | |
|     this is so that we can convert from the compressed to the uncompressed
 | |
|     event type with (type-WRITE_ROWS_COMPRESSED_EVENT + WRITE_ROWS_EVENT)
 | |
|     and similar for _V1.
 | |
|   */
 | |
|   QUERY_COMPRESSED_EVENT = 165,
 | |
|   WRITE_ROWS_COMPRESSED_EVENT_V1 = 166,
 | |
|   UPDATE_ROWS_COMPRESSED_EVENT_V1 = 167,
 | |
|   DELETE_ROWS_COMPRESSED_EVENT_V1 = 168,
 | |
|   WRITE_ROWS_COMPRESSED_EVENT = 169,
 | |
|   UPDATE_ROWS_COMPRESSED_EVENT = 170,
 | |
|   DELETE_ROWS_COMPRESSED_EVENT = 171,
 | |
| 
 | |
|   /* Add new MariaDB events here - right above this comment!  */
 | |
| 
 | |
|   ENUM_END_EVENT /* end marker */
 | |
| };
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Bit flags for what has been writing to cache. Used to
 | |
|   discard logs with table map events but not row events and
 | |
|   nothing else important. This is stored by cache.
 | |
| */
 | |
| 
 | |
| enum enum_logged_status
 | |
| {
 | |
|   LOGGED_TABLE_MAP= 1,
 | |
|   LOGGED_ROW_EVENT= 2,
 | |
|   LOGGED_NO_DATA=   4,
 | |
|   LOGGED_CRITICAL=  8
 | |
| };
 | |
| 
 | |
| static inline bool LOG_EVENT_IS_QUERY(enum Log_event_type type)
 | |
| {
 | |
|   return type == QUERY_EVENT || type == QUERY_COMPRESSED_EVENT;
 | |
| }
 | |
| 
 | |
| 
 | |
| static inline bool LOG_EVENT_IS_WRITE_ROW(enum Log_event_type type)
 | |
| {
 | |
|   return type == WRITE_ROWS_EVENT || type == WRITE_ROWS_EVENT_V1 ||
 | |
|     type == WRITE_ROWS_COMPRESSED_EVENT ||
 | |
|     type == WRITE_ROWS_COMPRESSED_EVENT_V1;
 | |
| }
 | |
| 
 | |
| 
 | |
| static inline bool LOG_EVENT_IS_UPDATE_ROW(enum Log_event_type type)
 | |
| {
 | |
|   return type == UPDATE_ROWS_EVENT || type == UPDATE_ROWS_EVENT_V1 ||
 | |
|     type == UPDATE_ROWS_COMPRESSED_EVENT ||
 | |
|     type == UPDATE_ROWS_COMPRESSED_EVENT_V1;
 | |
| }
 | |
| 
 | |
| 
 | |
| static inline bool LOG_EVENT_IS_DELETE_ROW(enum Log_event_type type)
 | |
| {
 | |
|   return type == DELETE_ROWS_EVENT || type == DELETE_ROWS_EVENT_V1 ||
 | |
|     type == DELETE_ROWS_COMPRESSED_EVENT ||
 | |
|     type == DELETE_ROWS_COMPRESSED_EVENT_V1;
 | |
| }
 | |
| 
 | |
| 
 | |
| static inline bool LOG_EVENT_IS_ROW_COMPRESSED(enum Log_event_type type)
 | |
| {
 | |
|   return type == WRITE_ROWS_COMPRESSED_EVENT ||
 | |
|     type == WRITE_ROWS_COMPRESSED_EVENT_V1 ||
 | |
|     type == UPDATE_ROWS_COMPRESSED_EVENT ||
 | |
|     type == UPDATE_ROWS_COMPRESSED_EVENT_V1 ||
 | |
|     type == DELETE_ROWS_COMPRESSED_EVENT ||
 | |
|     type == DELETE_ROWS_COMPRESSED_EVENT_V1;
 | |
| }
 | |
| 
 | |
| 
 | |
| static inline bool LOG_EVENT_IS_ROW_V2(enum Log_event_type type)
 | |
| {
 | |
|   return (type >= WRITE_ROWS_EVENT && type <= DELETE_ROWS_EVENT) ||
 | |
|     (type >= WRITE_ROWS_COMPRESSED_EVENT && type <= DELETE_ROWS_COMPRESSED_EVENT);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|    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
 | |
| };
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
| class String;
 | |
| class MYSQL_BIN_LOG;
 | |
| class THD;
 | |
| #endif
 | |
| 
 | |
| class Format_description_log_event;
 | |
| class Relay_log_info;
 | |
| class binlog_cache_data;
 | |
| 
 | |
| bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache, FILE *file);
 | |
| 
 | |
| #ifdef MYSQL_CLIENT
 | |
| enum enum_base64_output_mode {
 | |
|   BASE64_OUTPUT_NEVER= 0,
 | |
|   BASE64_OUTPUT_AUTO= 1,
 | |
|   BASE64_OUTPUT_UNSPEC= 2,
 | |
|   BASE64_OUTPUT_DECODE_ROWS= 3,
 | |
|   /* insert new output modes here */
 | |
|   BASE64_OUTPUT_MODE_COUNT
 | |
| };
 | |
| 
 | |
| bool copy_event_cache_to_string_and_reinit(IO_CACHE *cache, LEX_STRING *to);
 | |
| 
 | |
| /*
 | |
|   A structure for mysqlbinlog to know how to print events
 | |
| 
 | |
|   This structure is passed to the event's print() methods,
 | |
| 
 | |
|   There are two types of settings stored here:
 | |
|   1. Last db, flags2, sql_mode etc comes from the last printed event.
 | |
|      They are stored so that only the necessary USE and SET commands
 | |
|      are printed.
 | |
|   2. Other information on how to print the events, e.g. short_form,
 | |
|      hexdump_from.  These are not dependent on the last event.
 | |
| */
 | |
| typedef struct st_print_event_info
 | |
| {
 | |
|   /*
 | |
|     Settings for database, sql_mode etc that comes from the last event
 | |
|     that was printed.  We cache these so that we don't have to print
 | |
|     them if they are unchanged.
 | |
|   */
 | |
|   char db[FN_REFLEN+1]; // TODO: make this a LEX_STRING when thd->db is
 | |
|   char charset[6]; // 3 variables, each of them storable in 2 bytes
 | |
|   char time_zone_str[MAX_TIME_ZONE_NAME_LENGTH];
 | |
|   char delimiter[16];
 | |
|   sql_mode_t sql_mode;		/* must be same as THD.variables.sql_mode */
 | |
|   my_thread_id thread_id;
 | |
|   ulonglong row_events;
 | |
|   ulong auto_increment_increment, auto_increment_offset;
 | |
|   uint lc_time_names_number;
 | |
|   uint charset_database_number;
 | |
|   uint verbose;
 | |
|   uchar gtid_ev_flags2;
 | |
|   uint32 flags2;
 | |
|   uint32 server_id;
 | |
|   uint32 domain_id;
 | |
|   uint8 common_header_len;
 | |
|   enum_base64_output_mode base64_output_mode;
 | |
|   my_off_t hexdump_from;
 | |
| 
 | |
|   table_mapping m_table_map;
 | |
|   table_mapping m_table_map_ignored;
 | |
|   bool flags2_inited;
 | |
|   bool sql_mode_inited;
 | |
|   bool charset_inited;
 | |
|   bool thread_id_printed;
 | |
|   bool server_id_printed;
 | |
|   bool domain_id_printed;
 | |
|   bool allow_parallel;
 | |
|   bool allow_parallel_printed;
 | |
|   bool found_row_event;
 | |
|   bool print_row_count;
 | |
|   static const uint max_delimiter_size= 16;
 | |
|   /* Settings on how to print the events */
 | |
|   bool short_form;
 | |
|   /*
 | |
|     This is set whenever a Format_description_event is printed.
 | |
|     Later, when an event is printed in base64, this flag is tested: if
 | |
|     no Format_description_event has been seen, it is unsafe to print
 | |
|     the base64 event, so an error message is generated.
 | |
|   */
 | |
|   bool printed_fd_event;
 | |
|   /*
 | |
|     Track when @@skip_replication changes so we need to output a SET
 | |
|     statement for it.
 | |
|   */
 | |
|   bool skip_replication;
 | |
|   bool print_table_metadata;
 | |
| 
 | |
|   /*
 | |
|      These two caches are used by the row-based replication events to
 | |
|      collect the header information and the main body of the events
 | |
|      making up a statement.
 | |
|    */
 | |
|   IO_CACHE head_cache;
 | |
|   IO_CACHE body_cache;
 | |
|   IO_CACHE tail_cache;
 | |
| #ifdef WHEN_FLASHBACK_REVIEW_READY
 | |
|   /* Storing the SQL for reviewing */
 | |
|   IO_CACHE review_sql_cache;
 | |
| #endif
 | |
|   FILE *file;
 | |
| 
 | |
| 
 | |
| 
 | |
|   /*
 | |
|     Used to include the events within a GTID start/stop boundary
 | |
|   */
 | |
|   my_bool m_is_event_group_active;
 | |
| 
 | |
|   /*
 | |
|     Tracks whether or not output events must be explicitly activated in order
 | |
|     to be printed
 | |
|   */
 | |
|   my_bool m_is_event_group_filtering_enabled;
 | |
| 
 | |
|   st_print_event_info();
 | |
| 
 | |
|   ~st_print_event_info() {
 | |
|     close_cached_file(&head_cache);
 | |
|     close_cached_file(&body_cache);
 | |
|     close_cached_file(&tail_cache);
 | |
| #ifdef WHEN_FLASHBACK_REVIEW_READY
 | |
|     close_cached_file(&review_sql_cache);
 | |
| #endif
 | |
|   }
 | |
|   bool init_ok() /* tells if construction was successful */
 | |
|     { return my_b_inited(&head_cache) && my_b_inited(&body_cache)
 | |
| #ifdef WHEN_FLASHBACK_REVIEW_READY
 | |
|       && my_b_inited(&review_sql_cache)
 | |
| #endif
 | |
|     ; }
 | |
|   void flush_for_error()
 | |
|   {
 | |
|     if (!copy_event_cache_to_file_and_reinit(&head_cache, file))
 | |
|       copy_event_cache_to_file_and_reinit(&body_cache, file);
 | |
|     fflush(file);
 | |
|   }
 | |
| 
 | |
|   /*
 | |
|     Notify that all events part of the current group should be printed
 | |
|   */
 | |
|   void activate_current_event_group()
 | |
|   {
 | |
|     m_is_event_group_active= TRUE;
 | |
|   }
 | |
|   void deactivate_current_event_group()
 | |
|   {
 | |
|     m_is_event_group_active= FALSE;
 | |
|   }
 | |
| 
 | |
|   /*
 | |
|     Used for displaying events part of an event group.
 | |
|     Returns TRUE when both event group filtering is enabled and the current
 | |
|             event group should be displayed, OR if event group filtering is
 | |
|             disabled. More specifically, if filtering is disabled, all events
 | |
|             should be shown.
 | |
|     Returns FALSE when event group filtering is enabled and the current event
 | |
|             group is filtered out.
 | |
|   */
 | |
|   my_bool is_event_group_active()
 | |
|   {
 | |
|     return m_is_event_group_filtering_enabled ? m_is_event_group_active : TRUE;
 | |
|   }
 | |
| 
 | |
|   /*
 | |
|     Notify that events must be explicitly activated in order to be printed
 | |
|   */
 | |
|   void enable_event_group_filtering()
 | |
|   {
 | |
|     m_is_event_group_filtering_enabled= TRUE;
 | |
|   }
 | |
| 
 | |
|   my_bool is_xa_trans();
 | |
| } PRINT_EVENT_INFO;
 | |
| #endif  // MYSQL_CLIENT
 | |
| 
 | |
| /**
 | |
|   This class encapsulates writing of Log_event objects to IO_CACHE.
 | |
|   Automatically calculates the checksum and encrypts the data, if necessary.
 | |
| */
 | |
| 
 | |
| class Log_event_writer
 | |
| {
 | |
|   /* Log_event_writer is updated when ctx is set */
 | |
|   int (Log_event_writer::*encrypt_or_write)(const uchar *pos, size_t len);
 | |
| public:
 | |
|   ulonglong bytes_written;
 | |
|   void *ctx;         ///< Encryption context or 0 if no encryption is needed
 | |
|   uint checksum_len;
 | |
|   int write(Log_event *ev);
 | |
|   int write_header(uchar *pos, size_t len);
 | |
|   int write_data(const uchar *pos, size_t len);
 | |
|   int write_footer();
 | |
|   my_off_t pos() { return my_b_safe_tell(file); }
 | |
|   void add_status(enum_logged_status status);
 | |
|   void set_incident();
 | |
|   void set_encrypted_writer()
 | |
|   { encrypt_or_write= &Log_event_writer::encrypt_and_write; }
 | |
| 
 | |
|   Log_event_writer(IO_CACHE *file_arg, binlog_cache_data *cache_data_arg,
 | |
|                    Binlog_crypt_data *cr= 0)
 | |
|     :encrypt_or_write(&Log_event_writer::write_internal),
 | |
|     bytes_written(0), ctx(0),
 | |
|     file(file_arg), cache_data(cache_data_arg), crypto(cr) { }
 | |
| 
 | |
| private:
 | |
|   IO_CACHE *file;
 | |
|   binlog_cache_data *cache_data;
 | |
|   /**
 | |
|     Placeholder for event checksum while writing to binlog.
 | |
|    */
 | |
|   ha_checksum crc;
 | |
|   /**
 | |
|     Encryption data (key, nonce). Only used if ctx != 0.
 | |
|   */
 | |
|   Binlog_crypt_data *crypto;
 | |
|   /**
 | |
|     Event length to be written into the next encrypted block
 | |
|   */
 | |
|   uint event_len;
 | |
|   int write_internal(const uchar *pos, size_t len);
 | |
|   int encrypt_and_write(const uchar *pos, size_t len);
 | |
|   int maybe_write_event_len(uchar *pos, size_t len);
 | |
| };
 | |
| 
 | |
| /**
 | |
|   the struct aggregates two parameters that identify an event
 | |
|   uniquely in scope of communication of a particular master and slave couple.
 | |
|   I.e there can not be 2 events from the same staying connected master which
 | |
|   have the same coordinates.
 | |
|   @note
 | |
|   Such identifier is not yet unique generally as the event originating master
 | |
|   is resettable. Also the crashed master can be replaced with some other.
 | |
| */
 | |
| typedef struct event_coordinates
 | |
| {
 | |
|   char * file_name; // binlog file name (directories stripped)
 | |
|   my_off_t  pos;       // event's position in the binlog file
 | |
| } LOG_POS_COORD;
 | |
| 
 | |
| /**
 | |
|   @class Log_event
 | |
| 
 | |
|   This is the abstract base class for binary log events.
 | |
|   
 | |
|   @section Log_event_binary_format Binary Format
 | |
| 
 | |
|   Any @c Log_event saved on disk consists of the following three
 | |
|   components.
 | |
| 
 | |
|   - Common-Header
 | |
|   - Post-Header
 | |
|   - Body
 | |
| 
 | |
|   The Common-Header, documented in the table @ref Table_common_header
 | |
|   "below", always has the same form and length within one version of
 | |
|   MySQL.  Each event type specifies a format and length of the
 | |
|   Post-Header.  The length of the Common-Header is the same for all
 | |
|   events of the same type.  The Body may be of different format and
 | |
|   length even for different events of the same type.  The binary
 | |
|   formats of Post-Header and Body are documented separately in each
 | |
|   subclass.  The binary format of Common-Header is as follows.
 | |
| 
 | |
|   <table>
 | |
|   <caption>Common-Header</caption>
 | |
| 
 | |
|   <tr>
 | |
|     <th>Name</th>
 | |
|     <th>Format</th>
 | |
|     <th>Description</th>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>timestamp</td>
 | |
|     <td>4 byte unsigned integer</td>
 | |
|     <td>The time when the query started, in seconds since 1970.
 | |
|     </td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>type</td>
 | |
|     <td>1 byte enumeration</td>
 | |
|     <td>See enum #Log_event_type.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>server_id</td>
 | |
|     <td>4 byte unsigned integer</td>
 | |
|     <td>Server ID of the server that created the event.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>total_size</td>
 | |
|     <td>4 byte unsigned integer</td>
 | |
|     <td>The total size of this event, in bytes.  In other words, this
 | |
|     is the sum of the sizes of Common-Header, Post-Header, and Body.
 | |
|     </td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>master_position</td>
 | |
|     <td>4 byte unsigned integer</td>
 | |
|     <td>The position of the next event in the master binary log, in
 | |
|     bytes from the beginning of the file.  In a binlog that is not a
 | |
|     relay log, this is just the position of the next event, in bytes
 | |
|     from the beginning of the file.  In a relay log, this is
 | |
|     the position of the next event in the master's binlog.
 | |
|     </td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>flags</td>
 | |
|     <td>2 byte bitfield</td>
 | |
|     <td>See Log_event::flags.</td>
 | |
|   </tr>
 | |
|   </table>
 | |
| 
 | |
|   Summing up the numbers above, we see that the total size of the
 | |
|   common header is 19 bytes.
 | |
| 
 | |
|   @subsection Log_event_format_of_atomic_primitives Format of Atomic Primitives
 | |
| 
 | |
|   - All numbers, whether they are 16-, 24-, 32-, or 64-bit numbers,
 | |
|   are stored in little endian, i.e., the least significant byte first,
 | |
|   unless otherwise specified.
 | |
| 
 | |
|   @anchor packed_integer
 | |
|   - Some events use a special format for efficient representation of
 | |
|   unsigned integers, called Packed Integer.  A Packed Integer has the
 | |
|   capacity of storing up to 8-byte integers, while small integers
 | |
|   still can use 1, 3, or 4 bytes.  The value of the first byte
 | |
|   determines how to read the number, according to the following table:
 | |
| 
 | |
|   <table>
 | |
|   <caption>Format of Packed Integer</caption>
 | |
| 
 | |
|   <tr>
 | |
|     <th>First byte</th>
 | |
|     <th>Format</th>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>0-250</td>
 | |
|     <td>The first byte is the number (in the range 0-250), and no more
 | |
|     bytes are used.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>252</td>
 | |
|     <td>Two more bytes are used.  The number is in the range
 | |
|     251-0xffff.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>253</td>
 | |
|     <td>Three more bytes are used.  The number is in the range
 | |
|     0xffff-0xffffff.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>254</td>
 | |
|     <td>Eight more bytes are used.  The number is in the range
 | |
|     0xffffff-0xffffffffffffffff.</td>
 | |
|   </tr>
 | |
| 
 | |
|   </table>
 | |
| 
 | |
|   - Strings are stored in various formats.  The format of each string
 | |
|   is documented separately.
 | |
| */
 | |
| class Log_event
 | |
| {
 | |
| public:
 | |
|   /**
 | |
|      Enumeration of what kinds of skipping (and non-skipping) that can
 | |
|      occur when the slave executes an event.
 | |
| 
 | |
|      @see shall_skip
 | |
|      @see do_shall_skip
 | |
|    */
 | |
|   enum enum_skip_reason {
 | |
|     /**
 | |
|        Don't skip event.
 | |
|     */
 | |
|     EVENT_SKIP_NOT,
 | |
| 
 | |
|     /**
 | |
|        Skip event by ignoring it.
 | |
| 
 | |
|        This means that the slave skip counter will not be changed.
 | |
|     */
 | |
|     EVENT_SKIP_IGNORE,
 | |
| 
 | |
|     /**
 | |
|        Skip event and decrease skip counter.
 | |
|     */
 | |
|     EVENT_SKIP_COUNT
 | |
|   };
 | |
| 
 | |
|   enum enum_event_cache_type 
 | |
|   {
 | |
|     EVENT_INVALID_CACHE,
 | |
|     /* 
 | |
|       If possible the event should use a non-transactional cache before
 | |
|       being flushed to the binary log. This means that it must be flushed
 | |
|       right after its correspondent statement is completed.
 | |
|     */
 | |
|     EVENT_STMT_CACHE,
 | |
|     /* 
 | |
|       The event should use a transactional cache before being flushed to
 | |
|       the binary log. This means that it must be flushed upon commit or 
 | |
|       rollback. 
 | |
|     */
 | |
|     EVENT_TRANSACTIONAL_CACHE,
 | |
|     /* 
 | |
|       The event must be written directly to the binary log without going
 | |
|       through a cache.
 | |
|     */
 | |
|     EVENT_NO_CACHE,
 | |
|     /**
 | |
|        If there is a need for different types, introduce them before this.
 | |
|     */
 | |
|     EVENT_CACHE_COUNT
 | |
|   };
 | |
| 
 | |
|   /*
 | |
|     The following type definition is to be used whenever data is placed 
 | |
|     and manipulated in a common buffer. Use this typedef for buffers
 | |
|     that contain data containing binary and character data.
 | |
|   */
 | |
|   typedef unsigned char Byte;
 | |
| 
 | |
|   /*
 | |
|     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.
 | |
|   */
 | |
|   uchar *temp_buf;
 | |
|   
 | |
|   /*
 | |
|     TRUE <=> this event 'owns' temp_buf and should call my_free() when done
 | |
|     with it
 | |
|   */
 | |
|   bool event_owns_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).
 | |
|   */
 | |
|   my_time_t when;
 | |
|   ulong     when_sec_part;
 | |
|   /* The number of seconds the query took to run on the master. */
 | |
|   ulong exec_time;
 | |
|   /* Number of bytes written by write() function */
 | |
|   size_t 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;
 | |
| 
 | |
|   /**
 | |
|     Some 16 flags. See the definitions above for LOG_EVENT_TIME_F,
 | |
|     LOG_EVENT_FORCED_ROTATE_F, LOG_EVENT_THREAD_SPECIFIC_F,
 | |
|     LOG_EVENT_SUPPRESS_USE_F, and LOG_EVENT_SKIP_REPLICATION_F for notes.
 | |
|   */
 | |
|   uint16 flags;
 | |
| 
 | |
|   enum_event_cache_type cache_type;
 | |
| 
 | |
|   /**
 | |
|     A storage to cache the global system variable's value.
 | |
|     Handling of a separate event will be governed its member.
 | |
|   */
 | |
|   ulong slave_exec_mode;
 | |
| 
 | |
|   Log_event_writer *writer;
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   THD* thd;
 | |
| 
 | |
|   Log_event();
 | |
|   Log_event(THD* thd_arg, uint16 flags_arg, bool is_transactional);
 | |
| 
 | |
|   /*
 | |
|     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(THD *thd, List<Item>* field_list);
 | |
| #ifdef HAVE_REPLICATION
 | |
|   int net_send(Protocol *protocol, const char* log_name, my_off_t pos);
 | |
| 
 | |
|   /*
 | |
|     pack_info() is used by SHOW BINLOG EVENTS; as print() it prepares and sends
 | |
|     a string to display to the user, so it resembles print().
 | |
|   */
 | |
| 
 | |
|   virtual void pack_info(Protocol *protocol);
 | |
| 
 | |
| #endif /* HAVE_REPLICATION */
 | |
|   virtual const char* get_db()
 | |
|   {
 | |
|     return thd ? thd->db.str : 0;
 | |
|   }
 | |
| #else
 | |
|   Log_event() : temp_buf(0), when(0), flags(0) {}
 | |
|   ha_checksum crc;
 | |
|   /* print*() functions are used by mysqlbinlog */
 | |
|   virtual bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) = 0;
 | |
|   bool print_timestamp(IO_CACHE* file, time_t *ts = 0);
 | |
|   bool print_header(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info,
 | |
|                     bool is_more);
 | |
|   bool print_base64(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info,
 | |
|                     bool do_print_encoded);
 | |
| #endif /* MYSQL_SERVER */
 | |
| 
 | |
|   /* The following code used for Flashback */
 | |
| #ifdef MYSQL_CLIENT
 | |
|   my_bool is_flashback;
 | |
|   my_bool need_flashback_review;
 | |
|   String  output_buf; // Storing the event output
 | |
| #ifdef WHEN_FLASHBACK_REVIEW_READY
 | |
|   String  m_review_dbname;
 | |
|   String  m_review_tablename;
 | |
| 
 | |
|   void set_review_dbname(const char *name)
 | |
|   {
 | |
|     if (name)
 | |
|     {
 | |
|       m_review_dbname.free();
 | |
|       m_review_dbname.append(name);
 | |
|     }
 | |
|   }
 | |
|   void set_review_tablename(const char *name)
 | |
|   {
 | |
|     if (name)
 | |
|     {
 | |
|       m_review_tablename.free();
 | |
|       m_review_tablename.append(name);
 | |
|     }
 | |
|   }
 | |
|   const char *get_review_dbname() const { return m_review_dbname.ptr(); }
 | |
|   const char *get_review_tablename() const { return m_review_tablename.ptr(); }
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
|   /*
 | |
|     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.
 | |
|   */
 | |
|   static Log_event* read_log_event(IO_CACHE* file, int *out_error,
 | |
|                                    const Format_description_log_event
 | |
|                                    *description_event,
 | |
|                                    my_bool crc_check,
 | |
|                                    my_bool print_errors= 1);
 | |
| 
 | |
|   /**
 | |
|     Reads an event from a binlog or relay log. Used by the dump thread
 | |
|     this method reads the event into a raw buffer without parsing it.
 | |
| 
 | |
|     @Note If mutex is 0, the read will proceed without mutex.
 | |
| 
 | |
|     @Note If a log name is given than the method will check if the
 | |
|     given binlog is still active.
 | |
| 
 | |
|     @param[in]  file                log file to be read
 | |
|     @param[out] packet              packet to hold the event
 | |
|     @param[in]  checksum_alg_arg    verify the event checksum using this
 | |
|                                     algorithm (or don't if it's
 | |
|                                     use BINLOG_CHECKSUM_ALG_OFF)
 | |
| 
 | |
|     @retval 0                   success
 | |
|     @retval LOG_READ_EOF        end of file, nothing was read
 | |
|     @retval LOG_READ_BOGUS      malformed event
 | |
|     @retval LOG_READ_IO         io error while reading
 | |
|     @retval LOG_READ_MEM        packet memory allocation failed
 | |
|     @retval LOG_READ_TRUNC      only a partial event could be read
 | |
|     @retval LOG_READ_TOO_LARGE  event too large
 | |
|    */
 | |
|   static int read_log_event(IO_CACHE* file, String* packet,
 | |
|                             const Format_description_log_event *fdle,
 | |
|                             enum enum_binlog_checksum_alg checksum_alg_arg);
 | |
|   /* 
 | |
|      The value is set by caller of FD constructor and
 | |
|      Log_event::write_header() for the rest.
 | |
|      In the FD case it's propagated into the last byte 
 | |
|      of post_header_len[] at FD::write().
 | |
|      On the slave side the value is assigned from post_header_len[last] 
 | |
|      of the last seen FD event.
 | |
|   */
 | |
|   enum enum_binlog_checksum_alg checksum_alg;
 | |
| 
 | |
|   static void *operator new(size_t size)
 | |
|   {
 | |
|     extern PSI_memory_key key_memory_log_event;
 | |
|     return my_malloc(key_memory_log_event, size, MYF(MY_WME|MY_FAE));
 | |
|   }
 | |
| 
 | |
|   static void operator delete(void *ptr, size_t)
 | |
|   {
 | |
|     my_free(ptr);
 | |
|   }
 | |
| 
 | |
|   /* Placement version of the above operators */
 | |
|   static void *operator new(size_t, void* ptr) { return ptr; }
 | |
|   static void operator delete(void*, void*) { }
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write_header(size_t event_data_length);
 | |
|   bool write_data(const uchar *buf, size_t data_length)
 | |
|   { return writer->write_data(buf, data_length); }
 | |
|   bool write_data(const char *buf, size_t data_length)
 | |
|   { return write_data((uchar*)buf, data_length); }
 | |
|   bool write_footer()
 | |
|   { return writer->write_footer(); }
 | |
| 
 | |
|   my_bool need_checksum();
 | |
| 
 | |
|   virtual bool write()
 | |
|   {
 | |
|     return write_header(get_data_size()) || write_data_header() ||
 | |
| 	   write_data_body() || write_footer();
 | |
|   }
 | |
|   virtual bool write_data_header()
 | |
|   { return 0; }
 | |
|   virtual bool write_data_body()
 | |
|   { return 0; }
 | |
| 
 | |
|   /* Return start of query time or current time */
 | |
|   inline my_time_t get_time()
 | |
|   {
 | |
|     THD *tmp_thd;
 | |
|     if (when)
 | |
|       return when;
 | |
|     if (thd)
 | |
|     {
 | |
|       when= thd->start_time;
 | |
|       when_sec_part= thd->start_time_sec_part;
 | |
|       return when;
 | |
|     }
 | |
|     /* thd will only be 0 here at time of log creation */
 | |
|     if ((tmp_thd= current_thd))
 | |
|     {
 | |
|       when= tmp_thd->start_time;
 | |
|       when_sec_part= tmp_thd->start_time_sec_part;
 | |
|       return when;
 | |
|     }
 | |
|     my_hrtime_t hrtime= my_hrtime();
 | |
|     when= hrtime_to_my_time(hrtime);
 | |
|     when_sec_part= hrtime_sec_part(hrtime);
 | |
|     return when;
 | |
|   }
 | |
| #endif
 | |
|   virtual Log_event_type get_type_code() = 0;
 | |
|   virtual enum_logged_status logged_status() { return LOGGED_CRITICAL; }
 | |
|   virtual bool is_valid() const = 0;
 | |
|   virtual my_off_t get_header_len(my_off_t len) { return len; }
 | |
|   void set_artificial_event() { flags |= LOG_EVENT_ARTIFICIAL_F; }
 | |
|   void set_relay_log_event() { flags |= LOG_EVENT_RELAY_LOG_F; }
 | |
|   bool is_artificial_event() const { return flags & LOG_EVENT_ARTIFICIAL_F; }
 | |
|   bool is_relay_log_event() const { return flags & LOG_EVENT_RELAY_LOG_F; }
 | |
|   inline bool use_trans_cache() const
 | |
|   { 
 | |
|     return (cache_type == Log_event::EVENT_TRANSACTIONAL_CACHE);
 | |
|   }
 | |
|   inline void set_direct_logging()
 | |
|   {
 | |
|     cache_type = Log_event::EVENT_NO_CACHE;
 | |
|   }
 | |
|   inline bool use_direct_logging()
 | |
|   {
 | |
|     return (cache_type == Log_event::EVENT_NO_CACHE);
 | |
|   }
 | |
|   Log_event(const uchar *buf, const Format_description_log_event
 | |
|             *description_event);
 | |
|   virtual ~Log_event() { free_temp_buf();}
 | |
|   void register_temp_buf(uchar* buf, bool must_free)
 | |
|   { 
 | |
|     temp_buf= buf; 
 | |
|     event_owns_temp_buf= must_free;
 | |
|   }
 | |
|   void free_temp_buf()
 | |
|   {
 | |
|     if (temp_buf)
 | |
|     {
 | |
|       if (event_owns_temp_buf)
 | |
|         my_free(temp_buf);
 | |
|       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;}
 | |
|   static Log_event* read_log_event(const uchar *buf, uint event_len,
 | |
| 				   const char **error,
 | |
|                                    const Format_description_log_event
 | |
|                                    *description_event, my_bool crc_check,
 | |
|                                    my_bool print_errors= 1);
 | |
|   /**
 | |
|     Returns the human readable name of the given event type.
 | |
|   */
 | |
|   static const char* get_type_str(Log_event_type type);
 | |
|   /**
 | |
|     Returns the human readable name of this event's type.
 | |
|   */
 | |
|   const char* get_type_str();
 | |
| 
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
| 
 | |
|   /**
 | |
|      Apply the event to the database.
 | |
| 
 | |
|      This function represents the public interface for applying an
 | |
|      event.
 | |
| 
 | |
|      @see do_apply_event
 | |
|    */
 | |
|   int apply_event(rpl_group_info *rgi);
 | |
| 
 | |
| 
 | |
|   /**
 | |
|      Update the relay log position.
 | |
| 
 | |
|      This function represents the public interface for "stepping over"
 | |
|      the event and will update the relay log information.
 | |
| 
 | |
|      @see do_update_pos
 | |
|    */
 | |
|   int update_pos(rpl_group_info *rgi)
 | |
|   {
 | |
|     return do_update_pos(rgi);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|      Decide if the event shall be skipped, and the reason for skipping
 | |
|      it.
 | |
| 
 | |
|      @see do_shall_skip
 | |
|    */
 | |
|   enum_skip_reason shall_skip(rpl_group_info *rgi)
 | |
|   {
 | |
|     return do_shall_skip(rgi);
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /*
 | |
|     Check if an event is non-final part of a stand-alone event group,
 | |
|     such as Intvar_log_event (such events should be processed as part
 | |
|     of the following event group, not individually).
 | |
|     See also is_part_of_group()
 | |
|   */
 | |
|   static bool is_part_of_group(enum Log_event_type ev_type)
 | |
|   {
 | |
|     switch (ev_type)
 | |
|     {
 | |
|     case GTID_EVENT:
 | |
|     case INTVAR_EVENT:
 | |
|     case RAND_EVENT:
 | |
|     case USER_VAR_EVENT:
 | |
|     case TABLE_MAP_EVENT:
 | |
|     case ANNOTATE_ROWS_EVENT:
 | |
|       return true;
 | |
|     case DELETE_ROWS_EVENT:
 | |
|     case UPDATE_ROWS_EVENT:
 | |
|     case WRITE_ROWS_EVENT:
 | |
|     /*
 | |
|       ToDo: also check for non-final Rows_log_event (though such events
 | |
|       are usually in a BEGIN-COMMIT group).
 | |
|     */
 | |
|     default:
 | |
|       return false;
 | |
|     }
 | |
|   }
 | |
|   /*
 | |
|     Same as above, but works on the object. In addition this is true for all
 | |
|     rows event except the last one.
 | |
|   */
 | |
|   virtual bool is_part_of_group() { return 0; }
 | |
| 
 | |
|   static bool is_group_event(enum Log_event_type ev_type)
 | |
|   {
 | |
|     switch (ev_type)
 | |
|     {
 | |
|     case START_EVENT_V3:
 | |
|     case STOP_EVENT:
 | |
|     case ROTATE_EVENT:
 | |
|     case SLAVE_EVENT:
 | |
|     case FORMAT_DESCRIPTION_EVENT:
 | |
|     case INCIDENT_EVENT:
 | |
|     case HEARTBEAT_LOG_EVENT:
 | |
|     case BINLOG_CHECKPOINT_EVENT:
 | |
|     case GTID_LIST_EVENT:
 | |
|     case START_ENCRYPTION_EVENT:
 | |
|       return false;
 | |
| 
 | |
|     default:
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
|   
 | |
| protected:
 | |
| 
 | |
|   /**
 | |
|      Helper function to ignore an event w.r.t. the slave skip counter.
 | |
| 
 | |
|      This function can be used inside do_shall_skip() for functions
 | |
|      that cannot end a group. If the slave skip counter is 1 when
 | |
|      seeing such an event, the event shall be ignored, the counter
 | |
|      left intact, and processing continue with the next event.
 | |
| 
 | |
|      A typical usage is:
 | |
|      @code
 | |
|      enum_skip_reason do_shall_skip(rpl_group_info *rgi) {
 | |
|        return continue_group(rgi);
 | |
|      }
 | |
|      @endcode
 | |
| 
 | |
|      @return Skip reason
 | |
|    */
 | |
|   enum_skip_reason continue_group(rpl_group_info *rgi);
 | |
| 
 | |
|   /**
 | |
|     Primitive to apply an event to the database.
 | |
| 
 | |
|     This is where the change to the database is made.
 | |
| 
 | |
|     @note The primitive is protected instead of private, since there
 | |
|     is a hierarchy of actions to be performed in some cases.
 | |
| 
 | |
|     @see Format_description_log_event::do_apply_event()
 | |
| 
 | |
|     @param rli Pointer to relay log info structure
 | |
| 
 | |
|     @retval 0     Event applied successfully
 | |
|     @retval errno Error code if event application failed
 | |
|   */
 | |
|   virtual int do_apply_event(rpl_group_info *rgi)
 | |
|   {
 | |
|     return 0;                /* Default implementation does nothing */
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /**
 | |
|      Advance relay log coordinates.
 | |
| 
 | |
|      This function is called to advance the relay log coordinates to
 | |
|      just after the event.  It is essential that both the relay log
 | |
|      coordinate and the group log position is updated correctly, since
 | |
|      this function is used also for skipping events.
 | |
| 
 | |
|      Normally, each implementation of do_update_pos() shall:
 | |
| 
 | |
|      - Update the event position to refer to the position just after
 | |
|        the event.
 | |
| 
 | |
|      - Update the group log position to refer to the position just
 | |
|        after the event <em>if the event is last in a group</em>
 | |
| 
 | |
|      @param rli Pointer to relay log info structure
 | |
| 
 | |
|      @retval 0     Coordinates changed successfully
 | |
|      @retval errno Error code if advancing failed (usually just
 | |
|                    1). Observe that handler errors are returned by the
 | |
|                    do_apply_event() function, and not by this one.
 | |
|    */
 | |
|   virtual int do_update_pos(rpl_group_info *rgi);
 | |
| 
 | |
| 
 | |
|   /**
 | |
|      Decide if this event shall be skipped or not and the reason for
 | |
|      skipping it.
 | |
| 
 | |
|      The default implementation decide that the event shall be skipped
 | |
|      if either:
 | |
| 
 | |
|      - the server id of the event is the same as the server id of the
 | |
|        server and <code>rli->replicate_same_server_id</code> is true,
 | |
|        or
 | |
| 
 | |
|      - if <code>rli->slave_skip_counter</code> is greater than zero.
 | |
| 
 | |
|      @see do_apply_event
 | |
|      @see do_update_pos
 | |
| 
 | |
|      @retval Log_event::EVENT_SKIP_NOT
 | |
|      The event shall not be skipped and should be applied.
 | |
| 
 | |
|      @retval Log_event::EVENT_SKIP_IGNORE
 | |
|      The event shall be skipped by just ignoring it, i.e., the slave
 | |
|      skip counter shall not be changed. This happends if, for example,
 | |
|      the originating server id of the event is the same as the server
 | |
|      id of the slave.
 | |
| 
 | |
|      @retval Log_event::EVENT_SKIP_COUNT
 | |
|      The event shall be skipped because the slave skip counter was
 | |
|      non-zero. The caller shall decrease the counter by one.
 | |
|    */
 | |
|   virtual enum_skip_reason do_shall_skip(rpl_group_info *rgi);
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /*
 | |
|    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.
 | |
| */
 | |
| 
 | |
| /**
 | |
|   @class Query_log_event
 | |
|    
 | |
|   A @c Query_log_event is created for each query that modifies the
 | |
|   database, unless the query is logged row-based.
 | |
| 
 | |
|   @section Query_log_event_binary_format Binary format
 | |
| 
 | |
|   See @ref Log_event_binary_format "Binary format for log events" for
 | |
|   a general discussion and introduction to the binary format of binlog
 | |
|   events.
 | |
| 
 | |
|   The Post-Header has five components:
 | |
| 
 | |
|   <table>
 | |
|   <caption>Post-Header for Query_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>db_len</td>
 | |
|     <td>1 byte integer</td>
 | |
|     <td>The length of the name of the currently selected database.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>error_code</td>
 | |
|     <td>2 byte unsigned integer</td>
 | |
|     <td>Error code generated by the master.  If the master fails, the
 | |
|     slave will fail with the same error code, except for the error
 | |
|     codes ER_DB_CREATE_EXISTS == 1007 and ER_DB_DROP_EXISTS == 1008.
 | |
|     </td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>status_vars_len</td>
 | |
|     <td>2 byte unsigned integer</td>
 | |
|     <td>The length of the status_vars block of the Body, in bytes. See
 | |
|     @ref query_log_event_status_vars "below".
 | |
|     </td>
 | |
|   </tr>
 | |
|   </table>
 | |
| 
 | |
|   The Body has the following components:
 | |
| 
 | |
|   <table>
 | |
|   <caption>Body for Query_log_event</caption>
 | |
| 
 | |
|   <tr>
 | |
|     <th>Name</th>
 | |
|     <th>Format</th>
 | |
|     <th>Description</th>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>@anchor query_log_event_status_vars status_vars</td>
 | |
|     <td>status_vars_len bytes</td>
 | |
|     <td>Zero or more status variables.  Each status variable consists
 | |
|     of one byte identifying the variable stored, followed by the value
 | |
|     of the variable.  The possible variables are listed separately in
 | |
|     the table @ref Table_query_log_event_status_vars "below".  MySQL
 | |
|     always writes events in the order defined below; however, it is
 | |
|     capable of reading them in any order.  </td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>db</td>
 | |
|     <td>db_len+1</td>
 | |
|     <td>The currently selected database, as a null-terminated string.
 | |
| 
 | |
|     (The trailing zero is redundant since the length is already known;
 | |
|     it is db_len from Post-Header.)
 | |
|     </td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>query</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 SQL query.</td>
 | |
|   </tr>
 | |
|   </table>
 | |
| 
 | |
|   The following table lists the status variables that may appear in
 | |
|   the status_vars field.
 | |
| 
 | |
|   @anchor Table_query_log_event_status_vars
 | |
|   <table>
 | |
|   <caption>Status variables for Query_log_event</caption>
 | |
| 
 | |
|   <tr>
 | |
|     <th>Status variable</th>
 | |
|     <th>1 byte identifier</th>
 | |
|     <th>Format</th>
 | |
|     <th>Description</th>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>flags2</td>
 | |
|     <td>Q_FLAGS2_CODE == 0</td>
 | |
|     <td>4 byte bitfield</td>
 | |
|     <td>The flags in @c thd->options, binary AND-ed with @c
 | |
|     OPTIONS_WRITTEN_TO_BIN_LOG.  The @c thd->options bitfield contains
 | |
|     options for "SELECT".  @c OPTIONS_WRITTEN identifies those options
 | |
|     that need to be written to the binlog (not all do).
 | |
| 
 | |
|     These flags correspond to the SQL variables SQL_AUTO_IS_NULL,
 | |
|     FOREIGN_KEY_CHECKS, UNIQUE_CHECKS, and AUTOCOMMIT, documented in
 | |
|     the "SET Syntax" section of the MySQL Manual.
 | |
| 
 | |
|     This field is always written to the binlog in version >= 5.0, and
 | |
|     never written in version < 5.0.
 | |
|     </td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>sql_mode</td>
 | |
|     <td>Q_SQL_MODE_CODE == 1</td>
 | |
|     <td>8 byte bitfield</td>
 | |
|     <td>The @c sql_mode variable.  See the section "SQL Modes" in the
 | |
|     MySQL manual, and see sql_priv.h for a list of the possible
 | |
|     flags. Currently (2007-10-04), the following flags are available:
 | |
|     <pre>
 | |
|     MODE_REAL_AS_FLOAT==0x1
 | |
|     MODE_PIPES_AS_CONCAT==0x2
 | |
|     MODE_ANSI_QUOTES==0x4
 | |
|     MODE_IGNORE_SPACE==0x8
 | |
|     MODE_IGNORE_BAD_TABLE_OPTIONS==0x10
 | |
|     MODE_ONLY_FULL_GROUP_BY==0x20
 | |
|     MODE_NO_UNSIGNED_SUBTRACTION==0x40
 | |
|     MODE_NO_DIR_IN_CREATE==0x80
 | |
|     MODE_POSTGRESQL==0x100
 | |
|     MODE_ORACLE==0x200
 | |
|     MODE_MSSQL==0x400
 | |
|     MODE_DB2==0x800
 | |
|     MODE_MAXDB==0x1000
 | |
|     MODE_NO_KEY_OPTIONS==0x2000
 | |
|     MODE_NO_TABLE_OPTIONS==0x4000
 | |
|     MODE_NO_FIELD_OPTIONS==0x8000
 | |
|     MODE_MYSQL323==0x10000
 | |
|     MODE_MYSQL323==0x20000
 | |
|     MODE_MYSQL40==0x40000
 | |
|     MODE_ANSI==0x80000
 | |
|     MODE_NO_AUTO_VALUE_ON_ZERO==0x100000
 | |
|     MODE_NO_BACKSLASH_ESCAPES==0x200000
 | |
|     MODE_STRICT_TRANS_TABLES==0x400000
 | |
|     MODE_STRICT_ALL_TABLES==0x800000
 | |
|     MODE_NO_ZERO_IN_DATE==0x1000000
 | |
|     MODE_NO_ZERO_DATE==0x2000000
 | |
|     MODE_INVALID_DATES==0x4000000
 | |
|     MODE_ERROR_FOR_DIVISION_BY_ZERO==0x8000000
 | |
|     MODE_TRADITIONAL==0x10000000
 | |
|     MODE_NO_AUTO_CREATE_USER==0x20000000
 | |
|     MODE_HIGH_NOT_PRECEDENCE==0x40000000
 | |
|     MODE_PAD_CHAR_TO_FULL_LENGTH==0x80000000
 | |
|     </pre>
 | |
|     All these flags are replicated from the server.  However, all
 | |
|     flags except @c MODE_NO_DIR_IN_CREATE are honored by the slave;
 | |
|     the slave always preserves its old value of @c
 | |
|     MODE_NO_DIR_IN_CREATE.  For a rationale, see comment in
 | |
|     @c Query_log_event::do_apply_event in @c log_event.cc.
 | |
| 
 | |
|     This field is always written to the binlog.
 | |
|     </td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>catalog</td>
 | |
|     <td>Q_CATALOG_NZ_CODE == 6</td>
 | |
|     <td>Variable-length string: the length in bytes (1 byte) followed
 | |
|     by the characters (at most 255 bytes)
 | |
|     </td>
 | |
|     <td>Stores the client's current catalog.  Every database belongs
 | |
|     to a catalog, the same way that every table belongs to a
 | |
|     database.  Currently, there is only one catalog, "std".
 | |
| 
 | |
|     This field is written if the length of the catalog is > 0;
 | |
|     otherwise it is not written.
 | |
|     </td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>auto_increment</td>
 | |
|     <td>Q_AUTO_INCREMENT == 3</td>
 | |
|     <td>two 2 byte unsigned integers, totally 2+2=4 bytes</td>
 | |
| 
 | |
|     <td>The two variables auto_increment_increment and
 | |
|     auto_increment_offset, in that order.  For more information, see
 | |
|     "System variables" in the MySQL manual.
 | |
| 
 | |
|     This field is written if auto_increment > 1.  Otherwise, it is not
 | |
|     written.
 | |
|     </td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>charset</td>
 | |
|     <td>Q_CHARSET_CODE == 4</td>
 | |
|     <td>three 2 byte unsigned integers, totally 2+2+2=6 bytes</td>
 | |
|     <td>The three variables character_set_client,
 | |
|     collation_connection, and collation_server, in that order.
 | |
|     character_set_client is a code identifying the character set and
 | |
|     collation used by the client to encode the query.
 | |
|     collation_connection identifies the character set and collation
 | |
|     that the master converts the query to when it receives it; this is
 | |
|     useful when comparing literal strings.  collation_server is the
 | |
|     default character set and collation used when a new database is
 | |
|     created.
 | |
| 
 | |
|     See also "Connection Character Sets and Collations" in the MySQL
 | |
|     5.1 manual.
 | |
| 
 | |
|     All three variables are codes identifying a (character set,
 | |
|     collation) pair.  To see which codes map to which pairs, run the
 | |
|     query "SELECT id, character_set_name, collation_name FROM
 | |
|     COLLATIONS".
 | |
| 
 | |
|     Cf. Q_CHARSET_DATABASE_CODE below.
 | |
| 
 | |
|     This field is always written.
 | |
|     </td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>time_zone</td>
 | |
|     <td>Q_TIME_ZONE_CODE == 5</td>
 | |
|     <td>Variable-length string: the length in bytes (1 byte) followed
 | |
|     by the characters (at most 255 bytes).
 | |
|     <td>The time_zone of the master.
 | |
| 
 | |
|     See also "System Variables" and "MySQL Server Time Zone Support"
 | |
|     in the MySQL manual.
 | |
| 
 | |
|     This field is written if the length of the time zone string is >
 | |
|     0; otherwise, it is not written.
 | |
|     </td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>lc_time_names_number</td>
 | |
|     <td>Q_LC_TIME_NAMES_CODE == 7</td>
 | |
|     <td>2 byte integer</td>
 | |
|     <td>A code identifying a table of month and day names.  The
 | |
|     mapping from codes to languages is defined in @c sql_locale.cc.
 | |
| 
 | |
|     This field is written if it is not 0, i.e., if the locale is not
 | |
|     en_US.
 | |
|     </td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>charset_database_number</td>
 | |
|     <td>Q_CHARSET_DATABASE_CODE == 8</td>
 | |
|     <td>2 byte integer</td>
 | |
| 
 | |
|     <td>The value of the collation_database system variable (in the
 | |
|     source code stored in @c thd->variables.collation_database), which
 | |
|     holds the code for a (character set, collation) pair as described
 | |
|     above (see Q_CHARSET_CODE).
 | |
| 
 | |
|     collation_database was used in old versions (???WHEN).  Its value
 | |
|     was loaded when issuing a "use db" query and could be changed by
 | |
|     issuing a "SET collation_database=xxx" query.  It used to affect
 | |
|     the "LOAD DATA INFILE" and "CREATE TABLE" commands.
 | |
| 
 | |
|     In newer versions, "CREATE TABLE" has been changed to take the
 | |
|     character set from the database of the created table, rather than
 | |
|     the character set of the current database.  This makes a
 | |
|     difference when creating a table in another database than the
 | |
|     current one.  "LOAD DATA INFILE" has not yet changed to do this,
 | |
|     but there are plans to eventually do it, and to make
 | |
|     collation_database read-only.
 | |
| 
 | |
|     This field is written if it is not 0.
 | |
|     </td>
 | |
|   </tr>
 | |
|   <tr>
 | |
|     <td>table_map_for_update</td>
 | |
|     <td>Q_TABLE_MAP_FOR_UPDATE_CODE == 9</td>
 | |
|     <td>8 byte integer</td>
 | |
| 
 | |
|     <td>The value of the table map that is to be updated by the
 | |
|     multi-table update query statement. Every bit of this variable
 | |
|     represents a table, and is set to 1 if the corresponding table is
 | |
|     to be updated by this statement.
 | |
| 
 | |
|     The value of this variable is set when executing a multi-table update
 | |
|     statement and used by slave to apply filter rules without opening
 | |
|     all the tables on slave. This is required because some tables may
 | |
|     not exist on slave because of the filter rules.
 | |
|     </td>
 | |
|   </tr>
 | |
|   </table>
 | |
| 
 | |
|   @subsection Query_log_event_notes_on_previous_versions Notes on Previous Versions
 | |
| 
 | |
|   * Status vars were introduced in version 5.0.  To read earlier
 | |
|   versions correctly, check the length of the Post-Header.
 | |
| 
 | |
|   * The status variable Q_CATALOG_CODE == 2 existed in MySQL 5.0.x,
 | |
|   where 0<=x<=3.  It was identical to Q_CATALOG_CODE, except that the
 | |
|   string had a trailing '\0'.  The '\0' was removed in 5.0.4 since it
 | |
|   was redundant (the string length is stored before the string).  The
 | |
|   Q_CATALOG_CODE will never be written by a new master, but can still
 | |
|   be understood by a new slave.
 | |
| 
 | |
|   * See Q_CHARSET_DATABASE_CODE in the table above.
 | |
| 
 | |
|   * When adding new status vars, please don't forget to update the
 | |
|   MAX_SIZE_LOG_EVENT_STATUS, and update function code_name
 | |
| 
 | |
| */
 | |
| class Query_log_event: public Log_event
 | |
| {
 | |
|   LEX_CSTRING user;
 | |
|   LEX_CSTRING host;
 | |
| protected:
 | |
|   Log_event::Byte* data_buf;
 | |
| public:
 | |
|   const char* query;
 | |
|   const char* catalog;
 | |
|   const char* db;
 | |
|   /*
 | |
|     If we already know the length of the query string
 | |
|     we pass it with q_len, so we would not have to call strlen()
 | |
|     otherwise, set it to 0, in which case, we compute it with strlen()
 | |
|   */
 | |
|   uint32 q_len;
 | |
|   uint32 db_len;
 | |
|   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).
 | |
|   */
 | |
|   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_BIN_LOG).
 | |
|     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).
 | |
|   */
 | |
|   uint32 flags2_inited;
 | |
|   bool sql_mode_inited;
 | |
|   bool charset_inited;
 | |
| 
 | |
|   uint32 flags2;
 | |
|   sql_mode_t sql_mode;
 | |
|   ulong auto_increment_increment, auto_increment_offset;
 | |
|   char charset[6];
 | |
|   uint time_zone_len; /* 0 means uninited */
 | |
|   const char *time_zone_str;
 | |
|   uint lc_time_names_number; /* 0 means en_US */
 | |
|   uint charset_database_number;
 | |
|   /*
 | |
|     map for tables that will be updated for a multi-table update query
 | |
|     statement, for other query statements, this will be zero.
 | |
|   */
 | |
|   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.
 | |
|   */
 | |
|   uchar gtid_flags_extra;
 | |
|   decltype(rpl_gtid::seq_no) sa_seq_no;  /* data part for CA/RA flags */
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
| 
 | |
|   Query_log_event(THD* thd_arg, const char* query_arg, size_t query_length,
 | |
|                   bool using_trans, bool direct, bool suppress_use, int error);
 | |
|   const char* get_db() override { return db; }
 | |
| #ifdef HAVE_REPLICATION
 | |
|   void pack_info(Protocol* protocol) override;
 | |
| #endif /* HAVE_REPLICATION */
 | |
| #else
 | |
|   bool print_query_header(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info);
 | |
|   bool print_verbose(IO_CACHE* cache, PRINT_EVENT_INFO* print_event_info);
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override;
 | |
| #endif
 | |
| 
 | |
|   Query_log_event();
 | |
|   Query_log_event(const uchar *buf, uint event_len,
 | |
|                   const Format_description_log_event *description_event,
 | |
|                   Log_event_type event_type);
 | |
|   ~Query_log_event()
 | |
|   {
 | |
|     if (data_buf)
 | |
|       my_free(data_buf);
 | |
|   }
 | |
|   Log_event_type get_type_code() override { return QUERY_EVENT; }
 | |
|   static int dummy_event(String *packet, ulong ev_offset,
 | |
|                          enum enum_binlog_checksum_alg checksum_alg);
 | |
|   static int begin_event(String *packet, ulong ev_offset,
 | |
|                          enum enum_binlog_checksum_alg checksum_alg);
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write() override;
 | |
|   virtual bool write_post_header_for_derived() { return FALSE; }
 | |
| #endif
 | |
|   bool is_valid() const override { return query != 0; }
 | |
| 
 | |
|   /*
 | |
|     Returns number of bytes additionally 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. */
 | |
| 
 | |
| public:        /* !!! Public in this patch to allow old usage */
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   enum_skip_reason do_shall_skip(rpl_group_info *rgi) override;
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
| 
 | |
|   int do_apply_event(rpl_group_info *rgi,
 | |
|                        const char *query_arg,
 | |
|                        uint32 q_len_arg);
 | |
|   static bool peek_is_commit_rollback(const uchar *event_start,
 | |
|                                       size_t event_len,
 | |
|                                       enum enum_binlog_checksum_alg
 | |
|                                       checksum_alg);
 | |
|   int handle_split_alter_query_log_event(rpl_group_info *rgi,
 | |
|                                          bool &skip_error_check);
 | |
| 
 | |
| #endif /* HAVE_REPLICATION */
 | |
|   /*
 | |
|     If true, the event always be applied by slave SQL thread or be printed by
 | |
|     mysqlbinlog
 | |
|    */
 | |
|   bool is_trans_keyword(bool is_xa)
 | |
|   {
 | |
|     /*
 | |
|       Before the patch for bug#50407, The 'SAVEPOINT and ROLLBACK TO'
 | |
|       queries input by user was written into log events directly.
 | |
|       So the keywords can be written in both upper case and lower case
 | |
|       together, strncasecmp is used to check both cases. they also could be
 | |
|       binlogged with comments in the front of these keywords. for examples:
 | |
|         / * bla bla * / SAVEPOINT a;
 | |
|         / * bla bla * / ROLLBACK TO a;
 | |
|       but we don't handle these cases and after the patch, both quiries are
 | |
|       binlogged in upper case with no comments.
 | |
|      */
 | |
|     return is_xa ? !strncasecmp(query, C_STRING_WITH_LEN("XA "))
 | |
|                  : (!strncmp(query, "BEGIN", q_len) ||
 | |
|                     !strncmp(query, "COMMIT", q_len) ||
 | |
|                     !strncasecmp(query, "SAVEPOINT", 9) ||
 | |
|                     !strncasecmp(query, "ROLLBACK", 8));
 | |
|   }
 | |
|   virtual bool is_begin()    { return !strcmp(query, "BEGIN"); }
 | |
|   virtual bool is_commit()   { return !strcmp(query, "COMMIT"); }
 | |
|   virtual bool is_rollback() { return !strcmp(query, "ROLLBACK"); }
 | |
| };
 | |
| 
 | |
| class Query_compressed_log_event:public Query_log_event{
 | |
| protected:
 | |
|   Log_event::Byte* query_buf;  // point to the uncompressed query
 | |
| public:
 | |
|   Query_compressed_log_event(const uchar *buf, uint event_len,
 | |
|     const Format_description_log_event *description_event,
 | |
|     Log_event_type event_type);
 | |
|   ~Query_compressed_log_event()
 | |
|   {
 | |
|     if (query_buf)
 | |
|       my_free(query_buf);
 | |
|   }
 | |
|   Log_event_type get_type_code() override { return QUERY_COMPRESSED_EVENT; }
 | |
| 
 | |
|   /*
 | |
|     the min length of log_bin_compress_min_len is 10,
 | |
|     means that Begin/Commit/Rollback would never be compressed!  
 | |
|   */
 | |
|   bool is_begin() override    { return false; }
 | |
|   bool is_commit() override   { return false; }
 | |
|   bool is_rollback() override { return false; }
 | |
| #ifdef MYSQL_SERVER
 | |
|   Query_compressed_log_event(THD* thd_arg, const char* query_arg,
 | |
|                              ulong query_length,
 | |
|                              bool using_trans, bool direct, bool suppress_use,
 | |
|                              int error);
 | |
|   bool write() override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /*****************************************************************************
 | |
|   sql_ex_info struct
 | |
|  ****************************************************************************/
 | |
| struct sql_ex_info
 | |
| {
 | |
|   const char* field_term;
 | |
|   const char* enclosed;
 | |
|   const char* line_term;
 | |
|   const char* line_start;
 | |
|   const char* escaped;
 | |
|   int cached_new_format= -1;
 | |
|   uint8 field_term_len= 0, enclosed_len= 0, line_term_len= 0,
 | |
|     line_start_len= 0, escaped_len= 0;
 | |
|   char opt_flags;
 | |
|   char empty_flags= 0;
 | |
| 
 | |
|   // store in new format even if old is possible
 | |
|   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);
 | |
|   }
 | |
|   bool write_data(Log_event_writer *writer);
 | |
|   const uchar *init(const uchar *buf, const uchar* buf_end, bool use_new_format);
 | |
|   bool new_format()
 | |
|   {
 | |
|     return ((cached_new_format != -1) ? cached_new_format :
 | |
| 	    (cached_new_format=(field_term_len > 1 ||
 | |
| 				enclosed_len > 1 ||
 | |
| 				line_term_len > 1 || line_start_len > 1 ||
 | |
| 				escaped_len > 1)));
 | |
|   }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   @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() override { return db; }
 | |
| #ifdef HAVE_REPLICATION
 | |
|   void pack_info(Protocol* protocol) override;
 | |
| #endif /* HAVE_REPLICATION */
 | |
| #else
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override;
 | |
|   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() = default;
 | |
|   Log_event_type get_type_code() override
 | |
|   {
 | |
|     return sql_ex.new_format() ? NEW_LOAD_EVENT: LOAD_EVENT;
 | |
|   }
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write_data_header() override;
 | |
|   bool write_data_body() override;
 | |
| #endif
 | |
|   bool is_valid() const override { return table_name != 0; }
 | |
|   int get_data_size() override
 | |
|   {
 | |
|     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)
 | |
|   int do_apply_event(rpl_group_info *rgi) override
 | |
|   {
 | |
|     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) override;
 | |
| #endif /* HAVE_REPLICATION */
 | |
| #else
 | |
|   Start_log_event_v3() = default;
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override;
 | |
| #endif
 | |
| 
 | |
|   Start_log_event_v3(const uchar *buf, uint event_len,
 | |
|                      const Format_description_log_event* description_event);
 | |
|   ~Start_log_event_v3() = default;
 | |
|   Log_event_type get_type_code() override { return START_EVENT_V3;}
 | |
|   my_off_t get_header_len(my_off_t l __attribute__((unused))) override
 | |
|   { return LOG_EVENT_MINIMAL_HEADER_LEN; }
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write() override;
 | |
| #endif
 | |
|   bool is_valid() const override { return server_version[0] != 0; }
 | |
|   int get_data_size() override
 | |
|   {
 | |
|     return START_V3_HEADER_LEN; //no variable-sized part
 | |
|   }
 | |
| 
 | |
| protected:
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
|   enum_skip_reason do_shall_skip(rpl_group_info*) override
 | |
|   {
 | |
|     /*
 | |
|       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
 | |
| 
 | |
|   Start_encryption_log_event marks the beginning of encrypted data (all events
 | |
|   after this event are encrypted).
 | |
| 
 | |
|   It contains the cryptographic scheme used for the encryption as well as any
 | |
|   data required to decrypt (except the actual key).
 | |
| 
 | |
|   For binlog cryptoscheme 1: key version, and nonce for iv generation.
 | |
| */
 | |
| class Start_encryption_log_event : public Log_event
 | |
| {
 | |
| public:
 | |
| #ifdef MYSQL_SERVER
 | |
|   Start_encryption_log_event(uint crypto_scheme_arg, uint key_version_arg,
 | |
|                              const uchar* nonce_arg)
 | |
|   : crypto_scheme(crypto_scheme_arg), key_version(key_version_arg)
 | |
|   {
 | |
|     cache_type = EVENT_NO_CACHE;
 | |
|     DBUG_ASSERT(crypto_scheme == 1);
 | |
|     memcpy(nonce, nonce_arg, BINLOG_NONCE_LENGTH);
 | |
|   }
 | |
| 
 | |
|   bool write_data_body() override
 | |
|   {
 | |
|     uchar scheme_buf= crypto_scheme;
 | |
|     uchar key_version_buf[BINLOG_KEY_VERSION_LENGTH];
 | |
|     int4store(key_version_buf, key_version);
 | |
|     return write_data(&scheme_buf, sizeof(scheme_buf)) ||
 | |
|            write_data(key_version_buf, sizeof(key_version_buf)) ||
 | |
|            write_data(nonce, BINLOG_NONCE_LENGTH);
 | |
|   }
 | |
| #else
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override;
 | |
| #endif
 | |
| 
 | |
|   Start_encryption_log_event(const uchar *buf, uint event_len,
 | |
|                              const Format_description_log_event
 | |
|                              *description_event);
 | |
| 
 | |
|   bool is_valid() const override { return crypto_scheme == 1; }
 | |
| 
 | |
|   Log_event_type get_type_code() override { return START_ENCRYPTION_EVENT; }
 | |
| 
 | |
|   int get_data_size() override
 | |
|   {
 | |
|     return BINLOG_CRYPTO_SCHEME_LENGTH + BINLOG_KEY_VERSION_LENGTH +
 | |
|            BINLOG_NONCE_LENGTH;
 | |
|   }
 | |
| 
 | |
|   uint crypto_scheme;
 | |
|   uint key_version;
 | |
|   uchar nonce[BINLOG_NONCE_LENGTH];
 | |
| 
 | |
| protected:
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_apply_event(rpl_group_info* rgi) override;
 | |
|   int do_update_pos(rpl_group_info *rgi) override;
 | |
|   enum_skip_reason do_shall_skip(rpl_group_info* rgi) override
 | |
|   {
 | |
|      return Log_event::EVENT_SKIP_NOT;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
| };
 | |
| 
 | |
| 
 | |
| class Version
 | |
| {
 | |
| protected:
 | |
|   uchar m_ver[3];
 | |
|   int cmp(const Version &other) const
 | |
|   {
 | |
|     return memcmp(m_ver, other.m_ver, 3);
 | |
|   }
 | |
| public:
 | |
|   Version()
 | |
|   {
 | |
|     m_ver[0]= m_ver[1]= m_ver[2]= '\0';
 | |
|   }
 | |
|   Version(uchar v0, uchar v1, uchar v2)
 | |
|   {
 | |
|     m_ver[0]= v0;
 | |
|     m_ver[1]= v1;
 | |
|     m_ver[2]= v2;
 | |
|   }
 | |
|   Version(const char *version, const char **endptr);
 | |
|   const uchar& operator [] (size_t i) const
 | |
|   {
 | |
|     DBUG_ASSERT(i < 3);
 | |
|     return m_ver[i];
 | |
|   }
 | |
|   bool operator<(const Version &other) const { return cmp(other) < 0; }
 | |
|   bool operator>(const Version &other) const { return cmp(other) > 0; }
 | |
|   bool operator<=(const Version &other) const { return cmp(other) <= 0; }
 | |
|   bool operator>=(const Version &other) const { return cmp(other) >= 0; }
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @class Format_description_log_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).
 | |
| 
 | |
|   @section Format_description_log_event_binary_format Binary Format
 | |
| */
 | |
| 
 | |
| 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' lengths followed 
 | |
|      by the checksum alg description byte
 | |
|   */
 | |
|   uint8 *post_header_len;
 | |
|   class master_version_split: public Version {
 | |
|   public:
 | |
|     enum {KIND_MYSQL, KIND_MARIADB};
 | |
|     int kind;
 | |
|     master_version_split() :kind(KIND_MARIADB) { }
 | |
|     master_version_split(const char *version);
 | |
|     bool version_is_valid() const
 | |
|     {
 | |
|       /* It is invalid only when all version numbers are 0 */
 | |
|       return !(m_ver[0] == 0 && m_ver[1] == 0 && m_ver[2] == 0);
 | |
|     }
 | |
|   };
 | |
|   master_version_split server_version_split;
 | |
|   const uint8 *event_type_permutation;
 | |
|   uint32 options_written_to_bin_log;
 | |
| 
 | |
|   Format_description_log_event(uint8 binlog_ver, const char* server_ver=0);
 | |
|   Format_description_log_event(const uchar *buf, uint event_len,
 | |
|                                const Format_description_log_event
 | |
|                                *description_event);
 | |
|   ~Format_description_log_event()
 | |
|   {
 | |
|     my_free(post_header_len);
 | |
|   }
 | |
|   Log_event_type get_type_code() override { return FORMAT_DESCRIPTION_EVENT;}
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write() override;
 | |
| #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));
 | |
|   }
 | |
| 
 | |
|   bool is_valid() const override
 | |
|   {
 | |
|     return header_is_valid() && server_version_split.version_is_valid();
 | |
|   }
 | |
| 
 | |
|   int get_data_size() override
 | |
|   {
 | |
|     /*
 | |
|       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;
 | |
|   }
 | |
| 
 | |
|   Binlog_crypt_data crypto_data;
 | |
|   bool start_decryption(Start_encryption_log_event* sele);
 | |
|   void copy_crypto_data(const Format_description_log_event* o)
 | |
|   {
 | |
|     crypto_data= o->crypto_data;
 | |
|   }
 | |
|   void reset_crypto()
 | |
|   {
 | |
|     crypto_data.scheme= 0;
 | |
|   }
 | |
| 
 | |
|   void calc_server_version_split();
 | |
|   void deduct_options_written_to_bin_log();
 | |
|   static bool is_version_before_checksum(const master_version_split *version_split);
 | |
| protected:
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
|   int do_update_pos(rpl_group_info *rgi) override;
 | |
|   enum_skip_reason do_shall_skip(rpl_group_info *rgi) override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @class Intvar_log_event
 | |
| 
 | |
|   An Intvar_log_event will be created just before a Query_log_event,
 | |
|   if the query uses one of the variables LAST_INSERT_ID or INSERT_ID.
 | |
|   Each Intvar_log_event holds the value of one of these variables.
 | |
| 
 | |
|   @section Intvar_log_event_binary_format Binary Format
 | |
| 
 | |
|   The Post-Header for this event type is empty.  The Body has two
 | |
|   components:
 | |
| 
 | |
|   <table>
 | |
|   <caption>Body for Intvar_log_event</caption>
 | |
| 
 | |
|   <tr>
 | |
|     <th>Name</th>
 | |
|     <th>Format</th>
 | |
|     <th>Description</th>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>type</td>
 | |
|     <td>1 byte enumeration</td>
 | |
|     <td>One byte identifying the type of variable stored.  Currently,
 | |
|     two identifiers are supported:  LAST_INSERT_ID_EVENT==1 and
 | |
|     INSERT_ID_EVENT==2.
 | |
|     </td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>value</td>
 | |
|     <td>8 byte unsigned integer</td>
 | |
|     <td>The value of the variable.</td>
 | |
|   </tr>
 | |
| 
 | |
|   </table>
 | |
| */
 | |
| class Intvar_log_event: public Log_event
 | |
| {
 | |
| public:
 | |
|   ulonglong val;
 | |
|   uchar type;
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
| Intvar_log_event(THD* thd_arg,uchar type_arg, ulonglong val_arg,
 | |
|                  bool using_trans, bool direct)
 | |
|     :Log_event(thd_arg,0,using_trans),val(val_arg),type(type_arg)
 | |
|   {
 | |
|     if (direct)
 | |
|       cache_type= Log_event::EVENT_NO_CACHE;
 | |
|   }
 | |
| #ifdef HAVE_REPLICATION
 | |
|   void pack_info(Protocol* protocol) override;
 | |
| #endif /* HAVE_REPLICATION */
 | |
| #else
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override;
 | |
| #endif
 | |
| 
 | |
|   Intvar_log_event(const uchar *buf,
 | |
|                    const Format_description_log_event *description_event);
 | |
|   ~Intvar_log_event() = default;
 | |
|   Log_event_type get_type_code() override { return INTVAR_EVENT;}
 | |
|   const char* get_var_type_name();
 | |
|   int get_data_size() override { return  9; /* sizeof(type) + sizeof(val) */;}
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write() override;
 | |
| #ifdef HAVE_REPLICATION
 | |
|    bool is_part_of_group() override { return 1; }
 | |
| #endif
 | |
| #endif
 | |
|   bool is_valid() const override { return 1; }
 | |
| 
 | |
| private:
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
|   int do_update_pos(rpl_group_info *rgi) override;
 | |
|   enum_skip_reason do_shall_skip(rpl_group_info *rgi) override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @class Rand_log_event
 | |
| 
 | |
|   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).
 | |
| 
 | |
|   The state of the random number generation consists of 128 bits,
 | |
|   which are stored internally as two 64-bit numbers.
 | |
| 
 | |
|   @section Rand_log_event_binary_format Binary Format  
 | |
| 
 | |
|   The Post-Header for this event type is empty.  The Body has two
 | |
|   components:
 | |
| 
 | |
|   <table>
 | |
|   <caption>Body for Rand_log_event</caption>
 | |
| 
 | |
|   <tr>
 | |
|     <th>Name</th>
 | |
|     <th>Format</th>
 | |
|     <th>Description</th>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>seed1</td>
 | |
|     <td>8 byte unsigned integer</td>
 | |
|     <td>64 bit random seed1.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>seed2</td>
 | |
|     <td>8 byte unsigned integer</td>
 | |
|     <td>64 bit random seed2.</td>
 | |
|   </tr>
 | |
|   </table>
 | |
| */
 | |
| 
 | |
| class Rand_log_event: public Log_event
 | |
| {
 | |
|  public:
 | |
|   ulonglong seed1;
 | |
|   ulonglong seed2;
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   Rand_log_event(THD* thd_arg, ulonglong seed1_arg, ulonglong seed2_arg,
 | |
|                  bool using_trans, bool direct)
 | |
|     :Log_event(thd_arg,0,using_trans),seed1(seed1_arg),seed2(seed2_arg)
 | |
|   {
 | |
|     if (direct)
 | |
|       cache_type= Log_event::EVENT_NO_CACHE;
 | |
|   }
 | |
| #ifdef HAVE_REPLICATION
 | |
|    void pack_info(Protocol* protocol) override;
 | |
| #endif /* HAVE_REPLICATION */
 | |
| #else
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override;
 | |
| #endif
 | |
| 
 | |
|   Rand_log_event(const uchar *buf,
 | |
|                  const Format_description_log_event *description_event);
 | |
|   ~Rand_log_event() = default;
 | |
|   Log_event_type get_type_code() override { return RAND_EVENT;}
 | |
|   int get_data_size() override { return 16; /* sizeof(ulonglong) * 2*/ }
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write() override;
 | |
| #ifdef HAVE_REPLICATION
 | |
|    bool is_part_of_group() override { return 1; }
 | |
| #endif
 | |
| #endif
 | |
|   bool is_valid() const override { return 1; }
 | |
| 
 | |
| private:
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
|   int do_update_pos(rpl_group_info *rgi) override;
 | |
|   enum_skip_reason do_shall_skip(rpl_group_info *rgi) override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| class Xid_apply_log_event: public Log_event
 | |
| {
 | |
| public:
 | |
| #ifdef MYSQL_SERVER
 | |
|   Xid_apply_log_event(THD* thd_arg):
 | |
|    Log_event(thd_arg, 0, TRUE) {}
 | |
| #endif
 | |
|   Xid_apply_log_event(const uchar *buf,
 | |
|                 const Format_description_log_event *description_event):
 | |
|    Log_event(buf, description_event) {}
 | |
| 
 | |
|   ~Xid_apply_log_event() {}
 | |
|   bool is_valid() const override { return 1; }
 | |
| private:
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   virtual int do_commit()= 0;
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
|   int do_record_gtid(THD *thd, rpl_group_info *rgi, bool in_trans,
 | |
|                      void **out_hton, bool force_err= false);
 | |
|   enum_skip_reason do_shall_skip(rpl_group_info *rgi) override;
 | |
|   virtual const char* get_query()= 0;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @class Xid_log_event
 | |
| 
 | |
|   Logs xid of the transaction-to-be-committed in the 2pc protocol.
 | |
|   Has no meaning in replication, slaves ignore it.
 | |
| 
 | |
|   @section Xid_log_event_binary_format Binary Format  
 | |
| */
 | |
| #ifdef MYSQL_CLIENT
 | |
| typedef ulonglong my_xid; // this line is the same as in handler.h
 | |
| #endif
 | |
| 
 | |
| class Xid_log_event: public Xid_apply_log_event
 | |
| {
 | |
| public:
 | |
|   my_xid xid;
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   Xid_log_event(THD* thd_arg, my_xid x, bool direct):
 | |
|    Xid_apply_log_event(thd_arg), xid(x)
 | |
|    {
 | |
|      if (direct)
 | |
|        cache_type= Log_event::EVENT_NO_CACHE;
 | |
|    }
 | |
| #ifdef HAVE_REPLICATION
 | |
|   const char* get_query() override
 | |
|   {
 | |
|     return "COMMIT /* implicit, from Xid_log_event */";
 | |
|   }
 | |
|   void pack_info(Protocol* protocol) override;
 | |
| #endif /* HAVE_REPLICATION */
 | |
| #else
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override;
 | |
| #endif
 | |
| 
 | |
|   Xid_log_event(const uchar *buf,
 | |
|                 const Format_description_log_event *description_event);
 | |
|   ~Xid_log_event() = default;
 | |
|   Log_event_type get_type_code() override { return XID_EVENT;}
 | |
|   int get_data_size() override { return sizeof(xid); }
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write() override;
 | |
| #endif
 | |
| 
 | |
| private:
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_commit() override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @class XA_prepare_log_event
 | |
| 
 | |
|   Similar to Xid_log_event except that
 | |
|   - it is specific to XA transaction
 | |
|   - it carries out the prepare logics rather than the final committing
 | |
|     when @c one_phase member is off. The latter option is only for
 | |
|     compatibility with the upstream.
 | |
| 
 | |
|   From the groupping perspective the event finalizes the current
 | |
|   "prepare" group that is started with Gtid_log_event similarly to the
 | |
|   regular replicated transaction.
 | |
| */
 | |
| 
 | |
| /**
 | |
|   Function serializes XID which is characterized by by four last arguments
 | |
|   of the function.
 | |
|   Serialized XID is presented in valid hex format and is returned to
 | |
|   the caller in a buffer pointed by the first argument.
 | |
|   The buffer size provived by the caller must be not less than
 | |
|   8 + 2 * XIDDATASIZE +  4 * sizeof(XID::formatID) + 1, see
 | |
|   {MYSQL_,}XID definitions.
 | |
| 
 | |
|   @param buf  pointer to a buffer allocated for storing serialized data
 | |
|   @param fmt  formatID value
 | |
|   @param gln  gtrid_length value
 | |
|   @param bln  bqual_length value
 | |
|   @param dat  data value
 | |
| 
 | |
|   @return  the value of the buffer pointer
 | |
| */
 | |
| 
 | |
| inline char *serialize_xid(char *buf, long fmt, long gln, long bln,
 | |
|                            const char *dat)
 | |
| {
 | |
|   int i;
 | |
|   char *c= buf;
 | |
|   /*
 | |
|     Build a string consisting of the hex format representation of XID
 | |
|     as passed through fmt,gln,bln,dat argument:
 | |
|       X'hex11hex12...hex1m',X'hex21hex22...hex2n',11
 | |
|     and store it into buf.
 | |
|   */
 | |
|   c[0]= 'X';
 | |
|   c[1]= '\'';
 | |
|   c+= 2;
 | |
|   for (i= 0; i < gln; i++)
 | |
|   {
 | |
|     c[0]=_dig_vec_lower[((uchar*) dat)[i] >> 4];
 | |
|     c[1]=_dig_vec_lower[((uchar*) dat)[i] & 0x0f];
 | |
|     c+= 2;
 | |
|   }
 | |
|   c[0]= '\'';
 | |
|   c[1]= ',';
 | |
|   c[2]= 'X';
 | |
|   c[3]= '\'';
 | |
|   c+= 4;
 | |
| 
 | |
|   for (; i < gln + bln; i++)
 | |
|   {
 | |
|     c[0]=_dig_vec_lower[((uchar*) dat)[i] >> 4];
 | |
|     c[1]=_dig_vec_lower[((uchar*) dat)[i] & 0x0f];
 | |
|     c+= 2;
 | |
|   }
 | |
|   c[0]= '\'';
 | |
|   sprintf(c+1, ",%lu", fmt);
 | |
| 
 | |
|  return buf;
 | |
| }
 | |
| 
 | |
| /*
 | |
|   The size of the string containing serialized Xid representation
 | |
|   is computed as a sum of
 | |
|   eight as the number of formatting symbols (X'',X'',)
 | |
|   plus 2 x XIDDATASIZE (2 due to hex format),
 | |
|   plus space for decimal digits of XID::formatID,
 | |
|   plus one for 0x0.
 | |
| */
 | |
| static const uint ser_buf_size=
 | |
|   8 + 2 * MYSQL_XIDDATASIZE + 4 * sizeof(long) + 1;
 | |
| 
 | |
| struct event_mysql_xid_t :  MYSQL_XID
 | |
| {
 | |
|   char buf[ser_buf_size];
 | |
|   char *serialize()
 | |
|   {
 | |
|     return serialize_xid(buf, formatID, gtrid_length, bqual_length, data);
 | |
|   }
 | |
| };
 | |
| 
 | |
| #ifndef MYSQL_CLIENT
 | |
| struct event_xid_t : XID
 | |
| {
 | |
|   char buf[ser_buf_size];
 | |
| 
 | |
|   char *serialize(char *buf_arg)
 | |
|   {
 | |
|     return serialize_xid(buf_arg, formatID, gtrid_length, bqual_length, data);
 | |
|   }
 | |
|   char *serialize()
 | |
|   {
 | |
|     return serialize(buf);
 | |
|   }
 | |
| };
 | |
| #endif
 | |
| 
 | |
| class XA_prepare_log_event: public Xid_apply_log_event
 | |
| {
 | |
| protected:
 | |
| 
 | |
|   /* Constant contributor to subheader in write() by members of XID struct. */
 | |
|   static const int xid_subheader_no_data= 12;
 | |
|   event_mysql_xid_t m_xid;
 | |
|   void *xid;
 | |
|   bool one_phase;
 | |
| 
 | |
| public:
 | |
| #ifdef MYSQL_SERVER
 | |
|   XA_prepare_log_event(THD* thd_arg, XID *xid_arg, bool one_phase_arg):
 | |
|     Xid_apply_log_event(thd_arg), xid(xid_arg), one_phase(one_phase_arg)
 | |
|   {
 | |
|     cache_type= Log_event::EVENT_NO_CACHE;
 | |
|   }
 | |
| #ifdef HAVE_REPLICATION
 | |
|   void pack_info(Protocol* protocol) override;
 | |
| #endif /* HAVE_REPLICATION */
 | |
| #else
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override;
 | |
| #endif
 | |
|   XA_prepare_log_event(const uchar *buf,
 | |
|                        const Format_description_log_event *description_event);
 | |
|   ~XA_prepare_log_event() {}
 | |
|   Log_event_type get_type_code() override { return XA_PREPARE_LOG_EVENT; }
 | |
|   bool is_valid() const override { return m_xid.formatID != -1; }
 | |
|   int get_data_size() override
 | |
|   {
 | |
|     return xid_subheader_no_data + m_xid.gtrid_length + m_xid.bqual_length;
 | |
|   }
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write() override;
 | |
| #endif
 | |
| 
 | |
| private:
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   char query[sizeof("XA COMMIT ONE PHASE") + 1 + ser_buf_size];
 | |
|   int do_commit() override;
 | |
|   const char* get_query() override
 | |
|   {
 | |
|     sprintf(query,
 | |
|             (one_phase ? "XA COMMIT %s ONE PHASE" : "XA PREPARE %s"),
 | |
|             m_xid.serialize());
 | |
|     return query;
 | |
|   }
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @class User_var_log_event
 | |
| 
 | |
|   Every time a query uses the value of a user variable, a User_var_log_event is
 | |
|   written before the Query_log_event, to set the user variable.
 | |
| 
 | |
|   @section User_var_log_event_binary_format Binary Format  
 | |
| */
 | |
| 
 | |
| 
 | |
| class User_var_log_event: public Log_event, public Log_event_data_type
 | |
| {
 | |
| public:
 | |
|   const char *name;
 | |
|   size_t name_len;
 | |
|   const char *val;
 | |
|   size_t val_len;
 | |
|   bool is_null;
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool deferred;
 | |
|   query_id_t query_id;
 | |
|   User_var_log_event(THD* thd_arg, const char *name_arg, size_t name_len_arg,
 | |
|                      const char *val_arg, size_t val_len_arg,
 | |
|                      const Log_event_data_type &data_type,
 | |
|                      bool using_trans, bool direct)
 | |
|     :Log_event(thd_arg, 0, using_trans),
 | |
|     Log_event_data_type(data_type),
 | |
|     name(name_arg), name_len(name_len_arg), val(val_arg),
 | |
|     val_len(val_len_arg),
 | |
|     deferred(false)
 | |
|     {
 | |
|       is_null= !val;
 | |
|       if (direct)
 | |
|         cache_type= Log_event::EVENT_NO_CACHE;
 | |
|     }
 | |
| #ifdef HAVE_REPLICATION
 | |
|   void pack_info(Protocol* protocol) override;
 | |
| #endif
 | |
| #else
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override;
 | |
| #endif
 | |
| 
 | |
|   User_var_log_event(const uchar *buf, uint event_len,
 | |
|                      const Format_description_log_event *description_event);
 | |
|   ~User_var_log_event() = default;
 | |
|   Log_event_type get_type_code() override { return USER_VAR_EVENT;}
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write() override;
 | |
|   /* 
 | |
|      Getter and setter for deferred User-event. 
 | |
|      Returns true if the event is not applied directly 
 | |
|      and which case the applier adjusts execution path.
 | |
|   */
 | |
|   bool is_deferred() { return deferred; }
 | |
|   /*
 | |
|     In case of the deferred applying the variable instance is flagged
 | |
|     and the parsing time query id is stored to be used at applying time.
 | |
|   */
 | |
|   void set_deferred(query_id_t qid) { deferred= true; query_id= qid; }
 | |
| #ifdef HAVE_REPLICATION
 | |
|    bool is_part_of_group() override { return 1; }
 | |
| #endif
 | |
| #endif
 | |
|   bool is_valid() const override { return name != 0; }
 | |
| 
 | |
| private:
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
|   int do_update_pos(rpl_group_info *rgi) override;
 | |
|   enum_skip_reason do_shall_skip(rpl_group_info *rgi) override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @class Stop_log_event
 | |
| 
 | |
|   @section Stop_log_event_binary_format Binary Format
 | |
| 
 | |
|   The Post-Header and Body for this event type are empty; it only has
 | |
|   the Common-Header.
 | |
| */
 | |
| class Stop_log_event: public Log_event
 | |
| {
 | |
| public:
 | |
| #ifdef MYSQL_SERVER
 | |
|   Stop_log_event() :Log_event()
 | |
|   {}
 | |
| #else
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override;
 | |
| #endif
 | |
| 
 | |
|   Stop_log_event(const uchar *buf,
 | |
|                  const Format_description_log_event *description_event):
 | |
|     Log_event(buf, description_event)
 | |
|   {}
 | |
|   ~Stop_log_event() = default;
 | |
|   Log_event_type get_type_code() override { return STOP_EVENT;}
 | |
|   bool is_valid() const override { return 1; }
 | |
| 
 | |
| private:
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_update_pos(rpl_group_info *rgi) override;
 | |
|   enum_skip_reason do_shall_skip(rpl_group_info *rgi) override
 | |
|   {
 | |
|     /*
 | |
|       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 Rotate_log_event
 | |
| 
 | |
|   This will be deprecated when we move to using sequence ids.
 | |
| 
 | |
|   @section Rotate_log_event_binary_format Binary Format
 | |
| 
 | |
|   The Post-Header has one component:
 | |
| 
 | |
|   <table>
 | |
|   <caption>Post-Header for Rotate_log_event</caption>
 | |
| 
 | |
|   <tr>
 | |
|     <th>Name</th>
 | |
|     <th>Format</th>
 | |
|     <th>Description</th>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>position</td>
 | |
|     <td>8 byte integer</td>
 | |
|     <td>The position within the binlog to rotate to.</td>
 | |
|   </tr>
 | |
| 
 | |
|   </table>
 | |
| 
 | |
|   The Body has one component:
 | |
| 
 | |
|   <table>
 | |
|   <caption>Body for Rotate_log_event</caption>
 | |
| 
 | |
|   <tr>
 | |
|     <th>Name</th>
 | |
|     <th>Format</th>
 | |
|     <th>Description</th>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>new_log</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>Name of the binlog to rotate to.</td>
 | |
|   </tr>
 | |
| 
 | |
|   </table>
 | |
| */
 | |
| 
 | |
| class Rotate_log_event: public Log_event
 | |
| {
 | |
| public:
 | |
|   enum {
 | |
|     DUP_NAME= 2, // if constructor should dup the string argument
 | |
|     RELAY_LOG=4  // rotate event for relay log
 | |
|   };
 | |
|   const char *new_log_ident;
 | |
|   ulonglong pos;
 | |
|   uint ident_len;
 | |
|   uint flags;
 | |
| #ifdef MYSQL_SERVER
 | |
|   Rotate_log_event(const char* new_log_ident_arg,
 | |
| 		   uint ident_len_arg,
 | |
| 		   ulonglong pos_arg, uint flags);
 | |
| #ifdef HAVE_REPLICATION
 | |
|   void pack_info(Protocol* protocol) override;
 | |
| #endif /* HAVE_REPLICATION */
 | |
| #else
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override;
 | |
| #endif
 | |
| 
 | |
|   Rotate_log_event(const uchar *buf, uint event_len,
 | |
|                    const Format_description_log_event* description_event);
 | |
|   ~Rotate_log_event()
 | |
|   {
 | |
|     if (flags & DUP_NAME)
 | |
|       my_free((void*) new_log_ident);
 | |
|   }
 | |
|   Log_event_type get_type_code() override { return ROTATE_EVENT;}
 | |
|   my_off_t get_header_len(my_off_t l __attribute__((unused))) override
 | |
|   { return LOG_EVENT_MINIMAL_HEADER_LEN; }
 | |
|   int get_data_size() override { return  ident_len + ROTATE_HEADER_LEN;}
 | |
|   bool is_valid() const override { return new_log_ident != 0; }
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write() override;
 | |
| #endif
 | |
| 
 | |
| private:
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_update_pos(rpl_group_info *rgi) override;
 | |
|   enum_skip_reason do_shall_skip(rpl_group_info *rgi) override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| class Binlog_checkpoint_log_event: public Log_event
 | |
| {
 | |
| public:
 | |
|   char *binlog_file_name;
 | |
|   uint binlog_file_len;
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   Binlog_checkpoint_log_event(const char *binlog_file_name_arg,
 | |
|                               uint binlog_file_len_arg);
 | |
| #ifdef HAVE_REPLICATION
 | |
|   void pack_info(Protocol *protocol) override;
 | |
| #endif
 | |
| #else
 | |
|   bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override;
 | |
| #endif
 | |
|   Binlog_checkpoint_log_event(const uchar *buf, uint event_len,
 | |
|                               const Format_description_log_event
 | |
|                               *description_event);
 | |
|   ~Binlog_checkpoint_log_event() { my_free(binlog_file_name); }
 | |
|   Log_event_type get_type_code() override { return BINLOG_CHECKPOINT_EVENT;}
 | |
|   int get_data_size() override
 | |
|   { return binlog_file_len + BINLOG_CHECKPOINT_HEADER_LEN;}
 | |
|   bool is_valid() const override { return binlog_file_name != 0; }
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write() override;
 | |
| #ifdef HAVE_REPLICATION
 | |
|   enum_skip_reason do_shall_skip(rpl_group_info *rgi) override;
 | |
| #endif
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @class Gtid_log_event
 | |
| 
 | |
|   This event is logged as part of every event group to give the global
 | |
|   transaction id (GTID) of that group.
 | |
| 
 | |
|   It replaces the BEGIN query event used in earlier versions to begin most
 | |
|   event groups, but is also used for events that used to be stand-alone.
 | |
| 
 | |
|   @section Gtid_log_event_binary_format Binary Format
 | |
| 
 | |
|   The binary format for Gtid_log_event has 6 extra reserved bytes to make the
 | |
|   length a total of 19 byte (+ 19 bytes of header in common with all events).
 | |
|   This is just the minimal size for a BEGIN query event, which makes it easy
 | |
|   to replace this event with such BEGIN event to remain compatible with old
 | |
|   slave servers.
 | |
| 
 | |
|   <table>
 | |
|   <caption>Post-Header</caption>
 | |
| 
 | |
|   <tr>
 | |
|     <th>Name</th>
 | |
|     <th>Format</th>
 | |
|     <th>Description</th>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>seq_no</td>
 | |
|     <td>8 byte unsigned integer</td>
 | |
|     <td>increasing id within one server_id. Starts at 1, holes in the sequence
 | |
|         may occur</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>domain_id</td>
 | |
|     <td>4 byte unsigned integer</td>
 | |
|     <td>Replication domain id, identifying independent replication streams></td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>flags</td>
 | |
|     <td>1 byte bitfield</td>
 | |
|     <td>Bit 0 set indicates stand-alone event (no terminating COMMIT)</td>
 | |
|     <td>Bit 1 set indicates group commit, and that commit id exists</td>
 | |
|     <td>Bit 2 set indicates a transactional event group (can be safely rolled
 | |
|         back).</td>
 | |
|     <td>Bit 3 set indicates that user allowed optimistic parallel apply (the
 | |
|         @@SESSION.replicate_allow_parallel value was true at commit).</td>
 | |
|     <td>Bit 4 set indicates that this transaction encountered a row (or other)
 | |
|         lock wait during execution.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>Reserved (no group commit) / commit id (group commit) (see flags bit 1)</td>
 | |
|     <td>6 bytes / 8 bytes</td>
 | |
|     <td>Reserved bytes, set to 0. Maybe be used for future expansion (no
 | |
|         group commit). OR commit id, same for all GTIDs in the same group
 | |
|         commit (see flags bit 1).</td>
 | |
|   </tr>
 | |
|   </table>
 | |
| 
 | |
|   The Body of Gtid_log_event is empty. The total event size is 19 bytes +
 | |
|   the normal 19 bytes common-header.
 | |
| */
 | |
| 
 | |
| class Gtid_log_event: public Log_event
 | |
| {
 | |
| public:
 | |
|   uint64 seq_no;
 | |
|   uint64 commit_id;
 | |
|   uint32 domain_id;
 | |
|   uint64 sa_seq_no;   // start alter identifier for CA/RA
 | |
| #ifdef MYSQL_SERVER
 | |
|   event_xid_t xid;
 | |
| #else
 | |
|   event_mysql_xid_t xid;
 | |
| #endif
 | |
|   uchar flags2;
 | |
|   /*
 | |
|     More flags area placed after the regular flags2's area. The type
 | |
|     is declared to be in agreement with Query_log_event's member that
 | |
|     may copy the flags_extra value.
 | |
|   */
 | |
|   decltype(Query_log_event::gtid_flags_extra) flags_extra;
 | |
|   /*
 | |
|     Number of engine participants in transaction minus 1.
 | |
|     When zero the event does not contain that information.
 | |
|   */
 | |
|   uint8 extra_engines;
 | |
| 
 | |
|   /* Flags2. */
 | |
| 
 | |
|   /* FL_STANDALONE is set when there is no terminating COMMIT event. */
 | |
|   static const uchar FL_STANDALONE= 1;
 | |
|   /*
 | |
|     FL_GROUP_COMMIT_ID is set when event group is part of a group commit on the
 | |
|     master. Groups with same commit_id are part of the same group commit.
 | |
|   */
 | |
|   static const uchar FL_GROUP_COMMIT_ID= 2;
 | |
|   /*
 | |
|     FL_TRANSACTIONAL is set for an event group that can be safely rolled back
 | |
|     (no MyISAM, eg.).
 | |
|   */
 | |
|   static const uchar FL_TRANSACTIONAL= 4;
 | |
|   /*
 | |
|     FL_ALLOW_PARALLEL reflects the (negation of the) value of
 | |
|     @@SESSION.skip_parallel_replication at the time of commit.
 | |
|   */
 | |
|   static const uchar FL_ALLOW_PARALLEL= 8;
 | |
|   /*
 | |
|     FL_WAITED is set if a row lock wait (or other wait) is detected during the
 | |
|     execution of the transaction.
 | |
|   */
 | |
|   static const uchar FL_WAITED= 16;
 | |
|   /* FL_DDL is set for event group containing DDL. */
 | |
|   static const uchar FL_DDL= 32;
 | |
|   /* FL_PREPARED_XA is set for XA transaction. */
 | |
|   static const uchar FL_PREPARED_XA= 64;
 | |
|   /* FL_"COMMITTED or ROLLED-BACK"_XA is set for XA transaction. */
 | |
|   static const uchar FL_COMPLETED_XA= 128;
 | |
| 
 | |
|   /*
 | |
|     flags_extra 's bit values.
 | |
|     _E1 suffix below stands for Extra to infer the extra flags,
 | |
|     their "1st" generation (more *generations* can come when necessary).
 | |
| 
 | |
|     FL_EXTRA_MULTI_ENGINE_E1 is set for event group comprising a transaction
 | |
|     involving multiple storage engines. No flag and extra data are added
 | |
|     to the event when the transaction involves only one engine.
 | |
|   */
 | |
|   static const uchar FL_EXTRA_MULTI_ENGINE_E1= 1;
 | |
|   static const uchar FL_START_ALTER_E1= 2;
 | |
|   static const uchar FL_COMMIT_ALTER_E1= 4;
 | |
|   static const uchar FL_ROLLBACK_ALTER_E1= 8;
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   Gtid_log_event(THD *thd_arg, uint64 seq_no, uint32 domain_id, bool standalone,
 | |
|                  uint16 flags, bool is_transactional, uint64 commit_id,
 | |
|                  bool has_xid= false, bool is_ro_1pc= false);
 | |
| #ifdef HAVE_REPLICATION
 | |
|   void pack_info(Protocol *protocol) override;
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
|   int do_update_pos(rpl_group_info *rgi) override;
 | |
|   enum_skip_reason do_shall_skip(rpl_group_info *rgi) override;
 | |
| #endif
 | |
| #else
 | |
|   bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override;
 | |
| #endif
 | |
|   Gtid_log_event(const uchar *buf, uint event_len,
 | |
|                  const Format_description_log_event *description_event);
 | |
|   ~Gtid_log_event() = default;
 | |
|   Log_event_type get_type_code() override { return GTID_EVENT; }
 | |
|   enum_logged_status logged_status() override { return LOGGED_NO_DATA; }
 | |
|   int get_data_size() override
 | |
|   {
 | |
|     return GTID_HEADER_LEN + ((flags2 & FL_GROUP_COMMIT_ID) ? 2 : 0);
 | |
|   }
 | |
| 
 | |
|   bool is_valid() const override
 | |
|   {
 | |
|     /*
 | |
|       seq_no is set to 0 if the structure of a serialized GTID event does not
 | |
|       align with that as indicated by flags and extra_flags.
 | |
|     */
 | |
|     return seq_no != 0;
 | |
|   }
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write() override;
 | |
|   static int make_compatible_event(String *packet, bool *need_dummy_event,
 | |
|                                     ulong ev_offset, enum enum_binlog_checksum_alg checksum_alg);
 | |
|   static bool peek(const uchar *event_start, size_t event_len,
 | |
|                    enum enum_binlog_checksum_alg checksum_alg,
 | |
|                    uint32 *domain_id, uint32 *server_id, uint64 *seq_no,
 | |
|                    uchar *flags2, const Format_description_log_event *fdev);
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @class Gtid_list_log_event
 | |
| 
 | |
|   This event is logged at the start of every binlog file to record the
 | |
|   current replication state: the last global transaction id (GTID) applied
 | |
|   on the server within each replication domain.
 | |
| 
 | |
|   It consists of a list of GTIDs, one for each replication domain ever seen
 | |
|   on the server.
 | |
| 
 | |
|   @section Gtid_list_log_event_binary_format Binary Format
 | |
| 
 | |
|   <table>
 | |
|   <caption>Post-Header</caption>
 | |
| 
 | |
|   <tr>
 | |
|     <th>Name</th>
 | |
|     <th>Format</th>
 | |
|     <th>Description</th>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>count</td>
 | |
|     <td>4 byte unsigned integer</td>
 | |
|     <td>The lower 28 bits are the number of GTIDs. The upper 4 bits are
 | |
|         flags bits.</td>
 | |
|   </tr>
 | |
|   </table>
 | |
| 
 | |
|   <table>
 | |
|   <caption>Body</caption>
 | |
| 
 | |
|   <tr>
 | |
|     <th>Name</th>
 | |
|     <th>Format</th>
 | |
|     <th>Description</th>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>domain_id</td>
 | |
|     <td>4 byte unsigned integer</td>
 | |
|     <td>Replication domain id of one GTID</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>server_id</td>
 | |
|     <td>4 byte unsigned integer</td>
 | |
|     <td>Server id of one GTID</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>seq_no</td>
 | |
|     <td>8 byte unsigned integer</td>
 | |
|     <td>sequence number of one GTID</td>
 | |
|   </tr>
 | |
|   </table>
 | |
| 
 | |
|   The three elements in the body repeat COUNT times to form the GTID list.
 | |
| 
 | |
|   At the time of writing, only two flag bit are in use.
 | |
| 
 | |
|   Bit 28 of `count' is used for flag FLAG_UNTIL_REACHED, which is sent in a
 | |
|   Gtid_list event from the master to the slave to indicate that the START
 | |
|   SLAVE UNTIL master_gtid_pos=xxx condition has been reached. (This flag is
 | |
|   only sent in "fake" events generated on the fly, it is not written into
 | |
|   the binlog).
 | |
| */
 | |
| 
 | |
| class Gtid_list_log_event: public Log_event
 | |
| {
 | |
| public:
 | |
|   uint32 count;
 | |
|   uint32 gl_flags;
 | |
|   struct rpl_gtid *list;
 | |
|   uint64 *sub_id_list;
 | |
| 
 | |
|   static const uint element_size= 4+4+8;
 | |
|   /* Upper bits stored in 'count'. See comment above */
 | |
|   enum gtid_flags
 | |
|   {
 | |
|     FLAG_UNTIL_REACHED= (1<<28),
 | |
|     FLAG_IGN_GTIDS= (1<<29),
 | |
|   };
 | |
| #ifdef MYSQL_SERVER
 | |
|   Gtid_list_log_event(rpl_binlog_state *gtid_set, uint32 gl_flags);
 | |
|   Gtid_list_log_event(slave_connection_state *gtid_set, uint32 gl_flags);
 | |
| #ifdef HAVE_REPLICATION
 | |
|   void pack_info(Protocol *protocol) override;
 | |
| #endif
 | |
| #else
 | |
|   bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override;
 | |
| #endif
 | |
|   Gtid_list_log_event(const uchar *buf, uint event_len,
 | |
|                       const Format_description_log_event *description_event);
 | |
|   ~Gtid_list_log_event() { my_free(list); my_free(sub_id_list); }
 | |
|   Log_event_type get_type_code() override { return GTID_LIST_EVENT; }
 | |
|   int get_data_size() override {
 | |
|     /*
 | |
|       Replacing with dummy event, needed for older slaves, requires a minimum
 | |
|       of 6 bytes in the body.
 | |
|     */
 | |
|     return (count==0 ?
 | |
|             GTID_LIST_HEADER_LEN+2 : GTID_LIST_HEADER_LEN+count*element_size);
 | |
|   }
 | |
|   bool is_valid() const override { return list != NULL; }
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   bool to_packet(String *packet);
 | |
|   bool write() override;
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
|   enum_skip_reason do_shall_skip(rpl_group_info *rgi) override;
 | |
| #endif
 | |
|   static bool peek(const char *event_start, size_t event_len,
 | |
|                    enum enum_binlog_checksum_alg checksum_alg,
 | |
|                    rpl_gtid **out_gtid_list, uint32 *out_list_len,
 | |
|                    const Format_description_log_event *fdev);
 | |
| };
 | |
| 
 | |
| 
 | |
| /* 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) override;
 | |
| #endif /* HAVE_REPLICATION */
 | |
| #else
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override;
 | |
|   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() override
 | |
|   {
 | |
|     return fake_base ? Load_log_event::get_type_code() : CREATE_FILE_EVENT;
 | |
|   }
 | |
|   int get_data_size() override
 | |
|   {
 | |
|     return (fake_base ? Load_log_event::get_data_size() :
 | |
| 	    Load_log_event::get_data_size() +
 | |
| 	    4 + 1 + block_len);
 | |
|   }
 | |
|   bool is_valid() const override { return inited_from_old || block != 0; }
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write_data_header() override;
 | |
|   bool write_data_body() override;
 | |
|   /*
 | |
|     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)
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @class Append_block_log_event
 | |
| 
 | |
|   @section Append_block_log_event_binary_format Binary Format
 | |
| */
 | |
| 
 | |
| class Append_block_log_event: public Log_event
 | |
| {
 | |
| public:
 | |
|   uchar* block;
 | |
|   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 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.
 | |
|   */
 | |
|   const char* db;
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   Append_block_log_event(THD* thd, const char* db_arg, uchar* block_arg,
 | |
| 			 uint block_len_arg, bool using_trans);
 | |
| #ifdef HAVE_REPLICATION
 | |
|   void pack_info(Protocol* protocol) override;
 | |
|   virtual int get_create_or_append() const;
 | |
| #endif /* HAVE_REPLICATION */
 | |
| #else
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override;
 | |
| #endif
 | |
| 
 | |
|   Append_block_log_event(const uchar *buf, uint event_len,
 | |
|                          const Format_description_log_event
 | |
|                          *description_event);
 | |
|   ~Append_block_log_event() = default;
 | |
|   Log_event_type get_type_code() override { return APPEND_BLOCK_EVENT;}
 | |
|   int get_data_size() override { return  block_len + APPEND_BLOCK_HEADER_LEN ;}
 | |
|   bool is_valid() const override { return block != 0; }
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write() override;
 | |
|   const char* get_db() override { return db; }
 | |
| #endif
 | |
| 
 | |
| private:
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @class Delete_file_log_event
 | |
| 
 | |
|   @section Delete_file_log_event_binary_format Binary Format
 | |
| */
 | |
| 
 | |
| class Delete_file_log_event: public Log_event
 | |
| {
 | |
| public:
 | |
|   uint file_id;
 | |
|   const char* db; /* see comment in Append_block_log_event */
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   Delete_file_log_event(THD* thd, const char* db_arg, bool using_trans);
 | |
| #ifdef HAVE_REPLICATION
 | |
|   void pack_info(Protocol* protocol) override;
 | |
| #endif /* HAVE_REPLICATION */
 | |
| #else
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override;
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info,
 | |
|              bool enable_local);
 | |
| #endif
 | |
| 
 | |
|   Delete_file_log_event(const uchar *buf, uint event_len,
 | |
|                         const Format_description_log_event* description_event);
 | |
|   ~Delete_file_log_event() = default;
 | |
|   Log_event_type get_type_code() override { return DELETE_FILE_EVENT;}
 | |
|   int get_data_size() override { return DELETE_FILE_HEADER_LEN ;}
 | |
|   bool is_valid() const override { return file_id != 0; }
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write() override;
 | |
|   const char* get_db() override { return db; }
 | |
| #endif
 | |
| 
 | |
| private:
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @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) override;
 | |
| #endif /* HAVE_REPLICATION */
 | |
| #else
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override;
 | |
| #endif
 | |
| 
 | |
|   Execute_load_log_event(const uchar *buf, uint event_len,
 | |
|                          const Format_description_log_event
 | |
|                          *description_event);
 | |
|   ~Execute_load_log_event() = default;
 | |
|   Log_event_type get_type_code() override { return EXEC_LOAD_EVENT;}
 | |
|   int get_data_size() override { return  EXEC_LOAD_HEADER_LEN ;}
 | |
|   bool is_valid() const override { return file_id != 0; }
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write() override;
 | |
|   const char* get_db() override { return db; }
 | |
| #endif
 | |
| 
 | |
| private:
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @class Begin_load_query_log_event
 | |
| 
 | |
|   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.
 | |
| 
 | |
|   @section Begin_load_query_log_event_binary_format Binary Format
 | |
| */
 | |
| class Begin_load_query_log_event: public Append_block_log_event
 | |
| {
 | |
| public:
 | |
| #ifdef MYSQL_SERVER
 | |
|   Begin_load_query_log_event(THD* thd_arg, const char *db_arg,
 | |
|                              uchar* 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 override;
 | |
| #endif /* HAVE_REPLICATION */
 | |
| #endif
 | |
|   Begin_load_query_log_event(const uchar *buf, uint event_len,
 | |
|                              const Format_description_log_event
 | |
|                              *description_event);
 | |
|   ~Begin_load_query_log_event() = default;
 | |
|   Log_event_type get_type_code() override { return BEGIN_LOAD_QUERY_EVENT; }
 | |
| private:
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   enum_skip_reason do_shall_skip(rpl_group_info *rgi) override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /*
 | |
|   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 };
 | |
| 
 | |
| /**
 | |
|   @class Execute_load_query_log_event
 | |
| 
 | |
|   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.
 | |
| 
 | |
|   @section Execute_load_query_log_event_binary_format Binary Format
 | |
| */
 | |
| 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;
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   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 direct,
 | |
|                                bool suppress_use, int errcode);
 | |
| #ifdef HAVE_REPLICATION
 | |
|   void pack_info(Protocol* protocol) override;
 | |
| #endif /* HAVE_REPLICATION */
 | |
| #else
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override;
 | |
|   /* Prints the query as LOAD DATA LOCAL and with rewritten filename */
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info,
 | |
| 	     const char *local_fname);
 | |
| #endif
 | |
|   Execute_load_query_log_event(const uchar *buf, uint event_len,
 | |
|                                const Format_description_log_event
 | |
|                                *description_event);
 | |
|   ~Execute_load_query_log_event() = default;
 | |
| 
 | |
|   Log_event_type get_type_code() override { return EXECUTE_LOAD_QUERY_EVENT; }
 | |
|   bool is_valid() const override { return Query_log_event::is_valid() && file_id != 0; }
 | |
| 
 | |
|   ulong get_post_header_size_for_derived() override;
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write_post_header_for_derived() override;
 | |
| #endif
 | |
| 
 | |
| private:
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| #ifdef MYSQL_CLIENT
 | |
| /**
 | |
|   @class Unknown_log_event
 | |
| 
 | |
|   @section Unknown_log_event_binary_format Binary Format
 | |
| */
 | |
| class Unknown_log_event: public Log_event
 | |
| {
 | |
| public:
 | |
|   enum { UNKNOWN, ENCRYPTED } what;
 | |
|   /*
 | |
|     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 uchar *buf,
 | |
|                     const Format_description_log_event *description_event):
 | |
|     Log_event(buf, description_event), what(UNKNOWN)
 | |
|   {}
 | |
|   /* constructor for hopelessly corrupted events */
 | |
|   Unknown_log_event(): Log_event(), what(ENCRYPTED) {}
 | |
|   ~Unknown_log_event() = default;
 | |
|   bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override;
 | |
|   Log_event_type get_type_code() override { return UNKNOWN_EVENT;}
 | |
|   bool is_valid() const override { return 1; }
 | |
| };
 | |
| #endif
 | |
| char *str_to_hex(char *to, const char *from, size_t len);
 | |
| 
 | |
| /**
 | |
|   @class Annotate_rows_log_event
 | |
| 
 | |
|   In row-based mode, if binlog_annotate_row_events = ON, each group of
 | |
|   Table_map_log_events is preceded by an Annotate_rows_log_event which
 | |
|   contains the query which caused the subsequent rows operations.
 | |
| 
 | |
|   The Annotate_rows_log_event has no post-header and its body contains
 | |
|   the corresponding query (without trailing zero). Note. The query length
 | |
|   is to be calculated as a difference between the whole event length and
 | |
|   the common header length.
 | |
| */
 | |
| class Annotate_rows_log_event: public Log_event
 | |
| {
 | |
| public:
 | |
| #ifndef MYSQL_CLIENT
 | |
|   Annotate_rows_log_event(THD*, bool using_trans, bool direct);
 | |
| #endif
 | |
|   Annotate_rows_log_event(const uchar *buf, uint event_len,
 | |
|                           const Format_description_log_event*);
 | |
|   ~Annotate_rows_log_event();
 | |
| 
 | |
|   int get_data_size() override;
 | |
|   Log_event_type get_type_code() override;
 | |
|   enum_logged_status logged_status() override { return LOGGED_NO_DATA; }
 | |
|   bool is_valid() const override;
 | |
| 
 | |
| #ifndef MYSQL_CLIENT
 | |
| #ifdef HAVE_REPLICATION
 | |
|    bool is_part_of_group() override { return 1; }
 | |
| #endif
 | |
|   bool write_data_header() override;
 | |
|   bool write_data_body() override;
 | |
| #endif
 | |
| 
 | |
| #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
 | |
|   void pack_info(Protocol*) override;
 | |
| #endif
 | |
| 
 | |
| #ifdef MYSQL_CLIENT
 | |
|   bool print(FILE*, PRINT_EVENT_INFO*) override;
 | |
| #endif
 | |
| 
 | |
| #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
 | |
| private:
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
|   int do_update_pos(rpl_group_info *rgi) override;
 | |
|   enum_skip_reason do_shall_skip(rpl_group_info*) override;
 | |
| #endif
 | |
| 
 | |
| private:
 | |
|   char *m_query_txt;
 | |
|   uint  m_query_len;
 | |
|   char *m_save_thd_query_txt;
 | |
|   uint  m_save_thd_query_len;
 | |
|   bool  m_saved_thd_query;
 | |
|   bool  m_used_query_txt;
 | |
| };
 | |
| 
 | |
| /**
 | |
|   @class Table_map_log_event
 | |
| 
 | |
|   In row-based mode, every row operation event is preceded by a
 | |
|   Table_map_log_event which maps a table definition to a number.  The
 | |
|   table definition consists of database name, table name, and column
 | |
|   definitions.
 | |
| 
 | |
|   @section Table_map_log_event_binary_format Binary Format
 | |
| 
 | |
|   The Post-Header has the following components:
 | |
| 
 | |
|   <table>
 | |
|   <caption>Post-Header for Table_map_log_event</caption>
 | |
| 
 | |
|   <tr>
 | |
|     <th>Name</th>
 | |
|     <th>Format</th>
 | |
|     <th>Description</th>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>table_id</td>
 | |
|     <td>6 bytes unsigned integer</td>
 | |
|     <td>The number that identifies the table.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>flags</td>
 | |
|     <td>2 byte bitfield</td>
 | |
|     <td>Reserved for future use; currently always 0.</td>
 | |
|   </tr>
 | |
| 
 | |
|   </table>
 | |
| 
 | |
|   The Body has the following components:
 | |
| 
 | |
|   <table>
 | |
|   <caption>Body for Table_map_log_event</caption>
 | |
| 
 | |
|   <tr>
 | |
|     <th>Name</th>
 | |
|     <th>Format</th>
 | |
|     <th>Description</th>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>database_name</td>
 | |
|     <td>one byte string length, followed by null-terminated string</td>
 | |
|     <td>The name of the database in which the table resides.  The name
 | |
|     is represented as a one byte unsigned integer representing the
 | |
|     number of bytes in the name, followed by length bytes containing
 | |
|     the database name, followed by a terminating 0 byte.  (Note the
 | |
|     redundancy in the representation of the length.)  </td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>table_name</td>
 | |
|     <td>one byte string length, followed by null-terminated string</td>
 | |
|     <td>The name of the table, encoded the same way as the database
 | |
|     name above.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>column_count</td>
 | |
|     <td>@ref packed_integer "Packed Integer"</td>
 | |
|     <td>The number of columns in the table, represented as a packed
 | |
|     variable-length integer.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>column_type</td>
 | |
|     <td>List of column_count 1 byte enumeration values</td>
 | |
|     <td>The type of each column in the table, listed from left to
 | |
|     right.  Each byte is mapped to a column type according to the
 | |
|     enumeration type enum_field_types defined in mysql_com.h.  The
 | |
|     mapping of types to numbers is listed in the table @ref
 | |
|     Table_table_map_log_event_column_types "below" (along with
 | |
|     description of the associated metadata field).  </td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>metadata_length</td>
 | |
|     <td>@ref packed_integer "Packed Integer"</td>
 | |
|     <td>The length of the following metadata block</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>metadata</td>
 | |
|     <td>list of metadata for each column</td>
 | |
|     <td>For each column from left to right, a chunk of data who's
 | |
|     length and semantics depends on the type of the column.  The
 | |
|     length and semantics for the metadata for each column are listed
 | |
|     in the table @ref Table_table_map_log_event_column_types
 | |
|     "below".</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>null_bits</td>
 | |
|     <td>column_count bits, rounded up to nearest byte</td>
 | |
|     <td>For each column, a bit indicating whether data in the column
 | |
|     can be NULL or not.  The number of bytes needed for this is
 | |
|     int((column_count+7)/8).  The flag for the first column from the
 | |
|     left is in the least-significant bit of the first byte, the second
 | |
|     is in the second least significant bit of the first byte, the
 | |
|     ninth is in the least significant bit of the second byte, and so
 | |
|     on.  </td>
 | |
|   </tr>
 | |
|   <tr>
 | |
|     <td>optional metadata fields</td>
 | |
|     <td>optional metadata fields are stored in Type, Length, Value(TLV) format.
 | |
|     Type takes 1 byte. Length is a packed integer value. Values takes
 | |
|     Length bytes.
 | |
|     </td>
 | |
|     <td>There are some optional metadata defined. They are listed in the table
 | |
|     @ref Table_table_map_event_optional_metadata. Optional metadata fields
 | |
|     follow null_bits. Whether binlogging an optional metadata is decided by the
 | |
|     server. The order is not defined, so they can be binlogged in any order.
 | |
|     </td>
 | |
|   </tr>
 | |
| 
 | |
|   </table>
 | |
| 
 | |
|   The table below lists all column types, along with the numerical
 | |
|   identifier for it and the size and interpretation of meta-data used
 | |
|   to describe the type.
 | |
| 
 | |
|   @anchor Table_table_map_log_event_column_types
 | |
|   <table>
 | |
|   <caption>Table_map_log_event column types: numerical identifier and
 | |
|   metadata</caption>
 | |
|   <tr>
 | |
|     <th>Name</th>
 | |
|     <th>Identifier</th>
 | |
|     <th>Size of metadata in bytes</th>
 | |
|     <th>Description of metadata</th>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_DECIMAL</td><td>0</td>
 | |
|     <td>0</td>
 | |
|     <td>No column metadata.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_TINY</td><td>1</td>
 | |
|     <td>0</td>
 | |
|     <td>No column metadata.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_SHORT</td><td>2</td>
 | |
|     <td>0</td>
 | |
|     <td>No column metadata.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_LONG</td><td>3</td>
 | |
|     <td>0</td>
 | |
|     <td>No column metadata.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_FLOAT</td><td>4</td>
 | |
|     <td>1 byte</td>
 | |
|     <td>1 byte unsigned integer, representing the "pack_length", which
 | |
|     is equal to sizeof(float) on the server from which the event
 | |
|     originates.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_DOUBLE</td><td>5</td>
 | |
|     <td>1 byte</td>
 | |
|     <td>1 byte unsigned integer, representing the "pack_length", which
 | |
|     is equal to sizeof(double) on the server from which the event
 | |
|     originates.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_NULL</td><td>6</td>
 | |
|     <td>0</td>
 | |
|     <td>No column metadata.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_TIMESTAMP</td><td>7</td>
 | |
|     <td>0</td>
 | |
|     <td>No column metadata.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_LONGLONG</td><td>8</td>
 | |
|     <td>0</td>
 | |
|     <td>No column metadata.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_INT24</td><td>9</td>
 | |
|     <td>0</td>
 | |
|     <td>No column metadata.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_DATE</td><td>10</td>
 | |
|     <td>0</td>
 | |
|     <td>No column metadata.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_TIME</td><td>11</td>
 | |
|     <td>0</td>
 | |
|     <td>No column metadata.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_DATETIME</td><td>12</td>
 | |
|     <td>0</td>
 | |
|     <td>No column metadata.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_YEAR</td><td>13</td>
 | |
|     <td>0</td>
 | |
|     <td>No column metadata.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td><i>MYSQL_TYPE_NEWDATE</i></td><td><i>14</i></td>
 | |
|     <td>–</td>
 | |
|     <td><i>This enumeration value is only used internally and cannot
 | |
|     exist in a binlog.</i></td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_VARCHAR</td><td>15</td>
 | |
|     <td>2 bytes</td>
 | |
|     <td>2 byte unsigned integer representing the maximum length of
 | |
|     the string.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_BIT</td><td>16</td>
 | |
|     <td>2 bytes</td>
 | |
|     <td>A 1 byte unsigned int representing the length in bits of the
 | |
|     bitfield (0 to 64), followed by a 1 byte unsigned int
 | |
|     representing the number of bytes occupied by the bitfield.  The
 | |
|     number of bytes is either int((length+7)/8) or int(length/8).</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_NEWDECIMAL</td><td>246</td>
 | |
|     <td>2 bytes</td>
 | |
|     <td>A 1 byte unsigned int representing the precision, followed
 | |
|     by a 1 byte unsigned int representing the number of decimals.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td><i>MYSQL_TYPE_ENUM</i></td><td><i>247</i></td>
 | |
|     <td>–</td>
 | |
|     <td><i>This enumeration value is only used internally and cannot
 | |
|     exist in a binlog.</i></td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td><i>MYSQL_TYPE_SET</i></td><td><i>248</i></td>
 | |
|     <td>–</td>
 | |
|     <td><i>This enumeration value is only used internally and cannot
 | |
|     exist in a binlog.</i></td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_TINY_BLOB</td><td>249</td>
 | |
|     <td>–</td>
 | |
|     <td><i>This enumeration value is only used internally and cannot
 | |
|     exist in a binlog.</i></td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td><i>MYSQL_TYPE_MEDIUM_BLOB</i></td><td><i>250</i></td>
 | |
|     <td>–</td>
 | |
|     <td><i>This enumeration value is only used internally and cannot
 | |
|     exist in a binlog.</i></td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td><i>MYSQL_TYPE_LONG_BLOB</i></td><td><i>251</i></td>
 | |
|     <td>–</td>
 | |
|     <td><i>This enumeration value is only used internally and cannot
 | |
|     exist in a binlog.</i></td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_BLOB</td><td>252</td>
 | |
|     <td>1 byte</td>
 | |
|     <td>The pack length, i.e., the number of bytes needed to represent
 | |
|     the length of the blob: 1, 2, 3, or 4.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_VAR_STRING</td><td>253</td>
 | |
|     <td>2 bytes</td>
 | |
|     <td>This is used to store both strings and enumeration values.
 | |
|     The first byte is a enumeration value storing the <i>real
 | |
|     type</i>, which may be either MYSQL_TYPE_VAR_STRING or
 | |
|     MYSQL_TYPE_ENUM.  The second byte is a 1 byte unsigned integer
 | |
|     representing the field size, i.e., the number of bytes needed to
 | |
|     store the length of the string.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_STRING</td><td>254</td>
 | |
|     <td>2 bytes</td>
 | |
|     <td>The first byte is always MYSQL_TYPE_VAR_STRING (i.e., 253).
 | |
|     The second byte is the field size, i.e., the number of bytes in
 | |
|     the representation of size of the string: 3 or 4.</td>
 | |
|   </tr>
 | |
| 
 | |
|   <tr>
 | |
|     <td>MYSQL_TYPE_GEOMETRY</td><td>255</td>
 | |
|     <td>1 byte</td>
 | |
|     <td>The pack length, i.e., the number of bytes needed to represent
 | |
|     the length of the geometry: 1, 2, 3, or 4.</td>
 | |
|   </tr>
 | |
| 
 | |
|   </table>
 | |
|   The table below lists all optional metadata types, along with the numerical
 | |
|   identifier for it and the size and interpretation of meta-data used
 | |
|   to describe the type.
 | |
| 
 | |
|   @anchor Table_table_map_event_optional_metadata
 | |
|   <table>
 | |
|   <caption>Table_map_event optional metadata types: numerical identifier and
 | |
|   metadata. Optional metadata fields are stored in TLV fields.
 | |
|   Format of values are described in this table. </caption>
 | |
|   <tr>
 | |
|     <th>Type</th>
 | |
|     <th>Description</th>
 | |
|     <th>Format</th>
 | |
|   </tr>
 | |
|   <tr>
 | |
|     <td>SIGNEDNESS</td>
 | |
|     <td>signedness of numeric colums. This is included for all values of
 | |
|     binlog_row_metadata.</td>
 | |
|     <td>For each numeric column, a bit indicates whether the numeric
 | |
|     colunm has unsigned flag. 1 means it is unsigned. The number of
 | |
|     bytes needed for this is int((column_count + 7) / 8). The order is
 | |
|     the same as the order of column_type field.</td>
 | |
|   </tr>
 | |
|   <tr>
 | |
|     <td>DEFAULT_CHARSET</td>
 | |
|     <td>Charsets of character columns. It has a default charset for
 | |
|     the case that most of character columns have same charset and the
 | |
|     most used charset is binlogged as default charset.Collation
 | |
|     numbers are binlogged for identifying charsets. They are stored in
 | |
|     packed length format.  Either DEFAULT_CHARSET or COLUMN_CHARSET is
 | |
|     included for all values of binlog_row_metadata.</td>
 | |
|     <td>Default charset's collation is logged first. The charsets which are not
 | |
|     same to default charset are logged following default charset. They are
 | |
|     logged as column index and charset collation number pair sequence. The
 | |
|     column index is counted only in all character columns. The order is same to
 | |
|     the order of column_type
 | |
|     field. </td>
 | |
|   </tr>
 | |
|   <tr>
 | |
|     <td>COLUMN_CHARSET</td>
 | |
|     <td>Charsets of character columns. For the case that most of columns have
 | |
|     different charsets, this field is logged. It is never logged with
 | |
|     DEFAULT_CHARSET together.  Either DEFAULT_CHARSET or COLUMN_CHARSET is
 | |
|     included for all values of binlog_row_metadata.</td>
 | |
|     <td>It is a collation number sequence for all character columns.</td>
 | |
|   </tr>
 | |
|   <tr>
 | |
|     <td>COLUMN_NAME</td>
 | |
|     <td>Names of columns. This is only included if
 | |
|     binlog_row_metadata=FULL.</td>
 | |
|     <td>A sequence of column names. For each column name, 1 byte for
 | |
|     the string length in bytes is followed by a string without null
 | |
|     terminator.</td>
 | |
|   </tr>
 | |
|   <tr>
 | |
|     <td>SET_STR_VALUE</td>
 | |
|     <td>The string values of SET columns. This is only included if
 | |
|     binlog_row_metadata=FULL.</td>
 | |
|     <td>For each SET column, a pack_length representing the value
 | |
|     count is followed by a sequence of length and string pairs. length
 | |
|     is the byte count in pack_length format. The string has no null
 | |
|     terminator.</td>
 | |
|   </tr>
 | |
|   <tr>
 | |
|     <td>ENUM_STR_VALUE</td>
 | |
|     <td>The string values is ENUM columns. This is only included
 | |
|     if binlog_row_metadata=FULL.</td>
 | |
|     <td>The format is the same as SET_STR_VALUE.</td>
 | |
|   </tr>
 | |
|   <tr>
 | |
|     <td>GEOMETRY_TYPE</td>
 | |
|     <td>The real type of geometry columns. This is only included
 | |
|     if binlog_row_metadata=FULL.</td>
 | |
|     <td>A sequence of real type of geometry columns are stored in pack_length
 | |
|     format. </td>
 | |
|   </tr>
 | |
|   <tr>
 | |
|     <td>SIMPLE_PRIMARY_KEY</td>
 | |
|     <td>The primary key without any prefix. This is only included
 | |
|     if binlog_row_metadata=FULL and there is a primary key where every
 | |
|     key part covers an entire column.</td>
 | |
|     <td>A sequence of column indexes. The indexes are stored in pack_length
 | |
|     format.</td>
 | |
|   </tr>
 | |
|   <tr>
 | |
|     <td>PRIMARY_KEY_WITH_PREFIX</td>
 | |
|     <td>The primary key with some prefix. It doesn't appear together with
 | |
|     SIMPLE_PRIMARY_KEY. This is only included if
 | |
|     binlog_row_metadata=FULL and there is a primary key where some key
 | |
|     part covers a prefix of the column.</td>
 | |
|     <td>A sequence of column index and prefix length pairs. Both
 | |
|     column index and prefix length are in pack_length format. Prefix length
 | |
|     0 means that the whole column value is used.</td>
 | |
|   </tr>
 | |
|   <tr>
 | |
|     <td>ENUM_AND_SET_DEFAULT_CHARSET</td>
 | |
|     <td>Charsets of ENUM and SET columns. It has the same layout as
 | |
|     DEFAULT_CHARSET.  If there are SET or ENUM columns and
 | |
|     binlog_row_metadata=FULL, exactly one of
 | |
|     ENUM_AND_SET_DEFAULT_CHARSET and ENUM_AND_SET_COLUMN_CHARSET
 | |
|     appears (the encoder chooses the representation that uses the
 | |
|     least amount of space).  Otherwise, none of them appears.</td>
 | |
|     <td>The same format as for DEFAULT_CHARSET, except it counts ENUM
 | |
|     and SET columns rather than character columns.</td>
 | |
|   </tr>
 | |
|   <tr>
 | |
|     <td>ENUM_AND_SET_COLUMN_CHARSET</td>
 | |
|     <td>Charsets of ENUM and SET columns. It has the same layout as
 | |
|     COLUMN_CHARSET.  If there are SET or ENUM columns and
 | |
|     binlog_row_metadata=FULL, exactly one of
 | |
|     ENUM_AND_SET_DEFAULT_CHARSET and ENUM_AND_SET_COLUMN_CHARSET
 | |
|     appears (the encoder chooses the representation that uses the
 | |
|     least amount of space).  Otherwise, none of them appears.</td>
 | |
|     <td>The same format as for COLUMN_CHARSET, except it counts ENUM
 | |
|     and SET columns rather than character columns.</td>
 | |
|   </tr>
 | |
|   </table>
 | |
| */
 | |
| class Table_map_log_event : public Log_event
 | |
| {
 | |
| public:
 | |
|   /* Constants */
 | |
|   enum
 | |
|   {
 | |
|     TYPE_CODE = TABLE_MAP_EVENT
 | |
|   };
 | |
| 
 | |
|   /**
 | |
|      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 */
 | |
|   };
 | |
| 
 | |
|   enum enum_flag
 | |
|   {
 | |
|     /* 
 | |
|        Nothing here right now, but the flags support is there in
 | |
|        preparation for changes that are coming.  Need to add a
 | |
|        constant to make it compile under HP-UX: aCC does not like
 | |
|        empty enumerations.
 | |
|     */
 | |
|     ENUM_FLAG_COUNT
 | |
|   };
 | |
| 
 | |
|   typedef uint16 flag_set;
 | |
|   /**
 | |
|     DEFAULT_CHARSET and COLUMN_CHARSET don't appear together, and
 | |
|     ENUM_AND_SET_DEFAULT_CHARSET and ENUM_AND_SET_COLUMN_CHARSET don't
 | |
|     appear together. They are just alternative ways to pack character
 | |
|     set information. When binlogging, it logs character sets in the
 | |
|     way that occupies least storage.
 | |
| 
 | |
|     SIMPLE_PRIMARY_KEY and PRIMARY_KEY_WITH_PREFIX don't appear together.
 | |
|     SIMPLE_PRIMARY_KEY is for the primary keys which only use whole values of
 | |
|     pk columns. PRIMARY_KEY_WITH_PREFIX is
 | |
|     for the primary keys which just use part value of pk columns.
 | |
|    */
 | |
|   enum Optional_metadata_field_type
 | |
|   {
 | |
|     SIGNEDNESS = 1,  // UNSIGNED flag of numeric columns
 | |
|     DEFAULT_CHARSET, /* Character set of string columns, optimized to
 | |
|                         minimize space when many columns have the
 | |
|                         same charset. */
 | |
|     COLUMN_CHARSET,  /* Character set of string columns, optimized to
 | |
|                         minimize space when columns have many
 | |
|                         different charsets. */
 | |
|     COLUMN_NAME,
 | |
|     SET_STR_VALUE,                // String value of SET columns
 | |
|     ENUM_STR_VALUE,               // String value of ENUM columns
 | |
|     GEOMETRY_TYPE,                // Real type of geometry columns
 | |
|     SIMPLE_PRIMARY_KEY,           // Primary key without prefix
 | |
|     PRIMARY_KEY_WITH_PREFIX,      // Primary key with prefix
 | |
|     ENUM_AND_SET_DEFAULT_CHARSET, /* Character set of enum and set
 | |
|                                      columns, optimized to minimize
 | |
|                                      space when many columns have the
 | |
|                                      same charset. */
 | |
|     ENUM_AND_SET_COLUMN_CHARSET,  /* Character set of enum and set
 | |
|                                      columns, optimized to minimize
 | |
|                                      space when many columns have the
 | |
|                                      same charset. */
 | |
|   };
 | |
|   /**
 | |
|     Metadata_fields organizes m_optional_metadata into a structured format which
 | |
|     is easy to access.
 | |
|   */
 | |
|   // Values for binlog_row_metadata sysvar
 | |
|   enum enum_binlog_row_metadata
 | |
|   {
 | |
|     BINLOG_ROW_METADATA_NO_LOG= 0,
 | |
|     BINLOG_ROW_METADATA_MINIMAL= 1,
 | |
|     BINLOG_ROW_METADATA_FULL= 2
 | |
|   };
 | |
|   struct Optional_metadata_fields
 | |
|   {
 | |
|     typedef std::pair<unsigned int, unsigned int> uint_pair;
 | |
|     typedef std::vector<std::string> str_vector;
 | |
| 
 | |
|     struct Default_charset
 | |
|     {
 | |
|       Default_charset() : default_charset(0) {}
 | |
|       bool empty() const { return default_charset == 0; }
 | |
| 
 | |
|       // Default charset for the columns which are not in charset_pairs.
 | |
|       unsigned int default_charset;
 | |
| 
 | |
|       /* The uint_pair means <column index, column charset number>. */
 | |
|       std::vector<uint_pair> charset_pairs;
 | |
|     };
 | |
| 
 | |
|     // Contents of DEFAULT_CHARSET field is converted into Default_charset.
 | |
|     Default_charset m_default_charset;
 | |
|     // Contents of ENUM_AND_SET_DEFAULT_CHARSET are converted into
 | |
|     // Default_charset.
 | |
|     Default_charset m_enum_and_set_default_charset;
 | |
|     std::vector<bool> m_signedness;
 | |
|     // Character set number of every string column
 | |
|     std::vector<unsigned int> m_column_charset;
 | |
|     // Character set number of every ENUM or SET column.
 | |
|     std::vector<unsigned int> m_enum_and_set_column_charset;
 | |
|     std::vector<std::string> m_column_name;
 | |
|     // each str_vector stores values of one enum/set column
 | |
|     std::vector<str_vector> m_enum_str_value;
 | |
|     std::vector<str_vector> m_set_str_value;
 | |
|     std::vector<unsigned int> m_geometry_type;
 | |
|     /*
 | |
|       The uint_pair means <column index, prefix length>.  Prefix length is 0 if
 | |
|       whole column value is used.
 | |
|     */
 | |
|     std::vector<uint_pair> m_primary_key;
 | |
| 
 | |
|     /*
 | |
|       It parses m_optional_metadata and populates into above variables.
 | |
| 
 | |
|       @param[in] optional_metadata points to the begin of optional metadata
 | |
|                                    fields in table_map_event.
 | |
|       @param[in] optional_metadata_len length of optional_metadata field.
 | |
|      */
 | |
|     Optional_metadata_fields(unsigned char* optional_metadata,
 | |
|                              unsigned int optional_metadata_len);
 | |
|   };
 | |
| 
 | |
|   /**
 | |
|     Print column metadata. Its format looks like:
 | |
|     # Columns(colume_name type, colume_name type, ...)
 | |
|     if colume_name field is not logged into table_map_log_event, then
 | |
|     only type is printed.
 | |
| 
 | |
|     @@param[out] file the place where colume metadata is printed
 | |
|     @@param[in]  The metadata extracted from optional metadata fields
 | |
|  */
 | |
|   void print_columns(IO_CACHE *file,
 | |
|                      const Optional_metadata_fields &fields);
 | |
|   /**
 | |
|     Print primary information. Its format looks like:
 | |
|     # Primary Key(colume_name, column_name(prifix), ...)
 | |
|     if colume_name field is not logged into table_map_log_event, then
 | |
|     colume index is printed.
 | |
| 
 | |
|     @@param[out] file the place where primary key is printed
 | |
|     @@param[in]  The metadata extracted from optional metadata fields
 | |
|  */
 | |
|   void print_primary_key(IO_CACHE *file,
 | |
|                          const Optional_metadata_fields &fields);
 | |
| 
 | |
|   /* Special constants representing sets of flags */
 | |
|   enum 
 | |
|   {
 | |
|     TM_NO_FLAGS = 0U,
 | |
|     TM_BIT_LEN_EXACT_F = (1U << 0),
 | |
|     // MariaDB flags (we starts from the other end)
 | |
|     TM_BIT_HAS_TRIGGERS_F= (1U << 14)
 | |
|   };
 | |
| 
 | |
|   flag_set get_flags(flag_set flag) const { return m_flags & flag; }
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   Table_map_log_event(THD *thd, TABLE *tbl, ulonglong tid,
 | |
|                       bool is_transactional);
 | |
| #endif
 | |
| #ifdef HAVE_REPLICATION
 | |
|   Table_map_log_event(const uchar *buf, uint event_len,
 | |
|                       const Format_description_log_event *description_event);
 | |
| #endif
 | |
| 
 | |
|   ~Table_map_log_event();
 | |
| 
 | |
| #ifdef MYSQL_CLIENT
 | |
|   table_def *create_table_def()
 | |
|   {
 | |
|     return new table_def(m_coltype, m_colcnt, m_field_metadata,
 | |
|                          m_field_metadata_size, m_null_bits, m_flags);
 | |
|   }
 | |
|   int rewrite_db(const char* new_name, size_t new_name_len,
 | |
|                  const Format_description_log_event*);
 | |
| #endif
 | |
|   ulonglong get_table_id() const        { return m_table_id; }
 | |
|   const char *get_table_name() const { return m_tblnam; }
 | |
|   const char *get_db_name() const    { return m_dbnam; }
 | |
| 
 | |
|   Log_event_type get_type_code() override { return TABLE_MAP_EVENT; }
 | |
|   enum_logged_status logged_status() override { return LOGGED_TABLE_MAP; }
 | |
|   bool is_valid() const override { return m_memory != NULL; /* we check malloc */ }
 | |
| 
 | |
|   int get_data_size() override { return (uint) m_data_size; } 
 | |
| #ifdef MYSQL_SERVER
 | |
| #ifdef HAVE_REPLICATION
 | |
|    bool is_part_of_group() override { return 1; }
 | |
| #endif
 | |
|   virtual int save_field_metadata();
 | |
|   bool write_data_header() override;
 | |
|   bool write_data_body() override;
 | |
|   const char *get_db() override { return m_dbnam; }
 | |
| #endif
 | |
| 
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   void pack_info(Protocol *protocol) override;
 | |
| #endif
 | |
| 
 | |
| #ifdef MYSQL_CLIENT
 | |
|   bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override;
 | |
| #endif
 | |
| 
 | |
| 
 | |
| private:
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
|   int do_update_pos(rpl_group_info *rgi) override;
 | |
|   enum_skip_reason do_shall_skip(rpl_group_info *rgi) override;
 | |
| #endif
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   TABLE         *m_table;
 | |
|   Binlog_type_info *binlog_type_info_array;
 | |
| 
 | |
| 
 | |
|   // Metadata fields buffer
 | |
|   StringBuffer<1024> m_metadata_buf;
 | |
| 
 | |
|   /**
 | |
|     Capture the optional metadata fields which should be logged into
 | |
|     table_map_log_event and serialize them into m_metadata_buf.
 | |
|   */
 | |
|   void init_metadata_fields();
 | |
|   bool init_signedness_field();
 | |
|   /**
 | |
|     Capture and serialize character sets.  Character sets for
 | |
|     character columns (TEXT etc) and character sets for ENUM and SET
 | |
|     columns are stored in different metadata fields. The reason is
 | |
|     that TEXT character sets are included even when
 | |
|     binlog_row_metadata=MINIMAL, whereas ENUM and SET character sets
 | |
|     are included only when binlog_row_metadata=FULL.
 | |
| 
 | |
|     @param include_type Predicate to determine if a given Field object
 | |
|     is to be included in the metadata field.
 | |
| 
 | |
|     @param default_charset_type Type code when storing in "default
 | |
|     charset" format.  (See comment above Table_maps_log_event in
 | |
|     libbinlogevents/include/rows_event.h)
 | |
| 
 | |
|     @param column_charset_type Type code when storing in "column
 | |
|     charset" format.  (See comment above Table_maps_log_event in
 | |
|     libbinlogevents/include/rows_event.h)
 | |
|   */
 | |
|   bool init_charset_field(bool(* include_type)(Binlog_type_info *, Field *),
 | |
|                           Optional_metadata_field_type default_charset_type,
 | |
|                           Optional_metadata_field_type column_charset_type);
 | |
|   bool init_column_name_field();
 | |
|   bool init_set_str_value_field();
 | |
|   bool init_enum_str_value_field();
 | |
|   bool init_geometry_type_field();
 | |
|   bool init_primary_key_field();
 | |
| #endif
 | |
| 
 | |
| #ifdef MYSQL_CLIENT
 | |
|   class Charset_iterator;
 | |
|   class Default_charset_iterator;
 | |
|   class Column_charset_iterator;
 | |
| #endif
 | |
|   char const    *m_dbnam;
 | |
|   size_t         m_dblen;
 | |
|   char const    *m_tblnam;
 | |
|   size_t         m_tbllen;
 | |
|   ulong          m_colcnt;
 | |
|   uchar         *m_coltype;
 | |
| 
 | |
|   uchar         *m_memory;
 | |
|   ulonglong      m_table_id;
 | |
|   flag_set       m_flags;
 | |
| 
 | |
|   size_t         m_data_size;
 | |
| 
 | |
|   uchar          *m_field_metadata;        // buffer for field metadata
 | |
|   /*
 | |
|     The size of field metadata buffer set by calling save_field_metadata()
 | |
|   */
 | |
|   ulong          m_field_metadata_size;   
 | |
|   uchar         *m_null_bits;
 | |
|   uchar         *m_meta_memory;
 | |
|   unsigned int   m_optional_metadata_len;
 | |
|   unsigned char *m_optional_metadata;
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @class Rows_log_event
 | |
| 
 | |
|  Common base class for all row-containing log events.
 | |
| 
 | |
|  RESPONSIBILITIES
 | |
| 
 | |
|    Encode the common parts of all events containing rows, which are:
 | |
|    - Write data header and data body to an IO_CACHE.
 | |
|    - Provide an interface for adding an individual row to the event.
 | |
| 
 | |
|   @section Rows_log_event_binary_format Binary Format
 | |
| */
 | |
| 
 | |
| 
 | |
| class Rows_log_event : public 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),
 | |
| 
 | |
|     /* Value of the OPTION_NO_CHECK_CONSTRAINT_CHECKS flag in thd->options */
 | |
|     NO_CHECK_CONSTRAINT_CHECKS_F = (1U << 7)
 | |
|   };
 | |
| 
 | |
|   typedef uint16 flag_set;
 | |
| 
 | |
|   /* Special constants representing sets of flags */
 | |
|   enum 
 | |
|   {
 | |
|       RLE_NO_FLAGS = 0U
 | |
|   };
 | |
| 
 | |
|   virtual ~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; }
 | |
|   void update_flags() { int2store(temp_buf + m_flags_pos, m_flags); }
 | |
| 
 | |
|   Log_event_type get_type_code() override { return m_type; } /* Specific type (_V1 etc) */
 | |
|   enum_logged_status logged_status() override { return LOGGED_ROW_EVENT; }
 | |
|   virtual Log_event_type get_general_type_code() = 0; /* General rows op type, no version */
 | |
| 
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   void pack_info(Protocol *protocol) override;
 | |
| #endif
 | |
| 
 | |
| #ifdef MYSQL_CLIENT
 | |
|   /* not for direct call, each derived has its own ::print() */
 | |
|   bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override= 0;
 | |
|   void change_to_flashback_event(PRINT_EVENT_INFO *print_event_info, uchar *rows_buff, Log_event_type ev_type);
 | |
|   bool print_verbose(IO_CACHE *file,
 | |
|                      PRINT_EVENT_INFO *print_event_info);
 | |
|   size_t print_verbose_one_row(IO_CACHE *file, table_def *td,
 | |
|                                PRINT_EVENT_INFO *print_event_info,
 | |
|                                MY_BITMAP *cols_bitmap,
 | |
|                                const uchar *ptr, const uchar *prefix,
 | |
|                                const my_bool no_fill_output= 0); // if no_fill_output=1, then print result is unnecessary
 | |
|   size_t calc_row_event_length(table_def *td,
 | |
|                                PRINT_EVENT_INFO *print_event_info,
 | |
|                                MY_BITMAP *cols_bitmap,
 | |
|                                const uchar *value);
 | |
|   void count_row_events(PRINT_EVENT_INFO *print_event_info);
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   int add_row_data(uchar *data, size_t length)
 | |
|   {
 | |
|     return do_add_row_data(data,length); 
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   /* Member functions to implement superclass interface */
 | |
|   int get_data_size() override;
 | |
| 
 | |
|   MY_BITMAP const *get_cols() const { return &m_cols; }
 | |
|   MY_BITMAP const *get_cols_ai() const { return &m_cols_ai; }
 | |
|   size_t get_width() const          { return m_width; }
 | |
|   ulonglong get_table_id() const        { return m_table_id; }
 | |
| 
 | |
| #if defined(MYSQL_SERVER)
 | |
|   /*
 | |
|     This member function compares the table's read/write_set
 | |
|     with this event's m_cols and m_cols_ai. Comparison takes
 | |
|     into account what type of rows event is this: Delete, Write or
 | |
|     Update, therefore it uses the correct m_cols[_ai] according
 | |
|     to the event type code.
 | |
| 
 | |
|     Note that this member function should only be called for the
 | |
|     following events:
 | |
|     - Delete_rows_log_event
 | |
|     - Write_rows_log_event
 | |
|     - Update_rows_log_event
 | |
| 
 | |
|     @param[IN] table The table to compare this events bitmaps
 | |
|                      against.
 | |
| 
 | |
|     @return TRUE if sets match, FALSE otherwise. (following
 | |
|                  bitmap_cmp return logic).
 | |
| 
 | |
|    */
 | |
|   bool read_write_bitmaps_cmp(TABLE *table)
 | |
|   {
 | |
|     bool res= FALSE;
 | |
| 
 | |
|     switch (get_general_type_code())
 | |
|     {
 | |
|       case DELETE_ROWS_EVENT:
 | |
|         res= bitmap_cmp(get_cols(), table->read_set);
 | |
|         break;
 | |
|       case UPDATE_ROWS_EVENT:
 | |
|         res= (bitmap_cmp(get_cols(), table->read_set) &&
 | |
|               bitmap_cmp(get_cols_ai(), table->rpl_write_set));
 | |
|         break;
 | |
|       case WRITE_ROWS_EVENT:
 | |
|         res= bitmap_cmp(get_cols(), table->rpl_write_set);
 | |
|         break;
 | |
|       default:
 | |
|         /*
 | |
|           We should just compare bitmaps for Delete, Write
 | |
|           or Update rows events.
 | |
|         */
 | |
|         DBUG_ASSERT(0);
 | |
|     }
 | |
|     return res;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   bool write_data_header() override;
 | |
|   bool write_data_body() override;
 | |
|   virtual bool write_compressed();
 | |
|   const char *get_db() override { return m_table->s->db.str; }
 | |
| #ifdef HAVE_REPLICATION
 | |
|    bool is_part_of_group() override { return get_flags(STMT_END_F) != 0; }
 | |
| #endif
 | |
| #endif
 | |
|   /*
 | |
|     Check that malloc() succeeded in allocating memory for the rows
 | |
|     buffer and the COLS vector. Checking that an Update_rows_log_event
 | |
|     is valid is done in the Update_rows_log_event::is_valid()
 | |
|     function.
 | |
|   */
 | |
|   bool is_valid() const override
 | |
|   {
 | |
|     return m_cols.bitmap;
 | |
|   }
 | |
| 
 | |
|   uint     m_row_count;         /* The number of rows added to the event */
 | |
| 
 | |
|   const uchar* get_extra_row_data() const   { return m_extra_row_data; }
 | |
| 
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   virtual uint8 get_trg_event_map()= 0;
 | |
| 
 | |
|   inline bool do_invoke_trigger()
 | |
|   {
 | |
|     return (slave_run_triggers_for_rbr && !master_had_triggers) ||
 | |
|             slave_run_triggers_for_rbr == SLAVE_RUN_TRIGGERS_FOR_RBR_ENFORCE;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
| protected:
 | |
|   /* 
 | |
|      The constructors are protected since you're supposed to inherit
 | |
|      this class, not create instances of this class.
 | |
|   */
 | |
| #ifdef MYSQL_SERVER
 | |
|   Rows_log_event(THD*, TABLE*, ulonglong table_id,
 | |
| 		 MY_BITMAP const *cols, bool is_transactional,
 | |
| 		 Log_event_type event_type);
 | |
| #endif
 | |
|   Rows_log_event(const uchar *row_data, uint event_len,
 | |
| 		 const Format_description_log_event *description_event);
 | |
|   void uncompress_buf();
 | |
| 
 | |
| #ifdef MYSQL_CLIENT
 | |
|   bool print_helper(FILE *, PRINT_EVENT_INFO *, char const *const name);
 | |
| #endif
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   virtual int do_add_row_data(uchar *data, size_t length);
 | |
| #endif
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   TABLE *m_table;		/* The table the rows belong to */
 | |
| #endif
 | |
|   ulonglong       m_table_id;	/* Table ID */
 | |
|   MY_BITMAP   m_cols;		/* Bitmap denoting columns available */
 | |
|   ulong       m_width;          /* The width of the columns bitmap */
 | |
|   /*
 | |
|     Bitmap for columns available in the after image, if present. These
 | |
|     fields are only available for Update_rows events. Observe that the
 | |
|     width of both the before image COLS vector and the after image
 | |
|     COLS vector is the same: the number of columns of the table on the
 | |
|     master.
 | |
|   */
 | |
|   MY_BITMAP   m_cols_ai;
 | |
| 
 | |
|   ulong       m_master_reclength; /* Length of record on master side */
 | |
| 
 | |
|   /* Bit buffers in the same memory as the class */
 | |
|   my_bitmap_map  m_bitbuf[128/(sizeof(my_bitmap_map)*8)];
 | |
|   my_bitmap_map  m_bitbuf_ai[128/(sizeof(my_bitmap_map)*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 */
 | |
| 
 | |
|   size_t   m_rows_before_size;  /* The length before m_rows_buf */
 | |
|   size_t   m_flags_pos; /* The position of the m_flags */
 | |
| 
 | |
|   flag_set m_flags;		/* Flags for row-level events */
 | |
| 
 | |
|   Log_event_type m_type;        /* Actual event type */
 | |
| 
 | |
|   uchar    *m_extra_row_data;   /* Pointer to extra row data if any */
 | |
|                                 /* If non null, first byte is length */
 | |
| 
 | |
|   bool m_vers_from_plain;
 | |
| 
 | |
| 
 | |
|   /* helper functions */
 | |
| 
 | |
| #if defined(MYSQL_SERVER) && 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 */
 | |
|   KEY      *m_key_info; /* Pointer to KEY info for m_key_nr */
 | |
|   uint      m_key_nr;   /* Key number */
 | |
|   bool master_had_triggers;     /* set after tables opening */
 | |
| 
 | |
|   /*
 | |
|     RAII helper class to automatically handle the override/restore of thd->db
 | |
|     when applying row events, so it will be visible in SHOW PROCESSLIST.
 | |
| 
 | |
|     If triggers will be invoked, their logic frees the current thread's db,
 | |
|     so we use set_db() to use a copy of the table share's database.
 | |
| 
 | |
|     If not using triggers, the db is never freed, and we can reference the
 | |
|     same memory owned by the table share.
 | |
|   */
 | |
|   class Db_restore_ctx
 | |
|   {
 | |
|   private:
 | |
|     THD *thd;
 | |
|     LEX_CSTRING restore_db;
 | |
|     bool db_copied;
 | |
| 
 | |
|     Db_restore_ctx(Rows_log_event *rev)
 | |
|         : thd(rev->thd), restore_db(rev->thd->db)
 | |
|     {
 | |
|       TABLE *table= rev->m_table;
 | |
| 
 | |
|       if (table->triggers && rev->do_invoke_trigger())
 | |
|       {
 | |
|         thd->reset_db(&null_clex_str);
 | |
|         thd->set_db(&table->s->db);
 | |
|         db_copied= true;
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         thd->reset_db(&table->s->db);
 | |
|         db_copied= false;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     ~Db_restore_ctx()
 | |
|     {
 | |
|       if (db_copied)
 | |
|         thd->set_db(&null_clex_str);
 | |
|       thd->reset_db(&restore_db);
 | |
|     }
 | |
| 
 | |
|     friend class Rows_log_event;
 | |
|   };
 | |
| 
 | |
|   int find_key(); // Find a best key to use in find_row()
 | |
|   int find_row(rpl_group_info *);
 | |
|   int write_row(rpl_group_info *, const bool);
 | |
|   int update_sequence();
 | |
| 
 | |
|   // Unpack the current row into m_table->record[0], but with
 | |
|   // a different columns bitmap.
 | |
|   int unpack_current_row(rpl_group_info *rgi, MY_BITMAP const *cols)
 | |
|   {
 | |
|     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, cols,
 | |
|                                    &m_curr_row_end, &m_master_reclength, m_rows_end);
 | |
|   }
 | |
| 
 | |
|   // 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);
 | |
|   }
 | |
|   bool process_triggers(trg_event_type event,
 | |
|                         trg_action_time_type time_type,
 | |
|                         bool old_row_is_record1);
 | |
| 
 | |
|   /**
 | |
|     Helper function to check whether there is an auto increment
 | |
|     column on the table where the event is to be applied.
 | |
| 
 | |
|     @return true if there is an autoincrement field on the extra
 | |
|             columns, false otherwise.
 | |
|    */
 | |
|   inline bool is_auto_inc_in_extra_columns()
 | |
|   {
 | |
|     DBUG_ASSERT(m_table);
 | |
|     return (m_table->next_number_field &&
 | |
|             m_table->next_number_field->field_index >= m_width);
 | |
|   }
 | |
| #endif
 | |
| 
 | |
| private:
 | |
| 
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
|   int do_update_pos(rpl_group_info *rgi) override;
 | |
|   enum_skip_reason do_shall_skip(rpl_group_info *rgi) override;
 | |
| 
 | |
|   /*
 | |
|     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 *rli) = 0;
 | |
| #endif /* defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) */
 | |
| 
 | |
|   friend class Old_rows_log_event;
 | |
| };
 | |
| 
 | |
| /**
 | |
|   @class Write_rows_log_event
 | |
| 
 | |
|   Log row insertions and updates. The event contain several
 | |
|   insert/update rows for a table. Note that each event contains only
 | |
|   rows for one table.
 | |
| 
 | |
|   @section Write_rows_log_event_binary_format Binary Format
 | |
| */
 | |
| class Write_rows_log_event : public Rows_log_event
 | |
| {
 | |
| public:
 | |
|   enum 
 | |
|   {
 | |
|     /* Support interface to THD::binlog_prepare_pending_rows_event */
 | |
|     TYPE_CODE = WRITE_ROWS_EVENT
 | |
|   };
 | |
| 
 | |
| #if defined(MYSQL_SERVER)
 | |
|   Write_rows_log_event(THD*, TABLE*, ulonglong table_id,
 | |
|                        bool is_transactional);
 | |
| #endif
 | |
| #ifdef HAVE_REPLICATION
 | |
|   Write_rows_log_event(const uchar *buf, uint event_len,
 | |
|                        const Format_description_log_event *description_event);
 | |
| #endif
 | |
| #if defined(MYSQL_SERVER) 
 | |
|   static bool binlog_row_logging_function(THD *thd, TABLE *table,
 | |
|                                           bool is_transactional,
 | |
|                                           const uchar *before_record
 | |
|                                           __attribute__((unused)),
 | |
|                                           const uchar *after_record)
 | |
|   {
 | |
|     DBUG_ASSERT(!table->versioned(VERS_TRX_ID));
 | |
|     return thd->binlog_write_row(table, is_transactional, after_record);
 | |
|   }
 | |
| #endif
 | |
| 
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   uint8 get_trg_event_map() override;
 | |
| #endif
 | |
| 
 | |
| private:
 | |
|   Log_event_type get_general_type_code() override { return (Log_event_type)TYPE_CODE; }
 | |
| 
 | |
| #ifdef MYSQL_CLIENT
 | |
|   bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override;
 | |
| #endif
 | |
| 
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_before_row_operations(const Slave_reporting_capability *const) override;
 | |
|   int do_after_row_operations(const Slave_reporting_capability *const,int) override;
 | |
|   int do_exec_row(rpl_group_info *) override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| class Write_rows_compressed_log_event : public Write_rows_log_event
 | |
| {
 | |
| public:
 | |
| #if defined(MYSQL_SERVER)
 | |
|   Write_rows_compressed_log_event(THD*, TABLE*, ulonglong table_id,
 | |
|                        bool is_transactional);
 | |
|   bool write() override;
 | |
| #endif
 | |
| #ifdef HAVE_REPLICATION
 | |
|   Write_rows_compressed_log_event(const uchar *buf, uint event_len,
 | |
|                        const Format_description_log_event *description_event);
 | |
| #endif
 | |
| private:
 | |
| #if defined(MYSQL_CLIENT)
 | |
|   bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| /**
 | |
|   @class Update_rows_log_event
 | |
| 
 | |
|   Log row updates with a before image. The event contain several
 | |
|   update rows for a table. Note that each event contains only rows for
 | |
|   one table.
 | |
| 
 | |
|   Also note that the row data consists of pairs of row data: one row
 | |
|   for the old data and one row for the new data.
 | |
| 
 | |
|   @section Update_rows_log_event_binary_format Binary Format
 | |
| */
 | |
| class Update_rows_log_event : public Rows_log_event
 | |
| {
 | |
| public:
 | |
|   enum 
 | |
|   {
 | |
|     /* Support interface to THD::binlog_prepare_pending_rows_event */
 | |
|     TYPE_CODE = UPDATE_ROWS_EVENT
 | |
|   };
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   Update_rows_log_event(THD*, TABLE*, ulonglong table_id,
 | |
|                         bool is_transactional);
 | |
| 
 | |
|   void init(MY_BITMAP const *cols);
 | |
| #endif
 | |
| 
 | |
|   virtual ~Update_rows_log_event();
 | |
| 
 | |
| #ifdef HAVE_REPLICATION
 | |
|   Update_rows_log_event(const uchar *buf, uint event_len,
 | |
| 			const Format_description_log_event *description_event);
 | |
| #endif
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   static bool binlog_row_logging_function(THD *thd, TABLE *table,
 | |
|                                           bool is_transactional,
 | |
|                                           const uchar *before_record,
 | |
|                                           const uchar *after_record)
 | |
|   {
 | |
|     DBUG_ASSERT(!table->versioned(VERS_TRX_ID));
 | |
|     return thd->binlog_update_row(table, is_transactional,
 | |
|                                   before_record, after_record);
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   bool is_valid() const override
 | |
|   {
 | |
|     return Rows_log_event::is_valid() && m_cols_ai.bitmap;
 | |
|   }
 | |
| 
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   uint8 get_trg_event_map() override;
 | |
| #endif
 | |
| 
 | |
| protected:
 | |
|   Log_event_type get_general_type_code() override { return (Log_event_type)TYPE_CODE; }
 | |
| 
 | |
| #ifdef MYSQL_CLIENT
 | |
|   bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override;
 | |
| #endif
 | |
| 
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_before_row_operations(const Slave_reporting_capability *const) override;
 | |
|   int do_after_row_operations(const Slave_reporting_capability *const,int) override;
 | |
|   int do_exec_row(rpl_group_info *) override;
 | |
| #endif /* defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) */
 | |
| };
 | |
| 
 | |
| class Update_rows_compressed_log_event : public Update_rows_log_event
 | |
| {
 | |
| public:
 | |
| #if defined(MYSQL_SERVER)
 | |
|   Update_rows_compressed_log_event(THD*, TABLE*, ulonglong table_id,
 | |
|                         bool is_transactional);
 | |
|   bool write() override;
 | |
| #endif
 | |
| #ifdef HAVE_REPLICATION
 | |
|   Update_rows_compressed_log_event(const uchar *buf, uint event_len,
 | |
|                        const Format_description_log_event *description_event);
 | |
| #endif
 | |
| private:
 | |
| #if defined(MYSQL_CLIENT)
 | |
|   bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| /**
 | |
|   @class Delete_rows_log_event
 | |
| 
 | |
|   Log row deletions. The event contain several delete rows for a
 | |
|   table. Note that each event contains only rows for one table.
 | |
| 
 | |
|   RESPONSIBILITIES
 | |
| 
 | |
|     - Act as a container for rows that has been deleted on the master
 | |
|       and should be deleted on the slave. 
 | |
| 
 | |
|   COLLABORATION
 | |
| 
 | |
|     Row_writer
 | |
|       Create the event and add rows to the event.
 | |
|     Row_reader
 | |
|       Extract the rows from the event.
 | |
| 
 | |
|   @section Delete_rows_log_event_binary_format Binary Format
 | |
| */
 | |
| class Delete_rows_log_event : public Rows_log_event
 | |
| {
 | |
| public:
 | |
|   enum 
 | |
|   {
 | |
|     /* Support interface to THD::binlog_prepare_pending_rows_event */
 | |
|     TYPE_CODE = DELETE_ROWS_EVENT
 | |
|   };
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
|   Delete_rows_log_event(THD*, TABLE*, ulonglong, bool is_transactional);
 | |
| #endif
 | |
| #ifdef HAVE_REPLICATION
 | |
|   Delete_rows_log_event(const uchar *buf, uint event_len,
 | |
| 			const Format_description_log_event *description_event);
 | |
| #endif
 | |
| #ifdef MYSQL_SERVER
 | |
|   static bool binlog_row_logging_function(THD *thd, TABLE *table,
 | |
|                                           bool is_transactional,
 | |
|                                           const uchar *before_record,
 | |
|                                           const uchar *after_record
 | |
|                                           __attribute__((unused)))
 | |
|   {
 | |
|     DBUG_ASSERT(!table->versioned(VERS_TRX_ID));
 | |
|     return thd->binlog_delete_row(table, is_transactional,
 | |
|                                   before_record);
 | |
|   }
 | |
| #endif
 | |
| 
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   uint8 get_trg_event_map() override;
 | |
| #endif
 | |
| 
 | |
| protected:
 | |
|   Log_event_type get_general_type_code() override { return (Log_event_type)TYPE_CODE; }
 | |
| 
 | |
| #ifdef MYSQL_CLIENT
 | |
|   bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override;
 | |
| #endif
 | |
| 
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_before_row_operations(const Slave_reporting_capability *const) override;
 | |
|   int do_after_row_operations(const Slave_reporting_capability *const,int) override;
 | |
|   int do_exec_row(rpl_group_info *) override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| class Delete_rows_compressed_log_event : public Delete_rows_log_event
 | |
| {
 | |
| public:
 | |
| #if defined(MYSQL_SERVER)
 | |
|   Delete_rows_compressed_log_event(THD*, TABLE*, ulonglong,
 | |
|                                    bool is_transactional);
 | |
|   bool write() override;
 | |
| #endif
 | |
| #ifdef HAVE_REPLICATION
 | |
|   Delete_rows_compressed_log_event(const uchar *buf, uint event_len,
 | |
|                        const Format_description_log_event *description_event);
 | |
| #endif
 | |
| private:
 | |
| #if defined(MYSQL_CLIENT)
 | |
|   bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| #include "log_event_old.h"
 | |
| 
 | |
| /**
 | |
|   @class Incident_log_event
 | |
| 
 | |
|    Class representing an incident, an occurence out of the ordinary,
 | |
|    that happened on the master.
 | |
| 
 | |
|    The event is used to inform the slave that something out of the
 | |
|    ordinary happened on the master that might cause the database to be
 | |
|    in an inconsistent state.
 | |
| 
 | |
|    <table id="IncidentFormat">
 | |
|    <caption>Incident event format</caption>
 | |
|    <tr>
 | |
|      <th>Symbol</th>
 | |
|      <th>Format</th>
 | |
|      <th>Description</th>
 | |
|    </tr>
 | |
|    <tr>
 | |
|      <td>INCIDENT</td>
 | |
|      <td align="right">2</td>
 | |
|      <td>Incident number as an unsigned integer</td>
 | |
|    </tr>
 | |
|    <tr>
 | |
|      <td>MSGLEN</td>
 | |
|      <td align="right">1</td>
 | |
|      <td>Message length as an unsigned integer</td>
 | |
|    </tr>
 | |
|    <tr>
 | |
|      <td>MESSAGE</td>
 | |
|      <td align="right">MSGLEN</td>
 | |
|      <td>The message, if present. Not null terminated.</td>
 | |
|    </tr>
 | |
|    </table>
 | |
| 
 | |
|   @section Delete_rows_log_event_binary_format Binary Format
 | |
| */
 | |
| class Incident_log_event : public Log_event {
 | |
| public:
 | |
| #ifdef MYSQL_SERVER
 | |
|   Incident_log_event(THD *thd_arg, Incident incident)
 | |
|     : Log_event(thd_arg, 0, FALSE), m_incident(incident)
 | |
|   {
 | |
|     DBUG_ENTER("Incident_log_event::Incident_log_event");
 | |
|     DBUG_PRINT("enter", ("m_incident: %d", m_incident));
 | |
|     m_message.str= NULL;                    /* Just as a precaution */
 | |
|     m_message.length= 0;
 | |
|     set_direct_logging();
 | |
|     /* Replicate the incident regardless of @@skip_replication. */
 | |
|     flags&= ~LOG_EVENT_SKIP_REPLICATION_F;
 | |
|     DBUG_VOID_RETURN;
 | |
|   }
 | |
| 
 | |
|   Incident_log_event(THD *thd_arg, Incident incident, const LEX_CSTRING *msg)
 | |
|     : Log_event(thd_arg, 0, FALSE), m_incident(incident)
 | |
|   {
 | |
|     extern PSI_memory_key key_memory_Incident_log_event_message;
 | |
|     DBUG_ENTER("Incident_log_event::Incident_log_event");
 | |
|     DBUG_PRINT("enter", ("m_incident: %d", m_incident));
 | |
|     m_message.length= 0;
 | |
|     if (!(m_message.str= (char*) my_malloc(key_memory_Incident_log_event_message,
 | |
|                                            msg->length + 1, MYF(MY_WME))))
 | |
|     {
 | |
|       /* Mark this event invalid */
 | |
|       m_incident= INCIDENT_NONE;
 | |
|       DBUG_VOID_RETURN;
 | |
|     }
 | |
|     strmake(m_message.str, msg->str, msg->length);
 | |
|     m_message.length= msg->length;
 | |
|     set_direct_logging();
 | |
|     /* Replicate the incident regardless of @@skip_replication. */
 | |
|     flags&= ~LOG_EVENT_SKIP_REPLICATION_F;
 | |
|     DBUG_VOID_RETURN;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
| #ifdef HAVE_REPLICATION
 | |
|   void pack_info(Protocol*) override;
 | |
| #endif
 | |
|   bool write_data_header() override;
 | |
|   bool write_data_body() override;
 | |
| #endif
 | |
| 
 | |
|   Incident_log_event(const uchar *buf, uint event_len,
 | |
|                      const Format_description_log_event *descr_event);
 | |
| 
 | |
|   virtual ~Incident_log_event();
 | |
| 
 | |
| #ifdef MYSQL_CLIENT
 | |
|   bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override;
 | |
| #endif
 | |
| 
 | |
| #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 | |
|   int do_apply_event(rpl_group_info *rgi) override;
 | |
| #endif
 | |
| 
 | |
|   Log_event_type get_type_code() override { return INCIDENT_EVENT; }
 | |
| 
 | |
|   bool is_valid() const override
 | |
|   {
 | |
|     return m_incident > INCIDENT_NONE && m_incident < INCIDENT_COUNT;
 | |
|   }
 | |
|   int get_data_size() override {
 | |
|     return INCIDENT_HEADER_LEN + 1 + (uint) m_message.length;
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   const char *description() const;
 | |
| 
 | |
|   Incident m_incident;
 | |
|   LEX_STRING m_message;
 | |
| };
 | |
| 
 | |
| /**
 | |
|   @class Ignorable_log_event
 | |
| 
 | |
|   Base class for ignorable log events. Events deriving from
 | |
|   this class can be safely ignored by slaves that cannot
 | |
|   recognize them. Newer slaves, will be able to read and
 | |
|   handle them. This has been designed to be an open-ended
 | |
|   architecture, so adding new derived events shall not harm
 | |
|   the old slaves that support ignorable log event mechanism
 | |
|   (they will just ignore unrecognized ignorable events).
 | |
| 
 | |
|   @note The only thing that makes an event ignorable is that it has
 | |
|   the LOG_EVENT_IGNORABLE_F flag set.  It is not strictly necessary
 | |
|   that ignorable event types derive from Ignorable_log_event; they may
 | |
|   just as well derive from Log_event and pass LOG_EVENT_IGNORABLE_F as
 | |
|   argument to the Log_event constructor.
 | |
| **/
 | |
| 
 | |
| class Ignorable_log_event : public Log_event {
 | |
| public:
 | |
|   int number;
 | |
|   const char *description;
 | |
| 
 | |
| #ifndef MYSQL_CLIENT
 | |
|   Ignorable_log_event(THD *thd_arg)
 | |
|     :Log_event(thd_arg, LOG_EVENT_IGNORABLE_F, FALSE),
 | |
|     number(0), description("internal")
 | |
|   {
 | |
|     DBUG_ENTER("Ignorable_log_event::Ignorable_log_event");
 | |
|     DBUG_VOID_RETURN;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   Ignorable_log_event(const uchar *buf,
 | |
|                       const Format_description_log_event *descr_event,
 | |
|                       const char *event_name);
 | |
|   virtual ~Ignorable_log_event();
 | |
| 
 | |
| #ifndef MYSQL_CLIENT
 | |
| #ifdef HAVE_REPLICATION
 | |
|    void pack_info(Protocol*) override;
 | |
| #endif
 | |
| #else
 | |
|   bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override;
 | |
| #endif
 | |
| 
 | |
|   Log_event_type get_type_code() override { return IGNORABLE_LOG_EVENT; }
 | |
| 
 | |
|   bool is_valid() const override { return 1; }
 | |
| 
 | |
|   int get_data_size() override { return IGNORABLE_HEADER_LEN; }
 | |
| };
 | |
| 
 | |
| #ifdef MYSQL_CLIENT
 | |
| bool copy_cache_to_string_wrapped(IO_CACHE *body,
 | |
|                                   LEX_STRING *to,
 | |
|                                   bool do_wrap,
 | |
|                                   const char *delimiter,
 | |
|                                   bool is_verbose);
 | |
| bool copy_cache_to_file_wrapped(IO_CACHE *body,
 | |
|                                 FILE *file,
 | |
|                                 bool do_wrap,
 | |
|                                 const char *delimiter,
 | |
|                                 bool is_verbose);
 | |
| #endif
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
| /*****************************************************************************
 | |
| 
 | |
|   Heartbeat Log Event class
 | |
| 
 | |
|   Replication event to ensure to slave that master is alive.
 | |
|   The event is originated by master's dump thread and sent straight to
 | |
|   slave without being logged. Slave itself does not store it in relay log
 | |
|   but rather uses a data for immediate checks and throws away the event.
 | |
| 
 | |
|   Two members of the class log_ident and Log_event::log_pos comprise 
 | |
|   @see the event_coordinates instance. The coordinates that a heartbeat
 | |
|   instance carries correspond to the last event master has sent from
 | |
|   its binlog.
 | |
| 
 | |
|  ****************************************************************************/
 | |
| class Heartbeat_log_event: public Log_event
 | |
| {
 | |
| public:
 | |
|   uint8 hb_flags;
 | |
|   Heartbeat_log_event(const uchar *buf, uint event_len,
 | |
|                       const Format_description_log_event* description_event);
 | |
|   Log_event_type get_type_code() override { return HEARTBEAT_LOG_EVENT; }
 | |
|   bool is_valid() const override
 | |
|     {
 | |
|       return (log_ident != NULL && ident_len <= FN_REFLEN-1 &&
 | |
|               log_pos >= BIN_LOG_HEADER_SIZE);
 | |
|     }
 | |
|   const uchar * get_log_ident() { return log_ident; }
 | |
|   uint get_ident_len() { return ident_len; }
 | |
|   
 | |
| private:
 | |
|   uint ident_len;
 | |
|   const uchar *log_ident;
 | |
| };
 | |
| 
 | |
| inline int Log_event_writer::write(Log_event *ev)
 | |
| {
 | |
|   ev->writer= this;
 | |
|   int res= ev->write();
 | |
|   IF_DBUG(ev->writer= 0,); // writer must be set before every Log_event::write
 | |
|   add_status(ev->logged_status());
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| /**
 | |
|    The function is called by slave applier in case there are
 | |
|    active table filtering rules to force gathering events associated
 | |
|    with Query-log-event into an array to execute
 | |
|    them once the fate of the Query is determined for execution.
 | |
| */
 | |
| bool slave_execute_deferred_events(THD *thd);
 | |
| #endif
 | |
| 
 | |
| bool event_that_should_be_ignored(const uchar *buf);
 | |
| bool event_checksum_test(uchar *buf, ulong event_len,
 | |
|                          enum_binlog_checksum_alg alg);
 | |
| enum enum_binlog_checksum_alg get_checksum_alg(const uchar *buf, ulong len);
 | |
| extern TYPELIB binlog_checksum_typelib;
 | |
| #ifdef WITH_WSREP
 | |
| enum Log_event_type wsrep_peak_event(rpl_group_info *rgi, ulonglong* event_size);
 | |
| #endif /* WITH_WSREP */
 | |
| 
 | |
| /**
 | |
|   @} (end of group Replication)
 | |
| */
 | |
| 
 | |
| 
 | |
| int binlog_buf_compress(const uchar *src, uchar *dst, uint32 len,
 | |
|                         uint32 *comlen);
 | |
| int binlog_buf_uncompress(const uchar *src, uchar *dst, uint32 len,
 | |
|                           uint32 *newlen);
 | |
| uint32 binlog_get_compress_len(uint32 len);
 | |
| uint32 binlog_get_uncompress_len(const uchar *buf);
 | |
| 
 | |
| int query_event_uncompress(const Format_description_log_event *description_event,
 | |
|                            bool contain_checksum,
 | |
|                            const uchar *src, ulong src_len, uchar *buf,
 | |
|                            ulong buf_size, bool* is_malloc,
 | |
|                            uchar **dst, ulong *newlen);
 | |
| int row_log_event_uncompress(const Format_description_log_event
 | |
|                              *description_event,
 | |
|                              bool contain_checksum,
 | |
|                              const uchar *src, ulong src_len,
 | |
|                              uchar* buf, ulong buf_size, bool *is_malloc,
 | |
|                              uchar **dst, ulong *newlen);
 | |
| 
 | |
| bool is_parallel_retry_error(rpl_group_info *rgi, int err);
 | |
| 
 | |
| /*
 | |
|   Compares two GTIDs to facilitate sorting a GTID list log event by domain id
 | |
|   (ascending) and sequence number (ascending)
 | |
| */
 | |
| int compare_glle_gtids(const void * _gtid1, const void *_gtid2);
 | |
| 
 | |
| #endif /* _log_event_h */
 | 
