1 /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15
16 #include "sql_priv.h"
17 #include "unireg.h" // REQUIRED by other includes
18 #include "rpl_filter.h"
19 #include "hash.h" // my_hash_free
20 #include "table.h" // TABLE_LIST
21
22 #define TABLE_RULE_HASH_SIZE 16
23 #define TABLE_RULE_ARR_SIZE 16
24
Rpl_filter()25 Rpl_filter::Rpl_filter() :
26 table_rules_on(0), do_table_inited(0), ignore_table_inited(0),
27 wild_do_table_inited(0), wild_ignore_table_inited(0)
28 {
29 do_db.empty();
30 ignore_db.empty();
31 rewrite_db.empty();
32 }
33
34
~Rpl_filter()35 Rpl_filter::~Rpl_filter()
36 {
37 if (do_table_inited)
38 my_hash_free(&do_table);
39 if (ignore_table_inited)
40 my_hash_free(&ignore_table);
41 if (wild_do_table_inited)
42 free_string_array(&wild_do_table);
43 if (wild_ignore_table_inited)
44 free_string_array(&wild_ignore_table);
45 free_list(&do_db);
46 free_list(&ignore_db);
47 free_list(&rewrite_db);
48 }
49
50
51 /*
52 Returns true if table should be logged/replicated
53
54 SYNOPSIS
55 tables_ok()
56 db db to use if db in TABLE_LIST is undefined for a table
57 tables list of tables to check
58
59 NOTES
60 Changing table order in the list can lead to different results.
61
62 Note also order of precedence of do/ignore rules (see code). For
63 that reason, users should not set conflicting rules because they
64 may get unpredicted results (precedence order is explained in the
65 manual).
66
67 If no table in the list is marked "updating", then we always
68 return 0, because there is no reason to execute this statement on
69 slave if it updates nothing. (Currently, this can only happen if
70 statement is a multi-delete (SQLCOM_DELETE_MULTI) and "tables" are
71 the tables in the FROM):
72
73 In the case of SQLCOM_DELETE_MULTI, there will be a second call to
74 tables_ok(), with tables having "updating==TRUE" (those after the
75 DELETE), so this second call will make the decision (because
76 all_tables_not_ok() = !tables_ok(1st_list) &&
77 !tables_ok(2nd_list)).
78
79 TODO
80 "Include all tables like "abc.%" except "%.EFG"". (Can't be done now.)
81 If we supported Perl regexps, we could do it with pattern: /^abc\.(?!EFG)/
82 (I could not find an equivalent in the regex library MySQL uses).
83
84 RETURN VALUES
85 0 should not be logged/replicated
86 1 should be logged/replicated
87 */
88
89 bool
tables_ok(const char * db,TABLE_LIST * tables)90 Rpl_filter::tables_ok(const char* db, TABLE_LIST* tables)
91 {
92 bool some_tables_updating= 0;
93 DBUG_ENTER("Rpl_filter::tables_ok");
94
95 for (; tables; tables= tables->next_global)
96 {
97 char hash_key[2*NAME_LEN+2];
98 char *end;
99 uint len;
100
101 if (!tables->updating)
102 continue;
103 some_tables_updating= 1;
104 end= strmov(hash_key, tables->db ? tables->db : db);
105 *end++= '.';
106 len= (uint) (strmov(end, tables->table_name) - hash_key);
107 if (do_table_inited) // if there are any do's
108 {
109 if (my_hash_search(&do_table, (uchar*) hash_key, len))
110 DBUG_RETURN(1);
111 }
112 if (ignore_table_inited) // if there are any ignores
113 {
114 if (my_hash_search(&ignore_table, (uchar*) hash_key, len))
115 DBUG_RETURN(0);
116 }
117 if (wild_do_table_inited &&
118 find_wild(&wild_do_table, hash_key, len))
119 DBUG_RETURN(1);
120 if (wild_ignore_table_inited &&
121 find_wild(&wild_ignore_table, hash_key, len))
122 DBUG_RETURN(0);
123 }
124
125 /*
126 If no table was to be updated, ignore statement (no reason we play it on
127 slave, slave is supposed to replicate _changes_ only).
128 If no explicit rule found and there was a do list, do not replicate.
129 If there was no do list, go ahead
130 */
131 DBUG_RETURN(some_tables_updating &&
132 !do_table_inited && !wild_do_table_inited);
133 }
134
135
136 /*
137 Checks whether a db matches some do_db and ignore_db rules
138
139 SYNOPSIS
140 db_ok()
141 db name of the db to check
142
143 RETURN VALUES
144 0 should not be logged/replicated
145 1 should be logged/replicated
146 */
147
148 bool
db_ok(const char * db)149 Rpl_filter::db_ok(const char* db)
150 {
151 DBUG_ENTER("Rpl_filter::db_ok");
152
153 if (do_db.is_empty() && ignore_db.is_empty())
154 DBUG_RETURN(1); // Ok to replicate if the user puts no constraints
155
156 /*
157 Previous behaviour "if the user has specified restrictions on which
158 databases to replicate and db was not selected, do not replicate" has
159 been replaced with "do replicate".
160 Since the filtering criteria is not equal to "NULL" the statement should
161 be logged into binlog.
162 */
163 if (!db)
164 DBUG_RETURN(1);
165
166 if (!do_db.is_empty()) // if the do's are not empty
167 {
168 I_List_iterator<i_string> it(do_db);
169 i_string* tmp;
170
171 while ((tmp=it++))
172 {
173 if (!strcmp(tmp->ptr, db))
174 DBUG_RETURN(1); // match
175 }
176 DBUG_RETURN(0);
177 }
178 else // there are some elements in the don't, otherwise we cannot get here
179 {
180 I_List_iterator<i_string> it(ignore_db);
181 i_string* tmp;
182
183 while ((tmp=it++))
184 {
185 if (!strcmp(tmp->ptr, db))
186 DBUG_RETURN(0); // match
187 }
188 DBUG_RETURN(1);
189 }
190 }
191
192
193 /*
194 Checks whether a db matches wild_do_table and wild_ignore_table
195 rules (for replication)
196
197 SYNOPSIS
198 db_ok_with_wild_table()
199 db name of the db to check.
200 Is tested with check_db_name() before calling this function.
201
202 NOTES
203 Here is the reason for this function.
204 We advise users who want to exclude a database 'db1' safely to do it
205 with replicate_wild_ignore_table='db1.%' instead of binlog_ignore_db or
206 replicate_ignore_db because the two lasts only check for the selected db,
207 which won't work in that case:
208 USE db2;
209 UPDATE db1.t SET ... #this will be replicated and should not
210 whereas replicate_wild_ignore_table will work in all cases.
211 With replicate_wild_ignore_table, we only check tables. When
212 one does 'DROP DATABASE db1', tables are not involved and the
213 statement will be replicated, while users could expect it would not (as it
214 rougly means 'DROP db1.first_table, DROP db1.second_table...').
215 In other words, we want to interpret 'db1.%' as "everything touching db1".
216 That is why we want to match 'db1' against 'db1.%' wild table rules.
217
218 RETURN VALUES
219 0 should not be logged/replicated
220 1 should be logged/replicated
221 */
222
223 bool
db_ok_with_wild_table(const char * db)224 Rpl_filter::db_ok_with_wild_table(const char *db)
225 {
226 DBUG_ENTER("Rpl_filter::db_ok_with_wild_table");
227
228 char hash_key[NAME_LEN+2];
229 char *end;
230 int len;
231 end= strmov(hash_key, db);
232 *end++= '.';
233 len= end - hash_key ;
234 if (wild_do_table_inited && find_wild(&wild_do_table, hash_key, len))
235 {
236 DBUG_PRINT("return",("1"));
237 DBUG_RETURN(1);
238 }
239 if (wild_ignore_table_inited && find_wild(&wild_ignore_table, hash_key, len))
240 {
241 DBUG_PRINT("return",("0"));
242 DBUG_RETURN(0);
243 }
244
245 /*
246 If no explicit rule found and there was a do list, do not replicate.
247 If there was no do list, go ahead
248 */
249 DBUG_PRINT("return",("db=%s,retval=%d", db, !wild_do_table_inited));
250 DBUG_RETURN(!wild_do_table_inited);
251 }
252
253
254 bool
is_on()255 Rpl_filter::is_on()
256 {
257 return table_rules_on;
258 }
259
260
261 int
add_do_table(const char * table_spec)262 Rpl_filter::add_do_table(const char* table_spec)
263 {
264 DBUG_ENTER("Rpl_filter::add_do_table");
265 if (!do_table_inited)
266 init_table_rule_hash(&do_table, &do_table_inited);
267 table_rules_on= 1;
268 DBUG_RETURN(add_table_rule(&do_table, table_spec));
269 }
270
271
272 int
add_ignore_table(const char * table_spec)273 Rpl_filter::add_ignore_table(const char* table_spec)
274 {
275 DBUG_ENTER("Rpl_filter::add_ignore_table");
276 if (!ignore_table_inited)
277 init_table_rule_hash(&ignore_table, &ignore_table_inited);
278 table_rules_on= 1;
279 DBUG_RETURN(add_table_rule(&ignore_table, table_spec));
280 }
281
282
283 int
add_wild_do_table(const char * table_spec)284 Rpl_filter::add_wild_do_table(const char* table_spec)
285 {
286 DBUG_ENTER("Rpl_filter::add_wild_do_table");
287 if (!wild_do_table_inited)
288 init_table_rule_array(&wild_do_table, &wild_do_table_inited);
289 table_rules_on= 1;
290 DBUG_RETURN(add_wild_table_rule(&wild_do_table, table_spec));
291 }
292
293
294 int
add_wild_ignore_table(const char * table_spec)295 Rpl_filter::add_wild_ignore_table(const char* table_spec)
296 {
297 DBUG_ENTER("Rpl_filter::add_wild_ignore_table");
298 if (!wild_ignore_table_inited)
299 init_table_rule_array(&wild_ignore_table, &wild_ignore_table_inited);
300 table_rules_on= 1;
301 DBUG_RETURN(add_wild_table_rule(&wild_ignore_table, table_spec));
302 }
303
304
305 void
add_db_rewrite(const char * from_db,const char * to_db)306 Rpl_filter::add_db_rewrite(const char* from_db, const char* to_db)
307 {
308 i_string_pair *db_pair = new i_string_pair(from_db, to_db);
309 rewrite_db.push_back(db_pair);
310 }
311
312
313 int
add_table_rule(HASH * h,const char * table_spec)314 Rpl_filter::add_table_rule(HASH* h, const char* table_spec)
315 {
316 const char* dot = strchr(table_spec, '.');
317 if (!dot) return 1;
318 // len is always > 0 because we know the there exists a '.'
319 uint len = (uint)strlen(table_spec);
320 TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
321 + len, MYF(MY_WME));
322 if (!e) return 1;
323 e->db= (char*)e + sizeof(TABLE_RULE_ENT);
324 e->tbl_name= e->db + (dot - table_spec) + 1;
325 e->key_len= len;
326 memcpy(e->db, table_spec, len);
327
328 return my_hash_insert(h, (uchar*)e);
329 }
330
331
332 /*
333 Add table expression with wildcards to dynamic array
334 */
335
336 int
add_wild_table_rule(DYNAMIC_ARRAY * a,const char * table_spec)337 Rpl_filter::add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
338 {
339 const char* dot = strchr(table_spec, '.');
340 if (!dot) return 1;
341 uint len = (uint)strlen(table_spec);
342 TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
343 + len, MYF(MY_WME));
344 if (!e) return 1;
345 e->db= (char*)e + sizeof(TABLE_RULE_ENT);
346 e->tbl_name= e->db + (dot - table_spec) + 1;
347 e->key_len= len;
348 memcpy(e->db, table_spec, len);
349 return insert_dynamic(a, (uchar*)&e);
350 }
351
352
353 void
add_do_db(const char * table_spec)354 Rpl_filter::add_do_db(const char* table_spec)
355 {
356 DBUG_ENTER("Rpl_filter::add_do_db");
357 i_string *db = new i_string(table_spec);
358 do_db.push_back(db);
359 DBUG_VOID_RETURN;
360 }
361
362
363 void
add_ignore_db(const char * table_spec)364 Rpl_filter::add_ignore_db(const char* table_spec)
365 {
366 DBUG_ENTER("Rpl_filter::add_ignore_db");
367 i_string *db = new i_string(table_spec);
368 ignore_db.push_back(db);
369 DBUG_VOID_RETURN;
370 }
371
372 extern "C" uchar *get_table_key(const uchar *, size_t *, my_bool);
373 extern "C" void free_table_ent(void* a);
374
get_table_key(const uchar * a,size_t * len,my_bool)375 uchar *get_table_key(const uchar* a, size_t *len,
376 my_bool __attribute__((unused)))
377 {
378 TABLE_RULE_ENT *e= (TABLE_RULE_ENT *) a;
379
380 *len= e->key_len;
381 return (uchar*)e->db;
382 }
383
384
free_table_ent(void * a)385 void free_table_ent(void* a)
386 {
387 TABLE_RULE_ENT *e= (TABLE_RULE_ENT *) a;
388
389 my_free(e);
390 }
391
392
393 void
init_table_rule_hash(HASH * h,bool * h_inited)394 Rpl_filter::init_table_rule_hash(HASH* h, bool* h_inited)
395 {
396 my_hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0,
397 get_table_key, free_table_ent, 0);
398 *h_inited = 1;
399 }
400
401
402 void
init_table_rule_array(DYNAMIC_ARRAY * a,bool * a_inited)403 Rpl_filter::init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited)
404 {
405 my_init_dynamic_array(a, sizeof(TABLE_RULE_ENT*), TABLE_RULE_ARR_SIZE,
406 TABLE_RULE_ARR_SIZE);
407 *a_inited = 1;
408 }
409
410
411 TABLE_RULE_ENT*
find_wild(DYNAMIC_ARRAY * a,const char * key,int len)412 Rpl_filter::find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
413 {
414 uint i;
415 const char* key_end= key + len;
416
417 for (i= 0; i < a->elements; i++)
418 {
419 TABLE_RULE_ENT* e ;
420 get_dynamic(a, (uchar*)&e, i);
421 if (!my_wildcmp(system_charset_info, key, key_end,
422 (const char*)e->db,
423 (const char*)(e->db + e->key_len),
424 '\\',wild_one,wild_many))
425 return e;
426 }
427
428 return 0;
429 }
430
431
432 void
free_string_array(DYNAMIC_ARRAY * a)433 Rpl_filter::free_string_array(DYNAMIC_ARRAY *a)
434 {
435 uint i;
436 for (i= 0; i < a->elements; i++)
437 {
438 char* p;
439 get_dynamic(a, (uchar*) &p, i);
440 my_free(p);
441 }
442 delete_dynamic(a);
443 }
444
445
446 /*
447 Builds a String from a HASH of TABLE_RULE_ENT. Cannot be used for any other
448 hash, as it assumes that the hash entries are TABLE_RULE_ENT.
449
450 SYNOPSIS
451 table_rule_ent_hash_to_str()
452 s pointer to the String to fill
453 h pointer to the HASH to read
454
455 RETURN VALUES
456 none
457 */
458
459 void
table_rule_ent_hash_to_str(String * s,HASH * h,bool inited)460 Rpl_filter::table_rule_ent_hash_to_str(String* s, HASH* h, bool inited)
461 {
462 s->length(0);
463 if (inited)
464 {
465 for (uint i= 0; i < h->records; i++)
466 {
467 TABLE_RULE_ENT* e= (TABLE_RULE_ENT*) my_hash_element(h, i);
468 if (s->length())
469 s->append(',');
470 s->append(e->db,e->key_len);
471 }
472 }
473 }
474
475
476 void
table_rule_ent_dynamic_array_to_str(String * s,DYNAMIC_ARRAY * a,bool inited)477 Rpl_filter::table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a,
478 bool inited)
479 {
480 s->length(0);
481 if (inited)
482 {
483 for (uint i= 0; i < a->elements; i++)
484 {
485 TABLE_RULE_ENT* e;
486 get_dynamic(a, (uchar*)&e, i);
487 if (s->length())
488 s->append(',');
489 s->append(e->db,e->key_len);
490 }
491 }
492 }
493
494
495 void
get_do_table(String * str)496 Rpl_filter::get_do_table(String* str)
497 {
498 table_rule_ent_hash_to_str(str, &do_table, do_table_inited);
499 }
500
501
502 void
get_ignore_table(String * str)503 Rpl_filter::get_ignore_table(String* str)
504 {
505 table_rule_ent_hash_to_str(str, &ignore_table, ignore_table_inited);
506 }
507
508
509 void
get_wild_do_table(String * str)510 Rpl_filter::get_wild_do_table(String* str)
511 {
512 table_rule_ent_dynamic_array_to_str(str, &wild_do_table, wild_do_table_inited);
513 }
514
515
516 void
get_wild_ignore_table(String * str)517 Rpl_filter::get_wild_ignore_table(String* str)
518 {
519 table_rule_ent_dynamic_array_to_str(str, &wild_ignore_table, wild_ignore_table_inited);
520 }
521
522
523 const char*
get_rewrite_db(const char * db,size_t * new_len)524 Rpl_filter::get_rewrite_db(const char* db, size_t *new_len)
525 {
526 if (rewrite_db.is_empty() || !db)
527 return db;
528 I_List_iterator<i_string_pair> it(rewrite_db);
529 i_string_pair* tmp;
530
531 while ((tmp=it++))
532 {
533 if (!strcmp(tmp->key, db))
534 {
535 *new_len= strlen(tmp->val);
536 return tmp->val;
537 }
538 }
539 return db;
540 }
541
542
543 I_List<i_string>*
get_do_db()544 Rpl_filter::get_do_db()
545 {
546 return &do_db;
547 }
548
549
550 I_List<i_string>*
get_ignore_db()551 Rpl_filter::get_ignore_db()
552 {
553 return &ignore_db;
554 }
555