├── tests ├── t │ ├── replication_listener-master.opt │ ├── binlog_file_reader.test │ └── sys_vars.test ├── std-data │ ├── searchbin.000001 │ ├── binlog_savepoint.000001 │ └── binlog_transaction.000001 ├── CMakeLists.txt ├── replay_sys_vars.cpp ├── test-basic.cpp ├── test-transport.cpp ├── r │ └── sys_vars.result └── replaybinlog.cpp ├── doc └── libreplication.odp ├── examples ├── mysql2lucene │ ├── CMakeLists.txt │ ├── globals.h │ ├── table_delete.h │ ├── table_insert.h │ ├── table_update.h │ ├── table_update.cpp │ ├── table_index.h │ ├── table_index.cpp │ ├── table_delete.cpp │ ├── table_insert.cpp │ └── main.cpp ├── CMakeLists.txt ├── basic-1.cpp └── basic-2.cpp ├── .gitignore ├── homebrew └── mysql-replication-listener.rb ├── src ├── CMakeLists.txt ├── row_of_fields.cpp ├── binlog_driver.cpp ├── binlog_event.cpp ├── binary_log.cpp ├── field_iterator.cpp ├── basic_content_handler.cpp ├── access_method_factory.cpp ├── basic_transaction_parser.cpp ├── utilities.cpp ├── file_driver.cpp └── resultset_iterator.cpp ├── include ├── access_method_factory.h ├── row_of_fields.h ├── utilities.h ├── rowset.h ├── file_driver.h ├── binlog_driver.h ├── bounded_buffer.h ├── basic_transaction_parser.h ├── basic_content_handler.h ├── binlog_api.h ├── value.h ├── resultset_iterator.h ├── field_iterator.h ├── binlog_event.h ├── tcp_driver.h └── protocol.h ├── mysql-replication-listener.spec ├── README ├── CMakeLists.txt └── COPYING /tests/t/replication_listener-master.opt: -------------------------------------------------------------------------------- 1 | --log_bin=searchbin --binlog_format=row 2 | -------------------------------------------------------------------------------- /doc/libreplication.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SponsorPay/mysql-replication-listener/HEAD/doc/libreplication.odp -------------------------------------------------------------------------------- /tests/std-data/searchbin.000001: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SponsorPay/mysql-replication-listener/HEAD/tests/std-data/searchbin.000001 -------------------------------------------------------------------------------- /tests/std-data/binlog_savepoint.000001: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SponsorPay/mysql-replication-listener/HEAD/tests/std-data/binlog_savepoint.000001 -------------------------------------------------------------------------------- /tests/std-data/binlog_transaction.000001: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SponsorPay/mysql-replication-listener/HEAD/tests/std-data/binlog_transaction.000001 -------------------------------------------------------------------------------- /examples/mysql2lucene/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project (mysql2lucene) 2 | 3 | find_package(CLucene) 4 | 5 | add_executable(mysql2lucene 6 | main.cpp table_delete.cpp table_index.cpp 7 | table_insert.cpp table_update.cpp) 8 | include_directories(${CLUCENE_INCLUDE_DIR} ${CLUCENE_LIBRARY_DIR}) 9 | target_link_libraries(mysql2lucene ${CLUCENE_LIBRARY} replication_static) 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | CMakeCache.txt 3 | CMakeFiles 4 | CMakeFiles/* 5 | CPackConfig.cmake 6 | CPackSourceConfig.cmake 7 | CTestTestfile.cmake 8 | Makefile 9 | _CPack_Packages 10 | cmake_install.cmake 11 | install_manifest.txt 12 | lib/* 13 | source_downloads 14 | tags 15 | tests/mysql2lucene/mysql2lucene 16 | tests/replay_sys_vars 17 | tests/replaybinlog 18 | tests/test-basic 19 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(examples) 2 | 3 | link_directories(${PROJECT_BUILD_DIR}/lib) 4 | include_directories(${PROJECT_BUILD_DIR}/include) 5 | 6 | # Create build rules for all the simple examples that only require a 7 | # single file. 8 | foreach(prog basic-1 basic-2) 9 | ADD_EXECUTABLE(${prog} ${prog}.cpp) 10 | TARGET_LINK_LIBRARIES(${prog} replication) 11 | endforeach() 12 | 13 | add_subdirectory(mysql2lucene EXCLUDE_FROM_ALL) 14 | -------------------------------------------------------------------------------- /homebrew/mysql-replication-listener.rb: -------------------------------------------------------------------------------- 1 | require 'formula' 2 | 3 | class MysqlReplicationListener < Formula 4 | url 'https://github.com/SponsorPay/mysql-replication-listener.git' 5 | homepage 'https://github.com/SponsorPay/mysql-replication-listener' 6 | 7 | depends_on 'cmake' 8 | depends_on 'boost' 9 | #depends_on 'openssl' 10 | 11 | def install 12 | system 'cmake', "-DCMAKE_INSTALL_PREFIX:PATH=#{prefix}", '.' 13 | system 'make' 14 | system 'make install' 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /tests/t/binlog_file_reader.test: -------------------------------------------------------------------------------- 1 | -- source include/not_embedded.inc 2 | let $REPLICATION_LISTENER=""; 3 | let $SAMPLE_BINLOG_FILES_DIR=""; 4 | 5 | --echo # 6 | --echo # Reading binlogs files. 7 | --echo # 8 | --exec $REPLICATION_LISTENER file://$SAMPLE_BINLOG_FILES_DIR/searchbin.000001 9 | --exec $REPLICATION_LISTENER file://$SAMPLE_BINLOG_FILES_DIR/binlog_transaction.000001 10 | --exec $REPLICATION_LISTENER file://$SAMPLE_BINLOG_FILES_DIR/binlog_savepoint.000001 11 | 12 | --echo # End of test 13 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Right now, the tests are built using the static version of the 2 | # replication listener, but we need to decide which one to use. 3 | 4 | set(MySQL_SERVER_TESTS test-basic) 5 | set(MySQL_BINLOG_TESTS replaybinlog replay_sys_vars) 6 | set(MySQL_SIMPLE_TESTS test-transport) 7 | 8 | foreach(test ${MySQL_BINLOG_TESTS} ${MySQL_SERVER_TESTS} ${MySQL_SIMPLE_TESTS}) 9 | message("Adding test ${test}") 10 | add_executable(${test} ${test}.cpp) 11 | target_link_libraries(${test} replication_static gtest) 12 | endforeach() 13 | 14 | if(WITH_SERVER_TESTS) 15 | add_test(ServerTests ${MySQL_SERVER_TESTS}) 16 | endif(WITH_SERVER_TESTS) 17 | add_test(BasicTests ${MySQL_SIMPLE_TESTS}) 18 | add_test(BinlogTests ${MySQL_BINLOG_TESTS}) 19 | 20 | -------------------------------------------------------------------------------- /examples/basic-1.cpp: -------------------------------------------------------------------------------- 1 | #include "binlog_api.h" 2 | 3 | /** 4 | @file basic-1 5 | @author Mats Kindahl 6 | 7 | This is a basic example that just opens a binary log either from a 8 | file or a server and print out what events are found. It uses a 9 | simple event loop and checks information in the events using a 10 | switch. 11 | */ 12 | 13 | using mysql::Binary_log; 14 | using mysql::system::create_transport; 15 | 16 | int main(int argc, char** argv) { 17 | 18 | if (argc != 2) { 19 | std::cerr << "Usage: basic-2 " << std::endl; 20 | exit(2); 21 | } 22 | 23 | Binary_log binlog(create_transport(argv[1])); 24 | binlog.connect(); 25 | 26 | Binary_log_event *event; 27 | 28 | while (true) { 29 | int result = binlog.wait_for_next_event(&event); 30 | if (result == ERR_EOF) 31 | break; 32 | std::cout << "Found event of type " 33 | << event->get_event_type() 34 | << std::endl; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/mysql2lucene/globals.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | /* 22 | * File: globals.h 23 | * Author: thek 24 | * 25 | * Created on den 15 juni 2010, 09:37 26 | */ 27 | 28 | #ifndef _GLOBALS_H 29 | #define _GLOBALS_H 30 | #include 31 | #include "binlog_api.h" 32 | extern std::string cl_index_file; 33 | 34 | #endif /* _GLOBALS_H */ 35 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This configuration file builds both the static and shared version of 2 | # the library. 3 | set(replication_sources 4 | access_method_factory.cpp field_iterator.cpp row_of_fields.cpp 5 | binlog_driver.cpp basic_transaction_parser.cpp tcp_driver.cpp 6 | file_driver.cpp binary_log.cpp protocol.cpp value.cpp binlog_event.cpp 7 | resultset_iterator.cpp basic_transaction_parser.cpp 8 | basic_content_handler.cpp utilities.cpp) 9 | 10 | # Configure for building static library 11 | add_library(replication_static STATIC ${replication_sources}) 12 | target_link_libraries(replication_static crypto ${Boost_LIBRARIES}) 13 | set_target_properties(replication_static PROPERTIES 14 | OUTPUT_NAME "replication") 15 | 16 | # Configure for building shared library 17 | add_library(replication_shared SHARED ${replication_sources}) 18 | target_link_libraries(replication_shared crypto ${Boost_LIBRARIES}) 19 | 20 | set_target_properties(replication_shared PROPERTIES 21 | VERSION 0.1 SOVERSION 1 22 | OUTPUT_NAME "replication") 23 | 24 | install(TARGETS replication_shared LIBRARY DESTINATION lib) 25 | install(TARGETS replication_static ARCHIVE DESTINATION lib) 26 | -------------------------------------------------------------------------------- /examples/mysql2lucene/table_delete.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | /* 22 | * File: table_delete.h 23 | * Author: thek 24 | * 25 | * Created on den 17 juni 2010, 14:28 26 | */ 27 | 28 | #ifndef _TABLE_DELETE_H 29 | #define _TABLE_DELETE_H 30 | #include 31 | #include "binlog_api.h" 32 | 33 | void table_delete(std::string table_name, mysql::Row_of_fields &fields); 34 | 35 | #endif /* _TABLE_DELETE_H */ 36 | -------------------------------------------------------------------------------- /examples/mysql2lucene/table_insert.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | /* 22 | * File: table_insert.h 23 | * Author: thek 24 | * 25 | * Created on den 15 juni 2010, 09:34 26 | */ 27 | 28 | #ifndef _TABLE_INSERT_H 29 | #define _TABLE_INSERT_H 30 | 31 | #include 32 | #include "binlog_api.h" 33 | 34 | void table_insert(std::string table_name, mysql::Row_of_fields &fields); 35 | 36 | #endif /* _TABLE_INSERT_H */ 37 | -------------------------------------------------------------------------------- /examples/mysql2lucene/table_update.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | /* 22 | * File: table_update.h 23 | * Author: thek 24 | * 25 | * Created on den 17 juni 2010, 14:27 26 | */ 27 | 28 | #ifndef _TABLE_UPDATE_H 29 | #define _TABLE_UPDATE_H 30 | #include 31 | #include "binlog_api.h" 32 | void table_update(std::string table_name, mysql::Row_of_fields &old_fields, mysql::Row_of_fields &new_fields); 33 | 34 | #endif /* _TABLE_UPDATE_H */ 35 | -------------------------------------------------------------------------------- /tests/t/sys_vars.test: -------------------------------------------------------------------------------- 1 | # This test should work in embedded server after we fix mysqltest 2 | -- source include/not_embedded.inc 3 | 4 | let $REPLICATION_LISTENER="/home/nirbhay/Project/mysql/repo/worklogs/3283/sys-vars/tests/replay_sys_vars"; 5 | 6 | DROP DATABASE IF EXISTS `sys_var`; 7 | CREATE DATABASE `sys_var`; 8 | USE `sys_var`; 9 | 10 | CREATE TABLE t1 (c1 CHAR(3), c2 CHAR(1) DEFAULT 'a'); 11 | INSERT INTO t1 (c1) VALUES ('a'),('bb'),('ccc'); 12 | UPDATE t1 SET c1='aaaa' WHERE c1='a'; 13 | DELETE FROM t1; 14 | DROP TABLE t1; 15 | 16 | SET @@auto_increment_increment=19; 17 | SET @@auto_increment_offset=4; 18 | SET @@character_set_client='latin2'; 19 | SET @@collation_connection='latin2_bin'; 20 | SET @@collation_server='geostd8_general_ci'; 21 | SET @@time_zone='Japan'; 22 | SET @@lc_time_names='sv_SE'; 23 | SET @@collation_database='geostd8_bin'; 24 | 25 | CREATE TABLE t1 (c1 DATE); 26 | INSERT INTO t1 VALUES ('2006-01-01'); 27 | SELECT c1 FROM t1; 28 | DROP TABLE t1; 29 | 30 | CREATE TABLE t1 (c1 INT AUTO_INCREMENT PRIMARY KEY, c2 TEXT); 31 | INSERT INTO t1 (c1) VALUES ('a'),('bb'),('ccc'); 32 | SELECT * FROM t1; 33 | DROP TABLE t1; 34 | 35 | DROP DATABASE `sys_var`; 36 | 37 | --exec $REPLICATION_LISTENER 38 | 39 | --echo "#End of binary log" 40 | -------------------------------------------------------------------------------- /examples/mysql2lucene/table_update.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #include "table_update.h" 22 | #include "table_insert.h" 23 | #include "table_delete.h" 24 | 25 | void table_update(std::string table_name, mysql::Row_of_fields &old_fields, mysql::Row_of_fields &new_fields) 26 | { 27 | /* 28 | Find previous entry and delete it. 29 | */ 30 | table_delete(table_name, old_fields); 31 | 32 | /* 33 | Insert new entry. 34 | */ 35 | table_insert(table_name, new_fields); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /include/access_method_factory.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #ifndef _ACCESS_METHOD_FACTORY_H 22 | #define _ACCESS_METHOD_FACTORY_H 23 | 24 | #include "binlog_driver.h" 25 | 26 | namespace mysql { 27 | namespace system { 28 | Binary_log_driver *create_transport(const char *url); 29 | Binary_log_driver *parse_mysql_url(char *url, const char 30 | *mysql_access_method); 31 | Binary_log_driver *parse_file_url(char *url, const char 32 | *file_access_method); 33 | } 34 | } 35 | 36 | #endif /* _ACCESS_METHOD_FACTORY_H */ 37 | -------------------------------------------------------------------------------- /include/row_of_fields.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | #ifndef _ROW_OF_FIELDS_H 21 | #define _ROW_OF_FIELDS_H 22 | 23 | #include 24 | #include 25 | #include "value.h" 26 | using namespace mysql; 27 | 28 | namespace mysql 29 | { 30 | 31 | class Row_of_fields : public std::vector 32 | { 33 | public: 34 | Row_of_fields() : std::vector(0) { } 35 | Row_of_fields(int field_count) : std::vector(field_count) {} 36 | virtual ~Row_of_fields() {} 37 | 38 | Row_of_fields& operator=(const Row_of_fields &right); 39 | Row_of_fields& operator=(Row_of_fields &right); 40 | 41 | private: 42 | 43 | }; 44 | 45 | } 46 | 47 | #endif /* _ROW_OF_FIELDS_H */ 48 | -------------------------------------------------------------------------------- /examples/mysql2lucene/table_index.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | /* 22 | * File: table_index.h 23 | * Author: thek 24 | * 25 | * Created on den 8 september 2010, 13:47 26 | */ 27 | 28 | #ifndef TABLE_INDEX_H 29 | #define TABLE_INDEX_H 30 | #include "binlog_event.h" 31 | #include 32 | #include "basic_content_handler.h" 33 | 34 | typedef std::pair Event_index_element; 35 | typedef std::map Int2event_map; 36 | 37 | class Table_index : public mysql::Content_handler, public Int2event_map 38 | { 39 | public: 40 | mysql::Binary_log_event *process_event(mysql::Table_map_event *tm); 41 | 42 | ~Table_index(); 43 | 44 | int get_table_name(int table_id, std::string out); 45 | 46 | }; 47 | 48 | 49 | #endif /* TABLE_INDEX_H */ 50 | -------------------------------------------------------------------------------- /include/utilities.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #ifndef _UTILITIES_H 22 | #define _UTILITIES_H 23 | 24 | #include "value.h" 25 | #include "protocol.h" 26 | 27 | 28 | using namespace mysql; 29 | 30 | namespace mysql { 31 | 32 | typedef enum 33 | { 34 | Q_FLAGS2_CODE= 0, 35 | Q_SQL_MODE_CODE, 36 | Q_CATALOG_CODE, 37 | Q_AUTO_INCREMENT, 38 | Q_CHARSET_CODE, 39 | Q_TIME_ZONE_CODE, 40 | Q_CATALOG_NZ_CODE, 41 | Q_LC_TIME_NAMES_CODE, 42 | Q_CHARSET_DATABASE_CODE, 43 | Q_TABLE_MAP_FOR_UPDATE_CODE, 44 | Q_MASTER_DATA_WRITTEN_CODE, 45 | Q_INVOKER 46 | } enum_var_types; 47 | 48 | int server_var_decoder (std::map *my_var_map, 49 | std::vector variables); 50 | 51 | } 52 | 53 | #endif /* _UTILITIES_H */ 54 | -------------------------------------------------------------------------------- /src/row_of_fields.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | #include 21 | 22 | #include "row_of_fields.h" 23 | #include 24 | #include 25 | #include "value.h" 26 | 27 | using namespace mysql; 28 | 29 | Row_of_fields& Row_of_fields::operator=(const Row_of_fields &right) 30 | { 31 | if (size() != right.size()) 32 | throw std::length_error("Row dimension doesn't match."); 33 | int i= 0; 34 | BOOST_FOREACH(Value value, right) 35 | { 36 | this->assign(++i, value); 37 | } 38 | return *this; 39 | } 40 | 41 | Row_of_fields& Row_of_fields::operator=(Row_of_fields &right) 42 | { 43 | if (size() != right.size()) 44 | throw std::length_error("Row dimension doesn't match."); 45 | int i= 0; 46 | BOOST_FOREACH(Value value, right) 47 | { 48 | this->assign(++i, value); 49 | } 50 | return *this; 51 | } 52 | -------------------------------------------------------------------------------- /examples/mysql2lucene/table_index.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #include "table_index.h" 22 | 23 | mysql::Binary_log_event *Table_index::process_event(mysql::Table_map_event *tm) 24 | { 25 | if (find(tm->table_id) == end()) 26 | insert(Event_index_element(tm->table_id,tm)); 27 | 28 | /* Consume this event so it won't be deallocated beneith our feet */ 29 | return 0; 30 | } 31 | 32 | Table_index::~Table_index () 33 | { 34 | Int2event_map::iterator it= begin(); 35 | do 36 | { 37 | delete it->second; 38 | } while( ++it != end()); 39 | } 40 | 41 | int Table_index::get_table_name(int table_id, std::string out) 42 | { 43 | iterator it; 44 | if ((it= find(table_id)) == end()) 45 | { 46 | std::stringstream os; 47 | os << "unknown_table_" << table_id; 48 | out.append(os.str()); 49 | return 1; 50 | } 51 | 52 | out.append(it->second->table_name); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /include/rowset.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | #ifndef _ROWSET_H 21 | #define _ROWSET_H 22 | 23 | #include "field_iterator.h" 24 | #include "resultset_iterator.h" 25 | #include 26 | #include 27 | 28 | using namespace mysql; 29 | 30 | namespace mysql { 31 | 32 | class Row_event; 33 | class Table_map_event; 34 | 35 | class Row_event_set 36 | { 37 | public: 38 | typedef Row_event_iterator iterator; 39 | typedef Row_event_iterator const_iterator; 40 | 41 | Row_event_set(Row_event *arg1, Table_map_event *arg2) { source(arg1, arg2); } 42 | 43 | iterator begin() { return iterator(m_row_event, m_table_map_event); } 44 | iterator end() { return iterator(); } 45 | const_iterator begin() const { return const_iterator(m_row_event, m_table_map_event); } 46 | const_iterator end() const { return const_iterator(); } 47 | 48 | private: 49 | void source(Row_event *arg1, Table_map_event *arg2) { m_row_event= arg1; m_table_map_event= arg2; } 50 | Row_event *m_row_event; 51 | Table_map_event *m_table_map_event; 52 | }; 53 | 54 | } 55 | #endif /* _ROWSET_H */ 56 | -------------------------------------------------------------------------------- /include/file_driver.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #ifndef _FILE_DRIVER_H 22 | #define _FILE_DRIVER_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "binlog_api.h" 31 | #include "binlog_driver.h" 32 | #include "protocol.h" 33 | 34 | #define MAGIC_NUMBER_SIZE 4 35 | 36 | namespace mysql { 37 | namespace system { 38 | 39 | class Binlog_file_driver 40 | : public Binary_log_driver 41 | { 42 | public: 43 | template 44 | Binlog_file_driver(const TFilename& filename = TFilename(), 45 | unsigned int offset = 0) 46 | : Binary_log_driver(filename, offset) 47 | { 48 | } 49 | 50 | int connect(); 51 | int disconnect(); 52 | int wait_for_next_event(mysql::Binary_log_event **event); 53 | int set_position(const std::string &str, unsigned long position); 54 | int get_position(std::string *str, unsigned long *position); 55 | 56 | private: 57 | 58 | unsigned long m_binlog_file_size; 59 | 60 | /* 61 | Bytes that has been read so for from the file. 62 | Updated after every event is read. 63 | */ 64 | unsigned long m_bytes_read; 65 | 66 | std::ifstream m_binlog_file; 67 | 68 | Log_event_header m_event_log_header; 69 | }; 70 | 71 | } // namespace mysql::system 72 | } // namespace mysql 73 | 74 | #endif /* _FILE_DRIVER_H */ 75 | -------------------------------------------------------------------------------- /mysql-replication-listener.spec: -------------------------------------------------------------------------------- 1 | %define _libdir /usr/lib 2 | 3 | Name: mysql-replication-listener 4 | Version: 0.0.47 5 | Release: 10%{?dist} 6 | Summary: A STL/Boost based C++ library used for connecting to a MySQL server and process the replication stream as a slave. 7 | 8 | Group: Development/Libraries 9 | License: GNU GPL v2 10 | URL: https://bitbucket.org/winebarrel/mysql-replication-listener 11 | #URL: https://launchpad.net/mysql-replication-listener 12 | Source0: mysql-replication-listener.tar.gz 13 | # git clone https://bitbucket.org/winebarrel/mysql-replication-listener.git 14 | # cd mysql-replication-listener/ 15 | # git checkout refs/tags/0.0.47-10 16 | # cd .. 17 | # tar zcf mysql-replication-listener.tar.gz mysql-replication-listener/ 18 | BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) 19 | 20 | BuildRequires: gcc-c++, make, cmake, boost-devel, openssl-devel 21 | Requires: glibc, libstdc++, zlib, boost-devel, openssl 22 | 23 | %description 24 | The MySQL Replicant Library is a C++ library for reading MySQL 25 | replication events, either by connecting to a server or by reading 26 | from a file. To handle reading from a server, it includes a very 27 | simple client. 28 | 29 | %prep 30 | %setup -q -n %{name} 31 | 32 | %build 33 | %cmake 34 | make %{?_smp_mflags} 35 | 36 | %install 37 | rm -rf $RPM_BUILD_ROOT 38 | make install DESTDIR=$RPM_BUILD_ROOT 39 | 40 | %clean 41 | rm -rf $RPM_BUILD_ROOT 42 | 43 | %post -p /sbin/ldconfig 44 | %postun -p /sbin/ldconfig 45 | 46 | %files 47 | %defattr(-,root,root,-) 48 | %{_includedir}/access_method_factory.h 49 | %{_includedir}/basic_content_handler.h 50 | %{_includedir}/basic_transaction_parser.h 51 | %{_includedir}/binlog_api.h 52 | %{_includedir}/binlog_driver.h 53 | %{_includedir}/binlog_event.h 54 | %{_includedir}/bounded_buffer.h 55 | %{_includedir}/field_iterator.h 56 | %{_includedir}/file_driver.h 57 | %{_includedir}/protocol.h 58 | %{_includedir}/resultset_iterator.h 59 | %{_includedir}/row_of_fields.h 60 | %{_includedir}/rowset.h 61 | %{_includedir}/tcp_driver.h 62 | %{_includedir}/utilities.h 63 | %{_includedir}/value.h 64 | %{_libdir}/libreplication.a 65 | %{_libdir}/libreplication.so 66 | %{_libdir}/libreplication.so.0.1 67 | %{_libdir}/libreplication.so.1 68 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This repository was forked from https://launchpad.net/mysql-replication-listener. 2 | --- 3 | 4 | The MySQL Replicant Library is a C++ library for reading MySQL 5 | replication events, either by connecting to a server or by reading 6 | from a file. To handle reading from a server, it includes a very 7 | simple client. 8 | 9 | 10 | Dependencies 11 | ------------ 12 | 13 | You need to have CMake version 2.8 or later and Boost version 1.35.0 14 | or later since Asio is required. 15 | 16 | The code will not compile with gcc 6.x, use gcc 5.x. 17 | 18 | To be able to run the unit tests, you have to have Google Test 19 | installed. Google Test will be automatically installed if cmake is 20 | called as: 21 | 22 | cmake . -DENABLE_DOWNLOADS=1 23 | 24 | 25 | Directory structure 26 | ------------------- 27 | 28 | . 29 | |-- doc Documentation 30 | |-- examples Examples 31 | | `-- mysql2lucene Example application replicating rows to SOLR 32 | |-- include Include files 33 | |-- src Source files for library 34 | `-- tests Unit test files and directories 35 | 36 | 37 | Building 38 | -------- 39 | 40 | To build the entire package, it is first necessary to run CMake to build all the makefiles. 41 | 42 | cmake . 43 | make -j4 44 | 45 | Some of the examples are using third-party software, which can require 46 | extra parameters to be given to CMake. 47 | 48 | If you want to perform an out-of-source build, you can just create a 49 | build directory and execute CMake there. 50 | 51 | mkdir build 52 | cd build 53 | cmake 54 | make -j4 55 | 56 | 57 | Building the mysql2lucene Example 58 | --------------------------------- 59 | 60 | To build the mysql2lucene example, it is necessary to ensure that the 61 | 'FindCLucene.cmake' is in the CMAKE_MODULE_PATH, which on my machine 62 | require me to write: 63 | 64 | cmake . -DCMAKE_MODULE_PATH:String=/usr/share/kde4/apps/cmake/modules 65 | 66 | In addition, there is a bug in the packaging of CLucene on Ubuntu in 67 | that the 'clucene-config.h' file is placed in '/usr/lib/CLucene' but 68 | not in '/usr/include/CLucene', causing compiler failure when 69 | attempting to use CLucene. The 'CMakeLists.txt' file hacks around this 70 | by adding the libraries explicitly, but it seems unnecessary. 71 | -------------------------------------------------------------------------------- /src/binlog_driver.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #include "binlog_driver.h" 22 | 23 | namespace mysql { namespace system { 24 | 25 | /* 26 | Binary_log_event* Binary_log_driver::parse_event(boost::asio::streambuf 27 | &sbuff, Log_event_header 28 | *header) 29 | */ 30 | Binary_log_event* Binary_log_driver::parse_event(std::istream &is, 31 | Log_event_header *header) 32 | { 33 | Binary_log_event *parsed_event= 0; 34 | 35 | switch (header->type_code) { 36 | case TABLE_MAP_EVENT: 37 | parsed_event= proto_table_map_event(is, header); 38 | break; 39 | case QUERY_EVENT: 40 | parsed_event= proto_query_event(is, header); 41 | break; 42 | case INCIDENT_EVENT: 43 | parsed_event= proto_incident_event(is, header); 44 | break; 45 | case WRITE_ROWS_EVENT: 46 | case UPDATE_ROWS_EVENT: 47 | case DELETE_ROWS_EVENT: 48 | parsed_event= proto_rows_event(is, header); 49 | break; 50 | case ROTATE_EVENT: 51 | { 52 | Rotate_event *rot= proto_rotate_event(is, header); 53 | m_binlog_file_name= rot->binlog_file; 54 | m_binlog_offset= (unsigned long)rot->binlog_pos; 55 | parsed_event= rot; 56 | } 57 | break; 58 | case INTVAR_EVENT: 59 | parsed_event= proto_intvar_event(is, header); 60 | break; 61 | case USER_VAR_EVENT: 62 | parsed_event= proto_uservar_event(is, header); 63 | break; 64 | default: 65 | { 66 | // Create a dummy driver. 67 | parsed_event= new Binary_log_event(header); 68 | } 69 | } 70 | 71 | return parsed_event; 72 | } 73 | 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /examples/basic-2.cpp: -------------------------------------------------------------------------------- 1 | #include "binlog_api.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | /* 8 | Here is a basic system using the event loop to fetch context events 9 | and store them in an associative array. 10 | */ 11 | using mysql::Binary_log; 12 | using mysql::system::create_transport; 13 | using mysql::system::get_event_type_str; 14 | using mysql::User_var_event; 15 | 16 | /** 17 | * Class to maintain variable values. 18 | */ 19 | template 20 | class Save_variables : public Content_handler { 21 | public: 22 | Save_variables(AssociativeContainer& container) 23 | : m_var(container) 24 | { 25 | } 26 | 27 | Binary_log_event *process_event(User_var_event *event) { 28 | m_var[event->name] = event->value; 29 | return NULL; 30 | } 31 | 32 | private: 33 | AssociativeContainer &m_var; 34 | }; 35 | 36 | 37 | template 38 | class Replace_variables : public Content_handler { 39 | public: 40 | Replace_variables(AssociativeContainer& variables) 41 | : m_var(variables) 42 | { 43 | } 44 | 45 | Binary_log_event *process_event(Query_event *event) { 46 | std::string *query = &event->query; 47 | size_t start, end = 0; 48 | while (true) { 49 | start = query->find_first_of("@", end); 50 | if (start == std::string::npos) 51 | break; 52 | end = query->find_first_not_of("abcdefghijklmnopqrstuvwxyz", start+1); 53 | std::string key = query->substr(start + 1, end - start - 1); 54 | query->replace(start, end - start, "'" + m_var[key] + "'"); 55 | } 56 | return event; 57 | } 58 | private: 59 | AssociativeContainer &m_var; 60 | }; 61 | 62 | 63 | int main(int argc, char** argv) { 64 | typedef std::map Map; 65 | 66 | if (argc != 2) { 67 | std::cerr << "Usage: basic-2 " << std::endl; 68 | exit(2); 69 | } 70 | 71 | Binary_log binlog(create_transport(argv[1])); 72 | binlog.connect(); 73 | 74 | binlog.set_position(4); 75 | 76 | Map variables; 77 | Save_variables save_variables(variables); 78 | binlog.content_handler_pipeline()->push_back(&save_variables); 79 | Replace_variables replace_variables(variables); 80 | binlog.content_handler_pipeline()->push_back(&replace_variables); 81 | 82 | while (true) { 83 | Binary_log_event *event; 84 | int result = binlog.wait_for_next_event(&event); 85 | if (result == ERR_EOF) 86 | break; 87 | switch (event->get_event_type()) { 88 | case QUERY_EVENT: 89 | std::cout << static_cast(event)->query 90 | << std::endl; 91 | break; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /include/binlog_driver.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #ifndef _BINLOG_DRIVER_H 22 | #define _BINLOG_DRIVER_H 23 | #include "binlog_event.h" 24 | #include "protocol.h" 25 | 26 | namespace mysql { 27 | namespace system { 28 | 29 | class Binary_log_driver 30 | { 31 | public: 32 | template 33 | Binary_log_driver(const FilenameT& filename = FilenameT(), unsigned int offset = 0) 34 | : m_binlog_file_name(filename), m_binlog_offset(offset) 35 | { 36 | } 37 | 38 | ~Binary_log_driver() {} 39 | 40 | /** 41 | * Connect to the binary log using previously declared connection parameters 42 | * @return Success or error code 43 | * @retval 0 Success 44 | * @retval >0 Error code (to be specified) 45 | */ 46 | virtual int connect()= 0; 47 | 48 | 49 | /** 50 | * Blocking attempt to get the next binlog event from the stream 51 | * @param event [out] Pointer to a binary log event to be fetched. 52 | */ 53 | virtual int wait_for_next_event(mysql::Binary_log_event **event)= 0; 54 | 55 | /** 56 | * Set the reader position 57 | * @param str The file name 58 | * @param position The file position 59 | * 60 | * @return False on success and True if an error occurred. 61 | */ 62 | virtual int set_position(const std::string &str, unsigned long position)= 0; 63 | 64 | /** 65 | * Get the read position. 66 | * 67 | * @param[out] string_ptr Pointer to location where the filename will be stored. 68 | * @param[out] position_ptr Pointer to location where the position will be stored. 69 | * 70 | * @retval 0 Success 71 | * @retval >0 Error code 72 | */ 73 | virtual int get_position(std::string *filename_ptr, unsigned long *position_ptr) = 0; 74 | 75 | Binary_log_event* parse_event(std::istream &sbuff, Log_event_header *header); 76 | 77 | protected: 78 | /** 79 | * Used each time the client reconnects to the server to specify an 80 | * offset position. 81 | */ 82 | unsigned long m_binlog_offset; 83 | std::string m_binlog_file_name; 84 | }; 85 | 86 | } // namespace mysql::system 87 | } // namespace mysql 88 | #endif /* _BINLOG_DRIVER_H */ 89 | -------------------------------------------------------------------------------- /include/bounded_buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #ifndef _BOUNDED_BUFFER_H 22 | #define _BOUNDED_BUFFER_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | template 32 | class bounded_buffer 33 | { 34 | public: 35 | 36 | typedef boost::circular_buffer container_type; 37 | typedef typename container_type::size_type size_type; 38 | typedef typename container_type::value_type value_type; 39 | 40 | explicit bounded_buffer(size_type capacity) : m_unread(0), m_container(capacity) {} 41 | 42 | void push_front(const value_type& item) 43 | { 44 | boost::mutex::scoped_lock lock(m_mutex); 45 | m_not_full.wait(lock, boost::bind(&bounded_buffer::is_not_full, this)); 46 | m_container.push_front(item); 47 | ++m_unread; 48 | lock.unlock(); 49 | m_not_empty.notify_one(); 50 | } 51 | 52 | void pop_back(value_type* pItem) 53 | { 54 | boost::mutex::scoped_lock lock(m_mutex); 55 | m_not_empty.wait(lock, boost::bind(&bounded_buffer::is_not_empty, this)); 56 | *pItem = m_container[--m_unread]; 57 | lock.unlock(); 58 | m_not_full.notify_one(); 59 | } 60 | 61 | bool has_unread() 62 | { 63 | boost::mutex::scoped_lock lock(m_mutex); 64 | return is_not_empty(); 65 | } 66 | 67 | void lock() 68 | { 69 | m_mutex.lock(); 70 | } 71 | 72 | void unlock() 73 | { 74 | m_mutex.unlock(); 75 | } 76 | private: 77 | bounded_buffer(const bounded_buffer&); // Disabled copy constructor 78 | bounded_buffer& operator = (const bounded_buffer&); // Disabled assign operator 79 | 80 | bool is_not_empty() const { return m_unread > 0; } 81 | bool is_not_full() const { return m_unread < m_container.capacity(); } 82 | 83 | size_type m_unread; 84 | container_type m_container; 85 | boost::mutex m_mutex; 86 | boost::condition m_not_empty; 87 | boost::condition m_not_full; 88 | }; 89 | 90 | #endif /* _BOUNDED_BUFFER_H */ 91 | 92 | -------------------------------------------------------------------------------- /src/binlog_event.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #include "binlog_event.h" 22 | #include 23 | namespace mysql 24 | { 25 | 26 | namespace system { 27 | 28 | const char *get_event_type_str(Log_event_type type) 29 | { 30 | switch(type) { 31 | case START_EVENT_V3: return "Start_v3"; 32 | case STOP_EVENT: return "Stop"; 33 | case QUERY_EVENT: return "Query"; 34 | case ROTATE_EVENT: return "Rotate"; 35 | case INTVAR_EVENT: return "Intvar"; 36 | case LOAD_EVENT: return "Load"; 37 | case NEW_LOAD_EVENT: return "New_load"; 38 | case SLAVE_EVENT: return "Slave"; 39 | case CREATE_FILE_EVENT: return "Create_file"; 40 | case APPEND_BLOCK_EVENT: return "Append_block"; 41 | case DELETE_FILE_EVENT: return "Delete_file"; 42 | case EXEC_LOAD_EVENT: return "Exec_load"; 43 | case RAND_EVENT: return "RAND"; 44 | case XID_EVENT: return "Xid"; 45 | case USER_VAR_EVENT: return "User var"; 46 | case FORMAT_DESCRIPTION_EVENT: return "Format_desc"; 47 | case TABLE_MAP_EVENT: return "Table_map"; 48 | case PRE_GA_WRITE_ROWS_EVENT: return "Write_rows_event_old"; 49 | case PRE_GA_UPDATE_ROWS_EVENT: return "Update_rows_event_old"; 50 | case PRE_GA_DELETE_ROWS_EVENT: return "Delete_rows_event_old"; 51 | case WRITE_ROWS_EVENT: return "Write_rows"; 52 | case UPDATE_ROWS_EVENT: return "Update_rows"; 53 | case DELETE_ROWS_EVENT: return "Delete_rows"; 54 | case BEGIN_LOAD_QUERY_EVENT: return "Begin_load_query"; 55 | case EXECUTE_LOAD_QUERY_EVENT: return "Execute_load_query"; 56 | case INCIDENT_EVENT: return "Incident"; 57 | case USER_DEFINED: return "User defined"; 58 | default: return "Unknown"; 59 | } 60 | } 61 | 62 | } // end namespace system 63 | 64 | 65 | Binary_log_event::~Binary_log_event() 66 | { 67 | } 68 | 69 | 70 | Binary_log_event * create_incident_event(unsigned int type, const char *message, unsigned long pos) 71 | { 72 | Incident_event *incident= new Incident_event(); 73 | incident->header()->type_code= INCIDENT_EVENT; 74 | incident->header()->next_position= pos; 75 | incident->header()->event_length= LOG_EVENT_HEADER_SIZE + 2 + strlen(message); 76 | incident->type= type; 77 | incident->message.append(message); 78 | return incident; 79 | } 80 | 81 | } // end namespace mysql 82 | -------------------------------------------------------------------------------- /include/basic_transaction_parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | #ifndef _BASIC_TRANSACTION_PARSER_H 21 | #define _BASIC_TRANSACTION_PARSER_H 22 | 23 | /* 24 | TODO The Transaction_log_event and Basic_transaction_parser will be removed 25 | from this library and replaced with a table map indexer instead which can be 26 | used to retrive table names. 27 | */ 28 | 29 | #include 30 | #include 31 | #include "binlog_event.h" 32 | #include "basic_content_handler.h" 33 | 34 | #include 35 | 36 | namespace mysql { 37 | typedef std::pair Event_index_element; 38 | typedef std::map Int_to_Event_map; 39 | class Transaction_log_event : public Binary_log_event 40 | { 41 | public: 42 | Transaction_log_event() : Binary_log_event() {} 43 | Transaction_log_event(Log_event_header *header) : Binary_log_event(header) {} 44 | virtual ~Transaction_log_event(); 45 | 46 | Int_to_Event_map &table_map() { return m_table_map; } 47 | /** 48 | * Index for easier table name look up 49 | */ 50 | Int_to_Event_map m_table_map; 51 | 52 | std::list m_events; 53 | }; 54 | 55 | Transaction_log_event *create_transaction_log_event(void); 56 | 57 | class Basic_transaction_parser : public mysql::Content_handler 58 | { 59 | public: 60 | Basic_transaction_parser() : mysql::Content_handler() 61 | { 62 | m_transaction_state= NOT_IN_PROGRESS; 63 | } 64 | 65 | mysql::Binary_log_event *process_event(mysql::Query_event *ev); 66 | mysql::Binary_log_event *process_event(mysql::Row_event *ev); 67 | mysql::Binary_log_event *process_event(mysql::Table_map_event *ev); 68 | mysql::Binary_log_event *process_event(mysql::Xid *ev); 69 | mysql::Binary_log_event *process_event(mysql::Binary_log_event *ev) {return ev; } 70 | 71 | private: 72 | boost::uint32_t m_start_time; 73 | enum Transaction_states { STARTING, IN_PROGRESS, COMMITTING, NOT_IN_PROGRESS } ; 74 | enum Transaction_states m_transaction_state; 75 | std::list m_event_stack; 76 | mysql::Binary_log_event *process_transaction_state(mysql::Binary_log_event *ev); 77 | }; 78 | 79 | } // end namespace 80 | 81 | #endif /* _BASIC_TRANSACTION_PARSER_H */ 82 | 83 | -------------------------------------------------------------------------------- /include/basic_content_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | #ifndef BASIC_CONTENT_HANDLER_H 21 | #define BASIC_CONTENT_HANDLER_H 22 | 23 | #include "binlog_event.h" 24 | 25 | namespace mysql { 26 | 27 | class Injection_queue : public std::list 28 | { 29 | public: 30 | Injection_queue() : std::list() {} 31 | ~Injection_queue() {} 32 | }; 33 | 34 | /** 35 | * A content handler accepts an event and returns the same event, 36 | * a new one or 0 (the event was consumed by the content handler). 37 | * The default behaviour is to return the event unaffected. 38 | * The generic event handler is used for events which aren't routed to 39 | * a dedicated member function, user defined events being the most 40 | * common case. 41 | */ 42 | 43 | class Content_handler { 44 | public: 45 | Content_handler(); 46 | Content_handler(const mysql::Content_handler& orig); 47 | virtual ~Content_handler(); 48 | 49 | virtual mysql::Binary_log_event *process_event(mysql::Query_event *ev); 50 | virtual mysql::Binary_log_event *process_event(mysql::Row_event *ev); 51 | virtual mysql::Binary_log_event *process_event(mysql::Table_map_event *ev); 52 | virtual mysql::Binary_log_event *process_event(mysql::Xid *ev); 53 | virtual mysql::Binary_log_event *process_event(mysql::User_var_event *ev); 54 | virtual mysql::Binary_log_event *process_event(mysql::Incident_event *ev); 55 | virtual mysql::Binary_log_event *process_event(mysql::Rotate_event *ev); 56 | virtual mysql::Binary_log_event *process_event(mysql::Int_var_event *ev); 57 | 58 | /** 59 | Process any event which hasn't been registered yet. 60 | */ 61 | virtual mysql::Binary_log_event *process_event(mysql::Binary_log_event *ev); 62 | 63 | protected: 64 | /** 65 | * The Injection queue is emptied before any new event is pulled from 66 | * the Binary_log_driver. Injected events will pass through all content 67 | * handlers. The Injection_queue is a derived std::list. 68 | */ 69 | Injection_queue *get_injection_queue(); 70 | 71 | private: 72 | Injection_queue *m_reinject_queue; 73 | void set_injection_queue(Injection_queue *injection_queue); 74 | mysql::Binary_log_event *internal_process_event(mysql::Binary_log_event *ev); 75 | 76 | friend class Binary_log; 77 | }; 78 | 79 | } // end namespace 80 | #endif /* BASIC_CONTENT_HANDLER_H */ 81 | -------------------------------------------------------------------------------- /examples/mysql2lucene/table_delete.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #include "globals.h" 22 | #include "table_delete.h" 23 | 24 | #include 25 | 26 | CL_NS_USE(index) 27 | CL_NS_USE(util) 28 | CL_NS_USE(store) 29 | CL_NS_USE(search) 30 | CL_NS_USE(document) 31 | CL_NS_USE(queryParser) 32 | CL_NS_USE(analysis) 33 | CL_NS_USE2(analysis,standard) 34 | 35 | void table_delete(std::string table_name, mysql::Row_of_fields &fields) 36 | { 37 | 38 | mysql::Row_of_fields::iterator field_it= fields.begin(); 39 | /* 40 | * First column must be an integer key value 41 | */ 42 | if (!(field_it->type() == mysql::system::MYSQL_TYPE_LONG || 43 | field_it->type() == mysql::system::MYSQL_TYPE_SHORT || 44 | field_it->type() == mysql::system::MYSQL_TYPE_LONGLONG)) 45 | return; 46 | 47 | int field_id= 0; 48 | std::string key; 49 | std::string combined_key; 50 | mysql::Converter converter; 51 | converter.to(key, *field_it); 52 | combined_key.append (table_name); 53 | combined_key.append ("_"); 54 | combined_key.append (key); 55 | do { 56 | /* 57 | Each row contains a vector of Value objects. The converter 58 | allows us to transform the value into another 59 | representation. 60 | Only index fields which might contain searchable information. 61 | */ 62 | if (field_it->type() == mysql::system::MYSQL_TYPE_VARCHAR || 63 | field_it->type() == mysql::system::MYSQL_TYPE_MEDIUM_BLOB || 64 | field_it->type() == mysql::system::MYSQL_TYPE_BLOB) 65 | { 66 | std::string str; 67 | converter.to(str, *field_it); 68 | StandardAnalyzer an; 69 | IndexReader *reader; 70 | /* 71 | * Create a Lucene index writer 72 | */ 73 | if ( IndexReader::indexExists(cl_index_file.c_str()) ) 74 | { 75 | if ( IndexReader::isLocked(cl_index_file.c_str()) ) 76 | { 77 | std::cout << "Index was locked; unlocking it." 78 | << std::endl; 79 | IndexReader::unlock(cl_index_file.c_str()); 80 | } 81 | reader= IndexReader::open(cl_index_file.c_str()); 82 | } 83 | 84 | std::cout << "Deleting index '" 85 | << combined_key 86 | << "'" << std::endl; 87 | TCHAR *combined_key_w= STRDUP_AtoW(combined_key.c_str ()); 88 | Term uniqueKey(_T("id"),combined_key_w); 89 | reader->deleteDocuments(&uniqueKey); 90 | delete combined_key_w; 91 | reader->close(); 92 | delete reader; 93 | break; 94 | } 95 | } while(++field_it != fields.end()); 96 | } 97 | -------------------------------------------------------------------------------- /tests/replay_sys_vars.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #include 22 | #include 23 | #include "binlog_api.h" 24 | #include "utilities.h" 25 | 26 | int main (int argc, char* argv[]) 27 | { 28 | mysql::Binary_log 29 | binlog(mysql::system::create_transport("mysql://root@127.0.0.1:13000")); 30 | 31 | if (binlog.connect()) 32 | { 33 | std::cerr << "Can't connect!" << std::endl; 34 | exit(1); 35 | } 36 | std::cout << "Connected to server!!" << std::endl; 37 | 38 | if (binlog.set_position(4) != ERR_OK) 39 | { 40 | std::cerr << "Can't reposition the binary log reader." 41 | << std::endl; 42 | exit(1); 43 | } 44 | 45 | Binary_log_event *event; 46 | 47 | bool quit=false; 48 | while (!quit) 49 | { 50 | if (binlog.wait_for_next_event (&event)) 51 | { 52 | quit= true; 53 | continue; 54 | } 55 | 56 | std::cout << "Pos = " 57 | << event->header()->next_position 58 | <<" Event_type = " 59 | << event->get_event_type() 60 | << std::endl; 61 | 62 | switch (event->header()->type_code) 63 | { 64 | case mysql::QUERY_EVENT: 65 | { 66 | const mysql::Query_event *qev= static_cast(event); 67 | std::cout << "Query = " 68 | << qev->query 69 | << " DB = " 70 | << qev->db_name 71 | << std::endl; 72 | std::map my_var_map; 73 | 74 | if (server_var_decoder(&my_var_map, qev->variables)) 75 | return (EXIT_FAILURE); 76 | 77 | mysql::Converter converter; 78 | 79 | typedef std::map::value_type my_pair; 80 | BOOST_FOREACH (my_pair &ref, my_var_map) 81 | { 82 | std::string value; 83 | converter.to(value, ref.second); 84 | std::cout << ref.first 85 | << " = " 86 | << value 87 | << std::endl; 88 | } 89 | std::cout << "----------" << std::endl << std::endl; 90 | 91 | if (qev->query.find("DROP DATABASE `sys_var`") != std::string::npos 92 | || qev->query.find("DROP DATABASE sys_var") != std::string::npos) 93 | quit= true; 94 | } 95 | break; 96 | default: 97 | break; 98 | } 99 | delete event; 100 | } 101 | return 0; 102 | } 103 | 104 | -------------------------------------------------------------------------------- /src/binary_log.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #include 22 | 23 | #include "binlog_api.h" 24 | #include 25 | 26 | using namespace mysql; 27 | using namespace mysql::system; 28 | namespace mysql 29 | { 30 | Binary_log::Binary_log(Binary_log_driver *drv) : m_binlog_position(4), m_binlog_file("") 31 | { 32 | if (drv == NULL) 33 | { 34 | m_driver= &m_dummy_driver; 35 | } 36 | else 37 | m_driver= drv; 38 | } 39 | 40 | Content_handler_pipeline *Binary_log::content_handler_pipeline(void) 41 | { 42 | return &m_content_handlers; 43 | } 44 | 45 | int Binary_log::wait_for_next_event(mysql::Binary_log_event **event_ptr) 46 | { 47 | int rc; 48 | bool handler_code; 49 | mysql::Binary_log_event *event; 50 | 51 | mysql::Injection_queue reinjection_queue; 52 | 53 | do { 54 | handler_code= false; 55 | if (!reinjection_queue.empty()) 56 | { 57 | event= reinjection_queue.front(); 58 | reinjection_queue.pop_front(); 59 | } 60 | else 61 | { 62 | // Return in case of non-ERR_OK. 63 | if(rc= m_driver->wait_for_next_event(&event)) 64 | return rc; 65 | } 66 | m_binlog_position= event->header()->next_position; 67 | mysql::Content_handler *handler; 68 | 69 | BOOST_FOREACH(handler, m_content_handlers) 70 | { 71 | if (event) 72 | { 73 | handler->set_injection_queue(&reinjection_queue); 74 | event= handler->internal_process_event(event); 75 | } 76 | } 77 | } while(event == 0 || !reinjection_queue.empty()); 78 | 79 | if (event_ptr) 80 | *event_ptr= event; 81 | 82 | return 0; 83 | } 84 | 85 | int Binary_log::set_position(const std::string &filename, unsigned long position) 86 | { 87 | int status= m_driver->set_position(filename, position); 88 | if (status == ERR_OK) 89 | { 90 | m_binlog_file= filename; 91 | m_binlog_position= position; 92 | } 93 | return status; 94 | } 95 | 96 | int Binary_log::set_position(unsigned long position) 97 | { 98 | std::string filename; 99 | m_driver->get_position(&filename, NULL); 100 | return this->set_position(filename, position); 101 | } 102 | 103 | unsigned long Binary_log::get_position(void) 104 | { 105 | return m_binlog_position; 106 | } 107 | 108 | unsigned long Binary_log::get_position(std::string &filename) 109 | { 110 | m_driver->get_position(&m_binlog_file, &m_binlog_position); 111 | filename= m_binlog_file; 112 | return m_binlog_position; 113 | } 114 | 115 | int Binary_log::connect() 116 | { 117 | return m_driver->connect(); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/field_iterator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | #include "field_iterator.h" 21 | 22 | //Row_iterator Row_iterator::end() const 23 | //{ return Row_iterator(); } 24 | 25 | namespace mysql 26 | { 27 | 28 | 29 | bool is_null(unsigned char *bitmap, int index) 30 | { 31 | unsigned char *byte= bitmap + (index / 8); 32 | unsigned bit= 1 << ((index) & 7); 33 | return ((*byte) & bit) != 0; 34 | } 35 | 36 | 37 | boost::uint32_t extract_metadata(const Table_map_event *map, int col_no) 38 | { 39 | int offset= 0; 40 | 41 | for (int i=0; i < col_no; ++i) 42 | { 43 | unsigned int type= (unsigned int)map->columns[i]&0xFF; 44 | offset += lookup_metadata_field_size((enum mysql::system::enum_field_types)type); 45 | } 46 | 47 | boost::uint32_t metadata= 0; 48 | unsigned int type= (unsigned int)map->columns[col_no]&0xFF; 49 | switch(lookup_metadata_field_size((enum mysql::system::enum_field_types)type)) 50 | { 51 | case 1: 52 | metadata= map->metadata[offset]; 53 | break; 54 | case 2: 55 | { 56 | unsigned int tmp= ((unsigned int)map->metadata[offset])&0xFF; 57 | metadata= static_cast(tmp); 58 | tmp= (((unsigned int)map->metadata[offset+1])&0xFF) << 8; 59 | metadata+= static_cast(tmp); 60 | } 61 | break; 62 | } 63 | return metadata; 64 | } 65 | 66 | int lookup_metadata_field_size(enum mysql::system::enum_field_types field_type) 67 | { 68 | switch(field_type) 69 | { 70 | case mysql::system::MYSQL_TYPE_DOUBLE: 71 | case mysql::system::MYSQL_TYPE_FLOAT: 72 | case mysql::system::MYSQL_TYPE_BLOB: 73 | case mysql::system::MYSQL_TYPE_DATETIME2: 74 | case mysql::system::MYSQL_TYPE_GEOMETRY: 75 | return 1; 76 | case mysql::system::MYSQL_TYPE_BIT: 77 | case mysql::system::MYSQL_TYPE_VARCHAR: 78 | case mysql::system::MYSQL_TYPE_NEWDECIMAL: 79 | case mysql::system::MYSQL_TYPE_STRING: 80 | case mysql::system::MYSQL_TYPE_VAR_STRING: 81 | return 2; 82 | case mysql::system::MYSQL_TYPE_DECIMAL: 83 | case mysql::system::MYSQL_TYPE_SET: 84 | case mysql::system::MYSQL_TYPE_ENUM: 85 | case mysql::system::MYSQL_TYPE_YEAR: 86 | case mysql::system::MYSQL_TYPE_TINY: 87 | case mysql::system::MYSQL_TYPE_SHORT: 88 | case mysql::system::MYSQL_TYPE_INT24: 89 | case mysql::system::MYSQL_TYPE_LONG: 90 | case mysql::system::MYSQL_TYPE_NULL: 91 | case mysql::system::MYSQL_TYPE_NEWDATE: 92 | case mysql::system::MYSQL_TYPE_DATE: 93 | case mysql::system::MYSQL_TYPE_TIME: 94 | case mysql::system::MYSQL_TYPE_TIMESTAMP: 95 | case mysql::system::MYSQL_TYPE_DATETIME: 96 | case mysql::system::MYSQL_TYPE_TINY_BLOB: 97 | case mysql::system::MYSQL_TYPE_MEDIUM_BLOB: 98 | case mysql::system::MYSQL_TYPE_LONG_BLOB: 99 | default: 100 | return 0; 101 | } 102 | } 103 | 104 | } // end namespace mysql 105 | -------------------------------------------------------------------------------- /tests/test-basic.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #include "binlog_api.h" 22 | #include 23 | #include 24 | #include 25 | class TestBinaryLog : public ::testing::Test { 26 | protected: 27 | TestBinaryLog() { 28 | // You can do set-up work for each test here. 29 | } 30 | 31 | virtual ~TestBinaryLog() { 32 | // You can do clean-up work that doesn't throw exceptions here. 33 | } 34 | 35 | // If the constructor and destructor are not enough for setting up 36 | // and cleaning up each test, you can define the following methods: 37 | 38 | virtual void SetUp() { 39 | // Code here will be called immediately after the constructor (right 40 | // before each test). 41 | } 42 | 43 | virtual void TearDown() { 44 | // Code here will be called immediately after each test (right 45 | // before the destructor). 46 | } 47 | 48 | }; 49 | 50 | 51 | TEST_F(TestBinaryLog, ConnectTo_Bogus) 52 | { 53 | using mysql::system::create_transport; 54 | mysql::Binary_log *binlog= new mysql::Binary_log(create_transport("bogus-url")); 55 | EXPECT_GT(binlog->connect(), 0); 56 | delete(binlog); 57 | } 58 | 59 | TEST_F(TestBinaryLog, ConnectTo_TcpIp) 60 | { 61 | using mysql::system::create_transport; 62 | mysql::Binary_log *binlog= new mysql::Binary_log(create_transport("mysql://root@127.0.0.1:13000")); 63 | EXPECT_EQ(binlog->connect(),0); 64 | delete binlog; 65 | } 66 | 67 | TEST_F(TestBinaryLog, Connected_TcpIp) 68 | { 69 | using mysql::system::create_transport; 70 | mysql::Binary_log *binlog= new mysql::Binary_log(create_transport("mysql://root@127.0.0.1:13000")); 71 | EXPECT_EQ(binlog->connect(),0); 72 | mysql::Binary_log_event *event; 73 | binlog->wait_for_next_event(&event); 74 | EXPECT_TRUE(event->get_event_type() == mysql::ROTATE_EVENT); 75 | delete event; 76 | binlog->wait_for_next_event(&event); 77 | EXPECT_TRUE(event->get_event_type() == mysql::FORMAT_DESCRIPTION_EVENT); 78 | delete event; 79 | } 80 | 81 | TEST_F(TestBinaryLog, SetPosition) 82 | { 83 | using mysql::system::create_transport; 84 | mysql::Binary_log_event *event; 85 | mysql::Binary_log *binlog= new mysql::Binary_log(create_transport("mysql://root@127.0.0.1:13000")); 86 | EXPECT_EQ(binlog->connect(),0); 87 | std::string filename; 88 | unsigned long position= binlog->get_position(filename); 89 | int result= binlog->set_position(filename,4); 90 | EXPECT_EQ(result,ERR_OK); 91 | position= binlog->get_position(); 92 | EXPECT_EQ(position, 4); 93 | 94 | binlog->wait_for_next_event(&event); 95 | } 96 | 97 | int main(int argc, char **argv) { 98 | ::testing::InitGoogleTest(&argc, argv); 99 | 100 | // TODO require that the connection string is passed as an argument to the 101 | // test suite. 102 | std::cout << "Important: Make sure that the MySQL server is started using " 103 | "'mysql-test-run --mysqld=--log_bin=searchbin --mysqld=--binlog_format=row --start " 104 | "alias' and that the server is listening on IP 127.0.0.1 and port" 105 | " 13000." << std::endl; 106 | return RUN_ALL_TESTS(); 107 | } 108 | -------------------------------------------------------------------------------- /src/basic_content_handler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | #include "basic_content_handler.h" 21 | #include 22 | 23 | namespace mysql { 24 | 25 | Content_handler::Content_handler () {} 26 | Content_handler::~Content_handler () {} 27 | mysql::Binary_log_event *Content_handler::process_event(mysql::Query_event *ev) { return ev; } 28 | mysql::Binary_log_event *Content_handler::process_event(mysql::Row_event *ev) { return ev; } 29 | mysql::Binary_log_event *Content_handler::process_event(mysql::Table_map_event *ev) { return ev; } 30 | mysql::Binary_log_event *Content_handler::process_event(mysql::Xid *ev) { return ev; } 31 | mysql::Binary_log_event *Content_handler::process_event(mysql::User_var_event *ev) { return ev; } 32 | mysql::Binary_log_event *Content_handler::process_event(mysql::Incident_event *ev) { return ev; } 33 | mysql::Binary_log_event *Content_handler::process_event(mysql::Rotate_event *ev) { return ev; } 34 | mysql::Binary_log_event *Content_handler::process_event(mysql::Int_var_event *ev) { return ev; } 35 | mysql::Binary_log_event *Content_handler::process_event(mysql::Binary_log_event *ev) { return ev; } 36 | 37 | Injection_queue *Content_handler::get_injection_queue(void) 38 | { 39 | return m_reinject_queue; 40 | } 41 | 42 | void Content_handler::set_injection_queue(Injection_queue *queue) 43 | { 44 | m_reinject_queue= queue; 45 | } 46 | 47 | mysql::Binary_log_event* 48 | Content_handler::internal_process_event(mysql::Binary_log_event *ev) 49 | { 50 | mysql::Binary_log_event *processed_event= 0; 51 | switch(ev->header ()->type_code) { 52 | case mysql::QUERY_EVENT: 53 | processed_event= process_event(static_cast(ev)); 54 | break; 55 | case mysql::WRITE_ROWS_EVENT: 56 | case mysql::UPDATE_ROWS_EVENT: 57 | case mysql::DELETE_ROWS_EVENT: 58 | processed_event= process_event(static_cast(ev)); 59 | break; 60 | case mysql::USER_VAR_EVENT: 61 | processed_event= process_event(static_cast(ev)); 62 | break; 63 | case mysql::ROTATE_EVENT: 64 | processed_event= process_event(static_cast(ev)); 65 | break; 66 | case mysql::INCIDENT_EVENT: 67 | processed_event= process_event(static_cast(ev)); 68 | break; 69 | case mysql::XID_EVENT: 70 | processed_event= process_event(static_cast(ev)); 71 | break; 72 | case mysql::TABLE_MAP_EVENT: 73 | processed_event= process_event(static_cast(ev)); 74 | break; 75 | /* TODO ********************************************************************/ 76 | case mysql::FORMAT_DESCRIPTION_EVENT: 77 | processed_event= process_event(ev); 78 | break; 79 | case mysql::BEGIN_LOAD_QUERY_EVENT: 80 | processed_event= process_event(ev); 81 | break; 82 | case mysql::EXECUTE_LOAD_QUERY_EVENT: 83 | processed_event= process_event(ev); 84 | break; 85 | case mysql::INTVAR_EVENT: 86 | processed_event= process_event(ev); 87 | break; 88 | case mysql::STOP_EVENT: 89 | processed_event= process_event(ev); 90 | break; 91 | case mysql::RAND_EVENT: 92 | processed_event= process_event(ev); 93 | break; 94 | /****************************************************************************/ 95 | default: 96 | processed_event= process_event(ev); 97 | break; 98 | } 99 | return processed_event; 100 | } 101 | 102 | } // end namespace 103 | -------------------------------------------------------------------------------- /src/access_method_factory.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | #include "access_method_factory.h" 21 | #include "tcp_driver.h" 22 | #include "file_driver.h" 23 | 24 | using mysql::system::Binary_log_driver; 25 | using mysql::system::Binlog_tcp_driver; 26 | using mysql::system::Binlog_file_driver; 27 | 28 | /** 29 | Parse the body of a MySQL URI. 30 | 31 | The format is user[:password]@host[:port] 32 | */ 33 | static Binary_log_driver *parse_mysql_url(const char *body, size_t len) 34 | { 35 | /* Find the beginning of the user name */ 36 | if (strncmp(body, "//", 2) != 0) 37 | return 0; 38 | 39 | /* Find the user name, which is mandatory */ 40 | const char *user = body + 2; 41 | const char *user_end= strpbrk(user, ":@"); 42 | if (user_end == 0 || user_end == user) 43 | return 0; 44 | assert(user_end - user >= 1); // There has to be a username 45 | 46 | /* Find the password, which can be empty */ 47 | assert(*user_end == ':' || *user_end == '@'); 48 | const char *const pass = user_end + 1; // Skip the ':' (or '@') 49 | const char *pass_end = pass; 50 | if (*user_end == ':') 51 | { 52 | pass_end = strchr(pass, '@'); 53 | if (pass_end == 0) 54 | return 0; // There should be a password, but '@' was not found 55 | } 56 | assert(pass_end - pass >= 0); // Password can be empty 57 | 58 | /* Find the host name, which is mandatory */ 59 | // Skip the '@', if there is one 60 | const char *host = *pass_end == '@' ? pass_end + 1 : pass_end; 61 | const char *host_end = strchr(host, ':'); 62 | if (host == host_end) 63 | return 0; // No hostname was found 64 | /* If no ':' was found there is no port, so the host end at the end 65 | * of the string */ 66 | if (host_end == 0) 67 | host_end = body + len; 68 | assert(host_end - host >= 1); // There has to be a host 69 | 70 | /* Find the port number */ 71 | unsigned long portno = 3306; 72 | if (*host_end == ':') 73 | portno = strtoul(host_end + 1, NULL, 10); 74 | 75 | /* Host name is now the string [host, port-1) if port != NULL and [host, EOS) otherwise. */ 76 | /* Port number is stored in portno, either the default, or a parsed one */ 77 | return new Binlog_tcp_driver(std::string(user, user_end - user), 78 | std::string(pass, pass_end - pass), 79 | std::string(host, host_end - host), 80 | portno); 81 | } 82 | 83 | 84 | static Binary_log_driver *parse_file_url(const char *body, size_t length) 85 | { 86 | /* Find the beginning of the file name */ 87 | if (strncmp(body, "//", 2) != 0) 88 | return 0; 89 | 90 | /* 91 | Since we don't support host information yet, there should be a 92 | slash after the initial "//". 93 | */ 94 | if (body[2] != '/') 95 | return 0; 96 | 97 | return new Binlog_file_driver(body + 2); 98 | } 99 | 100 | /** 101 | URI parser information. 102 | */ 103 | struct Parser { 104 | const char* protocol; 105 | Binary_log_driver *(*parser)(const char *body, size_t length); 106 | }; 107 | 108 | /** 109 | Array of schema names and matching parsers. 110 | */ 111 | static Parser url_parser[] = { 112 | { "mysql", parse_mysql_url }, 113 | { "file", parse_file_url }, 114 | }; 115 | 116 | Binary_log_driver * 117 | mysql::system::create_transport(const char *url) 118 | { 119 | const char *pfx = strchr(url, ':'); 120 | if (pfx == 0) 121 | return NULL; 122 | for (int i = 0 ; i < sizeof(url_parser)/sizeof(*url_parser) ; ++i) 123 | { 124 | const char *proto = url_parser[i].protocol; 125 | if (strncmp(proto, url, strlen(proto)) == 0) 126 | return (*url_parser[i].parser)(pfx+1, strlen(pfx+1)); 127 | } 128 | return NULL; 129 | } 130 | -------------------------------------------------------------------------------- /include/binlog_api.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #ifndef _REPEVENT_H 22 | #define _REPEVENT_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "binlog_event.h" 34 | #include "binlog_driver.h" 35 | #include "tcp_driver.h" 36 | #include "file_driver.h" 37 | #include "basic_content_handler.h" 38 | #include "basic_transaction_parser.h" 39 | #include "field_iterator.h" 40 | #include "rowset.h" 41 | #include "access_method_factory.h" 42 | 43 | namespace io = boost::iostreams; 44 | 45 | namespace mysql 46 | { 47 | 48 | /** 49 | * Error codes. 50 | */ 51 | enum Error_code { 52 | ERR_OK = 0, /* All OK */ 53 | ERR_EOF, /* End of file */ 54 | ERR_FAIL, /* Unspecified failure */ 55 | ERROR_CODE_COUNT 56 | }; 57 | 58 | /** 59 | * Returns true if the event is consumed 60 | */ 61 | typedef boost::function< bool (Binary_log_event *& )> Event_content_handler; 62 | 63 | class Dummy_driver : public system::Binary_log_driver 64 | { 65 | public: 66 | Dummy_driver() : Binary_log_driver("", 0) {} 67 | virtual ~Dummy_driver() {} 68 | 69 | virtual int connect() { return 1; } 70 | 71 | virtual int wait_for_next_event(mysql::Binary_log_event **event) { 72 | return ERR_EOF; 73 | } 74 | 75 | virtual int set_position(const std::string &str, unsigned long position) { 76 | return ERR_OK; 77 | } 78 | 79 | virtual int get_position(std::string *str, unsigned long *position) { 80 | return ERR_OK; 81 | } 82 | }; 83 | 84 | class Content_handler; 85 | 86 | typedef std::list Content_handler_pipeline; 87 | 88 | class Binary_log { 89 | private: 90 | system::Binary_log_driver *m_driver; 91 | Dummy_driver m_dummy_driver; 92 | Content_handler_pipeline m_content_handlers; 93 | unsigned long m_binlog_position; 94 | std::string m_binlog_file; 95 | public: 96 | Binary_log(system::Binary_log_driver *drv); 97 | ~Binary_log() {} 98 | 99 | int connect(); 100 | 101 | /** 102 | * Blocking attempt to get the next binlog event from the stream 103 | */ 104 | int wait_for_next_event(Binary_log_event **event); 105 | 106 | 107 | /** 108 | * Inserts/removes content handlers in and out of the chain 109 | * The Content_handler_pipeline is a derived std::list 110 | */ 111 | Content_handler_pipeline *content_handler_pipeline(); 112 | 113 | /** 114 | * Set the binlog position (filename, position) 115 | * 116 | * @return Error_code 117 | * @retval ERR_OK The position is updated. 118 | * @retval ERR_EOF The position is out-of-range 119 | * @retval >= ERR_CODE_COUNT An unspecified error occurred 120 | */ 121 | int set_position(const std::string &filename, unsigned long position); 122 | 123 | /** 124 | * Set the binlog position using current filename 125 | * @param position Requested position 126 | * 127 | * @return Error_code 128 | * @retval ERR_OK The position is updated. 129 | * @retval ERR_EOF The position is out-of-range 130 | * @retval >= ERR_CODE_COUNT An unspecified error occurred 131 | */ 132 | int set_position(unsigned long position); 133 | 134 | /** 135 | * Fetch the binlog position for the current file 136 | */ 137 | unsigned long get_position(void); 138 | 139 | /** 140 | * Fetch the current active binlog file name. 141 | * @param[out] filename 142 | * TODO replace reference with a pointer. 143 | * @return The file position 144 | */ 145 | unsigned long get_position(std::string &filename); 146 | 147 | }; 148 | 149 | } 150 | 151 | #endif /* _REPEVENT_H */ 152 | -------------------------------------------------------------------------------- /tests/test-transport.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #include "binlog_api.h" 22 | #include 23 | #include 24 | #include 25 | 26 | using mysql::system::create_transport; 27 | using mysql::system::Binary_log_driver; 28 | using mysql::system::Binlog_tcp_driver; 29 | using mysql::system::Binlog_file_driver; 30 | 31 | class TestTransport : public ::testing::Test { 32 | protected: 33 | TestTransport() { } 34 | virtual ~TestTransport() { } 35 | }; 36 | 37 | void CheckTcpValues(Binlog_tcp_driver *tcp, 38 | const char *user, const char *passwd, 39 | const char *host, unsigned long port) 40 | { 41 | EXPECT_EQ(tcp->port(), port); 42 | EXPECT_EQ(tcp->host(), host); 43 | EXPECT_EQ(tcp->user(), user); 44 | EXPECT_EQ(tcp->password(), passwd); 45 | } 46 | 47 | 48 | /** 49 | Test a TCP transport URL. 50 | */ 51 | void TestTcpTransport(const char *uri, 52 | const char *user, const char *passwd, 53 | const char *host, unsigned long port) 54 | { 55 | Binary_log_driver *drv= create_transport(uri); 56 | EXPECT_TRUE(drv); 57 | Binlog_tcp_driver* tcp = dynamic_cast(drv); 58 | EXPECT_TRUE(tcp); 59 | CheckTcpValues(tcp, user, passwd, host, port); 60 | delete drv; 61 | } 62 | 63 | /** 64 | Test a file transport URL. 65 | 66 | @note We do not support user, password, host, or port in file URLs 67 | yet, so we ignore those for the time being. 68 | */ 69 | void TestFileTransport(const char *uri_arg, const char *filename_arg) 70 | { 71 | Binary_log_driver *drv= create_transport(uri_arg); 72 | EXPECT_TRUE(drv); 73 | Binlog_file_driver* file = dynamic_cast(drv); 74 | EXPECT_TRUE(file); 75 | std::string filename; 76 | unsigned long position; 77 | file->get_position(&filename, &position); 78 | EXPECT_EQ(filename, filename_arg); 79 | delete file; 80 | } 81 | 82 | 83 | TEST_F(TestTransport, CreateTransport_TcpIp) { 84 | TestTcpTransport("mysql://nosuchuser@128.0.0.1:99999", 85 | "nosuchuser", "", "128.0.0.1", 99999); 86 | TestTcpTransport("mysql://nosuchuser@128.0.0.1:3306", 87 | "nosuchuser", "", "128.0.0.1", 3306); 88 | TestTcpTransport("mysql://nosuchuser:magic@128.0.0.1:3306", 89 | "nosuchuser", "magic", "128.0.0.1", 3306); 90 | TestTcpTransport("mysql://nosuchuser:magic@example.com:3306", 91 | "nosuchuser", "magic", "example.com", 3306); 92 | TestTcpTransport("mysql://somebody@128.0.0.1", 93 | "somebody", "", "128.0.0.1", 3306); 94 | 95 | // Here are tests for bad URIs 96 | 97 | // Missing username 98 | EXPECT_FALSE(create_transport("mysql://:xyzzy@128.0.0.1:99999")); 99 | EXPECT_FALSE(create_transport("mysql://@128.0.0.1:99999")); 100 | 101 | // Missing hostname 102 | EXPECT_FALSE(create_transport("mysql://somebody@:99999")); 103 | EXPECT_FALSE(create_transport("mysql://somebody")); 104 | EXPECT_FALSE(create_transport("mysql://somebody:xyzzy")); 105 | } 106 | 107 | TEST_F(TestTransport, CreateTransport_File) { 108 | TestFileTransport("file:///master-bin.000003", "/master-bin.000003"); 109 | TestFileTransport("file:///etc/foo/master-bin.000003", "/etc/foo/master-bin.000003"); 110 | 111 | // Here are tests for bad URLs 112 | const char *bad_urls[] = { 113 | "file:master-bin.000003", 114 | "file://somebody/master-bin.000003", 115 | "file://somebody@localhost/master-bin.000003", 116 | "file://master-bin.000003", 117 | "file://somebody:xyzzy@localhost/master-bin.000003", 118 | }; 119 | 120 | for (int i = 0 ; i < sizeof(bad_urls)/sizeof(*bad_urls) ; ++i) 121 | EXPECT_FALSE(create_transport(bad_urls[i])); 122 | } 123 | 124 | TEST_F(TestTransport, CreateTransport_Bogus) 125 | { 126 | EXPECT_FALSE(create_transport("bogus-url")); 127 | EXPECT_FALSE(create_transport("fil")); 128 | EXPECT_FALSE(create_transport("fil://almost-correct.txt")); 129 | EXPECT_FALSE(create_transport("file")); 130 | EXPECT_FALSE(create_transport("mysq:")); 131 | } 132 | 133 | int main(int argc, char **argv) { 134 | ::testing::InitGoogleTest(&argc, argv); 135 | return RUN_ALL_TESTS(); 136 | } 137 | -------------------------------------------------------------------------------- /src/basic_transaction_parser.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #include "binlog_event.h" 22 | #include "basic_transaction_parser.h" 23 | #include "protocol.h" 24 | #include "value.h" 25 | #include 26 | #include 27 | #include 28 | #include "field_iterator.h" 29 | 30 | namespace mysql { 31 | 32 | mysql::Binary_log_event *Basic_transaction_parser::process_event(mysql::Query_event *qev) 33 | { 34 | if (qev->query == "BEGIN") 35 | { 36 | //std::cout << "Transaction has started!" << std::endl; 37 | m_transaction_state= STARTING; 38 | } 39 | else if (qev->query == "COMMIT") 40 | { 41 | m_transaction_state= COMMITTING; 42 | } 43 | 44 | return process_transaction_state(qev); 45 | } 46 | 47 | mysql::Binary_log_event *Basic_transaction_parser::process_event(mysql::Xid *ev) 48 | { 49 | m_transaction_state= COMMITTING; 50 | return process_transaction_state(ev); 51 | } 52 | 53 | mysql::Binary_log_event *Basic_transaction_parser::process_event(mysql::Table_map_event *ev) 54 | { 55 | if(m_transaction_state ==IN_PROGRESS) 56 | { 57 | m_event_stack.push_back(ev); 58 | return 0; 59 | } 60 | return ev; 61 | } 62 | 63 | mysql::Binary_log_event *Basic_transaction_parser::process_event(mysql::Row_event *ev) 64 | { 65 | if(m_transaction_state ==IN_PROGRESS) 66 | { 67 | m_event_stack.push_back(ev); 68 | return 0; 69 | } 70 | return ev; 71 | } 72 | 73 | mysql::Binary_log_event *Basic_transaction_parser::process_transaction_state(mysql::Binary_log_event *incomming_event) 74 | { 75 | switch(m_transaction_state) 76 | { 77 | case STARTING: 78 | { 79 | m_transaction_state= IN_PROGRESS; 80 | m_start_time= incomming_event->header()->timestamp; 81 | delete incomming_event; // drop the begin event 82 | return 0; 83 | } 84 | case COMMITTING: 85 | { 86 | delete incomming_event; // drop the commit event 87 | 88 | /** 89 | * Propagate the start time for the transaction to the newly created 90 | * event. 91 | */ 92 | mysql::Transaction_log_event *trans= mysql::create_transaction_log_event(); 93 | trans->header()->timestamp= m_start_time; 94 | 95 | //std::cout << "There are " << m_event_stack.size() << " events in the transaction: "; 96 | while( m_event_stack.size() > 0) 97 | { 98 | mysql::Binary_log_event *event= m_event_stack.front(); 99 | m_event_stack.pop_front(); 100 | switch(event->get_event_type()) 101 | { 102 | case mysql::TABLE_MAP_EVENT: 103 | { 104 | /* 105 | Index the table name with a table id to ease lookup later. 106 | */ 107 | mysql::Table_map_event *tm= static_cast(event); 108 | //std::cout << "Indexing table " << tm->table_id << " " << tm->table_name << std::endl; 109 | //std::cout.flush (); 110 | trans->m_table_map.insert(mysql::Event_index_element(tm->table_id,tm)); 111 | trans->m_events.push_back(event); 112 | } 113 | break; 114 | case mysql::WRITE_ROWS_EVENT: 115 | case mysql::DELETE_ROWS_EVENT: 116 | case mysql::UPDATE_ROWS_EVENT: 117 | { 118 | trans->m_events.push_back(event); 119 | /* 120 | * Propagate last known next position 121 | */ 122 | trans->header()->next_position= event->header()->next_position; 123 | } 124 | break; 125 | default: 126 | delete event; 127 | } 128 | } // end while 129 | m_transaction_state= NOT_IN_PROGRESS; 130 | return(trans); 131 | } 132 | case NOT_IN_PROGRESS: 133 | default: 134 | return incomming_event; 135 | } 136 | 137 | } 138 | 139 | Transaction_log_event *create_transaction_log_event(void) 140 | { 141 | Transaction_log_event *trans= new Transaction_log_event(); 142 | trans->header()->type_code= USER_DEFINED; 143 | return trans; 144 | }; 145 | 146 | Transaction_log_event::~Transaction_log_event() 147 | { 148 | Int_to_Event_map::iterator it; 149 | for(it = m_table_map.begin(); it != m_table_map.end();) 150 | { 151 | /* No need to delete the event here; it happens in the next iteration */ 152 | m_table_map.erase(it++); 153 | } 154 | 155 | while (m_events.size() > 0) 156 | { 157 | Binary_log_event *event= m_events.back(); 158 | m_events.pop_back(); 159 | delete(event); 160 | } 161 | 162 | } 163 | 164 | } // end namespace 165 | -------------------------------------------------------------------------------- /examples/mysql2lucene/table_insert.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #include "globals.h" 22 | #include "table_insert.h" 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | CL_NS_USE(index) 29 | CL_NS_USE(util) 30 | CL_NS_USE(store) 31 | CL_NS_USE(search) 32 | CL_NS_USE(document) 33 | CL_NS_USE(queryParser) 34 | CL_NS_USE(analysis) 35 | CL_NS_USE2(analysis,standard) 36 | 37 | void table_insert(std::string table_name, mysql::Row_of_fields &fields) 38 | { 39 | mysql::Row_of_fields::iterator field_it= fields.begin(); 40 | /* 41 | * First column must be an integer key value 42 | */ 43 | if (!(field_it->type() == mysql::system::MYSQL_TYPE_LONG || 44 | field_it->type() == mysql::system::MYSQL_TYPE_SHORT || 45 | field_it->type() == mysql::system::MYSQL_TYPE_LONGLONG)) 46 | return; 47 | 48 | Document *doc= new Document(); 49 | IndexWriter* writer = NULL; 50 | StandardAnalyzer an; 51 | mysql::Converter converter; 52 | bool found_searchable= false; 53 | int col= 0; 54 | TCHAR *w_table_name; 55 | TCHAR *w_str; 56 | TCHAR *w_key_str; 57 | TCHAR *w_combined_key; 58 | std::string aggstr; 59 | 60 | /* 61 | * Create a Lucene index writer 62 | */ 63 | if ( IndexReader::indexExists(cl_index_file.c_str()) ) 64 | { 65 | if ( IndexReader::isLocked(cl_index_file.c_str()) ) 66 | { 67 | printf("Index was locked... unlocking it.\n"); 68 | IndexReader::unlock(cl_index_file.c_str()); 69 | } 70 | writer = new IndexWriter( cl_index_file.c_str(), &an, false); 71 | }else{ 72 | writer = new IndexWriter( cl_index_file.c_str() ,&an, true); 73 | } 74 | writer->setMaxFieldLength(IndexWriter::DEFAULT_MAX_FIELD_LENGTH); 75 | 76 | /* 77 | * Save the presumed table key for later use when we discover if this row 78 | * should be indexed. 79 | */ 80 | std::string key; 81 | converter.to(key, *field_it); 82 | 83 | do { 84 | /* 85 | Each row contains a vector of Value objects. The converter 86 | allows us to transform the value into another 87 | representation. 88 | Only index fields which might contain searchable information. 89 | */ 90 | if (field_it->type() == mysql::system::MYSQL_TYPE_VARCHAR || 91 | field_it->type() == mysql::system::MYSQL_TYPE_MEDIUM_BLOB || 92 | field_it->type() == mysql::system::MYSQL_TYPE_BLOB) 93 | { 94 | std::string str; 95 | converter.to(str, *field_it); 96 | if (!found_searchable) 97 | { 98 | std::string combined_key; 99 | combined_key.append(table_name); 100 | combined_key.append("_"); 101 | combined_key.append(key); 102 | w_table_name= STRDUP_AtoW(table_name.c_str()); 103 | Field *table_field= new Field(_T("table"),w_table_name, Field::STORE_YES | Field::INDEX_UNTOKENIZED); 104 | doc->add( *table_field ); 105 | found_searchable= true; 106 | w_key_str= STRDUP_AtoW(key.c_str()); 107 | Field *key_field= new Field(_T("row_id"),w_key_str, Field::STORE_YES | Field::INDEX_UNTOKENIZED); 108 | doc->add(*key_field); 109 | w_combined_key= STRDUP_AtoW(combined_key.c_str()); 110 | Field *combined_key_field= new Field(_T("id"),w_combined_key, Field::STORE_YES | Field::INDEX_UNTOKENIZED); 111 | doc->add(*combined_key_field); 112 | } 113 | /* 114 | * Aggregate all searchable information into one string. The key is the 115 | * qualified table name. 116 | */ 117 | aggstr.append(" "); // This separator helps us loosing important tokens. 118 | aggstr.append(str); 119 | ++col; 120 | } 121 | } while(++field_it != fields.end()); 122 | if (found_searchable) 123 | { 124 | std::cout << "Indexing " 125 | << aggstr.length() 126 | << " characters in table '" 127 | << table_name 128 | << "' using key value '" 129 | << key 130 | << "'." 131 | << std::endl; 132 | std::cout.flush (); 133 | w_str= STRDUP_AtoW(aggstr.c_str()); 134 | Field *content_field= new Field(_T("text"),w_str, Field::STORE_YES | Field::INDEX_TOKENIZED); 135 | doc->add( *content_field ); 136 | } 137 | writer->addDocument(doc); 138 | writer->close(); 139 | 140 | /* 141 | * Clean up dynamic allocations during indexing 142 | */ 143 | if (found_searchable) 144 | { 145 | free(w_table_name); 146 | free(w_str); 147 | free(w_key_str); 148 | free(w_combined_key); 149 | } 150 | delete(doc); 151 | delete(writer); 152 | } 153 | -------------------------------------------------------------------------------- /src/utilities.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #include "utilities.h" 22 | 23 | using namespace mysql; 24 | 25 | namespace mysql { 26 | 27 | int server_var_decoder (std::map *my_var_map, 28 | std::vector variables) 29 | { 30 | boost::uint8_t length, i; 31 | std::string name; 32 | mysql::system::enum_field_types field_type; 33 | /* To handle special case of 'terminating null byte'. */ 34 | bool is_null_byte= 0; 35 | 36 | 37 | std::vector::iterator it= variables.begin(); 38 | 39 | while (it != variables.end()) 40 | { 41 | switch (*it++) 42 | { 43 | case Q_FLAGS2_CODE: 44 | length= 4; 45 | name= "flag2"; 46 | field_type= mysql::system::MYSQL_TYPE_LONG; 47 | break; 48 | case Q_SQL_MODE_CODE: 49 | length= 8; 50 | name= "sql_mode"; 51 | field_type= mysql::system::MYSQL_TYPE_LONGLONG; 52 | break; 53 | case Q_CATALOG_CODE: 54 | length= *it++; 55 | name= "catalog_name_old"; 56 | field_type= mysql::system::MYSQL_TYPE_VAR_STRING; 57 | is_null_byte= 1; 58 | break; 59 | case Q_AUTO_INCREMENT: 60 | length= 2; 61 | my_var_map->insert(std::make_pair 62 | ("auto_increment_increment", 63 | mysql::Value(mysql::system::MYSQL_TYPE_SHORT, 64 | length, (char*) &(*it)))); 65 | for (i= 0; i < length; i++) 66 | it++; 67 | 68 | name= "auto_increment_offset"; 69 | field_type= mysql::system::MYSQL_TYPE_SHORT; 70 | break; 71 | case Q_CHARSET_CODE: 72 | length= 2; 73 | my_var_map->insert(std::make_pair 74 | ("character_set_client", 75 | mysql::Value(mysql::system::MYSQL_TYPE_SHORT, 76 | length, (char*) &(*it)))); 77 | for (i= 0; i < length; i++) 78 | it++; 79 | 80 | my_var_map->insert(std::make_pair 81 | ("collation_connection", 82 | mysql::Value(mysql::system::MYSQL_TYPE_SHORT, 83 | length, (char*) &(*it)))); 84 | for (i= 0; i < length; i++) 85 | it++; 86 | 87 | name= "collation_server"; 88 | field_type= mysql::system::MYSQL_TYPE_SHORT; 89 | break; 90 | case Q_TIME_ZONE_CODE: 91 | length= *it++; 92 | name= "time_zone"; 93 | field_type= mysql::system::MYSQL_TYPE_VAR_STRING; 94 | break; 95 | case Q_CATALOG_NZ_CODE: 96 | length= *it++; 97 | name= "catalog_name"; 98 | field_type= mysql::system::MYSQL_TYPE_VAR_STRING; 99 | break; 100 | case Q_LC_TIME_NAMES_CODE: 101 | length= 2; 102 | name= "lc_time_names"; 103 | field_type= mysql::system::MYSQL_TYPE_SHORT; 104 | break; 105 | case Q_CHARSET_DATABASE_CODE: 106 | length= 2; 107 | name= "collation_database"; 108 | field_type= mysql::system::MYSQL_TYPE_SHORT; 109 | break; 110 | case Q_TABLE_MAP_FOR_UPDATE_CODE: 111 | length= 8; 112 | name= "table_map_for_update"; 113 | field_type= mysql::system::MYSQL_TYPE_LONGLONG; 114 | break; 115 | case Q_MASTER_DATA_WRITTEN_CODE: 116 | length= 4; 117 | name= "master_data_written"; 118 | field_type= mysql::system::MYSQL_TYPE_LONG; 119 | break; 120 | case Q_INVOKER: 121 | length= *it++; 122 | my_var_map->insert(std::make_pair 123 | ("user", 124 | mysql::Value(mysql::system::MYSQL_TYPE_VAR_STRING, 125 | length, (char*) &(*it)))); 126 | for (i= 0; i < length; i++) 127 | it++; 128 | 129 | length= *it++; 130 | name= "host"; 131 | field_type= mysql::system::MYSQL_TYPE_VARCHAR; 132 | break; 133 | default: 134 | /* Unknown status variables. Error!! */ 135 | return 1; 136 | } /* switch */ 137 | my_var_map->insert(std::make_pair 138 | (name, mysql::Value(field_type, length, 139 | (char*) &(*it)))); 140 | while (length --) 141 | ++it; 142 | 143 | /* Handle null termination byte. */ 144 | if (is_null_byte) 145 | { 146 | ++it; 147 | is_null_byte= 0; 148 | } 149 | } 150 | return 0; 151 | } /* server_var_decoder() */ 152 | 153 | } /* mysql namespace */ 154 | 155 | -------------------------------------------------------------------------------- /include/value.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #ifndef _VALUE_ADAPTER_H 22 | #define _VALUE_ADAPTER_H 23 | 24 | #include 25 | #include "protocol.h" 26 | #include 27 | #include 28 | 29 | using namespace mysql; 30 | namespace mysql { 31 | 32 | /** 33 | This helper function calculates the size in bytes of a particular field in a 34 | row type event as defined by the field_ptr and metadata_ptr arguments. 35 | @param column_type Field type code 36 | @param field_ptr The field data 37 | @param metadata_ptr The field metadata 38 | 39 | @note We need the actual field data because the string field size is not 40 | part of the meta data. :( 41 | 42 | @return The size in bytes of a particular field 43 | */ 44 | int calc_field_size(unsigned char column_type, const unsigned char *field_ptr, 45 | boost::uint32_t metadata); 46 | 47 | 48 | /** 49 | * A value object class which encapsluate a tuple (value type, metadata, storage) 50 | * and provide for views to this storage through a well defined interface. 51 | * 52 | * Can be used with a Converter to convert between different Values. 53 | */ 54 | class Value 55 | { 56 | public: 57 | Value(enum system::enum_field_types type, boost::uint32_t metadata, const char *storage) : 58 | m_type(type), m_storage(storage), m_metadata(metadata), m_is_null(false) 59 | { 60 | m_size= calc_field_size((unsigned char)type, 61 | (const unsigned char*)storage, 62 | metadata); 63 | //std::cout << "TYPE: " << type << " SIZE: " << m_size << std::endl; 64 | }; 65 | 66 | Value() 67 | { 68 | m_size= 0; 69 | m_storage= 0; 70 | m_metadata= 0; 71 | m_is_null= false; 72 | } 73 | 74 | /** 75 | * Copy constructor 76 | */ 77 | Value(const Value& val); 78 | 79 | Value &operator=(const Value &val); 80 | bool operator==(const Value &val) const; 81 | bool operator!=(const Value &val) const; 82 | 83 | ~Value() {} 84 | 85 | void is_null(bool s) { m_is_null= s; } 86 | bool is_null(void) const { return m_is_null; } 87 | 88 | const char *storage() const { return m_storage; } 89 | 90 | /** 91 | * Get the length in bytes of the entire storage (any metadata part + 92 | * atual data) 93 | */ 94 | size_t length() const { return m_size; } 95 | enum system::enum_field_types type() const { return m_type; } 96 | boost::uint32_t metadata() const { return m_metadata; } 97 | 98 | /** 99 | * Returns the integer representation of a storage of a pre-specified 100 | * type. 101 | */ 102 | boost::int32_t as_int32() const; 103 | 104 | /** 105 | * Returns the integer representation of a storage of pre-specified 106 | * type. 107 | */ 108 | boost::int64_t as_int64() const; 109 | 110 | /** 111 | * Returns the integer representation of a storage of pre-specified 112 | * type. 113 | */ 114 | boost::int8_t as_int8() const; 115 | 116 | /** 117 | * Returns the integer representation of a storage of pre-specified 118 | * type. 119 | */ 120 | boost::int16_t as_int16() const; 121 | 122 | /** 123 | * Returns a pointer to the character data of a string type stored 124 | * in the pre-defined storage. 125 | * @note The position is an offset of the storage pointer determined 126 | * by the metadata and type. 127 | * 128 | * @param[out] size The size in bytes of the character string. 129 | * 130 | */ 131 | char *as_c_str(unsigned long &size) const; 132 | 133 | /** 134 | * Returns a pointer to the byte data of a blob type stored in the pre- 135 | * defined storage. 136 | * @note The position is an offset of the storage pointer determined 137 | * by the metadata and type. 138 | * 139 | * @param[out] size The size in bytes of the blob data. 140 | */ 141 | unsigned char *as_blob(unsigned long &size) const; 142 | 143 | float as_float() const; 144 | double as_double() const; 145 | 146 | private: 147 | enum system::enum_field_types m_type; 148 | size_t m_size; 149 | const char *m_storage; 150 | boost::uint32_t m_metadata; 151 | bool m_is_null; 152 | }; 153 | 154 | class Converter 155 | { 156 | public: 157 | /** 158 | * Converts and copies the sql value to a std::string object. 159 | * @param[out] str The target string 160 | * @param[in] val The value object to be converted 161 | */ 162 | void to(std::string &str, const Value &val) const; 163 | 164 | /** 165 | * Converts and copies the sql value to a long integer. 166 | * @param[out] out The target variable 167 | * @param[in] val The value object to be converted 168 | */ 169 | void to(long &out, const Value &val) const; 170 | 171 | /** 172 | * Converts and copies the sql value to a floating point number. 173 | * @param[out] out The target variable 174 | * @param[in] val The value object to be converted 175 | */ 176 | void to(float &out, const Value &val) const; 177 | }; 178 | 179 | 180 | } // end namespace mysql 181 | #endif /* _VALUE_ADAPTER_H */ 182 | -------------------------------------------------------------------------------- /include/resultset_iterator.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #ifndef _RESULTSET_ITERATOR_H 22 | #define _RESULTSET_ITERATOR_H 23 | 24 | #include 25 | 26 | // if error; try #include 27 | #include 28 | 29 | #include 30 | #include "value.h" 31 | #include "rowset.h" 32 | #include "row_of_fields.h" 33 | 34 | using namespace mysql; 35 | 36 | namespace mysql 37 | { 38 | 39 | struct Field_packet 40 | { 41 | std::string catalog; // Length Coded String 42 | std::string db; // Length Coded String 43 | std::string table; // Length Coded String 44 | std::string org_table;// Length Coded String 45 | std::string name; // Length Coded String 46 | std::string org_name; // Length Coded String 47 | boost::uint8_t marker; // filler 48 | boost::uint16_t charsetnr; // charsetnr 49 | boost::uint32_t length; // length 50 | boost::uint8_t type; // field type 51 | boost::uint16_t flags; 52 | boost::uint8_t decimals; 53 | boost::uint16_t filler; // filler, always 0x00 54 | //boost::uint64_t default_value; // Length coded binary; only in table descr. 55 | }; 56 | 57 | typedef std::list String_storage; 58 | 59 | namespace system { 60 | void digest_result_header(std::istream &is, boost::uint64_t &field_count, boost::uint64_t extra); 61 | void digest_field_packet(std::istream &is, Field_packet &field_packet); 62 | void digest_marker(std::istream &is); 63 | void digest_row_content(std::istream &is, int field_count, Row_of_fields &row, String_storage &storage, bool &is_eof); 64 | } 65 | 66 | template 67 | class Result_set_iterator; 68 | 69 | class Result_set 70 | { 71 | public: 72 | typedef Result_set_iterator iterator; 73 | typedef Result_set_iterator const_iterator; 74 | 75 | Result_set(tcp::socket *socket) { source(socket); } 76 | void source(tcp::socket *socket) { m_socket= socket; digest_row_set(); } 77 | iterator begin(); 78 | iterator end(); 79 | const_iterator begin() const; 80 | const_iterator end() const; 81 | 82 | private: 83 | void digest_row_set(); 84 | friend class Result_set_iterator; 85 | friend class Result_set_iterator; 86 | 87 | std::vector m_field_types; 88 | int m_row_count; 89 | std::vector m_rows; 90 | String_storage m_storage; 91 | tcp::socket *m_socket; 92 | typedef enum { RESULT_HEADER, 93 | FIELD_PACKETS, 94 | MARKER, 95 | ROW_CONTENTS, 96 | EOF_PACKET 97 | } state_t; 98 | state_t m_current_state; 99 | 100 | /** 101 | * The number of fields in the field packets block 102 | */ 103 | boost::uint64_t m_field_count; 104 | /** 105 | * Used for SHOW COLUMNS to return the number of rows in the table 106 | */ 107 | boost::uint64_t m_extra; 108 | }; 109 | 110 | template 111 | class Result_set_iterator : 112 | public boost::iterator_facade, 113 | Iterator_value_type, 114 | boost::forward_traversal_tag > 115 | { 116 | public: 117 | Result_set_iterator() : m_feeder(0), m_current_row(-1) 118 | {} 119 | 120 | explicit Result_set_iterator(Result_set *feeder) : m_feeder(feeder), 121 | m_current_row(-1) 122 | { 123 | increment(); 124 | } 125 | 126 | private: 127 | friend class boost::iterator_core_access; 128 | 129 | void increment() 130 | { 131 | if (++m_current_row >= m_feeder->m_row_count) 132 | m_current_row= -1; 133 | } 134 | 135 | bool equal(const Result_set_iterator& other) const 136 | { 137 | if (other.m_feeder == 0 && m_feeder == 0) 138 | return true; 139 | if (other.m_feeder == 0) 140 | { 141 | if (m_current_row == -1) 142 | return true; 143 | else 144 | return false; 145 | } 146 | if (m_feeder == 0) 147 | { 148 | if (other.m_current_row == -1) 149 | return true; 150 | else 151 | return false; 152 | } 153 | 154 | if( other.m_feeder->m_field_count != m_feeder->m_field_count) 155 | return false; 156 | 157 | Iterator_value_type *row1= &m_feeder->m_rows[m_current_row]; 158 | Iterator_value_type *row2= &other.m_feeder->m_rows[m_current_row]; 159 | for (unsigned i=0; i< m_feeder->m_field_count; ++i) 160 | { 161 | Value val1= row1->at(i); 162 | Value val2= row2->at(i); 163 | if (val1 != val2) 164 | return false; 165 | } 166 | return true; 167 | } 168 | 169 | Iterator_value_type &dereference() const 170 | { 171 | return m_feeder->m_rows[m_current_row]; 172 | } 173 | 174 | private: 175 | Result_set *m_feeder; 176 | int m_current_row; 177 | 178 | }; 179 | 180 | 181 | } // end namespace mysql 182 | 183 | 184 | 185 | #endif /* _RESULTSET_ITERATOR_H */ 186 | -------------------------------------------------------------------------------- /src/file_driver.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #include "file_driver.h" 22 | 23 | namespace mysql { namespace system { 24 | 25 | using namespace std; 26 | 27 | 28 | int Binlog_file_driver::connect() 29 | { 30 | struct stat stat_buff; 31 | 32 | char magic[]= {0xfe, 0x62, 0x69, 0x6e, 0}; 33 | char magic_buf[MAGIC_NUMBER_SIZE]; 34 | 35 | // Get the file size. 36 | if (stat(m_binlog_file_name.c_str(), &stat_buff) == -1) 37 | return ERR_FAIL; // Can't stat binlog file. 38 | m_binlog_file_size= stat_buff.st_size; 39 | 40 | m_binlog_file.exceptions(ifstream::failbit | ifstream::badbit | 41 | ifstream::eofbit); 42 | 43 | try 44 | { 45 | // Check if the file can be opened for reading. 46 | m_binlog_file.open(m_binlog_file_name.c_str(), ios::in | ios::binary); 47 | 48 | // Check if a valid MySQL binlog file is provided, BINLOG_MAGIC. 49 | m_binlog_file.read(magic_buf, MAGIC_NUMBER_SIZE); 50 | 51 | if(memcmp(magic, magic_buf, MAGIC_NUMBER_SIZE)) 52 | return ERR_FAIL; // Not a valid binlog file. 53 | 54 | // Reset the get pointer. 55 | //m_binlog_file.seekg(0, ios::beg ); 56 | 57 | m_bytes_read= MAGIC_NUMBER_SIZE; 58 | 59 | } catch (...) 60 | { 61 | return ERR_FAIL; 62 | } 63 | return ERR_OK; 64 | } 65 | 66 | 67 | int Binlog_file_driver::disconnect() 68 | { 69 | m_binlog_file.close(); 70 | return ERR_OK; 71 | } 72 | 73 | 74 | int Binlog_file_driver::set_position(const string &str, unsigned long position) 75 | { 76 | m_binlog_file.exceptions(ifstream::failbit | ifstream::badbit | 77 | ifstream::eofbit); 78 | try 79 | { 80 | m_binlog_file.seekg(position, ios::beg ); 81 | } catch(...) 82 | { 83 | return ERR_FAIL; 84 | } 85 | 86 | m_bytes_read= position; 87 | 88 | return ERR_OK; 89 | } 90 | 91 | 92 | int Binlog_file_driver::get_position(string *str, unsigned long *position) 93 | { 94 | m_binlog_file.exceptions(ifstream::failbit | ifstream::badbit | 95 | ifstream::eofbit); 96 | try 97 | { 98 | if(position) 99 | *position= m_binlog_file.tellg(); 100 | } catch(...) 101 | { 102 | return ERR_FAIL; 103 | } 104 | 105 | return ERR_OK; 106 | } 107 | 108 | 109 | int Binlog_file_driver::wait_for_next_event(mysql::Binary_log_event **event) 110 | { 111 | 112 | assert(m_binlog_file.tellg() >= 4 ); 113 | m_binlog_file.exceptions(ifstream::failbit | ifstream::badbit | 114 | ifstream::eofbit); 115 | 116 | try 117 | { 118 | if(m_bytes_read < m_binlog_file_size && m_binlog_file.good()) 119 | { 120 | //Protocol_chunk prot_marker(m_event_log_header.marker); 121 | Protocol_chunk prot_timestamp(m_event_log_header.timestamp); 122 | Protocol_chunk prot_type_code(m_event_log_header.type_code); 123 | Protocol_chunk prot_server_id(m_event_log_header.server_id); 124 | Protocol_chunk 125 | prot_event_length(m_event_log_header.event_length); 126 | Protocol_chunk 127 | prot_next_position(m_event_log_header.next_position); 128 | Protocol_chunk prot_flags(m_event_log_header.flags); 129 | 130 | m_binlog_file >> prot_timestamp 131 | >> prot_type_code 132 | >> prot_server_id 133 | >> prot_event_length 134 | >> prot_next_position 135 | >> prot_flags; 136 | 137 | /* 138 | m_binlog_file.read(reinterpret_cast(&m_event_log_header.timestamp), 139 | sizeof(boost::uint32_t)); 140 | m_binlog_file.read(reinterpret_cast(&m_event_log_header.type_code), 141 | sizeof(boost::uint8_t)); 142 | m_binlog_file.read(reinterpret_cast(&m_event_log_header.server_id), 143 | sizeof(boost::uint32_t)); 144 | m_binlog_file.read(reinterpret_cast(&m_event_log_header.event_length), 145 | sizeof(boost::uint32_t)); 146 | m_binlog_file.read(reinterpret_cast(&m_event_log_header.next_position), 147 | sizeof(boost::uint32_t)); 148 | m_binlog_file.read(reinterpret_cast(&m_event_log_header.flags), 149 | sizeof(boost::uint16_t)); 150 | */ 151 | 152 | *event= parse_event(* static_cast (&m_binlog_file), 153 | &m_event_log_header); 154 | 155 | /* 156 | Correction. Except for the default case (above), this condition should 157 | always fail. 158 | */ 159 | if (m_bytes_read + m_event_log_header.event_length != 160 | m_binlog_file.tellg()) 161 | m_binlog_file.seekg(m_bytes_read + m_event_log_header.event_length, 162 | ios::beg); 163 | 164 | m_bytes_read= m_binlog_file.tellg(); 165 | 166 | if(*event) 167 | return ERR_OK; 168 | } 169 | } catch(...) 170 | { 171 | return ERR_FAIL; 172 | } 173 | return ERR_EOF; 174 | } 175 | 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/resultset_iterator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #include "resultset_iterator.h" 22 | #include "protocol.h" 23 | #include "row_of_fields.h" 24 | 25 | using namespace mysql; 26 | 27 | namespace mysql { 28 | 29 | Result_set::iterator Result_set::begin() { return iterator(this); } 30 | Result_set::iterator Result_set::end() { return iterator(); } 31 | Result_set::const_iterator Result_set::begin() const { return const_iterator(const_cast(this)); } 32 | Result_set::const_iterator Result_set::end() const { return const_iterator(); } 33 | 34 | void Result_set::digest_row_set() 35 | { 36 | unsigned long packet_length; 37 | unsigned char packet_no= 1; 38 | m_current_state= RESULT_HEADER; 39 | boost::asio::streambuf resultbuff; 40 | std::istream response_stream(&resultbuff); 41 | unsigned field_count= 0; 42 | try { 43 | do 44 | { 45 | /* 46 | * Get server response 47 | */ 48 | packet_length= system::proto_get_one_package(m_socket, resultbuff, &packet_no); 49 | 50 | switch(m_current_state) 51 | { 52 | case RESULT_HEADER: 53 | system::digest_result_header(response_stream, m_field_count, m_extra); 54 | m_row_count= 0; 55 | m_current_state= FIELD_PACKETS; 56 | break; 57 | case FIELD_PACKETS: 58 | { 59 | Field_packet field; 60 | system::digest_field_packet(response_stream, field); 61 | m_field_types.assign(field_count,field); 62 | 63 | if (++field_count == m_field_count) 64 | m_current_state= MARKER; 65 | } 66 | break; 67 | case MARKER: 68 | { 69 | char marker; 70 | response_stream >> marker; 71 | //assert(marker == 0xfe); 72 | system::digest_marker(response_stream); 73 | m_current_state= ROW_CONTENTS; 74 | } 75 | break; 76 | case ROW_CONTENTS: 77 | { 78 | bool is_eof= false; 79 | Row_of_fields row(0); 80 | system::digest_row_content(response_stream, m_field_count, row, m_storage, is_eof); 81 | if (is_eof) 82 | m_current_state= EOF_PACKET; 83 | else 84 | { 85 | m_rows.push_back(row); 86 | ++m_row_count; 87 | } 88 | } 89 | break; 90 | default: 91 | continue; 92 | } 93 | } while (m_current_state != EOF_PACKET); 94 | } catch(boost::system::system_error e) 95 | { 96 | // TODO log error 97 | m_field_count= 0; 98 | m_row_count= 0; 99 | } 100 | } 101 | 102 | namespace system { 103 | 104 | void digest_result_header(std::istream &is, boost::uint64_t &field_count, boost::uint64_t extra) 105 | { 106 | Protocol_chunk proto_field_count(field_count); 107 | //Protocol_chunk proto_extra(extra); 108 | 109 | proto_field_count.set_length_encoded_binary(true); 110 | //proto_extra.set_length_encoded_binary(true); 111 | 112 | is >> proto_field_count; 113 | //>> proto_extra; 114 | } 115 | 116 | void digest_field_packet(std::istream &is, Field_packet &field_packet) 117 | { 118 | Protocol_chunk_string_len proto_catalog(field_packet.catalog); 119 | Protocol_chunk_string_len proto_db(field_packet.db); 120 | Protocol_chunk_string_len proto_table(field_packet.table); 121 | Protocol_chunk_string_len proto_org_table(field_packet.org_table); 122 | Protocol_chunk_string_len proto_name(field_packet.name); 123 | Protocol_chunk_string_len proto_org_name(field_packet.org_name); 124 | Protocol_chunk proto_marker(field_packet.marker); 125 | Protocol_chunk proto_charsetnr(field_packet.charsetnr); 126 | Protocol_chunk proto_length(field_packet.length); 127 | Protocol_chunk proto_type(field_packet.type); 128 | Protocol_chunk proto_flags(field_packet.flags); 129 | Protocol_chunk proto_decimals(field_packet.decimals); 130 | Protocol_chunk proto_filler(field_packet.filler); 131 | //Protocol_chunk proto_default_value(field_packet.default_value); 132 | 133 | is >> proto_catalog 134 | >> proto_db 135 | >> proto_table 136 | >> proto_org_table 137 | >> proto_name 138 | >> proto_org_name 139 | >> proto_marker 140 | >> proto_charsetnr 141 | >> proto_length 142 | >> proto_type 143 | >> proto_flags 144 | >> proto_decimals 145 | >> proto_filler; 146 | } 147 | 148 | void digest_marker(std::istream &is) 149 | { 150 | struct st_eof_package eof; 151 | prot_parse_eof_message(is,eof); 152 | } 153 | 154 | void digest_row_content(std::istream &is, int field_count, Row_of_fields &row, String_storage &storage, bool &is_eof) 155 | { 156 | boost::uint8_t size; 157 | Protocol_chunk proto_size(size); 158 | is >> proto_size; 159 | if (size == 0xfe) 160 | { 161 | /* EOF packet is detected and there are no more rows to be expeced. */ 162 | is_eof= true; 163 | struct st_eof_package eof; 164 | prot_parse_eof_message(is, eof); 165 | return; 166 | } 167 | is.putback((char)size); 168 | for(int field_no=0; field_no < field_count; ++field_no) 169 | { 170 | std::string *storage= new std::string; 171 | 172 | Protocol_chunk_string_len proto_value(*storage); 173 | is >> proto_value; 174 | 175 | Value value(MYSQL_TYPE_VAR_STRING, storage->length(), storage->c_str()); 176 | row.push_back(value); 177 | } 178 | } 179 | 180 | }} // end namespace system, mysql 181 | -------------------------------------------------------------------------------- /examples/mysql2lucene/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | /* 22 | * File: main.cpp 23 | * Author: thek 24 | * 25 | * Created on den 12 maj 2010, 14:47 26 | */ 27 | 28 | #include 29 | #include 30 | #include "binlog_api.h" 31 | 32 | #include "table_update.h" 33 | #include "table_delete.h" 34 | #include "table_insert.h" 35 | 36 | #include "table_index.h" 37 | 38 | using mysql::system::create_transport; 39 | using mysql::Binary_log; 40 | 41 | std::string cl_index_file; 42 | 43 | class Incident_handler : public mysql::Content_handler 44 | { 45 | public: 46 | Incident_handler() : mysql::Content_handler() {} 47 | 48 | Binary_log_event *process_event(mysql::Incident_event *incident) 49 | { 50 | std::cout << "Event type: " 51 | << mysql::system::get_event_type_str(incident->get_event_type()) 52 | << " length: " << incident->header()->event_length 53 | << " next pos: " << incident->header()->next_position 54 | << std::endl; 55 | std::cout << "type= " 56 | << (unsigned)incident->type 57 | << " message= " 58 | << incident->message 59 | << std::endl 60 | << std::endl; 61 | /* Consume the event */ 62 | delete incident; 63 | return 0; 64 | } 65 | }; 66 | 67 | class Applier : public mysql::Content_handler 68 | { 69 | public: 70 | Applier(Table_index *index) 71 | { 72 | m_table_index= index; 73 | } 74 | 75 | mysql::Binary_log_event *process_event(mysql::Row_event *rev) 76 | { 77 | boost::uint64_t table_id= rev->table_id; 78 | Int2event_map::iterator ti_it= m_table_index->find(table_id); 79 | if (ti_it == m_table_index->end ()) 80 | { 81 | std::cout << "Table id " 82 | << table_id 83 | << " was not registered by any preceding table map event." 84 | << std::endl; 85 | return rev; 86 | } 87 | /* 88 | Each row event contains multiple rows and fields. The Row_iterator 89 | allows us to iterate one row at a time. 90 | */ 91 | mysql::Row_event_set rows(rev, ti_it->second); 92 | /* 93 | Create a fuly qualified table name 94 | */ 95 | std::ostringstream os; 96 | os << ti_it->second->db_name << '.' << ti_it->second->table_name; 97 | mysql::Row_event_set::iterator it= rows.begin(); 98 | do { 99 | mysql::Row_of_fields fields= *it; 100 | if (rev->get_event_type() == mysql::WRITE_ROWS_EVENT) 101 | table_insert(os.str(),fields); 102 | if (rev->get_event_type() == mysql::UPDATE_ROWS_EVENT) 103 | { 104 | ++it; 105 | mysql::Row_of_fields fields2= *it; 106 | table_update(os.str(),fields,fields2); 107 | } 108 | if (rev->get_event_type() == mysql::DELETE_ROWS_EVENT) 109 | table_delete(os.str(),fields); 110 | } while (++it != rows.end()); 111 | 112 | /* Consume the event */ 113 | delete rev; 114 | return 0; 115 | } 116 | private: 117 | Table_index *m_table_index; 118 | 119 | }; 120 | 121 | /* 122 | * 123 | */ 124 | int main(int argc, char** argv) 125 | { 126 | if (argc != 3) 127 | { 128 | fprintf(stderr,"Usage:\n\nmysql2lucene URL\n\nExample:\n\nmysql2lucene mysql://root@127.0.0.1:3306 myindexfile\n\n"); 129 | return (EXIT_FAILURE); 130 | } 131 | 132 | Binary_log binlog(create_transport(argv[1])); 133 | 134 | 135 | cl_index_file.append (argv[2]); 136 | 137 | /* 138 | Attach a custom event content handlers 139 | */ 140 | Incident_handler incident_hndlr; 141 | Table_index table_event_hdlr; 142 | Applier replay_hndlr(&table_event_hdlr); 143 | 144 | binlog.content_handler_pipeline()->push_back(&table_event_hdlr); 145 | binlog.content_handler_pipeline()->push_back(&incident_hndlr); 146 | binlog.content_handler_pipeline()->push_back(&replay_hndlr); 147 | 148 | if (binlog.connect()) 149 | { 150 | fprintf(stderr,"Can't connect to the master.\n"); 151 | return (EXIT_FAILURE); 152 | } 153 | 154 | binlog.set_position("searchbin.000001", 4); 155 | 156 | bool quit= false; 157 | while(!quit) 158 | { 159 | /* 160 | Pull events from the master. This is the heart beat of the event listener. 161 | */ 162 | Binary_log_event *event; 163 | binlog.wait_for_next_event(&event); 164 | 165 | /* 166 | Print the event 167 | */ 168 | std::cout << "Event type: " 169 | << mysql::system::get_event_type_str(event->get_event_type()) 170 | << " length: " << event->header()->event_length 171 | << " next pos: " << event->header()->next_position 172 | << std::endl; 173 | 174 | /* 175 | Perform a special action based on event type 176 | */ 177 | 178 | switch(event->header()->type_code) 179 | { 180 | case mysql::QUERY_EVENT: 181 | { 182 | const mysql::Query_event *qev= static_cast(event); 183 | std::cout << "query= " 184 | << qev->query 185 | << " db= " 186 | << qev->db_name 187 | << std::endl 188 | << std::endl; 189 | if (qev->query.find("DROP TABLE REPLICATION_LISTENER") != std::string::npos) 190 | { 191 | quit= true; 192 | } 193 | } 194 | break; 195 | 196 | case mysql::ROTATE_EVENT: 197 | { 198 | mysql::Rotate_event *rot= static_cast(event); 199 | std::cout << "filename= " 200 | << rot->binlog_file.c_str() 201 | << " pos= " 202 | << rot->binlog_pos 203 | << std::endl 204 | << std::endl; 205 | } 206 | break; 207 | 208 | } // end switch 209 | delete event; 210 | } // end loop 211 | return (EXIT_SUCCESS); 212 | } 213 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project (mysql-5.6-labs-binary-log-api) 2 | cmake_minimum_required (VERSION 2.6) 3 | 4 | set(MySQL_BINLOG_VERSION_MAJOR "0") 5 | set(MySQL_BINLOG_VERSION_MINOR "0.1") 6 | set(MRL_VERSION "${MySQL_BINLOG_VERSION_MAJOR}.${MySQL_BINLOG_VERSION_MINOR}") 7 | 8 | set(CMAKE_VERSION_STRING "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}") 9 | 10 | # Options for building 11 | option(WITH_SERVER_TESTS 12 | "Build the unit test suite with tests requiring a server" 13 | OFF) 14 | 15 | # GTest download variables 16 | set(GTEST_VERSION "1.5.0") 17 | set(GTEST_PACKAGE_NAME "gtest-${GTEST_VERSION}") 18 | set(GTEST_TARBALL "${GTEST_PACKAGE_NAME}.tar.gz") 19 | set(GTEST_DOWNLOAD_URL "http://googletest.googlecode.com/files/${GTEST_TARBALL}") 20 | if(NOT DOWNLOAD_ROOT) 21 | set(DOWNLOAD_ROOT ${CMAKE_SOURCE_DIR}/source_downloads) 22 | endif() 23 | set(GTEST_SOURCE_DIR ${DOWNLOAD_ROOT}/${GTEST_PACKAGE_NAME}) 24 | 25 | # General settings 26 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) 27 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) 28 | include_directories(include) 29 | link_directories(${PROJECT_BINARY_DIR}/lib) 30 | 31 | # ---------- Find Boost Headers/Libraries ----------------------- 32 | SET(Boost_DEBUG FALSE) 33 | SET(Boost_FIND_REQUIRED TRUE) 34 | SET(Boost_FIND_QUIETLY TRUE) 35 | SET(Boost_USE_STATIC_LIBS FALSE) 36 | SET(Boost_ADDITIONAL_VERSIONS "1.41" "1.41.0") 37 | FIND_PACKAGE(Boost REQUIRED system thread) 38 | 39 | # --------- Find crypt 40 | FIND_LIBRARY(LIB_CRYPTO crypto /opt/local/lib /opt/lib /usr/lib /usr/local/lib) 41 | LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) 42 | INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR}) 43 | 44 | # Locate Google Test package and enable tests if it is found 45 | find_package(GTest ${GTEST_VERSION} QUIET) 46 | 47 | if (NOT GTEST_FOUND) 48 | if (NOT ENABLE_DOWNLOADS) 49 | # Give one-time warning 50 | if (NOT ONETIME_GTEST_WARNING) 51 | message(STATUS 52 | "Googletest was not found. gtest-based unit tests will be disabled. " 53 | "You can run cmake . -DENABLE_DOWNLOADS=1 to automatically download and " 54 | "build required components from source.") 55 | SET(ONETIME_GTEST_WARNING 1 CACHE INTERNAL "") 56 | endif (NOT ONETIME_GTEST_WARNING) 57 | else (NOT ENABLE_DOWNLOADS) 58 | # Download gtest source 59 | if (NOT EXISTS ${GTEST_SOURCE_DIR} AND 60 | NOT EXISTS ${DOWNLOAD_ROOT}/${GTEST_TARBALL}) 61 | if (${CMAKE_VERSION_STRING} LESS "2.8") 62 | # In versions earlier than 2.8, try wget for downloading 63 | find_program(WGET_EXECUTABLE wget) 64 | mark_as_advanced(WGET_EXECUTABLE) 65 | if (WGET_EXECUTABLE) 66 | if (NOT EXISTS ${DOWNLOAD_ROOT}) 67 | make_directory(${DOWNLOAD_ROOT}) 68 | endif (NOT EXISTS ${DOWNLOAD_ROOT}) 69 | execute_process(COMMAND ${WGET_EXECUTABLE} -T 30 ${GTEST_DOWNLOAD_URL} 70 | WORKING_DIRECTORY ${DOWNLOAD_ROOT} RESULT_VARIABLE ERR) 71 | if (ERR EQUAL 0) 72 | SET(DOWNLOAD_SUCCEEDED 1) 73 | endif (ERR EQUAL 0) 74 | endif (WGET_EXECUTABLE) 75 | else (${CMAKE_VERSION_STRING} LESS "2.8") 76 | # Use CMake builtin download capabilities 77 | file(DOWNLOAD ${GTEST_DOWNLOAD_URL} ${DOWNLOAD_ROOT}/${GTEST_TARBALL} 78 | TIMEOUT 30 79 | STATUS ERR) 80 | if (ERR EQUAL 0) 81 | SET(DOWNLOAD_SUCCEEDED 1) 82 | endif (ERR EQUAL 0) 83 | endif(${CMAKE_VERSION_STRING} LESS "2.8") 84 | 85 | if (NOT DOWNLOAD_SUCCEEDED) 86 | message(STATUS 87 | "To enable google test, please download ${GTEST_DOWNLOAD_URL} " 88 | "to the directory ${DOWNLOAD_ROOT}") 89 | else (NOT DOWNLOAD_SUCCEEDED) 90 | message(STATUS 91 | "Successfully downloaded ${GTEST_DOWNLOAD_URL} to ${DOWNLOAD_ROOT}") 92 | # Unpack tarball 93 | execute_process ( 94 | COMMAND ${CMAKE_COMMAND} -E tar xfz "${DOWNLOAD_ROOT}/${GTEST_TARBALL}" 95 | WORKING_DIRECTORY "${DOWNLOAD_ROOT}" 96 | OUTPUT_QUIET 97 | ERROR_QUIET 98 | ) 99 | set(GTEST_DOWNLOADED 1 CACHE INTERNAL "") 100 | set(GTEST_FOUND 1 CACHE INTERNAL "") 101 | endif (NOT DOWNLOAD_SUCCEEDED) 102 | else(NOT EXISTS ${GTEST_SOURCE_DIR} AND NOT EXISTS ${DOWNLOAD_ROOT}/${GTEST_TARBALL}) 103 | set(GTEST_DOWNLOADED 1 CACHE INTERNAL "") 104 | set(GTEST_FOUND 1 CACHE INTERNAL "") 105 | endif(NOT EXISTS ${GTEST_SOURCE_DIR} AND NOT EXISTS ${DOWNLOAD_ROOT}/${GTEST_TARBALL}) 106 | endif (NOT ENABLE_DOWNLOADS) 107 | endif (NOT GTEST_FOUND) 108 | 109 | if (GTEST_DOWNLOADED) 110 | # Build gtest library 111 | include_directories( 112 | ${GTEST_SOURCE_DIR} 113 | ${GTEST_SOURCE_DIR}/include 114 | ) 115 | add_library(gtest STATIC ${GTEST_SOURCE_DIR}/src/gtest-all.cc) 116 | 117 | # Set CMake variables to make FindPackage(GTest) happy next time. 118 | SET(GTEST_FOUND 1 CACHE INTERNAL "") 119 | SET(GTEST_LIBRARY gtest CACHE INTERNAL "") 120 | SET(GTEST_LIBRARIES gtest CACHE INTERNAL "") 121 | SET(GTEST_MAIN_LIBRARY no_gtest_main_library CACHE INTERNAL "") 122 | SET(GTEST_INCLUDE_DIRS ${GTEST_SOURCE_DIR}/include CACHE INTERNAL "") 123 | SET(GTEST_INCLUDE_DIR "${GTEST_SOURCE_DIR}/include" CACHE INTERNAL "") 124 | endif (GTEST_DOWNLOADED) 125 | 126 | if(GTEST_FOUND) 127 | message(STATUS "Tests from subdirectory 'tests' added") 128 | enable_testing(true) 129 | include_directories(${GTEST_INCLUDE_DIRS}) 130 | add_subdirectory(tests) 131 | endif(GTEST_FOUND) 132 | 133 | add_subdirectory(src) 134 | 135 | # -- Build the examples 136 | add_subdirectory(examples EXCLUDE_FROM_ALL) 137 | 138 | # Configure installation 139 | install(DIRECTORY include DESTINATION . FILES_MATCHING PATTERN "*.h") 140 | 141 | include(InstallRequiredSystemLibraries) 142 | 143 | # Configure packaging 144 | SET(CPACK_PACKAGE_NAME "mysql-5.6-labs-binary-log-api") 145 | SET(CPACK_PACKAGE_VERSION_MAJOR "${MySQL_BINLOG_VERSION_MAJOR}") 146 | SET(CPACK_PACKAGE_VERSION_MINOR "${MySQL_BINLOG_VERSION_MINOR}") 147 | SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY 148 | "mysql-5.6-labs-binary-log-api: a MySQL client library for interfacing with the binary log mechanism.") 149 | 150 | SET(CPACK_GENERATOR "STGZ;TGZ;TZ;DEB;RPM") 151 | 152 | # Get package name correctly formatted with name, version, and platform 153 | execute_process(COMMAND uname -m OUTPUT_VARIABLE SYSTEM_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE) 154 | SET(CPACK_PACKAGE_FILE_NAME 155 | "${CPACK_PACKAGE_NAME}.${MRL_VERSION}.${CMAKE_SYSTEM_NAME}.${SYSTEM_ARCH}") 156 | 157 | SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Oracle Corporation") 158 | 159 | include(CPack) 160 | -------------------------------------------------------------------------------- /include/field_iterator.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #ifndef _FIELD_ITERATOR_H 22 | #define _FIELD_ITERATOR_H 23 | #include "binlog_event.h" 24 | #include "value.h" 25 | #include "row_of_fields.h" 26 | #include 27 | 28 | using namespace mysql; 29 | 30 | namespace mysql { 31 | 32 | bool is_null(unsigned char *bitmap, int index); 33 | 34 | int lookup_metadata_field_size(enum mysql::system::enum_field_types field_type); 35 | boost::uint32_t extract_metadata(const Table_map_event *map, int col_no); 36 | 37 | template 38 | class Row_event_iterator : public std::iterator 40 | { 41 | public: 42 | Row_event_iterator() : m_row_event(0), m_table_map(0), 43 | m_new_field_offset_calculated(0), m_field_offset(0) 44 | { } 45 | 46 | Row_event_iterator(const Row_event *row_event, 47 | const Table_map_event *table_map) 48 | : m_row_event(row_event), m_table_map(table_map), 49 | m_new_field_offset_calculated(0) 50 | { 51 | m_field_offset= 0; 52 | } 53 | 54 | Iterator_value_type operator*(); 55 | 56 | Row_event_iterator& operator++(); 57 | 58 | Row_event_iterator operator++(int); 59 | 60 | bool operator==(const Row_event_iterator& x) const; 61 | 62 | bool operator!=(const Row_event_iterator& x) const; 63 | 64 | //Row_iterator end() const; 65 | private: 66 | size_t fields(Iterator_value_type& fields_vector ); 67 | const Row_event *m_row_event; 68 | const Table_map_event *m_table_map; 69 | unsigned long m_new_field_offset_calculated; 70 | unsigned long m_field_offset; 71 | }; 72 | 73 | 74 | 75 | template 76 | size_t Row_event_iterator::fields(Iterator_value_type& fields_vector ) 77 | { 78 | size_t field_offset= m_field_offset; 79 | int row_field_col_index= 0; 80 | std::vector nullbits(m_row_event->null_bits_len); 81 | std::copy(m_row_event->row.begin()+m_field_offset, 82 | m_row_event->row.begin()+(m_field_offset+m_row_event->null_bits_len), 83 | nullbits.begin()); 84 | 85 | field_offset += m_row_event->null_bits_len; 86 | for(unsigned col_no=0; col_no < m_table_map->columns.size(); ++col_no) 87 | { 88 | ++row_field_col_index; 89 | unsigned int type= m_table_map->columns[col_no]&0xFF; 90 | boost::uint32_t metadata= extract_metadata(m_table_map, col_no); 91 | mysql::Value val((enum mysql::system::enum_field_types)type, 92 | metadata, 93 | (const char *)&m_row_event->row[field_offset]); 94 | if (is_null((unsigned char *)&nullbits[0], col_no )) 95 | { 96 | val.is_null(true); 97 | } 98 | else 99 | { 100 | /* 101 | If the value is null it is not in the list of values and thus we won't 102 | increse the offset. TODO what if all values are null?! 103 | */ 104 | field_offset += val.length(); 105 | } 106 | fields_vector.push_back(val); 107 | } 108 | return field_offset; 109 | } 110 | 111 | template 112 | Iterator_value_type Row_event_iterator::operator*() 113 | { // dereferencing 114 | Iterator_value_type fields_vector; 115 | /* 116 | * Remember this offset if we need to increate the row pointer 117 | */ 118 | m_new_field_offset_calculated= fields(fields_vector); 119 | 120 | return fields_vector; 121 | } 122 | 123 | template< class Iterator_value_type > 124 | Row_event_iterator< Iterator_value_type >& 125 | Row_event_iterator< Iterator_value_type >::operator++() 126 | { // prefix 127 | if (m_field_offset < m_row_event->row.size()) 128 | { 129 | /* 130 | * If we requested the fields in a previous operations 131 | * we also calculated the new offset at the same time. 132 | */ 133 | if (m_new_field_offset_calculated != 0) 134 | { 135 | m_field_offset= m_new_field_offset_calculated; 136 | //m_field_offset += m_row_event->null_bits_len; 137 | m_new_field_offset_calculated= 0; 138 | if (m_field_offset >= m_row_event->row.size()) 139 | m_field_offset= 0; 140 | return *this; 141 | } 142 | 143 | /* 144 | * Advance the field offset to the next row 145 | */ 146 | int row_field_col_index= 0; 147 | std::vector nullbits(m_row_event->null_bits_len); 148 | std::copy(m_row_event->row.begin()+m_field_offset, 149 | m_row_event->row.begin()+(m_field_offset+m_row_event->null_bits_len), 150 | nullbits.begin()); 151 | m_field_offset += m_row_event->null_bits_len; 152 | for(unsigned col_no=0; col_no < m_table_map->columns.size(); ++col_no) 153 | { 154 | ++row_field_col_index; 155 | mysql::Value val((enum mysql::system::enum_field_types)m_table_map->columns[col_no], 156 | m_table_map->metadata[col_no], 157 | (const char *)&m_row_event->row[m_field_offset]); 158 | if (!is_null((unsigned char *)&nullbits[0], col_no)) 159 | { 160 | m_field_offset += val.length(); 161 | } 162 | } 163 | 164 | return *this; 165 | } 166 | 167 | m_field_offset= 0; 168 | return *this; 169 | 170 | } 171 | 172 | template 173 | Row_event_iterator< Iterator_value_type > 174 | Row_event_iterator< Iterator_value_type >::operator++(int) 175 | { // postfix 176 | Row_event_iterator temp = *this; 177 | ++*this; 178 | return temp; 179 | } 180 | 181 | template 182 | bool Row_event_iterator< Iterator_value_type >::operator==(const Row_event_iterator& x) const 183 | { 184 | return m_field_offset == x.m_field_offset; 185 | } 186 | 187 | template 188 | bool Row_event_iterator< Iterator_value_type >::operator!=(const Row_event_iterator& x) const 189 | { 190 | return m_field_offset != x.m_field_offset; 191 | } 192 | 193 | } 194 | 195 | 196 | #endif /* _FIELD_ITERATOR_H */ 197 | -------------------------------------------------------------------------------- /include/binlog_event.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | #ifndef _BINLOG_EVENT_H 21 | #define _BINLOG_EVENT_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | namespace mysql 30 | { 31 | /** 32 | @enum Log_event_type 33 | 34 | Enumeration type for the different types of log events. 35 | */ 36 | enum Log_event_type 37 | { 38 | /* 39 | Every time you update this enum (when you add a type), you have to 40 | fix Format_description_log_event::Format_description_log_event(). 41 | */ 42 | UNKNOWN_EVENT= 0, 43 | START_EVENT_V3= 1, 44 | QUERY_EVENT= 2, 45 | STOP_EVENT= 3, 46 | ROTATE_EVENT= 4, 47 | INTVAR_EVENT= 5, 48 | LOAD_EVENT= 6, 49 | SLAVE_EVENT= 7, 50 | CREATE_FILE_EVENT= 8, 51 | APPEND_BLOCK_EVENT= 9, 52 | EXEC_LOAD_EVENT= 10, 53 | DELETE_FILE_EVENT= 11, 54 | /* 55 | NEW_LOAD_EVENT is like LOAD_EVENT except that it has a longer 56 | sql_ex, allowing multibyte TERMINATED BY etc; both types share the 57 | same class (Load_log_event) 58 | */ 59 | NEW_LOAD_EVENT= 12, 60 | RAND_EVENT= 13, 61 | USER_VAR_EVENT= 14, 62 | FORMAT_DESCRIPTION_EVENT= 15, 63 | XID_EVENT= 16, 64 | BEGIN_LOAD_QUERY_EVENT= 17, 65 | EXECUTE_LOAD_QUERY_EVENT= 18, 66 | 67 | TABLE_MAP_EVENT = 19, 68 | 69 | /* 70 | These event numbers were used for 5.1.0 to 5.1.15 and are 71 | therefore obsolete. 72 | */ 73 | PRE_GA_WRITE_ROWS_EVENT = 20, 74 | PRE_GA_UPDATE_ROWS_EVENT = 21, 75 | PRE_GA_DELETE_ROWS_EVENT = 22, 76 | 77 | /* 78 | These event numbers are used from 5.1.16 and forward 79 | */ 80 | WRITE_ROWS_EVENT = 23, 81 | UPDATE_ROWS_EVENT = 24, 82 | DELETE_ROWS_EVENT = 25, 83 | 84 | /* 85 | Something out of the ordinary happened on the master 86 | */ 87 | INCIDENT_EVENT= 26, 88 | 89 | /* 90 | * A user defined event 91 | */ 92 | USER_DEFINED= 27, 93 | /* 94 | Add new events here - right above this comment! 95 | Existing events (except ENUM_END_EVENT) should never change their numbers 96 | */ 97 | 98 | 99 | ENUM_END_EVENT /* end marker */ 100 | }; 101 | 102 | namespace system { 103 | /** 104 | * Convenience function to get the string representation of a binlog event. 105 | */ 106 | const char* get_event_type_str(Log_event_type type); 107 | } // end namespace system 108 | 109 | #define LOG_EVENT_HEADER_SIZE 20 110 | class Log_event_header 111 | { 112 | public: 113 | boost::uint8_t marker; // always 0 or 0xFF 114 | boost::uint32_t timestamp; 115 | boost::uint8_t type_code; 116 | boost::uint32_t server_id; 117 | boost::uint32_t event_length; 118 | boost::uint32_t next_position; 119 | boost::uint16_t flags; 120 | }; 121 | 122 | 123 | class Binary_log_event; 124 | 125 | /** 126 | * TODO Base class for events. Implementation is in body() 127 | */ 128 | class Binary_log_event 129 | { 130 | public: 131 | Binary_log_event() 132 | { 133 | /* 134 | An event length of 0 indicates that the header isn't initialized 135 | */ 136 | m_header.event_length= 0; 137 | m_header.type_code= 0; 138 | } 139 | 140 | Binary_log_event(Log_event_header *header) 141 | { 142 | m_header= *header; 143 | } 144 | 145 | virtual ~Binary_log_event(); 146 | 147 | /** 148 | * Helper method 149 | */ 150 | enum Log_event_type get_event_type() const 151 | { 152 | return (enum Log_event_type) m_header.type_code; 153 | } 154 | 155 | /** 156 | * Return a pointer to the header of the log event 157 | */ 158 | Log_event_header *header() { return &m_header; } 159 | 160 | private: 161 | Log_event_header m_header; 162 | }; 163 | 164 | class Query_event: public Binary_log_event 165 | { 166 | public: 167 | Query_event(Log_event_header *header) : Binary_log_event(header) {} 168 | boost::uint32_t thread_id; 169 | boost::uint32_t exec_time; 170 | boost::uint16_t error_code; 171 | std::vector variables; 172 | 173 | std::string db_name; 174 | std::string query; 175 | }; 176 | 177 | class Rotate_event: public Binary_log_event 178 | { 179 | public: 180 | Rotate_event(Log_event_header *header) : Binary_log_event(header) {} 181 | std::string binlog_file; 182 | boost::uint64_t binlog_pos; 183 | }; 184 | 185 | class Format_event: public Binary_log_event 186 | { 187 | public: 188 | Format_event(Log_event_header *header) : Binary_log_event(header) {} 189 | boost::uint16_t binlog_version; 190 | std::string master_version; 191 | boost::uint32_t created_ts; 192 | boost::uint8_t log_header_len; 193 | }; 194 | 195 | class User_var_event: public Binary_log_event 196 | { 197 | public: 198 | enum Value_type { 199 | STRING_TYPE, 200 | REAL_TYPE, 201 | INT_TYPE, 202 | ROW_TYPE, 203 | DECIMAL_TYPE, 204 | VALUE_TYPE_COUNT 205 | }; 206 | 207 | User_var_event(Log_event_header *header) : Binary_log_event(header) {} 208 | std::string name; 209 | boost::uint8_t is_null; 210 | boost::uint8_t type; 211 | boost::uint32_t charset; /* charset of the string */ 212 | std::string value; /* encoded in binary speak, depends on .type */ 213 | }; 214 | 215 | class Table_map_event: public Binary_log_event 216 | { 217 | public: 218 | Table_map_event(Log_event_header *header) : Binary_log_event(header) {} 219 | boost::uint64_t table_id; 220 | boost::uint16_t flags; 221 | std::string db_name; 222 | std::string table_name; 223 | std::vector columns; 224 | std::vector metadata; 225 | std::vector null_bits; 226 | }; 227 | 228 | class Row_event: public Binary_log_event 229 | { 230 | public: 231 | Row_event(Log_event_header *header) : Binary_log_event(header) {} 232 | boost::uint64_t table_id; 233 | boost::uint16_t flags; 234 | boost::uint64_t columns_len; 235 | boost::uint32_t null_bits_len; 236 | std::vector columns_before_image; 237 | std::vector used_columns; 238 | std::vector row; 239 | }; 240 | 241 | class Int_var_event: public Binary_log_event 242 | { 243 | public: 244 | Int_var_event(Log_event_header *header) : Binary_log_event(header) {} 245 | boost::uint8_t type; 246 | boost::uint64_t value; 247 | }; 248 | 249 | class Incident_event: public Binary_log_event 250 | { 251 | public: 252 | Incident_event() : Binary_log_event() {} 253 | Incident_event(Log_event_header *header) : Binary_log_event(header) {} 254 | boost::uint8_t type; 255 | std::string message; 256 | }; 257 | 258 | class Xid: public Binary_log_event 259 | { 260 | public: 261 | Xid(Log_event_header *header) : Binary_log_event(header) {} 262 | boost::uint64_t xid_id; 263 | }; 264 | 265 | Binary_log_event *create_incident_event(unsigned int type, const char *message, unsigned long pos= 0); 266 | 267 | } // end namespace mysql 268 | 269 | #endif /* _BINLOG_EVENT_H */ 270 | -------------------------------------------------------------------------------- /include/tcp_driver.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | 21 | #ifndef _TCP_DRIVER_H 22 | #define _TCP_DRIVER_H 23 | #include "binlog_driver.h" 24 | #include "bounded_buffer.h" 25 | #include "protocol.h" 26 | #include 27 | #include 28 | 29 | 30 | #define MAX_PACKAGE_SIZE 0xffffff 31 | 32 | #define GET_NEXT_PACKET_HEADER \ 33 | boost::asio::async_read(*m_socket, boost::asio::buffer(m_net_header, 4), \ 34 | boost::bind(&Binlog_tcp_driver::handle_net_packet_header, this, \ 35 | boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)) \ 36 | 37 | using boost::asio::ip::tcp; 38 | 39 | namespace mysql { namespace system { 40 | 41 | class Binlog_tcp_driver : public Binary_log_driver 42 | { 43 | public: 44 | 45 | Binlog_tcp_driver(const std::string& user, const std::string& passwd, 46 | const std::string& host, unsigned long port) 47 | : Binary_log_driver("", 4), m_host(host), m_user(user), m_passwd(passwd), 48 | m_port(port), m_socket(NULL), m_waiting_event(0), m_event_loop(0), 49 | m_total_bytes_transferred(0), m_shutdown(false), 50 | m_event_queue(new bounded_buffer(50)) 51 | { 52 | } 53 | 54 | ~Binlog_tcp_driver() 55 | { 56 | delete m_event_queue; 57 | delete m_socket; 58 | } 59 | 60 | /** 61 | * Connect using previously declared connection parameters. 62 | */ 63 | int connect(); 64 | 65 | /** 66 | * Blocking wait for the next binary log event to reach the client 67 | */ 68 | int wait_for_next_event(mysql::Binary_log_event **event); 69 | 70 | /** 71 | * Reconnects to the master with a new binlog dump request. 72 | */ 73 | int set_position(const std::string &str, unsigned long position); 74 | 75 | int get_position(std::string *str, unsigned long *position); 76 | 77 | const std::string& user() const { return m_user; } 78 | const std::string& password() const { return m_passwd; } 79 | const std::string& host() const { return m_host; } 80 | unsigned long port() const { return m_port; } 81 | 82 | protected: 83 | /** 84 | * Connects to a mysql server, authenticates and initiates the event 85 | * request loop. 86 | * 87 | * @param user The user account on the server side 88 | * @param passwd The password used to authenticate the user 89 | * @param host The DNS host name or IP of the server 90 | * @param port The service port number to connect to 91 | * 92 | * 93 | * @return Success or failure code 94 | * @retval 0 Successfully established a connection 95 | * @retval >1 An error occurred. 96 | */ 97 | int connect(const std::string& user, const std::string& passwd, 98 | const std::string& host, long port, 99 | const std::string& binlog_filename="", size_t offset=4); 100 | 101 | private: 102 | 103 | /** 104 | * Request a binlog dump and starts the event loop in a new thread 105 | * @param binlog_file_name The base name of the binlog files to query 106 | * 107 | */ 108 | void start_binlog_dump(const std::string &binlog_file_name, size_t offset); 109 | 110 | /** 111 | * Handles a completed mysql server package header and put a 112 | * request for the body in the job queue. 113 | */ 114 | void handle_net_packet_header(const boost::system::error_code& err, std::size_t bytes_transferred); 115 | 116 | /** 117 | * Handles a completed network package with the assumption that it contains 118 | * a binlog event. 119 | * 120 | * TODO rename to handle_event_log_packet? 121 | */ 122 | void handle_net_packet(const boost::system::error_code& err, std::size_t bytes_transferred); 123 | 124 | /** 125 | * Called from handle_net_packet(). The function handle a stream of bytes 126 | * representing event packets which may or may not be complete. 127 | * It uses m_waiting_event and the size of the stream as parameters 128 | * in a state machine. If there is no m_waiting_event then the event 129 | * header must be parsed for the event packet length. This can only 130 | * be done if the accumulated stream of bytes are more than 19. 131 | * Next, if there is a m_waiting_event, it can only be completed if 132 | * event_length bytes are waiting on the stream. 133 | * 134 | * If none of these conditions are fullfilled, the function exits without 135 | * any action. 136 | * 137 | * @param err Not used 138 | * @param bytes_transferred The number of bytes waiting in the event stream 139 | * 140 | */ 141 | void handle_event_packet(const boost::system::error_code& err, std::size_t bytes_transferred); 142 | 143 | /** 144 | * Executes io_service in a loop. 145 | * TODO Checks for connection errors and reconnects to the server 146 | * if necessary. 147 | */ 148 | void start_event_loop(void); 149 | 150 | /** 151 | * Reconnect to the server by first calling disconnect and then connect. 152 | */ 153 | void reconnect(void); 154 | 155 | /** 156 | * Disconnet from the server. The io service must have been stopped before 157 | * this function is called. 158 | * The event queue is emptied. 159 | */ 160 | void disconnect(void); 161 | 162 | /** 163 | * Terminates the io service and sets the shudown flag. 164 | * this causes the event loop to terminate. 165 | */ 166 | void shutdown(void); 167 | 168 | boost::thread *m_event_loop; 169 | boost::asio::io_service m_io_service; 170 | tcp::socket *m_socket; 171 | bool m_shutdown; 172 | 173 | /** 174 | * Temporary storage for a handshake package 175 | */ 176 | st_handshake_package m_handshake_package; 177 | 178 | /** 179 | * Temporary storage for an OK package 180 | */ 181 | st_ok_package m_ok_package; 182 | 183 | /** 184 | * Temporary storage for an error package 185 | */ 186 | st_error_package m_error_package; 187 | 188 | /** 189 | * each bin log event starts with a 19 byte long header 190 | * We use this sturcture every time we initiate an async 191 | * read. 192 | */ 193 | boost::uint8_t m_event_header[19]; 194 | 195 | /** 196 | * 197 | */ 198 | boost::uint8_t m_net_header[4]; 199 | 200 | /** 201 | * 202 | */ 203 | boost::uint8_t m_net_packet[MAX_PACKAGE_SIZE]; 204 | boost::asio::streambuf m_event_stream_buffer; 205 | char * m_event_packet; 206 | 207 | /** 208 | * This pointer points to an object constructed from event 209 | * stream during async communication with 210 | * server. If it is 0 it means that no event has been 211 | * constructed yet. 212 | */ 213 | Log_event_header *m_waiting_event; 214 | Log_event_header m_log_event_header; 215 | /** 216 | * A ring buffer used to dispatch aggregated events to the user application 217 | */ 218 | bounded_buffer *m_event_queue; 219 | 220 | std::string m_user; 221 | std::string m_host; 222 | std::string m_passwd; 223 | long m_port; 224 | 225 | boost::uint64_t m_total_bytes_transferred; 226 | 227 | 228 | }; 229 | 230 | /** 231 | * Sends a SHOW MASTER STATUS command to the server and retrieve the 232 | * current binlog position. 233 | * 234 | * @return False if the operation succeeded, true if it failed. 235 | */ 236 | bool fetch_master_status(tcp::socket *socket, std::string *filename, unsigned long *position); 237 | /** 238 | * Sends a SHOW BINARY LOGS command to the server and stores the file 239 | * names and sizes in a map. 240 | */ 241 | bool fetch_binlogs_name_and_size(tcp::socket *socket, std::map &binlog_map); 242 | 243 | int authenticate(tcp::socket *socket, const std::string& user, 244 | const std::string& passwd, 245 | const st_handshake_package &handshake_package); 246 | 247 | tcp::socket * 248 | sync_connect_and_authenticate(boost::asio::io_service &io_service, const std::string &user, 249 | const std::string &passwd, const std::string &host, long port); 250 | 251 | 252 | } } 253 | 254 | #endif /* _TCP_DRIVER_H */ 255 | -------------------------------------------------------------------------------- /tests/r/sys_vars.result: -------------------------------------------------------------------------------- 1 | DROP DATABASE IF EXISTS `sys_var`; 2 | Warnings: 3 | Note 1008 Can't drop database 'sys_var'; database doesn't exist 4 | CREATE DATABASE `sys_var`; 5 | USE `sys_var`; 6 | CREATE TABLE t1 (c1 CHAR(3), c2 CHAR(1) DEFAULT 'a'); 7 | INSERT INTO t1 (c1) VALUES ('a'),('bb'),('ccc'); 8 | UPDATE t1 SET c1='aaaa' WHERE c1='a'; 9 | Warnings: 10 | Warning 1265 Data truncated for column 'c1' at row 1 11 | DELETE FROM t1; 12 | DROP TABLE t1; 13 | SET @@auto_increment_increment=19; 14 | SET @@auto_increment_offset=4; 15 | SET @@character_set_client='latin2'; 16 | SET @@collation_connection='latin2_bin'; 17 | SET @@collation_server='geostd8_general_ci'; 18 | SET @@time_zone='Japan'; 19 | SET @@lc_time_names='sv_SE'; 20 | SET @@collation_database='geostd8_bin'; 21 | CREATE TABLE t1 (c1 DATE); 22 | INSERT INTO t1 VALUES ('2006-01-01'); 23 | SELECT c1 FROM t1; 24 | c1 25 | 2006-01-01 26 | DROP TABLE t1; 27 | CREATE TABLE t1 (c1 INT AUTO_INCREMENT PRIMARY KEY, c2 TEXT); 28 | INSERT INTO t1 (c1) VALUES ('a'),('bb'),('ccc'); 29 | Warnings: 30 | Warning 1366 Incorrect integer value: 'a' for column 'c1' at row 1 31 | Warning 1366 Incorrect integer value: 'bb' for column 'c1' at row 2 32 | Warning 1366 Incorrect integer value: 'ccc' for column 'c1' at row 3 33 | SELECT * FROM t1; 34 | c1 c2 35 | 4 NULL 36 | 23 NULL 37 | 42 NULL 38 | DROP TABLE t1; 39 | DROP DATABASE `sys_var`; 40 | Connected to server!! 41 | Pos = 4 Event_type = 26 42 | Pos = 0 Event_type = 4 43 | Pos = 114 Event_type = 15 44 | Pos = 213 Event_type = 2 45 | Query = DROP DATABASE IF EXISTS `sys_var` DB = sys_var 46 | catalog_name = std 47 | character_set_client = 8 48 | collation_connection = 8 49 | collation_server = 8 50 | flag2 = 0 51 | sql_mode = -453830021431164924 52 | ---------- 53 | 54 | Pos = 304 Event_type = 2 55 | Query = CREATE DATABASE `sys_var` DB = sys_var 56 | catalog_name = std 57 | character_set_client = 8 58 | collation_connection = 8 59 | collation_server = 8 60 | flag2 = 0 61 | sql_mode = -453830021431164924 62 | ---------- 63 | 64 | Pos = 422 Event_type = 2 65 | Query = CREATE TABLE t1 (c1 CHAR(3), c2 CHAR(1) DEFAULT 'a') DB = sys_var 66 | catalog_name = std 67 | character_set_client = 8 68 | collation_connection = 8 69 | collation_server = 8 70 | flag2 = 566648 71 | sql_mode = -453830021430627274 72 | ---------- 73 | 74 | Pos = 493 Event_type = 2 75 | Query = BEGIN DB = sys_var 76 | catalog_name = std 77 | character_set_client = 8 78 | collation_connection = 8 79 | collation_server = 8 80 | flag2 = 566656 81 | sql_mode = -453830021430758090 82 | ---------- 83 | 84 | Pos = 606 Event_type = 2 85 | Query = INSERT INTO t1 (c1) VALUES ('a'),('bb'),('ccc') DB = sys_var 86 | catalog_name = std 87 | character_set_client = 8 88 | collation_connection = 8 89 | collation_server = 8 90 | flag2 = 566654 91 | sql_mode = -453830021430889162 92 | ---------- 93 | 94 | Pos = 678 Event_type = 2 95 | Query = COMMIT DB = sys_var 96 | catalog_name = std 97 | character_set_client = 8 98 | collation_connection = 8 99 | collation_server = 8 100 | flag2 = 566650 101 | sql_mode = -453830021431151306 102 | ---------- 103 | 104 | Pos = 749 Event_type = 2 105 | Query = BEGIN DB = sys_var 106 | catalog_name = std 107 | character_set_client = 8 108 | collation_connection = 8 109 | collation_server = 8 110 | flag2 = 566652 111 | sql_mode = -453830021431020234 112 | ---------- 113 | 114 | Pos = 851 Event_type = 2 115 | Query = UPDATE t1 SET c1='aaaa' WHERE c1='a' DB = sys_var 116 | catalog_name = std 117 | character_set_client = 8 118 | collation_connection = 8 119 | collation_server = 8 120 | flag2 = 566652 121 | sql_mode = -453830021431020234 122 | ---------- 123 | 124 | Pos = 923 Event_type = 2 125 | Query = COMMIT DB = sys_var 126 | catalog_name = std 127 | character_set_client = 8 128 | collation_connection = 8 129 | collation_server = 8 130 | flag2 = 566652 131 | sql_mode = -453830021431020234 132 | ---------- 133 | 134 | Pos = 994 Event_type = 2 135 | Query = BEGIN DB = sys_var 136 | catalog_name = std 137 | character_set_client = 8 138 | collation_connection = 8 139 | collation_server = 8 140 | flag2 = 566652 141 | sql_mode = -453830021431020234 142 | ---------- 143 | 144 | Pos = 1074 Event_type = 2 145 | Query = DELETE FROM t1 DB = sys_var 146 | catalog_name = std 147 | character_set_client = 8 148 | collation_connection = 8 149 | collation_server = 8 150 | flag2 = 566652 151 | sql_mode = -453830021431020234 152 | ---------- 153 | 154 | Pos = 1146 Event_type = 2 155 | Query = COMMIT DB = sys_var 156 | catalog_name = std 157 | character_set_client = 8 158 | collation_connection = 8 159 | collation_server = 8 160 | flag2 = 566652 161 | sql_mode = -453830021431020234 162 | ---------- 163 | 164 | Pos = 1253 Event_type = 2 165 | Query = DROP TABLE `t1` /* generated by server */ DB = sys_var 166 | catalog_name = std 167 | character_set_client = 8 168 | collation_connection = 8 169 | collation_server = 8 170 | flag2 = 566652 171 | sql_mode = -453830021431020234 172 | ---------- 173 | 174 | Pos = 1355 Event_type = 2 175 | Query = CREATE TABLE t1 (c1 DATE) DB = sys_var 176 | auto_increment_increment = 19 177 | auto_increment_offset = 4 178 | catalog_name = std 179 | character_set_client = 9 180 | collation_connection = 77 181 | collation_database = 93 182 | collation_server = 92 183 | flag2 = 0 184 | lc_time_names = 3 185 | sql_mode = -453830021430968318 186 | ---------- 187 | 188 | Pos = 1437 Event_type = 2 189 | Query = BEGIN DB = sys_var 190 | auto_increment_increment = 19 191 | auto_increment_offset = 4 192 | catalog_name = std 193 | character_set_client = 9 194 | collation_connection = 77 195 | collation_database = 93 196 | collation_server = 92 197 | flag2 = 0 198 | lc_time_names = 3 199 | sql_mode = -453830021430968318 200 | ---------- 201 | 202 | Pos = 1550 Event_type = 2 203 | Query = INSERT INTO t1 VALUES ('2006-01-01') DB = sys_var 204 | auto_increment_increment = 19 205 | auto_increment_offset = 4 206 | catalog_name = std 207 | character_set_client = 9 208 | collation_connection = 77 209 | collation_database = 93 210 | collation_server = 92 211 | flag2 = 0 212 | lc_time_names = 3 213 | sql_mode = -453830021430968318 214 | ---------- 215 | 216 | Pos = 1633 Event_type = 2 217 | Query = COMMIT DB = sys_var 218 | auto_increment_increment = 19 219 | auto_increment_offset = 4 220 | catalog_name = std 221 | character_set_client = 9 222 | collation_connection = 77 223 | collation_database = 93 224 | collation_server = 92 225 | flag2 = 0 226 | lc_time_names = 3 227 | sql_mode = -453830021430968318 228 | ---------- 229 | 230 | Pos = 1751 Event_type = 2 231 | Query = DROP TABLE `t1` /* generated by server */ DB = sys_var 232 | auto_increment_increment = 19 233 | auto_increment_offset = 4 234 | catalog_name = std 235 | character_set_client = 9 236 | collation_connection = 77 237 | collation_database = 93 238 | collation_server = 92 239 | flag2 = 0 240 | lc_time_names = 3 241 | sql_mode = -453830021430968318 242 | ---------- 243 | 244 | Pos = 1888 Event_type = 2 245 | Query = CREATE TABLE t1 (c1 INT AUTO_INCREMENT PRIMARY KEY, c2 TEXT) DB = sys_var 246 | auto_increment_increment = 19 247 | auto_increment_offset = 4 248 | catalog_name = std 249 | character_set_client = 9 250 | collation_connection = 77 251 | collation_database = 93 252 | collation_server = 92 253 | flag2 = 0 254 | lc_time_names = 3 255 | sql_mode = -453830021430968318 256 | ---------- 257 | 258 | Pos = 1970 Event_type = 2 259 | Query = BEGIN DB = sys_var 260 | auto_increment_increment = 19 261 | auto_increment_offset = 4 262 | catalog_name = std 263 | character_set_client = 9 264 | collation_connection = 77 265 | collation_database = 93 266 | collation_server = 92 267 | flag2 = 0 268 | lc_time_names = 3 269 | sql_mode = -453830021430968318 270 | ---------- 271 | 272 | Pos = 1998 Event_type = 5 273 | Pos = 2122 Event_type = 2 274 | Query = INSERT INTO t1 (c1) VALUES ('a'),('bb'),('ccc') DB = sys_var 275 | auto_increment_increment = 19 276 | auto_increment_offset = 4 277 | catalog_name = std 278 | character_set_client = 9 279 | collation_connection = 77 280 | collation_database = 93 281 | collation_server = 92 282 | flag2 = 0 283 | lc_time_names = 3 284 | sql_mode = -453830021430968318 285 | ---------- 286 | 287 | Pos = 2205 Event_type = 2 288 | Query = COMMIT DB = sys_var 289 | auto_increment_increment = 19 290 | auto_increment_offset = 4 291 | catalog_name = std 292 | character_set_client = 9 293 | collation_connection = 77 294 | collation_database = 93 295 | collation_server = 92 296 | flag2 = 0 297 | lc_time_names = 3 298 | sql_mode = -453830021430968318 299 | ---------- 300 | 301 | Pos = 2323 Event_type = 2 302 | Query = DROP TABLE `t1` /* generated by server */ DB = sys_var 303 | auto_increment_increment = 19 304 | auto_increment_offset = 4 305 | catalog_name = std 306 | character_set_client = 9 307 | collation_connection = 77 308 | collation_database = 93 309 | collation_server = 92 310 | flag2 = 0 311 | lc_time_names = 3 312 | sql_mode = -453830021430968318 313 | ---------- 314 | 315 | Pos = 2423 Event_type = 2 316 | Query = DROP DATABASE `sys_var` DB = sys_var 317 | auto_increment_increment = 19 318 | auto_increment_offset = 4 319 | catalog_name = std 320 | character_set_client = 9 321 | collation_connection = 77 322 | collation_database = 93 323 | collation_server = 92 324 | flag2 = 0 325 | lc_time_names = 3 326 | sql_mode = -453830021430968318 327 | ---------- 328 | 329 | "#End of binary log" 330 | -------------------------------------------------------------------------------- /tests/replaybinlog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | #include 21 | #include 22 | #include "binlog_api.h" 23 | 24 | bool is_text_field(Value &val) 25 | { 26 | if (val.type() == mysql::system::MYSQL_TYPE_VARCHAR || 27 | val.type() == mysql::system::MYSQL_TYPE_BLOB || 28 | val.type() == mysql::system::MYSQL_TYPE_MEDIUM_BLOB || 29 | val.type() == mysql::system::MYSQL_TYPE_LONG_BLOB) 30 | return true; 31 | return false; 32 | } 33 | 34 | void table_insert(const std::string& table_name, mysql::Row_of_fields &fields) 35 | { 36 | std::cout << "INSERT INTO " 37 | << table_name 38 | << " VALUES ("; 39 | mysql::Row_of_fields::iterator field_it= fields.begin(); 40 | mysql::Converter converter; 41 | do { 42 | /* 43 | Each row contains a vector of Value objects. The converter 44 | allows us to transform the value into another 45 | representation. 46 | */ 47 | std::string str; 48 | converter.to(str, *field_it); 49 | if (is_text_field(*field_it)) 50 | std::cout << '\''; 51 | std::cout << str; 52 | if (is_text_field(*field_it)) 53 | std::cout << '\''; 54 | ++field_it; 55 | if (field_it != fields.end()) 56 | std::cout << ", "; 57 | } while(field_it != fields.end()); 58 | std::cout << ")" << std::endl; 59 | } 60 | 61 | 62 | void table_update(const std::string& table_name, 63 | mysql::Row_of_fields &old_fields, mysql::Row_of_fields &new_fields) 64 | { 65 | std::cout << "UPDATE " 66 | << table_name 67 | << " SET "; 68 | 69 | int field_id= 0; 70 | mysql::Row_of_fields::iterator field_it= new_fields.begin(); 71 | mysql::Converter converter; 72 | do { 73 | std::string str; 74 | converter.to(str, *field_it); 75 | std::cout << field_id << "= "; 76 | if (is_text_field(*field_it)) 77 | std::cout << '\''; 78 | std::cout << str; 79 | if (is_text_field(*field_it)) 80 | std::cout << '\''; 81 | ++field_it; 82 | ++field_id; 83 | if (field_it != new_fields.end()) 84 | std::cout << ", "; 85 | } while(field_it != new_fields.end()); 86 | std::cout << " WHERE "; 87 | field_it= old_fields.begin(); 88 | field_id= 0; 89 | do { 90 | std::string str; 91 | converter.to(str, *field_it); 92 | std::cout << field_id << "= "; 93 | if (is_text_field(*field_it)) 94 | std::cout << '\''; 95 | std::cout << str; 96 | if (is_text_field(*field_it)) 97 | std::cout << '\''; 98 | ++field_it; 99 | ++field_id; 100 | if (field_it != old_fields.end()) 101 | std::cout << " AND "; 102 | } while(field_it != old_fields.end()); 103 | std::cout << " LIMIT 1" << std::endl; 104 | 105 | } 106 | 107 | 108 | void table_delete(const std::string& table_name, mysql::Row_of_fields &fields) 109 | { 110 | std::cout << "DELETE FROM " 111 | << table_name 112 | << " WHERE "; 113 | mysql::Row_of_fields::iterator field_it= fields.begin(); 114 | int field_id= 0; 115 | mysql::Converter converter; 116 | do { 117 | 118 | std::string str; 119 | converter.to(str, *field_it); 120 | std::cout << field_id << "= "; 121 | if (is_text_field(*field_it)) 122 | std::cout << '\''; 123 | std::cout << str; 124 | if (is_text_field(*field_it)) 125 | std::cout << '\''; 126 | ++field_it; 127 | ++field_id; 128 | if (field_it != fields.end()) 129 | std::cout << " AND "; 130 | } while(field_it != fields.end()); 131 | std::cout << " LIMIT 1" << std::endl; 132 | } 133 | 134 | class Incident_handler : public mysql::Content_handler 135 | { 136 | public: 137 | Incident_handler() : mysql::Content_handler() {} 138 | 139 | mysql::Binary_log_event *process_event(mysql::Incident_event *incident) 140 | { 141 | std::cout << "Event type: " 142 | << mysql::system::get_event_type_str(incident->get_event_type()) 143 | << " length: " << incident->header()->event_length 144 | << " next pos: " << incident->header()->next_position 145 | << std::endl; 146 | std::cout << "type= " 147 | << (unsigned)incident->type 148 | << " message= " 149 | << incident->message 150 | << std::endl 151 | << std::endl; 152 | /* Consume the event */ 153 | delete incident; 154 | return 0; 155 | } 156 | }; 157 | 158 | class Replay_binlog : public mysql::Content_handler 159 | { 160 | public: 161 | Replay_binlog() : mysql::Content_handler() {} 162 | mysql::Binary_log_event *process_event(mysql::Binary_log_event *event) 163 | { 164 | if (event->get_event_type() != mysql::USER_DEFINED) 165 | return event; 166 | std::cout << "Event type: " 167 | << mysql::system::get_event_type_str(event->get_event_type()) 168 | << " length: " << event->header()->event_length 169 | << " next pos: " << event->header()->next_position 170 | << std::endl; 171 | mysql::Transaction_log_event *trans= static_cast(event); 172 | int row_count=0; 173 | /* 174 | The transaction event we created has aggregated all row events in an 175 | ordered list. 176 | */ 177 | BOOST_FOREACH(mysql::Binary_log_event * event, trans->m_events) 178 | { 179 | switch (event->get_event_type()) 180 | { 181 | case mysql::WRITE_ROWS_EVENT: 182 | case mysql::DELETE_ROWS_EVENT: 183 | case mysql::UPDATE_ROWS_EVENT: 184 | mysql::Row_event *rev= static_cast(event); 185 | boost::uint64_t table_id= rev->table_id; 186 | // BUG: will create a new event header if the table id doesn't exist. 187 | Binary_log_event * tmevent= trans->table_map()[table_id]; 188 | mysql::Table_map_event *tm; 189 | if (tmevent != NULL) 190 | tm= static_cast(tmevent); 191 | else 192 | { 193 | std::cout << "Table id " 194 | << table_id 195 | << " was not registered by any preceding table map event." 196 | << std::endl; 197 | continue; 198 | } 199 | /* 200 | Each row event contains multiple rows and fields. The Row_iterator 201 | allows us to iterate one row at a time. 202 | */ 203 | mysql::Row_event_set rows(rev, tm); 204 | /* 205 | Create a fuly qualified table name 206 | */ 207 | std::ostringstream os; 208 | os << tm->db_name << '.' << tm->table_name; 209 | mysql::Row_event_set::iterator it= rows.begin(); 210 | do { 211 | mysql::Row_of_fields fields= *it; 212 | 213 | if (event->get_event_type() == mysql::WRITE_ROWS_EVENT) 214 | table_insert(os.str(),fields); 215 | if (event->get_event_type() == mysql::UPDATE_ROWS_EVENT) 216 | { 217 | ++it; 218 | mysql::Row_of_fields fields2= *it; 219 | table_update(os.str(),fields,fields2); 220 | } 221 | if (event->get_event_type() == mysql::DELETE_ROWS_EVENT) 222 | table_delete(os.str(),fields); 223 | } while (++it != rows.end()); 224 | } // end switch 225 | } // end BOOST_FOREACH 226 | /* Consume the event */ 227 | delete trans; 228 | return 0; 229 | } 230 | }; 231 | /* 232 | * 233 | */ 234 | int main(int argc, char** argv) 235 | { 236 | if (argc != 2) 237 | { 238 | fprintf(stderr,"Usage:\n\treplaybinlog URL\n\nExample:\n\treplaybinlog mysql://root:mypasswd@127.0.0.1:3306\n\n"); 239 | return (EXIT_FAILURE); 240 | } 241 | 242 | mysql::Binary_log binlog(mysql::system::create_transport(argv[1])); 243 | 244 | 245 | /* 246 | Attach a custom event parser which produces user defined events 247 | */ 248 | mysql::Basic_transaction_parser transaction_parser; 249 | Incident_handler incident_hndlr; 250 | Replay_binlog replay_hndlr; 251 | 252 | binlog.content_handler_pipeline()->push_back(&transaction_parser); 253 | binlog.content_handler_pipeline()->push_back(&incident_hndlr); 254 | binlog.content_handler_pipeline()->push_back(&replay_hndlr); 255 | 256 | if (binlog.connect()) 257 | { 258 | fprintf(stderr,"Can't connect to the master.\n"); 259 | return (EXIT_FAILURE); 260 | } 261 | 262 | if (binlog.set_position(4) != ERR_OK) 263 | { 264 | fprintf(stderr,"Can't reposition the binary log reader.\n"); 265 | return (EXIT_FAILURE); 266 | } 267 | 268 | Binary_log_event *event; 269 | 270 | bool quit= false; 271 | while(!quit) 272 | { 273 | /* 274 | Pull events from the master. This is the heart beat of the event listener. 275 | */ 276 | if (binlog.wait_for_next_event(&event)) 277 | { 278 | quit= true; 279 | continue; 280 | } 281 | 282 | /* 283 | Print the event 284 | */ 285 | std::cout << "Event type: " 286 | << mysql::system::get_event_type_str(event->get_event_type()) 287 | << " length: " << event->header()->event_length 288 | << " next pos: " << event->header()->next_position 289 | << std::endl; 290 | 291 | /* 292 | Perform a special action based on event type 293 | */ 294 | 295 | switch(event->header()->type_code) 296 | { 297 | case mysql::QUERY_EVENT: 298 | { 299 | const mysql::Query_event *qev= static_cast(event); 300 | std::cout << "query= " 301 | << qev->query 302 | << " db= " 303 | << qev->db_name 304 | << std::endl 305 | << std::endl; 306 | if (qev->query.find("DROP TABLE REPLICATION_LISTENER") != std::string::npos || 307 | qev->query.find("DROP TABLE `REPLICATION_LISTENER`") != std::string::npos) 308 | { 309 | quit= true; 310 | } 311 | } 312 | break; 313 | 314 | case mysql::ROTATE_EVENT: 315 | { 316 | mysql::Rotate_event *rot= static_cast(event); 317 | std::cout << "filename= " 318 | << rot->binlog_file.c_str() 319 | << " pos= " 320 | << rot->binlog_pos 321 | << std::endl 322 | << std::endl; 323 | } 324 | break; 325 | 326 | } // end switch 327 | delete event; 328 | } // end loop 329 | return (EXIT_SUCCESS); 330 | } 331 | -------------------------------------------------------------------------------- /include/protocol.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights 3 | reserved. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; version 2 of 8 | the License. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | 02110-1301 USA 19 | */ 20 | #ifndef _PROTOCOL_H 21 | #define _PROTOCOL_H 22 | 23 | #include 24 | #include 25 | #include "binlog_event.h" 26 | 27 | using boost::asio::ip::tcp; 28 | namespace mysql { 29 | namespace system { 30 | 31 | /** 32 | Storage structure for the handshake package sent from the server to 33 | the client. 34 | */ 35 | struct st_handshake_package 36 | { 37 | boost::uint8_t protocol_version; 38 | std::string server_version_str; 39 | boost::uint32_t thread_id; 40 | boost::uint8_t scramble_buff[8]; 41 | boost::uint16_t server_capabilities; 42 | boost::uint8_t server_language; 43 | boost::uint16_t server_status; 44 | boost::uint8_t scramble_buff2[13]; 45 | }; 46 | 47 | /** 48 | Storage structure for the OK package sent from the server to 49 | the client. 50 | */ 51 | struct st_ok_package 52 | { 53 | boost::uint8_t result_type; 54 | boost::uint64_t affected_rows; 55 | boost::uint64_t insert_id; 56 | boost::uint16_t server_status; 57 | boost::uint16_t warning_count; 58 | std::string message; 59 | }; 60 | 61 | struct st_eof_package 62 | { 63 | boost::uint16_t warning_count; 64 | boost::uint16_t status_flags; 65 | }; 66 | 67 | /** 68 | Storage structure for the Error package sent from the server to 69 | the client. 70 | */ 71 | struct st_error_package 72 | { 73 | boost::uint16_t error_code; 74 | boost::uint8_t sql_state[5]; 75 | std::string message; 76 | }; 77 | 78 | #define CLIENT_LONG_PASSWORD 1 /* new more secure passwords */ 79 | #define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */ 80 | #define CLIENT_LONG_FLAG 4 /* Get all column flags */ 81 | #define CLIENT_CONNECT_WITH_DB 8 /* One can specify db on connect */ 82 | #define CLIENT_NO_SCHEMA 16 /* Don't allow database.table.column */ 83 | #define CLIENT_COMPRESS 32 /* Can use compression protocol */ 84 | #define CLIENT_ODBC 64 /* Odbc client */ 85 | #define CLIENT_LOCAL_FILES 128 /* Can use LOAD DATA LOCAL */ 86 | #define CLIENT_IGNORE_SPACE 256 /* Ignore spaces before '(' */ 87 | #define CLIENT_PROTOCOL_41 512 /* New 4.1 protocol */ 88 | #define CLIENT_INTERACTIVE 1024 /* This is an interactive client */ 89 | #define CLIENT_SSL 2048 /* Switch to SSL after handshake */ 90 | #define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */ 91 | #define CLIENT_TRANSACTIONS 8192 /* Client knows about transactions */ 92 | #define CLIENT_RESERVED 16384 /* Old flag for 4.1 protocol */ 93 | #define CLIENT_SECURE_CONNECTION 32768 /* New 4.1 authentication */ 94 | #define CLIENT_MULTI_STATEMENTS (1UL << 16) /* Enable/disable multi-stmt support */ 95 | #define CLIENT_MULTI_RESULTS (1UL << 17) /* Enable/disable multi-results */ 96 | 97 | #define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30) 98 | #define CLIENT_REMEMBER_OPTIONS (1UL << 31) 99 | 100 | /* Gather all possible capabilites (flags) supported by the server */ 101 | #define CLIENT_ALL_FLAGS (CLIENT_LONG_PASSWORD | \ 102 | CLIENT_FOUND_ROWS | \ 103 | CLIENT_LONG_FLAG | \ 104 | CLIENT_CONNECT_WITH_DB | \ 105 | CLIENT_NO_SCHEMA | \ 106 | CLIENT_COMPRESS | \ 107 | CLIENT_ODBC | \ 108 | CLIENT_LOCAL_FILES | \ 109 | CLIENT_IGNORE_SPACE | \ 110 | CLIENT_PROTOCOL_41 | \ 111 | CLIENT_INTERACTIVE | \ 112 | CLIENT_SSL | \ 113 | CLIENT_IGNORE_SIGPIPE | \ 114 | CLIENT_TRANSACTIONS | \ 115 | CLIENT_RESERVED | \ 116 | CLIENT_SECURE_CONNECTION | \ 117 | CLIENT_MULTI_STATEMENTS | \ 118 | CLIENT_MULTI_RESULTS | \ 119 | CLIENT_SSL_VERIFY_SERVER_CERT | \ 120 | CLIENT_REMEMBER_OPTIONS) 121 | 122 | /* 123 | Switch off the flags that are optional and depending on build flags 124 | If any of the optional flags is supported by the build it will be switched 125 | on before sending to the client during the connection handshake. 126 | */ 127 | #define CLIENT_BASIC_FLAGS (((CLIENT_ALL_FLAGS & ~CLIENT_SSL) \ 128 | & ~CLIENT_COMPRESS) \ 129 | & ~CLIENT_SSL_VERIFY_SERVER_CERT) 130 | enum enum_server_command 131 | { 132 | COM_SLEEP, COM_QUIT, COM_INIT_DB, COM_QUERY, COM_FIELD_LIST, 133 | COM_CREATE_DB, COM_DROP_DB, COM_REFRESH, COM_SHUTDOWN, COM_STATISTICS, 134 | COM_PROCESS_INFO, COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING, 135 | COM_TIME, COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP, 136 | COM_TABLE_DUMP, COM_CONNECT_OUT, COM_REGISTER_SLAVE, 137 | COM_STMT_PREPARE, COM_STMT_EXECUTE, COM_STMT_SEND_LONG_DATA, COM_STMT_CLOSE, 138 | COM_STMT_RESET, COM_SET_OPTION, COM_STMT_FETCH, COM_DAEMON, 139 | /* don't forget to update const char *command_name[] in sql_parse.cc */ 140 | 141 | /* Must be last */ 142 | COM_END 143 | }; 144 | 145 | enum enum_field_types { MYSQL_TYPE_DECIMAL, 146 | MYSQL_TYPE_TINY, 147 | MYSQL_TYPE_SHORT, 148 | MYSQL_TYPE_LONG, 149 | MYSQL_TYPE_FLOAT, 150 | MYSQL_TYPE_DOUBLE, 151 | MYSQL_TYPE_NULL, 152 | MYSQL_TYPE_TIMESTAMP, 153 | MYSQL_TYPE_LONGLONG, 154 | MYSQL_TYPE_INT24, 155 | MYSQL_TYPE_DATE, 156 | MYSQL_TYPE_TIME, 157 | MYSQL_TYPE_DATETIME, 158 | MYSQL_TYPE_YEAR, 159 | MYSQL_TYPE_NEWDATE, 160 | MYSQL_TYPE_VARCHAR, 161 | MYSQL_TYPE_BIT, 162 | MYSQL_TYPE_TIMESTAMP2, 163 | MYSQL_TYPE_DATETIME2, 164 | MYSQL_TYPE_TIME2, 165 | MYSQL_TYPE_NEWDECIMAL=246, 166 | MYSQL_TYPE_ENUM=247, 167 | MYSQL_TYPE_SET=248, 168 | MYSQL_TYPE_TINY_BLOB=249, 169 | MYSQL_TYPE_MEDIUM_BLOB=250, 170 | MYSQL_TYPE_LONG_BLOB=251, 171 | MYSQL_TYPE_BLOB=252, 172 | MYSQL_TYPE_VAR_STRING=253, 173 | MYSQL_TYPE_STRING=254, 174 | MYSQL_TYPE_GEOMETRY=255 175 | 176 | }; 177 | 178 | 179 | #define int3store(T,A) do { *(T)= (unsigned char) ((A));\ 180 | *(T+1)=(unsigned char) (((unsigned int) (A) >> 8));\ 181 | *(T+2)=(unsigned char) (((A) >> 16)); } while (0) 182 | 183 | /* 184 | * Helper functions 185 | * 186 | static void proto_append_int_len(boost::asio::streambuf &buf, unsigned long long num, int len) 187 | { 188 | std::ostream os(&buf); 189 | for (int i= 0; i< len; i++) 190 | { 191 | os << (char) (num & 0xFF); 192 | num= num >> 8; 193 | } 194 | } 195 | 196 | static void proto_append_int_len(std::ostream &os, unsigned long long num, int len) 197 | { 198 | for (int i= 0; i< len; i++) 199 | { 200 | unsigned char shift= (num >> i) & 0xFF; 201 | os << shift; 202 | } 203 | } 204 | 205 | static void proto_append_int_len(char *buff, unsigned long long num, int len) 206 | { 207 | for (int i= 0; i< len; i++) 208 | { 209 | buff[i]= (unsigned char) (num & 0xFF); 210 | num= num >> 8; 211 | } 212 | } 213 | */ 214 | 215 | void write_packet_header(char *buff, boost::uint16_t size, boost::uint8_t packet_no); 216 | 217 | class Protocol_validator; 218 | class buffer_source; 219 | 220 | /** 221 | * The Protocol interface is used to describe a grammar consisting of 222 | * chunks of bytes that are read or written in consequtive order. 223 | * Example: 224 | * class Protocol_impl : public Protocol; 225 | * Protocol_impl chunk1(chunk_datastore1); 226 | * Protocol_impl chunk2(chunk_datastore2); 227 | * input_stream >> chunk1 228 | * >> chunk2; 229 | */ 230 | class Protocol 231 | { 232 | public: 233 | Protocol() { m_length_encoded_binary= false; } 234 | /** 235 | Return the number of bytes which is read or written by this protocol chunk. 236 | The default size is equal to the underlying storage data type. 237 | */ 238 | virtual unsigned int size()=0; 239 | 240 | /** Return a pointer to the first byte in a linear storage buffer */ 241 | virtual const char *data()=0; 242 | 243 | /** 244 | Change the number of bytes which will be read or written to the storage. 245 | The default size is euqal to the storage type size. This can change if the 246 | protocol is reading a length encoded binary. 247 | The new size must always be less than the size of the underlying storage 248 | type. 249 | */ 250 | virtual void collapse_size(unsigned int new_size)=0; 251 | 252 | /** 253 | The first byte will have a special interpretation which will indicate 254 | how many bytes should be read next. 255 | */ 256 | void set_length_encoded_binary(bool bswitch) { m_length_encoded_binary= bswitch; } 257 | bool is_length_encoded_binary(void) { return m_length_encoded_binary; } 258 | 259 | private: 260 | bool m_length_encoded_binary; 261 | 262 | friend std::istream &operator<<(std::istream &is, Protocol &chunk); 263 | friend std::istream &operator>>(std::istream &is, Protocol &chunk); 264 | friend buffer_source &operator>>(buffer_source &src, Protocol &chunk); 265 | friend std::istream &operator>>(std::istream &is, std::string &str); 266 | }; 267 | 268 | template 269 | class Protocol_chunk : public Protocol 270 | { 271 | public: 272 | 273 | Protocol_chunk() : Protocol() 274 | { 275 | m_size= 0; 276 | m_data= 0; 277 | } 278 | 279 | Protocol_chunk(T &chunk) : Protocol() 280 | { 281 | m_data= (const char *)&chunk; 282 | m_size= sizeof(T); 283 | } 284 | 285 | Protocol_chunk(const T &chunk) : Protocol () 286 | { 287 | m_data= (const char *) &chunk; 288 | m_size= sizeof(T); 289 | } 290 | 291 | /** 292 | * @param buffer A pointer to the storage 293 | * @param size The size of the storage 294 | * 295 | * @note If size == 0 then the chunk is a 296 | * length coded binary. 297 | */ 298 | Protocol_chunk(T *buffer, unsigned long size) : Protocol () 299 | { 300 | m_data= (const char *)buffer; 301 | m_size= size; 302 | } 303 | 304 | virtual unsigned int size() { return m_size; } 305 | virtual const char *data() { return m_data; } 306 | virtual void collapse_size(unsigned int new_size) 307 | { 308 | //assert(new_size <= m_size); 309 | memset((char *)m_data+new_size,'\0', m_size-new_size); 310 | m_size= new_size; 311 | } 312 | private: 313 | const char *m_data; 314 | unsigned long m_size; 315 | }; 316 | 317 | std::ostream &operator<<(std::ostream &os, Protocol &chunk); 318 | 319 | typedef Protocol_chunk Protocol_chunk_uint8; 320 | 321 | class Protocol_chunk_string //: public Protocol_chunk_uint8 322 | { 323 | public: 324 | Protocol_chunk_string(std::string &chunk, unsigned long size) //: Protocol_chunk_uint8() 325 | { 326 | m_str= &chunk; 327 | m_str->assign(size,'*'); 328 | } 329 | 330 | virtual unsigned int size() const { return m_str->size(); } 331 | virtual const char *data() const { return m_str->data(); } 332 | virtual void collapse_size(unsigned int new_size) 333 | { 334 | m_str->resize(new_size); 335 | } 336 | private: 337 | friend std::istream &operator>>(std::istream &is, Protocol_chunk_string &str); 338 | std::string *m_str; 339 | }; 340 | 341 | class Protocol_chunk_vector : public Protocol_chunk_uint8 342 | { 343 | public: 344 | Protocol_chunk_vector(std::vector &chunk, unsigned long size) 345 | : Protocol_chunk_uint8() 346 | { 347 | m_vec= &chunk; 348 | m_vec->reserve(size); 349 | m_size= size; 350 | } 351 | 352 | virtual unsigned int size() { return m_vec->size(); } 353 | virtual const char *data() { return reinterpret_cast(&*m_vec->begin()); } 354 | virtual void collapse_size(unsigned int new_size) 355 | { 356 | m_vec->resize(new_size); 357 | } 358 | private: 359 | friend std::istream &operator>>(std::istream &is, Protocol_chunk_vector &chunk); 360 | std::vector *m_vec; 361 | unsigned long m_size; 362 | }; 363 | 364 | 365 | std::istream &operator>>(std::istream &is, Protocol_chunk_vector &chunk); 366 | 367 | class buffer_source 368 | { 369 | public: 370 | 371 | buffer_source(const char *src, int sz) 372 | { 373 | m_src= src; 374 | m_size= sz; 375 | m_ptr= 0; 376 | } 377 | 378 | friend buffer_source &operator>>(buffer_source &src, Protocol &chunk); 379 | private: 380 | const char *m_src; 381 | int m_size; 382 | int m_ptr; 383 | 384 | }; 385 | 386 | class Protocol_chunk_string_len 387 | { 388 | public: 389 | Protocol_chunk_string_len(std::string &str) 390 | { 391 | m_storage= &str; 392 | } 393 | 394 | private: 395 | friend std::istream &operator>>(std::istream &is, Protocol_chunk_string_len &lenstr); 396 | std::string *m_storage; 397 | }; 398 | 399 | buffer_source &operator>>(buffer_source &src, Protocol &chunk); 400 | /** TODO assert that the correct endianess is used */ 401 | std::istream &operator>>(std::istream &is, Protocol &chunk); 402 | std::istream &operator>>(std::istream &is, std::string &str); 403 | std::istream &operator>>(std::istream &is, Protocol_chunk_string_len &lenstr); 404 | std::istream &operator>>(std::istream &is, Protocol_chunk_string &str); 405 | 406 | int proto_read_package_header(tcp::socket *socket, unsigned long *packet_length, unsigned char *packet_no); 407 | 408 | /** 409 | * Read a server package header from a stream buffer 410 | * 411 | * @retval 0 Success 412 | * @retval >0 An error occurred 413 | */ 414 | int proto_read_package_header(tcp::socket *socket, boost::asio::streambuf &buff, unsigned long *packet_length, unsigned char *packet_no); 415 | 416 | /** 417 | * Get one complete packet from the server 418 | * 419 | * @param socket Pointer to the active tcp-socket 420 | * @param buff A reference to a stream buffer 421 | * @param packet_no [out] The number of the packet as given by the server 422 | * 423 | * @return the size of the packet or 0 to indicate an error 424 | */ 425 | int proto_get_one_package(tcp::socket *socket, boost::asio::streambuf &buff, boost::uint8_t *packet_no); 426 | void prot_parse_error_message(std::istream &is, struct st_error_package &err, int packet_length); 427 | void prot_parse_ok_message(std::istream &is, struct st_ok_package &ok, int packet_length); 428 | void prot_parse_eof_message(std::istream &is, struct st_eof_package &eof); 429 | void proto_get_handshake_package(std::istream &is, struct st_handshake_package &p, int packet_length); 430 | 431 | /** 432 | Allocates a new event and copy the header. The caller must be responsible for 433 | releasing the allocated memory. 434 | */ 435 | Query_event *proto_query_event(std::istream &is, Log_event_header *header); 436 | Rotate_event *proto_rotate_event(std::istream &is, Log_event_header *header); 437 | Incident_event *proto_incident_event(std::istream &is, Log_event_header *header); 438 | Row_event *proto_rows_event(std::istream &is, Log_event_header *header); 439 | Table_map_event *proto_table_map_event(std::istream &is, Log_event_header *header); 440 | Int_var_event *proto_intvar_event(std::istream &is, Log_event_header *header); 441 | User_var_event *proto_uservar_event(std::istream &is, Log_event_header *header); 442 | 443 | } // end namespace system 444 | } // end namespace mysql 445 | 446 | #endif /* _PROTOCOL_H */ 447 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | --------------------------------------------------------------------------------