~linuxjedi/drizzle/trunk-bug-667053

« back to all changes in this revision

Viewing changes to sql/rpl_filter.cc

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

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
  insert_dynamic(a, (uchar*)&e);
 
344
  return 0;
 
345
}
 
346
 
 
347
 
 
348
void
 
349
Rpl_filter::add_do_db(const char* table_spec)
 
350
{
 
351
  DBUG_ENTER("Rpl_filter::add_do_db");
 
352
  i_string *db = new i_string(table_spec);
 
353
  do_db.push_back(db);
 
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
}
 
364
 
 
365
extern "C" uchar *get_table_key(const uchar *, size_t *, my_bool);
 
366
extern "C" void free_table_ent(void* a);
 
367
 
 
368
uchar *get_table_key(const uchar* a, size_t *len,
 
369
                     my_bool __attribute__((unused)))
 
370
{
 
371
  TABLE_RULE_ENT *e= (TABLE_RULE_ENT *) a;
 
372
 
 
373
  *len= e->key_len;
 
374
  return (uchar*)e->db;
 
375
}
 
376
 
 
377
 
 
378
void free_table_ent(void* a)
 
379
{
 
380
  TABLE_RULE_ENT *e= (TABLE_RULE_ENT *) a;
 
381
  
 
382
  my_free((uchar*) e, MYF(0));
 
383
}
 
384
 
 
385
 
 
386
void 
 
387
Rpl_filter::init_table_rule_hash(HASH* h, bool* h_inited)
 
388
{
 
389
  hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0,
 
390
            get_table_key, free_table_ent, 0);
 
391
  *h_inited = 1;
 
392
}
 
393
 
 
394
 
 
395
void 
 
396
Rpl_filter::init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited)
 
397
{
 
398
  my_init_dynamic_array(a, sizeof(TABLE_RULE_ENT*), TABLE_RULE_ARR_SIZE,
 
399
                        TABLE_RULE_ARR_SIZE);
 
400
  *a_inited = 1;
 
401
}
 
402
 
 
403
 
 
404
TABLE_RULE_ENT* 
 
405
Rpl_filter::find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
 
406
{
 
407
  uint i;
 
408
  const char* key_end= key + len;
 
409
  
 
410
  for (i= 0; i < a->elements; i++)
 
411
  {
 
412
    TABLE_RULE_ENT* e ;
 
413
    get_dynamic(a, (uchar*)&e, i);
 
414
    if (!my_wildcmp(system_charset_info, key, key_end, 
 
415
                    (const char*)e->db,
 
416
                    (const char*)(e->db + e->key_len),
 
417
                    '\\',wild_one,wild_many))
 
418
      return e;
 
419
  }
 
420
  
 
421
  return 0;
 
422
}
 
423
 
 
424
 
 
425
void 
 
426
Rpl_filter::free_string_array(DYNAMIC_ARRAY *a)
 
427
{
 
428
  uint i;
 
429
  for (i= 0; i < a->elements; i++)
 
430
  {
 
431
    char* p;
 
432
    get_dynamic(a, (uchar*) &p, i);
 
433
    my_free(p, MYF(MY_WME));
 
434
  }
 
435
  delete_dynamic(a);
 
436
}
 
437
 
 
438
 
 
439
/*
 
440
  Builds a String from a HASH of TABLE_RULE_ENT. Cannot be used for any other 
 
441
  hash, as it assumes that the hash entries are TABLE_RULE_ENT.
 
442
 
 
443
  SYNOPSIS
 
444
    table_rule_ent_hash_to_str()
 
445
    s               pointer to the String to fill
 
446
    h               pointer to the HASH to read
 
447
 
 
448
  RETURN VALUES
 
449
    none
 
450
*/
 
451
 
 
452
void 
 
453
Rpl_filter::table_rule_ent_hash_to_str(String* s, HASH* h, bool inited)
 
454
{
 
455
  s->length(0);
 
456
  if (inited)
 
457
  {
 
458
    for (uint i= 0; i < h->records; i++)
 
459
    {
 
460
      TABLE_RULE_ENT* e= (TABLE_RULE_ENT*) hash_element(h, i);
 
461
      if (s->length())
 
462
        s->append(',');
 
463
      s->append(e->db,e->key_len);
 
464
    }
 
465
  }
 
466
}
 
467
 
 
468
 
 
469
void 
 
470
Rpl_filter::table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a,
 
471
                                                bool inited)
 
472
{
 
473
  s->length(0);
 
474
  if (inited)
 
475
  {
 
476
    for (uint i= 0; i < a->elements; i++)
 
477
    {
 
478
      TABLE_RULE_ENT* e;
 
479
      get_dynamic(a, (uchar*)&e, i);
 
480
      if (s->length())
 
481
        s->append(',');
 
482
      s->append(e->db,e->key_len);
 
483
    }
 
484
  }
 
485
}
 
486
 
 
487
 
 
488
void
 
489
Rpl_filter::get_do_table(String* str)
 
490
{
 
491
  table_rule_ent_hash_to_str(str, &do_table, do_table_inited);
 
492
}
 
493
 
 
494
 
 
495
void
 
496
Rpl_filter::get_ignore_table(String* str)
 
497
{
 
498
  table_rule_ent_hash_to_str(str, &ignore_table, ignore_table_inited);
 
499
}
 
500
 
 
501
 
 
502
void
 
503
Rpl_filter::get_wild_do_table(String* str)
 
504
{
 
505
  table_rule_ent_dynamic_array_to_str(str, &wild_do_table, wild_do_table_inited);
 
506
}
 
507
 
 
508
 
 
509
void
 
510
Rpl_filter::get_wild_ignore_table(String* str)
 
511
{
 
512
  table_rule_ent_dynamic_array_to_str(str, &wild_ignore_table, wild_ignore_table_inited);
 
513
}
 
514
 
 
515
 
 
516
const char*
 
517
Rpl_filter::get_rewrite_db(const char* db, size_t *new_len)
 
518
{
 
519
  if (rewrite_db.is_empty() || !db)
 
520
    return db;
 
521
  I_List_iterator<i_string_pair> it(rewrite_db);
 
522
  i_string_pair* tmp;
 
523
 
 
524
  while ((tmp=it++))
 
525
  {
 
526
    if (!strcmp(tmp->key, db))
 
527
    {
 
528
      *new_len= strlen(tmp->val);
 
529
      return tmp->val;
 
530
    }
 
531
  }
 
532
  return db;
 
533
}
 
534
 
 
535
 
 
536
I_List<i_string>*
 
537
Rpl_filter::get_do_db()
 
538
{
 
539
  return &do_db;
 
540
}
 
541
  
 
542
 
 
543
I_List<i_string>*
 
544
Rpl_filter::get_ignore_db()
 
545
{
 
546
  return &ignore_db;
 
547
}