mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 18:20:07 +01:00
Merge
This commit is contained in:
commit
efb077502d
16 changed files with 743 additions and 504 deletions
|
@ -55,7 +55,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
|
|||
ha_ndbcluster.h opt_range.h protocol.h \
|
||||
sql_select.h structs.h table.h sql_udf.h hash_filo.h\
|
||||
lex.h lex_symbol.h sql_acl.h sql_crypt.h \
|
||||
log_event.h sql_repl.h slave.h \
|
||||
log_event.h sql_repl.h slave.h rpl_filter.h \
|
||||
stacktrace.h sql_sort.h sql_cache.h set_var.h \
|
||||
spatial.h gstream.h client_settings.h tzfile.h \
|
||||
tztime.h my_decimal.h\
|
||||
|
@ -90,7 +90,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
|
|||
sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \
|
||||
sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
|
||||
sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
|
||||
slave.cc sql_repl.cc sql_union.cc sql_derived.cc \
|
||||
slave.cc sql_repl.cc rpl_filter.cc \
|
||||
sql_union.cc sql_derived.cc \
|
||||
client.c sql_client.cc mini_client_errors.c pack.c\
|
||||
stacktrace.c repl_failsafe.h repl_failsafe.cc \
|
||||
sql_olap.cc sql_view.cc \
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "mysql_priv.h"
|
||||
#include "sql_repl.h"
|
||||
#include "rpl_filter.h"
|
||||
|
||||
#include <my_dir.h>
|
||||
#include <stdarg.h>
|
||||
|
@ -1571,10 +1572,11 @@ bool MYSQL_LOG::write(Log_event *event_info)
|
|||
binlog_[wild_]{do|ignore}_table?" (WL#1049)"
|
||||
*/
|
||||
if ((thd && !(thd->options & OPTION_BIN_LOG)) ||
|
||||
(!db_ok(local_db, binlog_do_db, binlog_ignore_db)))
|
||||
(!binlog_filter->db_ok(local_db)))
|
||||
{
|
||||
VOID(pthread_mutex_unlock(&LOCK_log));
|
||||
DBUG_PRINT("error",("!db_ok('%s')", local_db));
|
||||
DBUG_PRINT("info",("db_ok('%s')==%d", local_db,
|
||||
binlog_filter->db_ok(local_db)));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
#endif /* HAVE_REPLICATION */
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#endif
|
||||
#include "mysql_priv.h"
|
||||
#include "slave.h"
|
||||
#include "rpl_filter.h"
|
||||
#include <my_dir.h>
|
||||
#endif /* MYSQL_CLIENT */
|
||||
|
||||
|
@ -1445,7 +1446,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli, const char *query
|
|||
*/
|
||||
thd->catalog= (char*) catalog;
|
||||
thd->db_length= db_len;
|
||||
thd->db= (char*) rewrite_db(db, &thd->db_length);
|
||||
thd->db= (char *) rpl_filter->get_rewrite_db(db, &thd->db_length);
|
||||
thd->variables.auto_increment_increment= auto_increment_increment;
|
||||
thd->variables.auto_increment_offset= auto_increment_offset;
|
||||
|
||||
|
@ -1464,7 +1465,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli, const char *query
|
|||
|
||||
clear_all_errors(thd, rli);
|
||||
|
||||
if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
|
||||
if (rpl_filter->db_ok(thd->db))
|
||||
{
|
||||
thd->set_time((time_t)when);
|
||||
thd->query_length= q_len_arg;
|
||||
|
@ -2569,7 +2570,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
|
|||
bool use_rli_only_for_errors)
|
||||
{
|
||||
thd->db_length= db_len;
|
||||
thd->db= (char*) rewrite_db(db, &thd->db_length);
|
||||
thd->db= (char *) rpl_filter->get_rewrite_db(db, &thd->db_length);
|
||||
DBUG_ASSERT(thd->query == 0);
|
||||
thd->query_length= 0; // Should not be needed
|
||||
thd->query_error= 0;
|
||||
|
@ -2598,7 +2599,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
|
|||
al. Another way is do the filtering in the I/O thread (more efficient: no
|
||||
disk writes at all).
|
||||
*/
|
||||
if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
|
||||
if (rpl_filter->db_ok(thd->db))
|
||||
{
|
||||
thd->set_time((time_t)when);
|
||||
VOID(pthread_mutex_lock(&LOCK_thread_count));
|
||||
|
@ -2620,7 +2621,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
|
|||
tables.updating= 1;
|
||||
|
||||
// the table will be opened in mysql_load
|
||||
if (table_rules_on && !tables_ok(thd, &tables))
|
||||
if (rpl_filter->is_on() && !rpl_filter->tables_ok(thd->db, &tables))
|
||||
{
|
||||
// TODO: this is a bug - this needs to be moved to the I/O thread
|
||||
if (net)
|
||||
|
|
|
@ -1128,7 +1128,6 @@ extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[];
|
|||
extern String null_string;
|
||||
extern HASH open_cache;
|
||||
extern TABLE *unused_tables;
|
||||
extern I_List<i_string> binlog_do_db, binlog_ignore_db;
|
||||
extern const char* any_db;
|
||||
extern struct my_option my_long_options[];
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <my_dir.h>
|
||||
#include "slave.h"
|
||||
#include "sql_repl.h"
|
||||
#include "rpl_filter.h"
|
||||
#include "repl_failsafe.h"
|
||||
#include "stacktrace.h"
|
||||
#include "mysqld_suffix.h"
|
||||
|
@ -397,12 +398,10 @@ Le_creator le_creator;
|
|||
FILE *bootstrap_file;
|
||||
int bootstrap_error;
|
||||
|
||||
I_List<i_string_pair> replicate_rewrite_db;
|
||||
I_List<i_string> replicate_do_db, replicate_ignore_db;
|
||||
// allow the user to tell us which db to replicate and which to ignore
|
||||
I_List<i_string> binlog_do_db, binlog_ignore_db;
|
||||
I_List<THD> threads,thread_cache;
|
||||
I_List<NAMED_LIST> key_caches;
|
||||
Rpl_filter* rpl_filter;
|
||||
Rpl_filter* binlog_filter;
|
||||
|
||||
struct system_variables global_system_variables;
|
||||
struct system_variables max_system_variables;
|
||||
|
@ -1013,12 +1012,9 @@ void clean_up(bool print_message)
|
|||
free_max_user_conn();
|
||||
#ifdef HAVE_REPLICATION
|
||||
end_slave_list();
|
||||
free_list(&replicate_do_db);
|
||||
free_list(&replicate_ignore_db);
|
||||
free_list(&binlog_do_db);
|
||||
free_list(&binlog_ignore_db);
|
||||
free_list(&replicate_rewrite_db);
|
||||
#endif
|
||||
delete binlog_filter;
|
||||
delete rpl_filter;
|
||||
#ifdef HAVE_OPENSSL
|
||||
if (ssl_acceptor_fd)
|
||||
my_free((gptr) ssl_acceptor_fd, MYF(MY_ALLOW_ZERO_PTR));
|
||||
|
@ -2970,9 +2966,16 @@ int win_main(int argc, char **argv)
|
|||
int main(int argc, char **argv)
|
||||
#endif
|
||||
{
|
||||
|
||||
DEBUGGER_OFF;
|
||||
|
||||
rpl_filter= new Rpl_filter;
|
||||
binlog_filter= new Rpl_filter;
|
||||
if (!rpl_filter || !binlog_filter)
|
||||
{
|
||||
sql_perror("Could not allocate replication and binlog filters");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
MY_INIT(argv[0]); // init my_sys library & pthreads
|
||||
|
||||
#ifdef _CUSTOMSTARTUPCONFIG_
|
||||
|
@ -3309,7 +3312,6 @@ default_service_handling(char **argv,
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
/* When several instances are running on the same machine, we
|
||||
need to have an unique named hEventShudown through the
|
||||
application PID e.g.: MySQLShutdown1890; MySQLShutdown2342
|
||||
|
@ -5882,13 +5884,6 @@ static void mysql_init_variables(void)
|
|||
exit(1);
|
||||
multi_keycache_init(); /* set key_cache_hash.default_value = dflt_key_cache */
|
||||
|
||||
/* Initialize structures that is used when processing options */
|
||||
replicate_rewrite_db.empty();
|
||||
replicate_do_db.empty();
|
||||
replicate_ignore_db.empty();
|
||||
binlog_do_db.empty();
|
||||
binlog_ignore_db.empty();
|
||||
|
||||
/* Set directory paths */
|
||||
strmake(language, LANGUAGE, sizeof(language)-1);
|
||||
strmake(mysql_real_data_home, get_relative_path(DATADIR),
|
||||
|
@ -6143,14 +6138,12 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
|
|||
}
|
||||
case (int)OPT_REPLICATE_IGNORE_DB:
|
||||
{
|
||||
i_string *db = new i_string(argument);
|
||||
replicate_ignore_db.push_back(db);
|
||||
rpl_filter->add_ignore_db(argument);
|
||||
break;
|
||||
}
|
||||
case (int)OPT_REPLICATE_DO_DB:
|
||||
{
|
||||
i_string *db = new i_string(argument);
|
||||
replicate_do_db.push_back(db);
|
||||
rpl_filter->add_do_db(argument);
|
||||
break;
|
||||
}
|
||||
case (int)OPT_REPLICATE_REWRITE_DB:
|
||||
|
@ -6183,71 +6176,54 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
|
|||
exit(1);
|
||||
}
|
||||
|
||||
i_string_pair *db_pair = new i_string_pair(key, val);
|
||||
replicate_rewrite_db.push_back(db_pair);
|
||||
rpl_filter->add_db_rewrite(key, val);
|
||||
break;
|
||||
}
|
||||
|
||||
case (int)OPT_BINLOG_IGNORE_DB:
|
||||
{
|
||||
i_string *db = new i_string(argument);
|
||||
binlog_ignore_db.push_back(db);
|
||||
binlog_filter->add_ignore_db(argument);
|
||||
break;
|
||||
}
|
||||
case (int)OPT_BINLOG_DO_DB:
|
||||
{
|
||||
i_string *db = new i_string(argument);
|
||||
binlog_do_db.push_back(db);
|
||||
binlog_filter->add_do_db(argument);
|
||||
break;
|
||||
}
|
||||
case (int)OPT_REPLICATE_DO_TABLE:
|
||||
{
|
||||
if (!do_table_inited)
|
||||
init_table_rule_hash(&replicate_do_table, &do_table_inited);
|
||||
if (add_table_rule(&replicate_do_table, argument))
|
||||
if (rpl_filter->add_do_table(argument))
|
||||
{
|
||||
fprintf(stderr, "Could not add do table rule '%s'!\n", argument);
|
||||
exit(1);
|
||||
}
|
||||
table_rules_on = 1;
|
||||
break;
|
||||
}
|
||||
case (int)OPT_REPLICATE_WILD_DO_TABLE:
|
||||
{
|
||||
if (!wild_do_table_inited)
|
||||
init_table_rule_array(&replicate_wild_do_table,
|
||||
&wild_do_table_inited);
|
||||
if (add_wild_table_rule(&replicate_wild_do_table, argument))
|
||||
if (rpl_filter->add_wild_do_table(argument))
|
||||
{
|
||||
fprintf(stderr, "Could not add do table rule '%s'!\n", argument);
|
||||
exit(1);
|
||||
}
|
||||
table_rules_on = 1;
|
||||
break;
|
||||
}
|
||||
case (int)OPT_REPLICATE_WILD_IGNORE_TABLE:
|
||||
{
|
||||
if (!wild_ignore_table_inited)
|
||||
init_table_rule_array(&replicate_wild_ignore_table,
|
||||
&wild_ignore_table_inited);
|
||||
if (add_wild_table_rule(&replicate_wild_ignore_table, argument))
|
||||
if (rpl_filter->add_wild_ignore_table(argument))
|
||||
{
|
||||
fprintf(stderr, "Could not add ignore table rule '%s'!\n", argument);
|
||||
exit(1);
|
||||
}
|
||||
table_rules_on = 1;
|
||||
break;
|
||||
}
|
||||
case (int)OPT_REPLICATE_IGNORE_TABLE:
|
||||
{
|
||||
if (!ignore_table_inited)
|
||||
init_table_rule_hash(&replicate_ignore_table, &ignore_table_inited);
|
||||
if (add_table_rule(&replicate_ignore_table, argument))
|
||||
if (rpl_filter->add_ignore_table(argument))
|
||||
{
|
||||
fprintf(stderr, "Could not add ignore table rule '%s'!\n", argument);
|
||||
exit(1);
|
||||
}
|
||||
table_rules_on = 1;
|
||||
break;
|
||||
}
|
||||
#endif /* HAVE_REPLICATION */
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "repl_failsafe.h"
|
||||
#include "sql_repl.h"
|
||||
#include "slave.h"
|
||||
#include "rpl_filter.h"
|
||||
#include "log_event.h"
|
||||
#include <mysql.h>
|
||||
|
||||
|
@ -735,14 +736,14 @@ static int fetch_db_tables(THD *thd, MYSQL *mysql, const char *db,
|
|||
TABLE_LIST table;
|
||||
const char* table_name= row[0];
|
||||
int error;
|
||||
if (table_rules_on)
|
||||
if (rpl_filter->is_on())
|
||||
{
|
||||
bzero((char*) &table, sizeof(table)); //just for safe
|
||||
table.db= (char*) db;
|
||||
table.table_name= (char*) table_name;
|
||||
table.updating= 1;
|
||||
|
||||
if (!tables_ok(thd, &table))
|
||||
if (!rpl_filter->tables_ok(thd->db, &table))
|
||||
continue;
|
||||
}
|
||||
/* download master's table and overwrite slave's table */
|
||||
|
@ -860,8 +861,8 @@ bool load_master_data(THD* thd)
|
|||
data from master
|
||||
*/
|
||||
|
||||
if (!db_ok(db, replicate_do_db, replicate_ignore_db) ||
|
||||
!db_ok_with_wild_table(db) ||
|
||||
if (!rpl_filter->db_ok(db) ||
|
||||
!rpl_filter->db_ok_with_wild_table(db) ||
|
||||
!strcmp(db,"mysql"))
|
||||
{
|
||||
*cur_table_res = 0;
|
||||
|
|
539
sql/rpl_filter.cc
Normal file
539
sql/rpl_filter.cc
Normal file
|
@ -0,0 +1,539 @@
|
|||
/* Copyright (C) 2000-2003 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "mysql_priv.h"
|
||||
#include "rpl_filter.h"
|
||||
|
||||
#define TABLE_RULE_HASH_SIZE 16
|
||||
#define TABLE_RULE_ARR_SIZE 16
|
||||
|
||||
Rpl_filter::Rpl_filter() :
|
||||
table_rules_on(0), do_table_inited(0), ignore_table_inited(0),
|
||||
wild_do_table_inited(0), wild_ignore_table_inited(0)
|
||||
{
|
||||
do_db.empty();
|
||||
ignore_db.empty();
|
||||
rewrite_db.empty();
|
||||
}
|
||||
|
||||
|
||||
Rpl_filter::~Rpl_filter()
|
||||
{
|
||||
if (do_table_inited)
|
||||
hash_free(&do_table);
|
||||
if (ignore_table_inited)
|
||||
hash_free(&ignore_table);
|
||||
if (wild_do_table_inited)
|
||||
free_string_array(&wild_do_table);
|
||||
if (wild_ignore_table_inited)
|
||||
free_string_array(&wild_ignore_table);
|
||||
free_list(&do_db);
|
||||
free_list(&ignore_db);
|
||||
free_list(&rewrite_db);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Returns true if table should be logged/replicated
|
||||
|
||||
SYNOPSIS
|
||||
tables_ok()
|
||||
db db to use if db in TABLE_LIST is undefined for a table
|
||||
tables list of tables to check
|
||||
|
||||
NOTES
|
||||
Changing table order in the list can lead to different results.
|
||||
|
||||
Note also order of precedence of do/ignore rules (see code). For
|
||||
that reason, users should not set conflicting rules because they
|
||||
may get unpredicted results (precedence order is explained in the
|
||||
manual).
|
||||
|
||||
If no table in the list is marked "updating", then we always
|
||||
return 0, because there is no reason to execute this statement on
|
||||
slave if it updates nothing. (Currently, this can only happen if
|
||||
statement is a multi-delete (SQLCOM_DELETE_MULTI) and "tables" are
|
||||
the tables in the FROM):
|
||||
|
||||
In the case of SQLCOM_DELETE_MULTI, there will be a second call to
|
||||
tables_ok(), with tables having "updating==TRUE" (those after the
|
||||
DELETE), so this second call will make the decision (because
|
||||
all_tables_not_ok() = !tables_ok(1st_list) &&
|
||||
!tables_ok(2nd_list)).
|
||||
|
||||
TODO
|
||||
"Include all tables like "abc.%" except "%.EFG"". (Can't be done now.)
|
||||
If we supported Perl regexps, we could do it with pattern: /^abc\.(?!EFG)/
|
||||
(I could not find an equivalent in the regex library MySQL uses).
|
||||
|
||||
RETURN VALUES
|
||||
0 should not be logged/replicated
|
||||
1 should be logged/replicated
|
||||
*/
|
||||
|
||||
bool
|
||||
Rpl_filter::tables_ok(const char* db, TABLE_LIST* tables)
|
||||
{
|
||||
bool some_tables_updating= 0;
|
||||
DBUG_ENTER("Rpl_filter::tables_ok");
|
||||
|
||||
for (; tables; tables= tables->next_global)
|
||||
{
|
||||
char hash_key[2*NAME_LEN+2];
|
||||
char *end;
|
||||
uint len;
|
||||
|
||||
if (!tables->updating)
|
||||
continue;
|
||||
some_tables_updating= 1;
|
||||
end= strmov(hash_key, tables->db ? tables->db : db);
|
||||
*end++= '.';
|
||||
len= (uint) (strmov(end, tables->table_name) - hash_key);
|
||||
if (do_table_inited) // if there are any do's
|
||||
{
|
||||
if (hash_search(&do_table, (byte*) hash_key, len))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (ignore_table_inited) // if there are any ignores
|
||||
{
|
||||
if (hash_search(&ignore_table, (byte*) hash_key, len))
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
if (wild_do_table_inited &&
|
||||
find_wild(&wild_do_table, hash_key, len))
|
||||
DBUG_RETURN(1);
|
||||
if (wild_ignore_table_inited &&
|
||||
find_wild(&wild_ignore_table, hash_key, len))
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*
|
||||
If no table was to be updated, ignore statement (no reason we play it on
|
||||
slave, slave is supposed to replicate _changes_ only).
|
||||
If no explicit rule found and there was a do list, do not replicate.
|
||||
If there was no do list, go ahead
|
||||
*/
|
||||
DBUG_RETURN(some_tables_updating &&
|
||||
!do_table_inited && !wild_do_table_inited);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Checks whether a db matches some do_db and ignore_db rules
|
||||
|
||||
SYNOPSIS
|
||||
db_ok()
|
||||
db name of the db to check
|
||||
|
||||
RETURN VALUES
|
||||
0 should not be logged/replicated
|
||||
1 should be logged/replicated
|
||||
*/
|
||||
|
||||
bool
|
||||
Rpl_filter::db_ok(const char* db)
|
||||
{
|
||||
DBUG_ENTER("Rpl_filter::db_ok");
|
||||
|
||||
if (do_db.is_empty() && ignore_db.is_empty())
|
||||
DBUG_RETURN(1); // Ok to replicate if the user puts no constraints
|
||||
|
||||
/*
|
||||
If the user has specified restrictions on which databases to replicate
|
||||
and db was not selected, do not replicate.
|
||||
*/
|
||||
if (!db)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
if (!do_db.is_empty()) // if the do's are not empty
|
||||
{
|
||||
I_List_iterator<i_string> it(do_db);
|
||||
i_string* tmp;
|
||||
|
||||
while ((tmp=it++))
|
||||
{
|
||||
if (!strcmp(tmp->ptr, db))
|
||||
DBUG_RETURN(1); // match
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else // there are some elements in the don't, otherwise we cannot get here
|
||||
{
|
||||
I_List_iterator<i_string> it(ignore_db);
|
||||
i_string* tmp;
|
||||
|
||||
while ((tmp=it++))
|
||||
{
|
||||
if (!strcmp(tmp->ptr, db))
|
||||
DBUG_RETURN(0); // match
|
||||
}
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Checks whether a db matches wild_do_table and wild_ignore_table
|
||||
rules (for replication)
|
||||
|
||||
SYNOPSIS
|
||||
db_ok_with_wild_table()
|
||||
db name of the db to check.
|
||||
Is tested with check_db_name() before calling this function.
|
||||
|
||||
NOTES
|
||||
Here is the reason for this function.
|
||||
We advise users who want to exclude a database 'db1' safely to do it
|
||||
with replicate_wild_ignore_table='db1.%' instead of binlog_ignore_db or
|
||||
replicate_ignore_db because the two lasts only check for the selected db,
|
||||
which won't work in that case:
|
||||
USE db2;
|
||||
UPDATE db1.t SET ... #this will be replicated and should not
|
||||
whereas replicate_wild_ignore_table will work in all cases.
|
||||
With replicate_wild_ignore_table, we only check tables. When
|
||||
one does 'DROP DATABASE db1', tables are not involved and the
|
||||
statement will be replicated, while users could expect it would not (as it
|
||||
rougly means 'DROP db1.first_table, DROP db1.second_table...').
|
||||
In other words, we want to interpret 'db1.%' as "everything touching db1".
|
||||
That is why we want to match 'db1' against 'db1.%' wild table rules.
|
||||
|
||||
RETURN VALUES
|
||||
0 should not be logged/replicated
|
||||
1 should be logged/replicated
|
||||
*/
|
||||
|
||||
bool
|
||||
Rpl_filter::db_ok_with_wild_table(const char *db)
|
||||
{
|
||||
DBUG_ENTER("Rpl_filter::db_ok_with_wild_table");
|
||||
|
||||
char hash_key[NAME_LEN+2];
|
||||
char *end;
|
||||
int len;
|
||||
end= strmov(hash_key, db);
|
||||
*end++= '.';
|
||||
len= end - hash_key ;
|
||||
if (wild_do_table_inited && find_wild(&wild_do_table, hash_key, len))
|
||||
{
|
||||
DBUG_PRINT("return",("1"));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (wild_ignore_table_inited && find_wild(&wild_ignore_table, hash_key, len))
|
||||
{
|
||||
DBUG_PRINT("return",("0"));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*
|
||||
If no explicit rule found and there was a do list, do not replicate.
|
||||
If there was no do list, go ahead
|
||||
*/
|
||||
DBUG_PRINT("return",("db=%s,retval=%d", db, !wild_do_table_inited));
|
||||
DBUG_RETURN(!wild_do_table_inited);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Rpl_filter::is_on()
|
||||
{
|
||||
return table_rules_on;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Rpl_filter::add_do_table(const char* table_spec)
|
||||
{
|
||||
DBUG_ENTER("Rpl_filter::add_do_table");
|
||||
if (!do_table_inited)
|
||||
init_table_rule_hash(&do_table, &do_table_inited);
|
||||
table_rules_on= 1;
|
||||
DBUG_RETURN(add_table_rule(&do_table, table_spec));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Rpl_filter::add_ignore_table(const char* table_spec)
|
||||
{
|
||||
DBUG_ENTER("Rpl_filter::add_ignore_table");
|
||||
if (!ignore_table_inited)
|
||||
init_table_rule_hash(&ignore_table, &ignore_table_inited);
|
||||
table_rules_on= 1;
|
||||
DBUG_RETURN(add_table_rule(&ignore_table, table_spec));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Rpl_filter::add_wild_do_table(const char* table_spec)
|
||||
{
|
||||
DBUG_ENTER("Rpl_filter::add_wild_do_table");
|
||||
if (!wild_do_table_inited)
|
||||
init_table_rule_array(&wild_do_table, &wild_do_table_inited);
|
||||
table_rules_on= 1;
|
||||
DBUG_RETURN(add_wild_table_rule(&wild_do_table, table_spec));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Rpl_filter::add_wild_ignore_table(const char* table_spec)
|
||||
{
|
||||
DBUG_ENTER("Rpl_filter::add_wild_ignore_table");
|
||||
if (!wild_ignore_table_inited)
|
||||
init_table_rule_array(&wild_ignore_table, &wild_ignore_table_inited);
|
||||
table_rules_on= 1;
|
||||
DBUG_RETURN(add_wild_table_rule(&wild_ignore_table, table_spec));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rpl_filter::add_db_rewrite(const char* from_db, const char* to_db)
|
||||
{
|
||||
i_string_pair *db_pair = new i_string_pair(from_db, to_db);
|
||||
rewrite_db.push_back(db_pair);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Rpl_filter::add_table_rule(HASH* h, const char* table_spec)
|
||||
{
|
||||
const char* dot = strchr(table_spec, '.');
|
||||
if (!dot) return 1;
|
||||
// len is always > 0 because we know the there exists a '.'
|
||||
uint len = (uint)strlen(table_spec);
|
||||
TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
|
||||
+ len, MYF(MY_WME));
|
||||
if (!e) return 1;
|
||||
e->db= (char*)e + sizeof(TABLE_RULE_ENT);
|
||||
e->tbl_name= e->db + (dot - table_spec) + 1;
|
||||
e->key_len= len;
|
||||
memcpy(e->db, table_spec, len);
|
||||
|
||||
return my_hash_insert(h, (byte*)e);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Add table expression with wildcards to dynamic array
|
||||
*/
|
||||
|
||||
int
|
||||
Rpl_filter::add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
|
||||
{
|
||||
const char* dot = strchr(table_spec, '.');
|
||||
if (!dot) return 1;
|
||||
uint len = (uint)strlen(table_spec);
|
||||
TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
|
||||
+ len, MYF(MY_WME));
|
||||
if (!e) return 1;
|
||||
e->db= (char*)e + sizeof(TABLE_RULE_ENT);
|
||||
e->tbl_name= e->db + (dot - table_spec) + 1;
|
||||
e->key_len= len;
|
||||
memcpy(e->db, table_spec, len);
|
||||
insert_dynamic(a, (gptr)&e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rpl_filter::add_do_db(const char* table_spec)
|
||||
{
|
||||
DBUG_ENTER("Rpl_filter::add_do_db");
|
||||
i_string *db = new i_string(table_spec);
|
||||
do_db.push_back(db);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rpl_filter::add_ignore_db(const char* table_spec)
|
||||
{
|
||||
DBUG_ENTER("Rpl_filter::add_ignore_db");
|
||||
i_string *db = new i_string(table_spec);
|
||||
ignore_db.push_back(db);
|
||||
}
|
||||
|
||||
|
||||
static byte* get_table_key(const byte* a, uint* len,
|
||||
my_bool __attribute__((unused)))
|
||||
{
|
||||
TABLE_RULE_ENT *e= (TABLE_RULE_ENT *) a;
|
||||
|
||||
*len= e->key_len;
|
||||
return (byte*)e->db;
|
||||
}
|
||||
|
||||
|
||||
static void free_table_ent(void* a)
|
||||
{
|
||||
TABLE_RULE_ENT *e= (TABLE_RULE_ENT *) a;
|
||||
|
||||
my_free((gptr) e, MYF(0));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rpl_filter::init_table_rule_hash(HASH* h, bool* h_inited)
|
||||
{
|
||||
hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0,
|
||||
get_table_key, free_table_ent, 0);
|
||||
*h_inited = 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rpl_filter::init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited)
|
||||
{
|
||||
my_init_dynamic_array(a, sizeof(TABLE_RULE_ENT*), TABLE_RULE_ARR_SIZE,
|
||||
TABLE_RULE_ARR_SIZE);
|
||||
*a_inited = 1;
|
||||
}
|
||||
|
||||
|
||||
TABLE_RULE_ENT*
|
||||
Rpl_filter::find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
|
||||
{
|
||||
uint i;
|
||||
const char* key_end= key + len;
|
||||
|
||||
for (i= 0; i < a->elements; i++)
|
||||
{
|
||||
TABLE_RULE_ENT* e ;
|
||||
get_dynamic(a, (gptr)&e, i);
|
||||
if (!my_wildcmp(system_charset_info, key, key_end,
|
||||
(const char*)e->db,
|
||||
(const char*)(e->db + e->key_len),
|
||||
'\\',wild_one,wild_many))
|
||||
return e;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rpl_filter::free_string_array(DYNAMIC_ARRAY *a)
|
||||
{
|
||||
uint i;
|
||||
for (i= 0; i < a->elements; i++)
|
||||
{
|
||||
char* p;
|
||||
get_dynamic(a, (gptr) &p, i);
|
||||
my_free(p, MYF(MY_WME));
|
||||
}
|
||||
delete_dynamic(a);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Builds a String from a HASH of TABLE_RULE_ENT. Cannot be used for any other
|
||||
hash, as it assumes that the hash entries are TABLE_RULE_ENT.
|
||||
|
||||
SYNOPSIS
|
||||
table_rule_ent_hash_to_str()
|
||||
s pointer to the String to fill
|
||||
h pointer to the HASH to read
|
||||
|
||||
RETURN VALUES
|
||||
none
|
||||
*/
|
||||
|
||||
void
|
||||
Rpl_filter::table_rule_ent_hash_to_str(String* s, HASH* h)
|
||||
{
|
||||
s->length(0);
|
||||
for (uint i= 0; i < h->records; i++)
|
||||
{
|
||||
TABLE_RULE_ENT* e= (TABLE_RULE_ENT*) hash_element(h, i);
|
||||
if (s->length())
|
||||
s->append(',');
|
||||
s->append(e->db,e->key_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rpl_filter::table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a)
|
||||
{
|
||||
s->length(0);
|
||||
for (uint i= 0; i < a->elements; i++)
|
||||
{
|
||||
TABLE_RULE_ENT* e;
|
||||
get_dynamic(a, (gptr)&e, i);
|
||||
if (s->length())
|
||||
s->append(',');
|
||||
s->append(e->db,e->key_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rpl_filter::get_do_table(String* str)
|
||||
{
|
||||
table_rule_ent_hash_to_str(str, &do_table);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rpl_filter::get_ignore_table(String* str)
|
||||
{
|
||||
table_rule_ent_hash_to_str(str, &ignore_table);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rpl_filter::get_wild_do_table(String* str)
|
||||
{
|
||||
table_rule_ent_dynamic_array_to_str(str, &wild_do_table);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rpl_filter::get_wild_ignore_table(String* str)
|
||||
{
|
||||
table_rule_ent_dynamic_array_to_str(str, &wild_ignore_table);
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
Rpl_filter::get_rewrite_db(const char* db, uint32 *new_len)
|
||||
{
|
||||
if (rewrite_db.is_empty() || !db)
|
||||
return db;
|
||||
I_List_iterator<i_string_pair> it(rewrite_db);
|
||||
i_string_pair* tmp;
|
||||
|
||||
while ((tmp=it++))
|
||||
{
|
||||
if (!strcmp(tmp->key, db))
|
||||
{
|
||||
*new_len= strlen(tmp->val);
|
||||
return tmp->val;
|
||||
}
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
|
||||
I_List<i_string>*
|
||||
Rpl_filter::get_do_db()
|
||||
{
|
||||
return &do_db;
|
||||
}
|
||||
|
||||
|
||||
I_List<i_string>*
|
||||
Rpl_filter::get_ignore_db()
|
||||
{
|
||||
return &ignore_db;
|
||||
}
|
110
sql/rpl_filter.h
Normal file
110
sql/rpl_filter.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
/* Copyright (C) 2000-2003 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#ifndef __RPL_FILTER_H__
|
||||
#define __RPL_FILTER_H__
|
||||
|
||||
#include "mysql.h"
|
||||
#include "my_list.h"
|
||||
|
||||
typedef struct st_table_rule_ent
|
||||
{
|
||||
char* db;
|
||||
char* tbl_name;
|
||||
uint key_len;
|
||||
} TABLE_RULE_ENT;
|
||||
|
||||
/*
|
||||
Rpl_filter
|
||||
|
||||
Inclusion and exclusion rules of tables and databases.
|
||||
Also handles rewrites of db.
|
||||
Used for replication and binlogging.
|
||||
*/
|
||||
class Rpl_filter
|
||||
{
|
||||
public:
|
||||
Rpl_filter();
|
||||
~Rpl_filter();
|
||||
Rpl_filter(Rpl_filter const&);
|
||||
Rpl_filter& operator=(Rpl_filter const&);
|
||||
|
||||
/* Checks - returns true if ok to replicate/log */
|
||||
|
||||
bool tables_ok(const char* db, TABLE_LIST* tables);
|
||||
bool db_ok(const char* db);
|
||||
bool db_ok_with_wild_table(const char *db);
|
||||
|
||||
bool is_on();
|
||||
|
||||
/* Setters - add filtering rules */
|
||||
|
||||
int add_do_table(const char* table_spec);
|
||||
int add_ignore_table(const char* table_spec);
|
||||
|
||||
int add_wild_do_table(const char* table_spec);
|
||||
int add_wild_ignore_table(const char* table_spec);
|
||||
|
||||
void add_do_db(const char* db_spec);
|
||||
void add_ignore_db(const char* db_spec);
|
||||
|
||||
void add_db_rewrite(const char* from_db, const char* to_db);
|
||||
|
||||
/* Getters - to get information about current rules */
|
||||
|
||||
void get_do_table(String* str);
|
||||
void get_ignore_table(String* str);
|
||||
|
||||
void get_wild_do_table(String* str);
|
||||
void get_wild_ignore_table(String* str);
|
||||
|
||||
const char* get_rewrite_db(const char* db, uint32 *new_len);
|
||||
|
||||
I_List<i_string>* get_do_db();
|
||||
I_List<i_string>* get_ignore_db();
|
||||
|
||||
private:
|
||||
bool table_rules_on;
|
||||
|
||||
void init_table_rule_hash(HASH* h, bool* h_inited);
|
||||
void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited);
|
||||
|
||||
int add_table_rule(HASH* h, const char* table_spec);
|
||||
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec);
|
||||
|
||||
void free_string_array(DYNAMIC_ARRAY *a);
|
||||
|
||||
void table_rule_ent_hash_to_str(String* s, HASH* h);
|
||||
void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a);
|
||||
TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len);
|
||||
|
||||
HASH do_table;
|
||||
HASH ignore_table;
|
||||
DYNAMIC_ARRAY wild_do_table;
|
||||
DYNAMIC_ARRAY wild_ignore_table;
|
||||
|
||||
bool do_table_inited;
|
||||
bool ignore_table_inited;
|
||||
bool wild_do_table_inited;
|
||||
bool wild_ignore_table_inited;
|
||||
|
||||
I_List<i_string> do_db;
|
||||
I_List<i_string> ignore_db;
|
||||
|
||||
I_List<i_string_pair> rewrite_db;
|
||||
};
|
||||
|
||||
#endif // __TABLE_FILTER_H__
|
390
sql/slave.cc
390
sql/slave.cc
|
@ -22,6 +22,7 @@
|
|||
#include <myisam.h>
|
||||
#include "slave.h"
|
||||
#include "sql_repl.h"
|
||||
#include "rpl_filter.h"
|
||||
#include "repl_failsafe.h"
|
||||
#include <thr_alarm.h>
|
||||
#include <my_dir.h>
|
||||
|
@ -35,11 +36,7 @@ typedef bool (*CHECK_KILLED_FUNC)(THD*,void*);
|
|||
volatile bool slave_sql_running = 0, slave_io_running = 0;
|
||||
char* slave_load_tmpdir = 0;
|
||||
MASTER_INFO *active_mi;
|
||||
HASH replicate_do_table, replicate_ignore_table;
|
||||
DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table;
|
||||
bool do_table_inited = 0, ignore_table_inited = 0;
|
||||
bool wild_do_table_inited = 0, wild_ignore_table_inited = 0;
|
||||
bool table_rules_on= 0, replicate_same_server_id;
|
||||
bool replicate_same_server_id;
|
||||
ulonglong relay_log_space_limit = 0;
|
||||
|
||||
/*
|
||||
|
@ -193,20 +190,6 @@ err:
|
|||
}
|
||||
|
||||
|
||||
static void free_table_ent(TABLE_RULE_ENT* e)
|
||||
{
|
||||
my_free((gptr) e, MYF(0));
|
||||
}
|
||||
|
||||
|
||||
static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
|
||||
my_bool not_used __attribute__((unused)))
|
||||
{
|
||||
*len = e->key_len;
|
||||
return (byte*)e->db;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Open the given relay log
|
||||
|
||||
|
@ -808,228 +791,6 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
|
|||
}
|
||||
|
||||
|
||||
void init_table_rule_hash(HASH* h, bool* h_inited)
|
||||
{
|
||||
hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0,
|
||||
(hash_get_key) get_table_key,
|
||||
(hash_free_key) free_table_ent, 0);
|
||||
*h_inited = 1;
|
||||
}
|
||||
|
||||
|
||||
void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited)
|
||||
{
|
||||
my_init_dynamic_array(a, sizeof(TABLE_RULE_ENT*), TABLE_RULE_ARR_SIZE,
|
||||
TABLE_RULE_ARR_SIZE);
|
||||
*a_inited = 1;
|
||||
}
|
||||
|
||||
|
||||
static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
|
||||
{
|
||||
uint i;
|
||||
const char* key_end = key + len;
|
||||
|
||||
for (i = 0; i < a->elements; i++)
|
||||
{
|
||||
TABLE_RULE_ENT* e ;
|
||||
get_dynamic(a, (gptr)&e, i);
|
||||
if (!my_wildcmp(system_charset_info, key, key_end,
|
||||
(const char*)e->db,
|
||||
(const char*)(e->db + e->key_len),
|
||||
'\\',wild_one,wild_many))
|
||||
return e;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Checks whether tables match some (wild_)do_table and (wild_)ignore_table
|
||||
rules (for replication)
|
||||
|
||||
SYNOPSIS
|
||||
tables_ok()
|
||||
thd thread (SQL slave thread normally)
|
||||
tables list of tables to check
|
||||
|
||||
NOTES
|
||||
Note that changing the order of the tables in the list can lead to
|
||||
different results. Note also the order of precedence of the do/ignore
|
||||
rules (see code below). For that reason, users should not set conflicting
|
||||
rules because they may get unpredicted results (precedence order is
|
||||
explained in the manual).
|
||||
If no table of the list is marked "updating" (so far this can only happen
|
||||
if the statement is a multi-delete (SQLCOM_DELETE_MULTI) and the "tables"
|
||||
is the tables in the FROM): then we always return 0, because there is no
|
||||
reason we play this statement on this slave if it updates nothing. In the
|
||||
case of SQLCOM_DELETE_MULTI, there will be a second call to tables_ok(),
|
||||
with tables having "updating==TRUE" (those after the DELETE), so this
|
||||
second call will make the decision (because
|
||||
all_tables_not_ok() = !tables_ok(1st_list) && !tables_ok(2nd_list)).
|
||||
|
||||
Thought which arose from a question of a big customer "I want to include
|
||||
all tables like "abc.%" except the "%.EFG"". This can't be done now. If we
|
||||
supported Perl regexps we could do it with this pattern: /^abc\.(?!EFG)/
|
||||
(I could not find an equivalent in the regex library MySQL uses).
|
||||
|
||||
RETURN VALUES
|
||||
0 should not be logged/replicated
|
||||
1 should be logged/replicated
|
||||
*/
|
||||
|
||||
bool tables_ok(THD* thd, TABLE_LIST* tables)
|
||||
{
|
||||
bool some_tables_updating= 0;
|
||||
DBUG_ENTER("tables_ok");
|
||||
|
||||
for (; tables; tables= tables->next_global)
|
||||
{
|
||||
char hash_key[2*NAME_LEN+2];
|
||||
char *end;
|
||||
uint len;
|
||||
|
||||
if (!tables->updating)
|
||||
continue;
|
||||
some_tables_updating= 1;
|
||||
end= strmov(hash_key, tables->db ? tables->db : thd->db);
|
||||
*end++= '.';
|
||||
len= (uint) (strmov(end, tables->table_name) - hash_key);
|
||||
if (do_table_inited) // if there are any do's
|
||||
{
|
||||
if (hash_search(&replicate_do_table, (byte*) hash_key, len))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (ignore_table_inited) // if there are any ignores
|
||||
{
|
||||
if (hash_search(&replicate_ignore_table, (byte*) hash_key, len))
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
if (wild_do_table_inited && find_wild(&replicate_wild_do_table,
|
||||
hash_key, len))
|
||||
DBUG_RETURN(1);
|
||||
if (wild_ignore_table_inited && find_wild(&replicate_wild_ignore_table,
|
||||
hash_key, len))
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*
|
||||
If no table was to be updated, ignore statement (no reason we play it on
|
||||
slave, slave is supposed to replicate _changes_ only).
|
||||
If no explicit rule found and there was a do list, do not replicate.
|
||||
If there was no do list, go ahead
|
||||
*/
|
||||
DBUG_RETURN(some_tables_updating &&
|
||||
!do_table_inited && !wild_do_table_inited);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Checks whether a db matches wild_do_table and wild_ignore_table
|
||||
rules (for replication)
|
||||
|
||||
SYNOPSIS
|
||||
db_ok_with_wild_table()
|
||||
db name of the db to check.
|
||||
Is tested with check_db_name() before calling this function.
|
||||
|
||||
NOTES
|
||||
Here is the reason for this function.
|
||||
We advise users who want to exclude a database 'db1' safely to do it
|
||||
with replicate_wild_ignore_table='db1.%' instead of binlog_ignore_db or
|
||||
replicate_ignore_db because the two lasts only check for the selected db,
|
||||
which won't work in that case:
|
||||
USE db2;
|
||||
UPDATE db1.t SET ... #this will be replicated and should not
|
||||
whereas replicate_wild_ignore_table will work in all cases.
|
||||
With replicate_wild_ignore_table, we only check tables. When
|
||||
one does 'DROP DATABASE db1', tables are not involved and the
|
||||
statement will be replicated, while users could expect it would not (as it
|
||||
rougly means 'DROP db1.first_table, DROP db1.second_table...').
|
||||
In other words, we want to interpret 'db1.%' as "everything touching db1".
|
||||
That is why we want to match 'db1' against 'db1.%' wild table rules.
|
||||
|
||||
RETURN VALUES
|
||||
0 should not be logged/replicated
|
||||
1 should be logged/replicated
|
||||
*/
|
||||
|
||||
int db_ok_with_wild_table(const char *db)
|
||||
{
|
||||
char hash_key[NAME_LEN+2];
|
||||
char *end;
|
||||
int len;
|
||||
end= strmov(hash_key, db);
|
||||
*end++= '.';
|
||||
len= end - hash_key ;
|
||||
if (wild_do_table_inited && find_wild(&replicate_wild_do_table,
|
||||
hash_key, len))
|
||||
return 1;
|
||||
if (wild_ignore_table_inited && find_wild(&replicate_wild_ignore_table,
|
||||
hash_key, len))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
If no explicit rule found and there was a do list, do not replicate.
|
||||
If there was no do list, go ahead
|
||||
*/
|
||||
return !wild_do_table_inited;
|
||||
}
|
||||
|
||||
|
||||
int add_table_rule(HASH* h, const char* table_spec)
|
||||
{
|
||||
const char* dot = strchr(table_spec, '.');
|
||||
if (!dot) return 1;
|
||||
// len is always > 0 because we know the there exists a '.'
|
||||
uint len = (uint)strlen(table_spec);
|
||||
TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
|
||||
+ len, MYF(MY_WME));
|
||||
if (!e) return 1;
|
||||
e->db = (char*)e + sizeof(TABLE_RULE_ENT);
|
||||
e->tbl_name = e->db + (dot - table_spec) + 1;
|
||||
e->key_len = len;
|
||||
memcpy(e->db, table_spec, len);
|
||||
(void)my_hash_insert(h, (byte*)e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Add table expression with wildcards to dynamic array
|
||||
*/
|
||||
|
||||
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
|
||||
{
|
||||
const char* dot = strchr(table_spec, '.');
|
||||
if (!dot) return 1;
|
||||
uint len = (uint)strlen(table_spec);
|
||||
TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
|
||||
+ len, MYF(MY_WME));
|
||||
if (!e) return 1;
|
||||
e->db = (char*)e + sizeof(TABLE_RULE_ENT);
|
||||
e->tbl_name = e->db + (dot - table_spec) + 1;
|
||||
e->key_len = len;
|
||||
memcpy(e->db, table_spec, len);
|
||||
insert_dynamic(a, (gptr)&e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void free_string_array(DYNAMIC_ARRAY *a)
|
||||
{
|
||||
uint i;
|
||||
for (i = 0; i < a->elements; i++)
|
||||
{
|
||||
char* p;
|
||||
get_dynamic(a, (gptr) &p, i);
|
||||
my_free(p, MYF(MY_WME));
|
||||
}
|
||||
delete_dynamic(a);
|
||||
}
|
||||
|
||||
|
||||
#ifdef NOT_USED_YET
|
||||
static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/)
|
||||
{
|
||||
|
@ -1065,14 +826,6 @@ void end_slave()
|
|||
*/
|
||||
terminate_slave_threads(active_mi,SLAVE_FORCE_ALL);
|
||||
end_master_info(active_mi);
|
||||
if (do_table_inited)
|
||||
hash_free(&replicate_do_table);
|
||||
if (ignore_table_inited)
|
||||
hash_free(&replicate_ignore_table);
|
||||
if (wild_do_table_inited)
|
||||
free_string_array(&replicate_wild_do_table);
|
||||
if (wild_ignore_table_inited)
|
||||
free_string_array(&replicate_wild_ignore_table);
|
||||
delete active_mi;
|
||||
active_mi= 0;
|
||||
}
|
||||
|
@ -1152,24 +905,6 @@ bool net_request_file(NET* net, const char* fname)
|
|||
}
|
||||
|
||||
|
||||
const char *rewrite_db(const char* db, uint32 *new_len)
|
||||
{
|
||||
if (replicate_rewrite_db.is_empty() || !db)
|
||||
return db;
|
||||
I_List_iterator<i_string_pair> it(replicate_rewrite_db);
|
||||
i_string_pair* tmp;
|
||||
|
||||
while ((tmp=it++))
|
||||
{
|
||||
if (!strcmp(tmp->key, db))
|
||||
{
|
||||
*new_len= (uint32)strlen(tmp->val);
|
||||
return tmp->val;
|
||||
}
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
/*
|
||||
From other comments and tests in code, it looks like
|
||||
sometimes Query_log_event and Load_log_event can have db == 0
|
||||
|
@ -1182,60 +917,6 @@ const char *print_slave_db_safe(const char* db)
|
|||
return (db ? db : "");
|
||||
}
|
||||
|
||||
/*
|
||||
Checks whether a db matches some do_db and ignore_db rules
|
||||
(for logging or replication)
|
||||
|
||||
SYNOPSIS
|
||||
db_ok()
|
||||
db name of the db to check
|
||||
do_list either binlog_do_db or replicate_do_db
|
||||
ignore_list either binlog_ignore_db or replicate_ignore_db
|
||||
|
||||
RETURN VALUES
|
||||
0 should not be logged/replicated
|
||||
1 should be logged/replicated
|
||||
*/
|
||||
|
||||
int db_ok(const char* db, I_List<i_string> &do_list,
|
||||
I_List<i_string> &ignore_list )
|
||||
{
|
||||
if (do_list.is_empty() && ignore_list.is_empty())
|
||||
return 1; // ok to replicate if the user puts no constraints
|
||||
|
||||
/*
|
||||
If the user has specified restrictions on which databases to replicate
|
||||
and db was not selected, do not replicate.
|
||||
*/
|
||||
if (!db)
|
||||
return 0;
|
||||
|
||||
if (!do_list.is_empty()) // if the do's are not empty
|
||||
{
|
||||
I_List_iterator<i_string> it(do_list);
|
||||
i_string* tmp;
|
||||
|
||||
while ((tmp=it++))
|
||||
{
|
||||
if (!strcmp(tmp->ptr, db))
|
||||
return 1; // match
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else // there are some elements in the don't, otherwise we cannot get here
|
||||
{
|
||||
I_List_iterator<i_string> it(ignore_list);
|
||||
i_string* tmp;
|
||||
|
||||
while ((tmp=it++))
|
||||
{
|
||||
if (!strcmp(tmp->ptr, db))
|
||||
return 0; // match
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
|
||||
const char *default_val)
|
||||
|
@ -2245,48 +1926,6 @@ int register_slave_on_master(MYSQL* mysql)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Builds a String from a HASH of TABLE_RULE_ENT. Cannot be used for any other
|
||||
hash, as it assumes that the hash entries are TABLE_RULE_ENT.
|
||||
|
||||
SYNOPSIS
|
||||
table_rule_ent_hash_to_str()
|
||||
s pointer to the String to fill
|
||||
h pointer to the HASH to read
|
||||
|
||||
RETURN VALUES
|
||||
none
|
||||
*/
|
||||
|
||||
void table_rule_ent_hash_to_str(String* s, HASH* h)
|
||||
{
|
||||
s->length(0);
|
||||
for (uint i=0 ; i < h->records ; i++)
|
||||
{
|
||||
TABLE_RULE_ENT* e= (TABLE_RULE_ENT*) hash_element(h, i);
|
||||
if (s->length())
|
||||
s->append(',');
|
||||
s->append(e->db,e->key_len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Mostly the same thing as above
|
||||
*/
|
||||
|
||||
void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a)
|
||||
{
|
||||
s->length(0);
|
||||
for (uint i=0 ; i < a->elements ; i++)
|
||||
{
|
||||
TABLE_RULE_ENT* e;
|
||||
get_dynamic(a, (gptr)&e, i);
|
||||
if (s->length())
|
||||
s->append(',');
|
||||
s->append(e->db,e->key_len);
|
||||
}
|
||||
}
|
||||
|
||||
bool show_master_info(THD* thd, MASTER_INFO* mi)
|
||||
{
|
||||
// TODO: fix this for multi-master
|
||||
|
@ -2381,23 +2020,18 @@ bool show_master_info(THD* thd, MASTER_INFO* mi)
|
|||
protocol->store(mi->rli.group_master_log_name, &my_charset_bin);
|
||||
protocol->store(mi->slave_running ? "Yes":"No", &my_charset_bin);
|
||||
protocol->store(mi->rli.slave_running ? "Yes":"No", &my_charset_bin);
|
||||
protocol->store(&replicate_do_db);
|
||||
protocol->store(&replicate_ignore_db);
|
||||
/*
|
||||
We can't directly use some protocol->store for
|
||||
replicate_*_table,
|
||||
as Protocol doesn't know the TABLE_RULE_ENT struct.
|
||||
We first build Strings and then pass them to protocol->store.
|
||||
*/
|
||||
protocol->store(rpl_filter->get_do_db());
|
||||
protocol->store(rpl_filter->get_ignore_db());
|
||||
|
||||
char buf[256];
|
||||
String tmp(buf, sizeof(buf), &my_charset_bin);
|
||||
table_rule_ent_hash_to_str(&tmp, &replicate_do_table);
|
||||
rpl_filter->get_do_table(&tmp);
|
||||
protocol->store(&tmp);
|
||||
table_rule_ent_hash_to_str(&tmp, &replicate_ignore_table);
|
||||
rpl_filter->get_ignore_table(&tmp);
|
||||
protocol->store(&tmp);
|
||||
table_rule_ent_dynamic_array_to_str(&tmp, &replicate_wild_do_table);
|
||||
rpl_filter->get_wild_do_table(&tmp);
|
||||
protocol->store(&tmp);
|
||||
table_rule_ent_dynamic_array_to_str(&tmp, &replicate_wild_ignore_table);
|
||||
rpl_filter->get_wild_ignore_table(&tmp);
|
||||
protocol->store(&tmp);
|
||||
|
||||
protocol->store((uint32) mi->rli.last_slave_errno);
|
||||
|
@ -3845,10 +3479,8 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev)
|
|||
|
||||
if (unlikely(!cev->is_valid()))
|
||||
DBUG_RETURN(1);
|
||||
/*
|
||||
TODO: fix to honor table rules, not only db rules
|
||||
*/
|
||||
if (!db_ok(cev->db, replicate_do_db, replicate_ignore_db))
|
||||
|
||||
if (!rpl_filter->db_ok(cev->db))
|
||||
{
|
||||
skip_load_data_infile(net);
|
||||
DBUG_RETURN(0);
|
||||
|
|
39
sql/slave.h
39
sql/slave.h
|
@ -21,10 +21,14 @@
|
|||
|
||||
#include "mysql.h"
|
||||
#include "my_list.h"
|
||||
#include "rpl_filter.h"
|
||||
|
||||
#define SLAVE_NET_TIMEOUT 3600
|
||||
#define MAX_SLAVE_ERRMSG 1024
|
||||
#define MAX_SLAVE_ERROR 2000
|
||||
|
||||
extern Rpl_filter *rpl_filter;
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
MySQL Replication
|
||||
|
@ -454,15 +458,6 @@ typedef struct st_master_info
|
|||
|
||||
int queue_event(MASTER_INFO* mi,const char* buf,ulong event_len);
|
||||
|
||||
typedef struct st_table_rule_ent
|
||||
{
|
||||
char* db;
|
||||
char* tbl_name;
|
||||
uint key_len;
|
||||
} TABLE_RULE_ENT;
|
||||
|
||||
#define TABLE_RULE_HASH_SIZE 16
|
||||
#define TABLE_RULE_ARR_SIZE 16
|
||||
#define MAX_SLAVE_ERRMSG 1024
|
||||
|
||||
#define RPL_LOG_NAME (rli->group_master_log_name[0] ? rli->group_master_log_name :\
|
||||
|
@ -516,27 +511,9 @@ int mysql_table_dump(THD* thd, const char* db,
|
|||
int fetch_master_table(THD* thd, const char* db_name, const char* table_name,
|
||||
MASTER_INFO* mi, MYSQL* mysql, bool overwrite);
|
||||
|
||||
void table_rule_ent_hash_to_str(String* s, HASH* h);
|
||||
void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a);
|
||||
bool show_master_info(THD* thd, MASTER_INFO* mi);
|
||||
bool show_binlog_info(THD* thd);
|
||||
|
||||
/* See if the query uses any tables that should not be replicated */
|
||||
bool tables_ok(THD* thd, TABLE_LIST* tables);
|
||||
|
||||
/*
|
||||
Check to see if the database is ok to operate on with respect to the
|
||||
do and ignore lists - used in replication
|
||||
*/
|
||||
int db_ok(const char* db, I_List<i_string> &do_list,
|
||||
I_List<i_string> &ignore_list );
|
||||
int db_ok_with_wild_table(const char *db);
|
||||
|
||||
int add_table_rule(HASH* h, const char* table_spec);
|
||||
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec);
|
||||
void init_table_rule_hash(HASH* h, bool* h_inited);
|
||||
void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited);
|
||||
const char *rewrite_db(const char* db, uint32 *new_db_len);
|
||||
const char *print_slave_db_safe(const char *db);
|
||||
int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int error_code);
|
||||
void skip_load_data_infile(NET* net);
|
||||
|
@ -569,11 +546,7 @@ extern "C" pthread_handler_decl(handle_slave_sql,arg);
|
|||
extern bool volatile abort_loop;
|
||||
extern MASTER_INFO main_mi, *active_mi; /* active_mi for multi-master */
|
||||
extern LIST master_list;
|
||||
extern HASH replicate_do_table, replicate_ignore_table;
|
||||
extern DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table;
|
||||
extern bool do_table_inited, ignore_table_inited,
|
||||
wild_do_table_inited, wild_ignore_table_inited;
|
||||
extern bool table_rules_on, replicate_same_server_id;
|
||||
extern bool replicate_same_server_id;
|
||||
|
||||
extern int disconnect_slave_event_count, abort_slave_event_count ;
|
||||
|
||||
|
@ -587,8 +560,6 @@ extern my_bool master_ssl;
|
|||
extern my_string master_ssl_ca, master_ssl_capath, master_ssl_cert,
|
||||
master_ssl_cipher, master_ssl_key;
|
||||
|
||||
extern I_List<i_string> replicate_do_db, replicate_ignore_db;
|
||||
extern I_List<i_string_pair> replicate_rewrite_db;
|
||||
extern I_List<THD> threads;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,9 +27,6 @@
|
|||
|
||||
#include "mysql_priv.h"
|
||||
#include "hash_filo.h"
|
||||
#ifdef HAVE_REPLICATION
|
||||
#include "sql_repl.h" //for tables_ok()
|
||||
#endif
|
||||
#include <m_ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include "sp_head.h"
|
||||
|
@ -1499,7 +1496,7 @@ static bool update_user_table(THD *thd, const char *host, const char *user,
|
|||
GRANT and REVOKE are applied the slave in/exclusion rules as they are
|
||||
some kind of updates to the mysql.% tables.
|
||||
*/
|
||||
if (thd->slave_thread && table_rules_on)
|
||||
if (thd->slave_thread && rpl_filter->is_on())
|
||||
{
|
||||
/*
|
||||
The tables must be marked "updating" so that tables_ok() takes them into
|
||||
|
@ -1507,7 +1504,7 @@ static bool update_user_table(THD *thd, const char *host, const char *user,
|
|||
*/
|
||||
tables.updating= 1;
|
||||
/* Thanks to bzero, tables.next==0 */
|
||||
if (!tables_ok(0, &tables))
|
||||
if (!rpl_filter->tables_ok(0, &tables))
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
#endif
|
||||
|
@ -2670,14 +2667,14 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
|
|||
GRANT and REVOKE are applied the slave in/exclusion rules as they are
|
||||
some kind of updates to the mysql.% tables.
|
||||
*/
|
||||
if (thd->slave_thread && table_rules_on)
|
||||
if (thd->slave_thread && rpl_filter->is_on())
|
||||
{
|
||||
/*
|
||||
The tables must be marked "updating" so that tables_ok() takes them into
|
||||
account in tests.
|
||||
*/
|
||||
tables[0].updating= tables[1].updating= tables[2].updating= 1;
|
||||
if (!tables_ok(0, tables))
|
||||
if (!rpl_filter->tables_ok(0, tables))
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
#endif
|
||||
|
@ -2873,14 +2870,14 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list,
|
|||
GRANT and REVOKE are applied the slave in/exclusion rules as they are
|
||||
some kind of updates to the mysql.% tables.
|
||||
*/
|
||||
if (thd->slave_thread && table_rules_on)
|
||||
if (thd->slave_thread && rpl_filter->is_on())
|
||||
{
|
||||
/*
|
||||
The tables must be marked "updating" so that tables_ok() takes them into
|
||||
account in tests.
|
||||
*/
|
||||
tables[0].updating= tables[1].updating= 1;
|
||||
if (!tables_ok(0, tables))
|
||||
if (!rpl_filter->tables_ok(0, tables))
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
#endif
|
||||
|
@ -3002,14 +2999,14 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
|
|||
GRANT and REVOKE are applied the slave in/exclusion rules as they are
|
||||
some kind of updates to the mysql.% tables.
|
||||
*/
|
||||
if (thd->slave_thread && table_rules_on)
|
||||
if (thd->slave_thread && rpl_filter->is_on())
|
||||
{
|
||||
/*
|
||||
The tables must be marked "updating" so that tables_ok() takes them into
|
||||
account in tests.
|
||||
*/
|
||||
tables[0].updating= tables[1].updating= 1;
|
||||
if (!tables_ok(0, tables))
|
||||
if (!rpl_filter->tables_ok(0, tables))
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
#endif
|
||||
|
@ -4210,7 +4207,7 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables)
|
|||
GRANT and REVOKE are applied the slave in/exclusion rules as they are
|
||||
some kind of updates to the mysql.% tables.
|
||||
*/
|
||||
if (thd->slave_thread && table_rules_on)
|
||||
if (thd->slave_thread && rpl_filter->is_on())
|
||||
{
|
||||
/*
|
||||
The tables must be marked "updating" so that tables_ok() takes them into
|
||||
|
@ -4218,7 +4215,7 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables)
|
|||
*/
|
||||
tables[0].updating=tables[1].updating=tables[2].updating=
|
||||
tables[3].updating=tables[4].updating=1;
|
||||
if (!tables_ok(0, tables))
|
||||
if (!rpl_filter->tables_ok(0, tables))
|
||||
DBUG_RETURN(1);
|
||||
tables[0].updating=tables[1].updating=tables[2].updating=
|
||||
tables[3].updating=tables[4].updating=0;;
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "slave.h" // for tables_ok(), rpl_filter
|
||||
extern Rpl_filter *rpl_filter;
|
||||
|
||||
#define SELECT_ACL (1L << 0)
|
||||
#define INSERT_ACL (1L << 1)
|
||||
#define UPDATE_ACL (1L << 2)
|
||||
|
|
|
@ -466,19 +466,20 @@ public:
|
|||
class i_string: public ilink
|
||||
{
|
||||
public:
|
||||
char* ptr;
|
||||
const char* ptr;
|
||||
i_string():ptr(0) { }
|
||||
i_string(char* s) : ptr(s) {}
|
||||
i_string(const char* s) : ptr(s) {}
|
||||
};
|
||||
|
||||
/* needed for linked list of two strings for replicate-rewrite-db */
|
||||
class i_string_pair: public ilink
|
||||
{
|
||||
public:
|
||||
char* key;
|
||||
char* val;
|
||||
const char* key;
|
||||
const char* val;
|
||||
i_string_pair():key(0),val(0) { }
|
||||
i_string_pair(char* key_arg, char* val_arg) : key(key_arg),val(val_arg) {}
|
||||
i_string_pair(const char* key_arg, const char* val_arg) :
|
||||
key(key_arg),val(val_arg) {}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "mysql_priv.h"
|
||||
#include "sql_repl.h"
|
||||
#include "rpl_filter.h"
|
||||
#include "repl_failsafe.h"
|
||||
#include <m_ctype.h>
|
||||
#include <myisam.h>
|
||||
|
@ -167,10 +168,12 @@ static bool begin_trans(THD *thd)
|
|||
#ifdef HAVE_REPLICATION
|
||||
inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
|
||||
{
|
||||
return (table_rules_on && tables && !tables_ok(thd,tables) &&
|
||||
return (rpl_filter->is_on() && tables &&
|
||||
!rpl_filter->tables_ok(thd->db, tables) &&
|
||||
((thd->lex->sql_command != SQLCOM_DELETE_MULTI) ||
|
||||
!tables_ok(thd,
|
||||
(TABLE_LIST *)thd->lex->auxilliary_table_list.first)));
|
||||
!rpl_filter->tables_ok(thd->db,
|
||||
(TABLE_LIST *)
|
||||
thd->lex->auxilliary_table_list.first)));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3441,9 +3444,9 @@ unsent_create_error:
|
|||
above was not called. So we have to check rules again here.
|
||||
*/
|
||||
#ifdef HAVE_REPLICATION
|
||||
if (thd->slave_thread &&
|
||||
(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
|
||||
!db_ok_with_wild_table(lex->name)))
|
||||
if (thd->slave_thread &&
|
||||
(!rpl_filter->db_ok(lex->name) ||
|
||||
!rpl_filter->db_ok_with_wild_table(lex->name)))
|
||||
{
|
||||
my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
|
||||
break;
|
||||
|
@ -3471,8 +3474,8 @@ unsent_create_error:
|
|||
*/
|
||||
#ifdef HAVE_REPLICATION
|
||||
if (thd->slave_thread &&
|
||||
(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
|
||||
!db_ok_with_wild_table(lex->name)))
|
||||
(!rpl_filter->db_ok(lex->name) ||
|
||||
!rpl_filter->db_ok_with_wild_table(lex->name)))
|
||||
{
|
||||
my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
|
||||
break;
|
||||
|
@ -3511,8 +3514,8 @@ unsent_create_error:
|
|||
*/
|
||||
#ifdef HAVE_REPLICATION
|
||||
if (thd->slave_thread &&
|
||||
(!db_ok(db, replicate_do_db, replicate_ignore_db) ||
|
||||
!db_ok_with_wild_table(db)))
|
||||
(!rpl_filter->db_ok(lex->name) ||
|
||||
!rpl_filter->db_ok_with_wild_table(lex->name)))
|
||||
{
|
||||
my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
|
||||
break;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "sql_repl.h"
|
||||
#include "log_event.h"
|
||||
#include "rpl_filter.h"
|
||||
#include <my_dir.h>
|
||||
|
||||
int max_binlog_dump_events = 0; // unlimited
|
||||
|
@ -1429,8 +1430,8 @@ bool show_binlog_info(THD* thd)
|
|||
int dir_len = dirname_length(li.log_file_name);
|
||||
protocol->store(li.log_file_name + dir_len, &my_charset_bin);
|
||||
protocol->store((ulonglong) li.pos);
|
||||
protocol->store(&binlog_do_db);
|
||||
protocol->store(&binlog_ignore_db);
|
||||
protocol->store(binlog_filter->get_do_db());
|
||||
protocol->store(binlog_filter->get_ignore_db());
|
||||
if (protocol->write())
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
#ifdef HAVE_REPLICATION
|
||||
#include "slave.h"
|
||||
|
||||
extern Rpl_filter *binlog_filter;
|
||||
extern Rpl_filter *rpl_filter;
|
||||
|
||||
typedef struct st_slave_info
|
||||
{
|
||||
uint32 server_id;
|
||||
|
@ -31,7 +34,6 @@ typedef struct st_slave_info
|
|||
extern my_bool opt_show_slave_auth_info;
|
||||
extern char *master_host, *master_info_file;
|
||||
extern bool server_id_supplied;
|
||||
extern I_List<i_string> binlog_do_db, binlog_ignore_db;
|
||||
|
||||
extern int max_binlog_dump_events;
|
||||
extern my_bool opt_sporadic_binlog_dump_fail;
|
||||
|
|
Loading…
Add table
Reference in a new issue