From be088c54b46e907bd453da2b3bb7af19ead67b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Mon, 16 Dec 2019 11:07:14 +0200 Subject: [PATCH] Add LOAD DATA INFILE support The events are similar to normal query events except that they have an extra 13 bytes of static data. This data is of no relevance to Maxscale and thus can be ignored. This also allows the reuse of the same query event code for execute load query events. --- .../filter/binlogfilter/binlogfiltersession.cc | 17 ++++++++++++----- .../filter/binlogfilter/binlogfiltersession.hh | 6 ++++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/server/modules/filter/binlogfilter/binlogfiltersession.cc b/server/modules/filter/binlogfilter/binlogfiltersession.cc index 33cac4618..08770dc6b 100644 --- a/server/modules/filter/binlogfilter/binlogfiltersession.cc +++ b/server/modules/filter/binlogfilter/binlogfiltersession.cc @@ -303,6 +303,7 @@ bool BinlogFilterSession::checkEvent(GWBUF** buffer, const REP_HEADER& hdr) } else { + int extra_bytes = 0; // Current event size is less than MYSQL_PACKET_LENGTH_MAX // or is the beginning of large event. switch (hdr.event_type) @@ -342,9 +343,14 @@ bool BinlogFilterSession::checkEvent(GWBUF** buffer, const REP_HEADER& hdr) skipDatabaseTable(body); break; + case EXECUTE_LOAD_QUERY_EVENT: + // EXECUTE_LOAD_QUERY_EVENT has an extra 13 bytes of data (file ID, file offset etc.) + extra_bytes = 4 + 4 + 4 + 1; + /** Fallthrough */ + case QUERY_EVENT: // Handle the SQL statement: DDL, DML, BEGIN, COMMIT - checkStatement(buffer, hdr); + checkStatement(buffer, hdr, extra_bytes); // checkStatement can reallocate the buffer in case the size changes: use fresh pointers fixEvent(GWBUF_DATA(*buffer) + MYSQL_HEADER_LEN + 1, @@ -828,10 +834,11 @@ void BinlogFilterSession::handleEventData(uint32_t len) * This function checks whether the statement should be replicated and whether the database/table name should * be rewritten. If a rewrite takes place, the buffer can be reallocated. * - * @param bufer Pointer to the buffer containing the event - * @param hdr The extracted replication header + * @param bufer Pointer to the buffer containing the event + * @param hdr The extracted replication header + * @param extra_len Extra static bytes that this event has (only EXECUTE_LOAD_QUERY_EVENT uses it) */ -void BinlogFilterSession::checkStatement(GWBUF** buffer, const REP_HEADER& hdr) +void BinlogFilterSession::checkStatement(GWBUF** buffer, const REP_HEADER& hdr, int extra_len) { uint8_t* event = GWBUF_DATA(*buffer) + MYSQL_HEADER_LEN + 1 + BINLOG_EVENT_HDR_LEN; uint32_t event_size = hdr.event_size - BINLOG_EVENT_HDR_LEN; @@ -839,7 +846,7 @@ void BinlogFilterSession::checkStatement(GWBUF** buffer, const REP_HEADER& hdr) int db_name_len = event[4 + 4]; int var_block_len_offset = 4 + 4 + 1 + 2; int var_block_len = gw_mysql_get_byte2(event + var_block_len_offset); - int static_size = 4 + 4 + 1 + 2 + 2; + int static_size = 4 + 4 + 1 + 2 + 2 + extra_len; int statement_len = event_size - static_size - var_block_len - db_name_len - 1 - (m_crc ? 4 : 0); std::string db((char*)event + static_size + var_block_len, db_name_len); diff --git a/server/modules/filter/binlogfilter/binlogfiltersession.hh b/server/modules/filter/binlogfilter/binlogfiltersession.hh index acd386107..2b53ca2e0 100644 --- a/server/modules/filter/binlogfilter/binlogfiltersession.hh +++ b/server/modules/filter/binlogfilter/binlogfiltersession.hh @@ -22,6 +22,8 @@ #define RAND_EVENT 0x000D #define TABLE_MAP_EVENT 0x0013 #define XID_EVENT 0x0010 +#define BEGIN_LOAD_QUERY_EVENT 0x0011 +#define EXECUTE_LOAD_QUERY_EVENT 0x0012 #define QUERY_EVENT 0x0002 #define MARIADB10_GTID_EVENT 0x00a2 #define MARIADB_ANNOTATE_ROWS_EVENT 0x00a0 @@ -99,8 +101,8 @@ private: // Handle event data void handleEventData(uint32_t len); - // Check SQL statement in QUERY_EVENT - void checkStatement(GWBUF** buffer, const REP_HEADER& hdr); + // Check SQL statement in QUERY_EVENT or EXECUTE_LOAD_QUERY_EVENT + void checkStatement(GWBUF** buffer, const REP_HEADER& hdr, int extra_len = 0); // Check DB.TABLE in ANNOTATE_ROWS event void checkAnnotate(const uint8_t* event,