summaryrefslogtreecommitdiff
path: root/client/mysqlbinlog.cc
diff options
context:
space:
mode:
Diffstat (limited to 'client/mysqlbinlog.cc')
-rw-r--r--client/mysqlbinlog.cc144
1 files changed, 137 insertions, 7 deletions
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index b931bd125d6..420042e6055 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -35,6 +35,15 @@
#include "log_event.h"
#include "sql_common.h"
+/* Needed for Rpl_filter */
+CHARSET_INFO* system_charset_info= &my_charset_utf8_general_ci;
+
+#include "sql_string.h" // needed for Rpl_filter
+#include "sql_list.h" // needed for Rpl_filter
+#include "rpl_filter.h"
+
+Rpl_filter *binlog_filter;
+
#define BIN_LOG_HEADER_SIZE 4
#define PROBE_HEADER_LEN (EVENT_LEN_OFFSET+4)
@@ -620,6 +629,42 @@ static bool shall_skip_database(const char *log_dbname)
/**
+ Print "use <db>" statement when current db is to be changed.
+
+ We have to control emiting USE statements according to rewrite-db options.
+ We have to do it here (see process_event() below) and to suppress
+ producing USE statements by corresponding log event print-functions.
+*/
+
+void print_use_stmt(PRINT_EVENT_INFO* pinfo, const char* db, size_t db_len)
+{
+ // pinfo->db is the current db.
+ // If current db is the same as required db, do nothing.
+ if (!db || !memcmp(pinfo->db, db, db_len + 1))
+ return;
+
+ // Current db and required db are different.
+ // Check for rewrite rule for required db. (Note that in a rewrite rule
+ // neither db_from nor db_to part can be empty).
+ size_t len_to= 0;
+ const char *db_to= binlog_filter->get_rewrite_db(db, &len_to);
+
+ // If there is no rewrite rule for db (in this case len_to is left = 0),
+ // printing of the corresponding USE statement is left for log event
+ // print-function.
+ if (!len_to)
+ return;
+
+ // In case of rewrite rule print USE statement for db_to
+ fprintf(result_file, "use %s%s\n", db_to, pinfo->delimiter);
+
+ // Copy the *original* db to pinfo to suppress emiting
+ // of USE stmts by log_event print-functions.
+ memcpy(pinfo->db, db, db_len + 1);
+}
+
+
+/**
Prints the given event in base64 format.
The header is printed to the head cache and the body is printed to
@@ -730,9 +775,11 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
switch (ev_type) {
case QUERY_EVENT:
- if (!((Query_log_event*)ev)->is_trans_keyword() &&
- shall_skip_database(((Query_log_event*)ev)->db))
+ {
+ Query_log_event *qe= (Query_log_event*)ev;
+ if (!qe->is_trans_keyword() && shall_skip_database(qe->db))
goto end;
+ print_use_stmt(print_event_info, qe->db, qe->db_len);
if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS)
{
if ((retval= write_event_header_and_base64(ev, result_file,
@@ -743,6 +790,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
else
ev->print(result_file, print_event_info);
break;
+ }
case CREATE_FILE_EVENT:
{
@@ -864,6 +912,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
if (!shall_skip_database(exlq->db))
{
+ print_use_stmt(print_event_info, exlq->db, exlq->db_len);
if (fname)
{
convert_path_to_forward_slashes(fname);
@@ -887,6 +936,13 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
destroy_evt= FALSE;
goto end;
}
+ size_t len_to= 0;
+ const char* db_to= binlog_filter->get_rewrite_db(map->get_db_name(), &len_to);
+ if (len_to && map->rewrite_db(db_to, len_to, glob_description_event))
+ {
+ error("Could not rewrite database name");
+ goto err;
+ }
}
case WRITE_ROWS_EVENT:
case DELETE_ROWS_EVENT:
@@ -971,14 +1027,16 @@ err:
retval= ERROR_STOP;
end:
rec_count++;
+
/*
- Destroy the log_event object. If reading from a remote host,
- set the temp_buf to NULL so that memory isn't freed twice.
+ Destroy the log_event object.
+ MariaDB MWL#36: mainline does this:
+ If reading from a remote host,
+ set the temp_buf to NULL so that memory isn't freed twice.
+ We no longer do that, we use Rpl_filter::event_owns_temp_buf instead.
*/
if (ev)
{
- if (remote_opt)
- ev->temp_buf= 0;
if (destroy_evt) /* destroy it later if not set (ignored table map) */
delete ev;
}
@@ -1144,6 +1202,10 @@ that may lead to an endless loop.",
"Used to reserve file descriptors for use by this program.",
&open_files_limit, &open_files_limit, 0, GET_ULONG,
REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0},
+ {"rewrite-db", OPT_REWRITE_DB,
+ "Updates to a database with a different name than the original. \
+Example: rewrite-db='from->to'.",
+ 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
@@ -1338,6 +1400,53 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
(find_type_or_exit(argument, &base64_output_mode_typelib, opt->name)-1);
}
break;
+ case OPT_REWRITE_DB: // db_from->db_to
+ {
+ /* See also handling of OPT_REPLICATE_REWRITE_DB in sql/mysqld.cc */
+ char* ptr;
+ char* key= argument; // db-from
+ char* val; // db-to
+
+ // Where key begins
+ while (*key && my_isspace(&my_charset_latin1, *key))
+ key++;
+
+ // Where val begins
+ if (!(ptr= strstr(argument, "->")))
+ {
+ sql_print_error("Bad syntax in rewrite-db: missing '->'!\n");
+ return 1;
+ }
+ val= ptr + 2;
+ while (*val && my_isspace(&my_charset_latin1, *val))
+ val++;
+
+ // Write \0 and skip blanks at the end of key
+ *ptr-- = 0;
+ while (my_isspace(&my_charset_latin1, *ptr) && ptr > argument)
+ *ptr-- = 0;
+
+ if (!*key)
+ {
+ sql_print_error("Bad syntax in rewrite-db: empty db-from!\n");
+ return 1;
+ }
+
+ // Skip blanks at the end of val
+ ptr= val;
+ while (*ptr && !my_isspace(&my_charset_latin1, *ptr))
+ ptr++;
+ *ptr= 0;
+
+ if (!*val)
+ {
+ sql_print_error("Bad syntax in rewrite-db: empty db-to!\n");
+ return 1;
+ }
+
+ binlog_filter->add_db_rewrite(key, val);
+ break;
+ }
case 'v':
if (argument == disabled_my_option)
verbose= 0;
@@ -1611,7 +1720,7 @@ static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
If reading from a remote host, ensure the temp_buf for the
Log_event class is pointing to the incoming stream.
*/
- ev->register_temp_buf((char *) net->read_pos + 1);
+ ev->register_temp_buf((char *) net->read_pos + 1, FALSE);
Log_event_type type= ev->get_type_code();
if (glob_description_event->binlog_version >= 3 ||
@@ -2011,6 +2120,8 @@ end:
return retval;
}
+/* Used in sql_alloc(). Inited and freed in main() */
+MEM_ROOT s_mem_root;
int main(int argc, char** argv)
{
@@ -2023,8 +2134,16 @@ int main(int argc, char** argv)
my_init_time(); // for time functions
+ init_alloc_root(&s_mem_root, 16384, 0);
+ if (!(binlog_filter= new Rpl_filter))
+ {
+ error("Failed to create Rpl_filter");
+ exit(1);
+ }
+
if (load_defaults("my", load_default_groups, &argc, &argv))
exit(1);
+
defaults_argv= argv;
parse_args(&argc, (char***)&argv);
@@ -2111,6 +2230,8 @@ int main(int argc, char** argv)
if (result_file != stdout)
my_fclose(result_file, MYF(0));
cleanup();
+ delete binlog_filter;
+ free_root(&s_mem_root, MYF(0));
free_defaults(defaults_argv);
my_free_open_file_info();
load_processor.destroy();
@@ -2122,6 +2243,12 @@ int main(int argc, char** argv)
DBUG_RETURN(retval == ERROR_STOP ? 1 : 0);
}
+
+void *sql_alloc(size_t size)
+{
+ return alloc_root(&s_mem_root, size);
+}
+
/*
We must include this here as it's compiled with different options for
the server
@@ -2132,4 +2259,7 @@ int main(int argc, char** argv)
#include "my_decimal.cc"
#include "log_event.cc"
#include "log_event_old.cc"
+#include "sql_string.cc"
+#include "sql_list.cc"
+#include "rpl_filter.cc"