MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
rpl_filter.cc
1 /* Copyright (c) 2000, 2010, 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 Foundation,
14  51 Franklin Street, Suite 500, Boston, MA 02110-1335 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 
25 Rpl_filter::Rpl_filter() :
26  table_rules_on(0),
27  do_table_hash_inited(0), ignore_table_hash_inited(0),
28  do_table_array_inited(0), ignore_table_array_inited(0),
29  wild_do_table_inited(0), wild_ignore_table_inited(0)
30 {
31  do_db.empty();
32  ignore_db.empty();
33  rewrite_db.empty();
34 }
35 
36 
37 Rpl_filter::~Rpl_filter()
38 {
39  if (do_table_hash_inited)
40  my_hash_free(&do_table_hash);
41  if (ignore_table_hash_inited)
42  my_hash_free(&ignore_table_hash);
43  if (do_table_array_inited)
44  free_string_array(&do_table_array);
45  if (ignore_table_array_inited)
46  free_string_array(&ignore_table_array);
47  if (wild_do_table_inited)
48  free_string_array(&wild_do_table);
49  if (wild_ignore_table_inited)
50  free_string_array(&wild_ignore_table);
51  free_list(&do_db);
52  free_list(&ignore_db);
53  free_list(&rewrite_db);
54 }
55 
56 
57 /*
58  Returns true if table should be logged/replicated
59 
60  SYNOPSIS
61  tables_ok()
62  db db to use if db in TABLE_LIST is undefined for a table
63  tables list of tables to check
64 
65  NOTES
66  Changing table order in the list can lead to different results.
67 
68  Note also order of precedence of do/ignore rules (see code). For
69  that reason, users should not set conflicting rules because they
70  may get unpredicted results (precedence order is explained in the
71  manual).
72 
73  If no table in the list is marked "updating", then we always
74  return 0, because there is no reason to execute this statement on
75  slave if it updates nothing. (Currently, this can only happen if
76  statement is a multi-delete (SQLCOM_DELETE_MULTI) and "tables" are
77  the tables in the FROM):
78 
79  In the case of SQLCOM_DELETE_MULTI, there will be a second call to
80  tables_ok(), with tables having "updating==TRUE" (those after the
81  DELETE), so this second call will make the decision (because
82  all_tables_not_ok() = !tables_ok(1st_list) &&
83  !tables_ok(2nd_list)).
84 
85  TODO
86  "Include all tables like "abc.%" except "%.EFG"". (Can't be done now.)
87  If we supported Perl regexps, we could do it with pattern: /^abc\.(?!EFG)/
88  (I could not find an equivalent in the regex library MySQL uses).
89 
90  RETURN VALUES
91  0 should not be logged/replicated
92  1 should be logged/replicated
93 */
94 
95 bool
96 Rpl_filter::tables_ok(const char* db, TABLE_LIST* tables)
97 {
98  bool some_tables_updating= 0;
99  DBUG_ENTER("Rpl_filter::tables_ok");
100 
101  for (; tables; tables= tables->next_global)
102  {
103  char hash_key[2*NAME_LEN+2];
104  char *end;
105  uint len;
106 
107  if (!tables->updating)
108  continue;
109  some_tables_updating= 1;
110  end= strmov(hash_key, tables->db ? tables->db : db);
111  *end++= '.';
112  len= (uint) (strmov(end, tables->table_name) - hash_key);
113  if (do_table_hash_inited) // if there are any do's
114  {
115  if (my_hash_search(&do_table_hash, (uchar*) hash_key, len))
116  DBUG_RETURN(1);
117  }
118  if (ignore_table_hash_inited) // if there are any ignores
119  {
120  if (my_hash_search(&ignore_table_hash, (uchar*) hash_key, len))
121  DBUG_RETURN(0);
122  }
123  if (wild_do_table_inited &&
124  find_wild(&wild_do_table, hash_key, len))
125  DBUG_RETURN(1);
126  if (wild_ignore_table_inited &&
127  find_wild(&wild_ignore_table, hash_key, len))
128  DBUG_RETURN(0);
129  }
130 
131  /*
132  If no table was to be updated, ignore statement (no reason we play it on
133  slave, slave is supposed to replicate _changes_ only).
134  If no explicit rule found and there was a do list, do not replicate.
135  If there was no do list, go ahead
136  */
137  DBUG_RETURN(some_tables_updating &&
138  !do_table_hash_inited && !wild_do_table_inited);
139 }
140 
141 
142 /*
143  Checks whether a db matches some do_db and ignore_db rules
144 
145  SYNOPSIS
146  db_ok()
147  db name of the db to check
148 
149  RETURN VALUES
150  0 should not be logged/replicated
151  1 should be logged/replicated
152 */
153 
154 bool
155 Rpl_filter::db_ok(const char* db)
156 {
157  DBUG_ENTER("Rpl_filter::db_ok");
158 
159  if (do_db.is_empty() && ignore_db.is_empty())
160  DBUG_RETURN(1); // Ok to replicate if the user puts no constraints
161 
162  /*
163  Previous behaviour "if the user has specified restrictions on which
164  databases to replicate and db was not selected, do not replicate" has
165  been replaced with "do replicate".
166  Since the filtering criteria is not equal to "NULL" the statement should
167  be logged into binlog.
168  */
169  if (!db)
170  DBUG_RETURN(1);
171 
172  if (!do_db.is_empty()) // if the do's are not empty
173  {
174  I_List_iterator<i_string> it(do_db);
175  i_string* tmp;
176 
177  while ((tmp=it++))
178  {
179  /*
180  Filters will follow the setting of lower_case_table_name
181  to be case sensitive when setting lower_case_table_name=0.
182  Otherwise they will be case insensitive but accent sensitive.
183  */
184  if (!my_strcasecmp(table_alias_charset, tmp->ptr, db))
185  DBUG_RETURN(1); // match
186  }
187  DBUG_RETURN(0);
188  }
189  else // there are some elements in the don't, otherwise we cannot get here
190  {
191  I_List_iterator<i_string> it(ignore_db);
192  i_string* tmp;
193 
194  while ((tmp=it++))
195  {
196  /*
197  Filters will follow the setting of lower_case_table_name
198  to be case sensitive when setting lower_case_table_name=0.
199  Otherwise they will be case insensitive but accent sensitive.
200  */
201  if (!my_strcasecmp(table_alias_charset, tmp->ptr, db))
202  DBUG_RETURN(0); // match
203  }
204  DBUG_RETURN(1);
205  }
206 }
207 
208 
209 /*
210  Checks whether a db matches wild_do_table and wild_ignore_table
211  rules (for replication)
212 
213  SYNOPSIS
214  db_ok_with_wild_table()
215  db name of the db to check.
216  Is tested with check_db_name() before calling this function.
217 
218  NOTES
219  Here is the reason for this function.
220  We advise users who want to exclude a database 'db1' safely to do it
221  with replicate_wild_ignore_table='db1.%' instead of binlog_ignore_db or
222  replicate_ignore_db because the two lasts only check for the selected db,
223  which won't work in that case:
224  USE db2;
225  UPDATE db1.t SET ... #this will be replicated and should not
226  whereas replicate_wild_ignore_table will work in all cases.
227  With replicate_wild_ignore_table, we only check tables. When
228  one does 'DROP DATABASE db1', tables are not involved and the
229  statement will be replicated, while users could expect it would not (as it
230  rougly means 'DROP db1.first_table, DROP db1.second_table...').
231  In other words, we want to interpret 'db1.%' as "everything touching db1".
232  That is why we want to match 'db1' against 'db1.%' wild table rules.
233 
234  RETURN VALUES
235  0 should not be logged/replicated
236  1 should be logged/replicated
237 */
238 
239 bool
240 Rpl_filter::db_ok_with_wild_table(const char *db)
241 {
242  DBUG_ENTER("Rpl_filter::db_ok_with_wild_table");
243 
244  char hash_key[NAME_LEN+2];
245  char *end;
246  int len;
247  end= strmov(hash_key, db);
248  *end++= '.';
249  len= end - hash_key ;
250  if (wild_do_table_inited && find_wild(&wild_do_table, hash_key, len))
251  {
252  DBUG_PRINT("return",("1"));
253  DBUG_RETURN(1);
254  }
255  if (wild_ignore_table_inited && find_wild(&wild_ignore_table, hash_key, len))
256  {
257  DBUG_PRINT("return",("0"));
258  DBUG_RETURN(0);
259  }
260 
261  /*
262  If no explicit rule found and there was a do list, do not replicate.
263  If there was no do list, go ahead
264  */
265  DBUG_PRINT("return",("db=%s,retval=%d", db, !wild_do_table_inited));
266  DBUG_RETURN(!wild_do_table_inited);
267 }
268 
269 
270 bool
271 Rpl_filter::is_on()
272 {
273  return table_rules_on;
274 }
275 
276 
277 bool
278 Rpl_filter::is_rewrite_empty()
279 {
280  return rewrite_db.is_empty();
281 }
282 
283 
284 int
285 Rpl_filter::add_do_table_array(const char* table_spec)
286 {
287  DBUG_ENTER("Rpl_filter::add_do_table");
288  if (!do_table_array_inited)
289  init_table_rule_array(&do_table_array, &do_table_array_inited);
290  table_rules_on= 1;
291  DBUG_RETURN(add_table_rule_to_array(&do_table_array, table_spec));
292 }
293 
294 
295 int
296 Rpl_filter::add_ignore_table_array(const char* table_spec)
297 {
298  DBUG_ENTER("Rpl_filter::add_ignore_table");
299  if (!ignore_table_array_inited)
300  init_table_rule_array(&ignore_table_array, &ignore_table_array_inited);
301  table_rules_on= 1;
302  DBUG_RETURN(add_table_rule_to_array(&ignore_table_array, table_spec));
303 }
304 
305 
306 int
307 Rpl_filter::add_wild_do_table(const char* table_spec)
308 {
309  DBUG_ENTER("Rpl_filter::add_wild_do_table");
310  if (!wild_do_table_inited)
311  init_table_rule_array(&wild_do_table, &wild_do_table_inited);
312  table_rules_on= 1;
313  DBUG_RETURN(add_table_rule_to_array(&wild_do_table, table_spec));
314 }
315 
316 
317 int
318 Rpl_filter::add_wild_ignore_table(const char* table_spec)
319 {
320  DBUG_ENTER("Rpl_filter::add_wild_ignore_table");
321  if (!wild_ignore_table_inited)
322  init_table_rule_array(&wild_ignore_table, &wild_ignore_table_inited);
323  table_rules_on= 1;
324  DBUG_RETURN(add_table_rule_to_array(&wild_ignore_table, table_spec));
325 }
326 
327 
328 void
329 Rpl_filter::add_db_rewrite(const char* from_db, const char* to_db)
330 {
331  i_string_pair *db_pair = new i_string_pair(from_db, to_db);
332  rewrite_db.push_back(db_pair);
333 }
334 
335 
336 /*
337  Build do_table rules to HASH from DYNAMIC_ARRAY
338  for faster filter checking.
339 
340  @return
341  0 ok
342  1 error
343 */
344 int
345 Rpl_filter::build_do_table_hash()
346 {
347  DBUG_ENTER("Rpl_filter::build_do_table_hash");
348 
349  if (build_table_hash_from_array(&do_table_array, &do_table_hash,
350  do_table_array_inited, &do_table_hash_inited))
351  DBUG_RETURN(1);
352 
353  /* Free do table ARRAY as it is a copy in do table HASH */
354  if (do_table_array_inited)
355  {
356  free_string_array(&do_table_array);
357  do_table_array_inited= FALSE;
358  }
359 
360  DBUG_RETURN(0);
361 }
362 
363 /*
364  Build ignore_table rules to HASH from DYNAMIC_ARRAY
365  for faster filter checking.
366 
367  @return
368  0 ok
369  1 error
370 */
371 int
372 Rpl_filter::build_ignore_table_hash()
373 {
374  DBUG_ENTER("Rpl_filter::build_ignore_table_hash");
375 
376  if (build_table_hash_from_array(&ignore_table_array, &ignore_table_hash,
377  ignore_table_array_inited, &ignore_table_hash_inited))
378  DBUG_RETURN(1);
379 
380  /* Free ignore table ARRAY as it is a copy in ignore table HASH */
381  if (ignore_table_array_inited)
382  {
383  free_string_array(&ignore_table_array);
384  ignore_table_array_inited= FALSE;
385  }
386 
387  DBUG_RETURN(0);
388 }
389 
390 
405 int
406 Rpl_filter::build_table_hash_from_array(DYNAMIC_ARRAY *table_array, HASH *table_hash,
407  bool array_inited, bool *hash_inited)
408 {
409  DBUG_ENTER("Rpl_filter::build_table_hash");
410 
411  if (array_inited)
412  {
413  init_table_rule_hash(table_hash, hash_inited);
414  for (uint i= 0; i < table_array->elements; i++)
415  {
416  TABLE_RULE_ENT* e;
417  get_dynamic(table_array, (uchar*)&e, i);
418  if (add_table_rule_to_hash(table_hash, e->db, e->key_len))
419  DBUG_RETURN(1);
420  }
421  }
422 
423  DBUG_RETURN(0);
424 }
425 
426 
438 int
439 Rpl_filter::add_table_rule_to_hash(HASH* h, const char* table_spec, uint len)
440 {
441  const char* dot = strchr(table_spec, '.');
442  if (!dot) return 1;
443  // len is always > 0 because we know the there exists a '.'
444  TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
445  + len, MYF(MY_WME));
446  if (!e) return 1;
447  e->db= (char*)e + sizeof(TABLE_RULE_ENT);
448  e->tbl_name= e->db + (dot - table_spec) + 1;
449  e->key_len= len;
450  memcpy(e->db, table_spec, len);
451 
452  if (my_hash_insert(h, (uchar*)e))
453  {
454  my_free(e);
455  return 1;
456  }
457  return 0;
458 }
459 
460 
461 /*
462  Add table expression to dynamic array
463 */
464 
465 int
466 Rpl_filter::add_table_rule_to_array(DYNAMIC_ARRAY* a, const char* table_spec)
467 {
468  const char* dot = strchr(table_spec, '.');
469  if (!dot) return 1;
470  uint len = (uint)strlen(table_spec);
471  TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
472  + len, MYF(MY_WME));
473  if (!e) return 1;
474  e->db= (char*)e + sizeof(TABLE_RULE_ENT);
475  e->tbl_name= e->db + (dot - table_spec) + 1;
476  e->key_len= len;
477  memcpy(e->db, table_spec, len);
478 
479  if (insert_dynamic(a, &e))
480  {
481  my_free(e);
482  return 1;
483  }
484  return 0;
485 }
486 
487 
488 void
489 Rpl_filter::add_do_db(const char* table_spec)
490 {
491  DBUG_ENTER("Rpl_filter::add_do_db");
492  i_string *db = new i_string(table_spec);
493  do_db.push_back(db);
494  DBUG_VOID_RETURN;
495 }
496 
497 
498 void
499 Rpl_filter::add_ignore_db(const char* table_spec)
500 {
501  DBUG_ENTER("Rpl_filter::add_ignore_db");
502  i_string *db = new i_string(table_spec);
503  ignore_db.push_back(db);
504  DBUG_VOID_RETURN;
505 }
506 
507 extern "C" uchar *get_table_key(const uchar *, size_t *, my_bool);
508 extern "C" void free_table_ent(void* a);
509 
510 uchar *get_table_key(const uchar* a, size_t *len,
511  my_bool __attribute__((unused)))
512 {
513  TABLE_RULE_ENT *e= (TABLE_RULE_ENT *) a;
514 
515  *len= e->key_len;
516  return (uchar*)e->db;
517 }
518 
519 
520 void free_table_ent(void* a)
521 {
522  TABLE_RULE_ENT *e= (TABLE_RULE_ENT *) a;
523 
524  my_free(e);
525 }
526 
527 
528 void
529 Rpl_filter::init_table_rule_hash(HASH* h, bool* h_inited)
530 {
531  my_hash_init(h, table_alias_charset, TABLE_RULE_HASH_SIZE,0,0,
532  get_table_key, free_table_ent, 0);
533  *h_inited = 1;
534 }
535 
536 
537 void
538 Rpl_filter::init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited)
539 {
540  my_init_dynamic_array(a, sizeof(TABLE_RULE_ENT*), TABLE_RULE_ARR_SIZE,
541  TABLE_RULE_ARR_SIZE);
542  *a_inited = 1;
543 }
544 
545 
547 Rpl_filter::find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
548 {
549  uint i;
550  const char* key_end= key + len;
551 
552  for (i= 0; i < a->elements; i++)
553  {
554  TABLE_RULE_ENT* e ;
555  get_dynamic(a, (uchar*)&e, i);
556  /*
557  Filters will follow the setting of lower_case_table_name
558  to be case sensitive when setting lower_case_table_name=0.
559  Otherwise they will be case insensitive but accent sensitive.
560  */
561  if (!my_wildcmp(table_alias_charset, key, key_end,
562  (const char*)e->db,
563  (const char*)(e->db + e->key_len),
564  '\\',wild_one,wild_many))
565  return e;
566  }
567 
568  return 0;
569 }
570 
571 
572 void
573 Rpl_filter::free_string_array(DYNAMIC_ARRAY *a)
574 {
575  uint i;
576  for (i= 0; i < a->elements; i++)
577  {
578  char* p;
579  get_dynamic(a, (uchar*) &p, i);
580  my_free(p);
581  }
582  delete_dynamic(a);
583 }
584 
585 
586 /*
587  Builds a String from a HASH of TABLE_RULE_ENT. Cannot be used for any other
588  hash, as it assumes that the hash entries are TABLE_RULE_ENT.
589 
590  SYNOPSIS
591  table_rule_ent_hash_to_str()
592  s pointer to the String to fill
593  h pointer to the HASH to read
594 
595  RETURN VALUES
596  none
597 */
598 
599 void
600 Rpl_filter::table_rule_ent_hash_to_str(String* s, HASH* h, bool inited)
601 {
602  s->length(0);
603  if (inited)
604  {
605  for (uint i= 0; i < h->records; i++)
606  {
607  TABLE_RULE_ENT* e= (TABLE_RULE_ENT*) my_hash_element(h, i);
608  if (s->length())
609  s->append(',');
610  s->append(e->db,e->key_len);
611  }
612  }
613 }
614 
615 
616 void
617 Rpl_filter::table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a,
618  bool inited)
619 {
620  s->length(0);
621  if (inited)
622  {
623  for (uint i= 0; i < a->elements; i++)
624  {
625  TABLE_RULE_ENT* e;
626  get_dynamic(a, (uchar*)&e, i);
627  if (s->length())
628  s->append(',');
629  s->append(e->db,e->key_len);
630  }
631  }
632 }
633 
634 
635 void
636 Rpl_filter::get_do_table(String* str)
637 {
638  table_rule_ent_hash_to_str(str, &do_table_hash, do_table_hash_inited);
639 }
640 
641 
642 void
643 Rpl_filter::get_ignore_table(String* str)
644 {
645  table_rule_ent_hash_to_str(str, &ignore_table_hash, ignore_table_hash_inited);
646 }
647 
648 
649 void
650 Rpl_filter::get_wild_do_table(String* str)
651 {
652  table_rule_ent_dynamic_array_to_str(str, &wild_do_table, wild_do_table_inited);
653 }
654 
655 
656 void
657 Rpl_filter::get_wild_ignore_table(String* str)
658 {
659  table_rule_ent_dynamic_array_to_str(str, &wild_ignore_table, wild_ignore_table_inited);
660 }
661 
662 
663 const char*
664 Rpl_filter::get_rewrite_db(const char* db, size_t *new_len)
665 {
666  if (rewrite_db.is_empty() || !db)
667  return db;
668  I_List_iterator<i_string_pair> it(rewrite_db);
669  i_string_pair* tmp;
670 
671  while ((tmp=it++))
672  {
673  /*
674  Filters will follow the setting of lower_case_table_name
675  to be case sensitive when setting lower_case_table_name=0.
676  Otherwise they will be case insensitive but accent sensitive.
677  */
678  if (!my_strcasecmp(table_alias_charset, tmp->key, db))
679  {
680  *new_len= strlen(tmp->val);
681  return tmp->val;
682  }
683  }
684  return db;
685 }
686 
687 
689 Rpl_filter::get_do_db()
690 {
691  return &do_db;
692 }
693 
694 
696 Rpl_filter::get_ignore_db()
697 {
698  return &ignore_db;
699 }