~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to sql/rpl_filter.cc

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

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