~drizzle-trunk/drizzle/development

1 by brian
clean slate
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
}