/* Copyright (c) 2014, 2024, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is designed to work with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have either included with the program or referenced in the documentation. 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, version 2.0, 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-1301 USA */ /** @file load_data_events.h @brief LOAD DATA INFILE is not written to the binary log like other statements. It is written as one or more events in a packed format, not as a cleartext statement in the binary log. The events indicate what options are present in the statement and how to process the data file. */ #ifndef MYSQL_BINLOG_EVENT_LOAD_DATA_EVENTS_H #define MYSQL_BINLOG_EVENT_LOAD_DATA_EVENTS_H #include #include "mysql/binlog/event/statement_events.h" #include "mysql/binlog/event/table_id.h" /// @addtogroup GroupLibsMysqlBinlogEvent /// @{ /* These are flags and structs to handle all the LOAD DATA INFILE options (LINES TERMINATED etc). DUMPFILE_FLAG is probably not used (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 namespace mysql::binlog::event { /** Elements of this enum describe how LOAD DATA handles duplicates. */ enum enum_load_dup_handling { LOAD_DUP_ERROR = 0, LOAD_DUP_IGNORE, LOAD_DUP_REPLACE }; /** @class Execute_load_query_event Event responsible for LOAD DATA execution, it similar to Query_event but before executing the query it substitutes original filename in LOAD DATA query with name of temporary file. The first 13 bytes of the Post-Header for this event are the same as for Query_event, as is the initial status variable block in the Body. @section Execute_load_query_event_binary_format Binary Format The additional members of the events are the following:
Body for Execute_load_query_event
Name Format Description
file_id 4 byte unsigned integer ID of the temporary file to load
fn_pos_start 4 byte unsigned integer The start position within the statement for filename substitution
fn_pos_end 4 byte unsigned integer The end position within the statement for filename substitution
dup_handling enum_load_dup_handling Represents information on how to handle duplicates: LOAD_DUP_ERROR= 0, LOAD_DUP_IGNORE= 1, LOAD_DUP_REPLACE= 2
*/ class Execute_load_query_event : public virtual Query_event { public: enum Execute_load_query_event_offset { /** ELQ = "Execute Load Query" */ ELQ_FILE_ID_OFFSET = QUERY_HEADER_LEN, ELQ_FN_POS_START_OFFSET = ELQ_FILE_ID_OFFSET + 4, ELQ_FN_POS_END_OFFSET = ELQ_FILE_ID_OFFSET + 8, ELQ_DUP_HANDLING_OFFSET = ELQ_FILE_ID_OFFSET + 12 }; int32_t file_id; /** file_id of temporary file */ uint32_t fn_pos_start; /** pointer to the part of the query that should be substituted */ uint32_t 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; Execute_load_query_event(uint32_t file_id_arg, uint32_t fn_pos_start, uint32_t fn_pos_end, enum_load_dup_handling dup); /** The constructor receives a buffer and instantiates a Execute_load_query_event filled in with the data from the buffer.
    The fixed event data part buffer layout is as follows:
    +---------------------------------------------------------------------+
    | thread_id | query_exec_time | db_len | error_code | status_vars_len |
    +---------------------------------------------------------------------+
    +----------------------------------------------------+
    | file_id | fn_pos_start | fn_pos_end | dup_handling |
    +----------------------------------------------------+
    
    The fixed event data part buffer layout is as follows:
    +------------------------------------------------------------------+
    | Zero or more status variables | db |  LOAD DATA INFILE statement |
    +------------------------------------------------------------------+
    
@param buf Contains the serialized event. @param fde An FDE event (see Rotate_event constructor for more info). */ Execute_load_query_event(const char *buf, const Format_description_event *fde); ~Execute_load_query_event() override = default; }; /** @class Delete_file_event DELETE_FILE_EVENT occurs when the LOAD DATA failed on the master. This event notifies the slave not to do the load and to delete the temporary file. @section Delete_file_event_binary_format Binary Format The variable data part is empty. The post header contains the following:
Post header for Delete_file_event
Name Format Description
file_id 32 bit integer The ID of the file to be deleted
*/ class Delete_file_event : public Binary_log_event { protected: // Required by Delete_file_log_event(THD* ..) Delete_file_event(uint32_t file_id_arg, const char *db_arg) : Binary_log_event(DELETE_FILE_EVENT), file_id(file_id_arg), db(db_arg) {} public: enum Delete_file_offset { /** DF = "Delete File" */ DF_FILE_ID_OFFSET = 0 }; uint32_t file_id; const char *db; /** see comment in Append_block_event */ /** The buffer layout for fixed data part is as follows:
    +---------+
    | file_id |
    +---------+
    
@param buf Contains the serialized event. @param fde An FDE event (see Rotate_event constructor for more info). */ Delete_file_event(const char *buf, const Format_description_event *fde); ~Delete_file_event() override = default; #ifndef HAVE_MYSYS // TODO(WL#7684): Implement the method print_event_info and print_long_info // for // all the events supported in MySQL Binlog void print_event_info(std::ostream &) override {} void print_long_info(std::ostream &) override {} #endif }; /** @class Append_block_event This event is created to contain the file data. One LOAD_DATA_INFILE can have 0 or more instances of this event written to the binary log depending on the size of the file. If the file to be loaded is greater than the threshold value, which is roughly 2^17 bytes, the file is divided into blocks of size equal to the threshold, and each block is sent across as a separate event. @section Append_block_event_binary_format Binary Format The post header contains the following:
Post header for Append_block_event
Name Format Description
file_id 32 bit integer The ID of the file to append the block to
The body of the event contains the raw data to load. The raw data size is the event size minus the size of all the fixed event parts. */ class Append_block_event : public Binary_log_event { protected: /** This constructor is used by the MySQL server. */ Append_block_event(const char *db_arg, unsigned char *block_arg, unsigned int block_len_arg, uint32_t file_id_arg) : Binary_log_event(APPEND_BLOCK_EVENT), block(block_arg), block_len(block_len_arg), file_id(file_id_arg), db(db_arg) {} Append_block_event(Log_event_type type_arg = APPEND_BLOCK_EVENT) : Binary_log_event(type_arg) {} public: enum Append_block_offset { /** AB = "Append Block" */ AB_FILE_ID_OFFSET = 0, AB_DATA_OFFSET = APPEND_BLOCK_HEADER_LEN }; unsigned char *block; unsigned int block_len; uint32_t 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_event(const char* buf, int event_len) constructor. In other words, 'db' is used only for filtering by binlog-*-db rules. Create_file_event is different: it's 'db' (which is inherited from Load_event) is written to the binlog and can be re-read. */ const char *db; /** Appends the buffered data, received as a parameter, to the file being loaded via LOAD_DATA_FILE. The buffer layout for fixed data part is as follows:
    +---------+
    | file_id |
    +---------+
    
The buffer layout for variable data part is as follows:
    +-------------------+
    | block | block_len |
    +-------------------+
    
@param buf Contains the serialized event. @param fde An FDE event (see Rotate_event constructor for more info). */ Append_block_event(const char *buf, const Format_description_event *fde); ~Append_block_event() override = default; #ifndef HAVE_MYSYS // TODO(WL#7684): Implement the method print_event_info and print_long_info // for // all the events supported in MySQL Binlog void print_event_info(std::ostream &) override {} void print_long_info(std::ostream &) override {} #endif }; /** @class Begin_load_query_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_event_binary_format Binary Format The Post-Header and Body for this event type are empty; it only has the Common-Header. */ class Begin_load_query_event : public virtual Append_block_event { protected: Begin_load_query_event() : Append_block_event(BEGIN_LOAD_QUERY_EVENT) {} public: /** The buffer layout for fixed data part is as follows:
    +---------+
    | file_id |
    +---------+
    
The buffer layout for variable data part is as follows:
    +-------------------+
    | block | block_len |
    +-------------------+
    
@param buf Contains the serialized event. @param fde An FDE event (see Rotate_event constructor for more info). */ Begin_load_query_event(const char *buf, const Format_description_event *fde); ~Begin_load_query_event() override = default; #ifndef HAVE_MYSYS // TODO(WL#7684): Implement the method print_event_info and print_long_info // for // all the events supported in MySQL Binlog void print_event_info(std::ostream &) override {} void print_long_info(std::ostream &) override {} #endif }; } // end namespace mysql::binlog::event /// @} #endif // MYSQL_BINLOG_EVENT_LOAD_DATA_EVENTS_H