~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
243.1.17 by Jay Pipes
FINAL PHASE removal of mysql_priv.h (Bye, bye my friend.)
16
#include <drizzled/server_includes.h>
1 by brian
clean slate
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
  
91
  for (; tables; tables= tables->next_global)
92
  {
93
    char hash_key[2*NAME_LEN+2];
94
    char *end;
95
    uint len;
96
97
    if (!tables->updating) 
98
      continue;
99
    some_tables_updating= 1;
266.1.21 by Monty Taylor
Removed references to strmov and strnmov
100
    end= stpcpy(hash_key, tables->db ? tables->db : db);
1 by brian
clean slate
101
    *end++= '.';
266.1.21 by Monty Taylor
Removed references to strmov and strnmov
102
    len= (uint) (stpcpy(end, tables->table_name) - hash_key);
1 by brian
clean slate
103
    if (do_table_inited) // if there are any do's
104
    {
105
      if (hash_search(&do_table, (uchar*) hash_key, len))
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
106
	return(1);
1 by brian
clean slate
107
    }
108
    if (ignore_table_inited) // if there are any ignores
109
    {
110
      if (hash_search(&ignore_table, (uchar*) hash_key, len))
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
111
	return(0); 
1 by brian
clean slate
112
    }
113
    if (wild_do_table_inited && 
114
	find_wild(&wild_do_table, hash_key, len))
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
115
      return(1);
1 by brian
clean slate
116
    if (wild_ignore_table_inited && 
117
	find_wild(&wild_ignore_table, hash_key, len))
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
118
      return(0);
1 by brian
clean slate
119
  }
120
121
  /*
122
    If no table was to be updated, ignore statement (no reason we play it on
123
    slave, slave is supposed to replicate _changes_ only).
124
    If no explicit rule found and there was a do list, do not replicate.
125
    If there was no do list, go ahead
126
  */
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
127
  return(some_tables_updating &&
1 by brian
clean slate
128
              !do_table_inited && !wild_do_table_inited);
129
}
130
131
132
/*
133
  Checks whether a db matches some do_db and ignore_db rules
134
135
  SYNOPSIS
136
    db_ok()
137
    db              name of the db to check
138
139
  RETURN VALUES
140
    0           should not be logged/replicated
141
    1           should be logged/replicated                  
142
*/
143
144
bool
145
Rpl_filter::db_ok(const char* db)
146
{
147
  if (do_db.is_empty() && ignore_db.is_empty())
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
148
    return(1); // Ok to replicate if the user puts no constraints
1 by brian
clean slate
149
150
  /*
151
    If the user has specified restrictions on which databases to replicate
152
    and db was not selected, do not replicate.
153
  */
154
  if (!db)
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
155
    return(0);
1 by brian
clean slate
156
157
  if (!do_db.is_empty()) // if the do's are not empty
158
  {
159
    I_List_iterator<i_string> it(do_db);
160
    i_string* tmp;
161
162
    while ((tmp=it++))
163
    {
164
      if (!strcmp(tmp->ptr, db))
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
165
	return(1); // match
1 by brian
clean slate
166
    }
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
167
    return(0);
1 by brian
clean slate
168
  }
169
  else // there are some elements in the don't, otherwise we cannot get here
170
  {
171
    I_List_iterator<i_string> it(ignore_db);
172
    i_string* tmp;
173
174
    while ((tmp=it++))
175
    {
176
      if (!strcmp(tmp->ptr, db))
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
177
	return(0); // match
1 by brian
clean slate
178
    }
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
179
    return(1);
1 by brian
clean slate
180
  }
181
}
182
183
184
/*
185
  Checks whether a db matches wild_do_table and wild_ignore_table
186
  rules (for replication)
187
188
  SYNOPSIS
189
    db_ok_with_wild_table()
190
    db		name of the db to check.
191
		Is tested with check_db_name() before calling this function.
192
193
  NOTES
194
    Here is the reason for this function.
195
    We advise users who want to exclude a database 'db1' safely to do it
196
    with replicate_wild_ignore_table='db1.%' instead of binlog_ignore_db or
197
    replicate_ignore_db because the two lasts only check for the selected db,
198
    which won't work in that case:
199
    USE db2;
200
    UPDATE db1.t SET ... #this will be replicated and should not
201
    whereas replicate_wild_ignore_table will work in all cases.
202
    With replicate_wild_ignore_table, we only check tables. When
203
    one does 'DROP DATABASE db1', tables are not involved and the
204
    statement will be replicated, while users could expect it would not (as it
205
    rougly means 'DROP db1.first_table, DROP db1.second_table...').
206
    In other words, we want to interpret 'db1.%' as "everything touching db1".
207
    That is why we want to match 'db1' against 'db1.%' wild table rules.
208
209
  RETURN VALUES
210
    0           should not be logged/replicated
211
    1           should be logged/replicated
212
*/
213
214
bool
215
Rpl_filter::db_ok_with_wild_table(const char *db)
216
{
217
  char hash_key[NAME_LEN+2];
218
  char *end;
219
  int len;
266.1.21 by Monty Taylor
Removed references to strmov and strnmov
220
  end= stpcpy(hash_key, db);
1 by brian
clean slate
221
  *end++= '.';
222
  len= end - hash_key ;
223
  if (wild_do_table_inited && find_wild(&wild_do_table, hash_key, len))
224
  {
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
225
    return(1);
1 by brian
clean slate
226
  }
227
  if (wild_ignore_table_inited && find_wild(&wild_ignore_table, hash_key, len))
228
  {
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
229
    return(0);
1 by brian
clean slate
230
  }  
231
232
  /*
233
    If no explicit rule found and there was a do list, do not replicate.
234
    If there was no do list, go ahead
235
  */
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
236
  return(!wild_do_table_inited);
1 by brian
clean slate
237
}
238
239
240
bool
241
Rpl_filter::is_on()
242
{
243
  return table_rules_on;
244
}
245
246
247
int 
248
Rpl_filter::add_do_table(const char* table_spec) 
249
{
250
  if (!do_table_inited)
251
    init_table_rule_hash(&do_table, &do_table_inited);
252
  table_rules_on= 1;
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
253
  return(add_table_rule(&do_table, table_spec));
1 by brian
clean slate
254
}
255
  
256
257
int 
258
Rpl_filter::add_ignore_table(const char* table_spec) 
259
{
260
  if (!ignore_table_inited)
261
    init_table_rule_hash(&ignore_table, &ignore_table_inited);
262
  table_rules_on= 1;
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
263
  return(add_table_rule(&ignore_table, table_spec));
1 by brian
clean slate
264
}
265
266
267
int 
268
Rpl_filter::add_wild_do_table(const char* table_spec)
269
{
270
  if (!wild_do_table_inited)
271
    init_table_rule_array(&wild_do_table, &wild_do_table_inited);
272
  table_rules_on= 1;
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
273
  return(add_wild_table_rule(&wild_do_table, table_spec));
1 by brian
clean slate
274
}
275
  
276
277
int 
278
Rpl_filter::add_wild_ignore_table(const char* table_spec) 
279
{
280
  if (!wild_ignore_table_inited)
281
    init_table_rule_array(&wild_ignore_table, &wild_ignore_table_inited);
282
  table_rules_on= 1;
51.1.38 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
283
  return(add_wild_table_rule(&wild_ignore_table, table_spec));
1 by brian
clean slate
284
}
285
286
287
void
288
Rpl_filter::add_db_rewrite(const char* from_db, const char* to_db)
289
{
290
  i_string_pair *db_pair = new i_string_pair(from_db, to_db);
291
  rewrite_db.push_back(db_pair);
292
}
293
294
295
int 
296
Rpl_filter::add_table_rule(HASH* h, const char* table_spec)
297
{
298
  const char* dot = strchr(table_spec, '.');
299
  if (!dot) return 1;
300
  // len is always > 0 because we know the there exists a '.'
301
  uint len = (uint)strlen(table_spec);
302
  TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
303
						 + len, MYF(MY_WME));
304
  if (!e) return 1;
305
  e->db= (char*)e + sizeof(TABLE_RULE_ENT);
306
  e->tbl_name= e->db + (dot - table_spec) + 1;
307
  e->key_len= len;
308
  memcpy(e->db, table_spec, len);
309
310
  return my_hash_insert(h, (uchar*)e);
311
}
312
313
314
/*
315
  Add table expression with wildcards to dynamic array
316
*/
317
318
int 
319
Rpl_filter::add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
320
{
321
  const char* dot = strchr(table_spec, '.');
322
  if (!dot) return 1;
323
  uint len = (uint)strlen(table_spec);
324
  TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
325
						 + len, MYF(MY_WME));
326
  if (!e) return 1;
327
  e->db= (char*)e + sizeof(TABLE_RULE_ENT);
328
  e->tbl_name= e->db + (dot - table_spec) + 1;
329
  e->key_len= len;
330
  memcpy(e->db, table_spec, len);
331
  insert_dynamic(a, (uchar*)&e);
332
  return 0;
333
}
334
335
336
void
337
Rpl_filter::add_do_db(const char* table_spec)
338
{
339
  i_string *db = new i_string(table_spec);
340
  do_db.push_back(db);
341
}
342
343
344
void
345
Rpl_filter::add_ignore_db(const char* table_spec)
346
{
347
  i_string *db = new i_string(table_spec);
348
  ignore_db.push_back(db);
349
}
350
149 by Brian Aker
More bool conversion.
351
extern "C" uchar *get_table_key(const uchar *, size_t *, bool);
1 by brian
clean slate
352
extern "C" void free_table_ent(void* a);
353
354
uchar *get_table_key(const uchar* a, size_t *len,
146 by Brian Aker
my_bool cleanup.
355
                     bool __attribute__((unused)))
1 by brian
clean slate
356
{
357
  TABLE_RULE_ENT *e= (TABLE_RULE_ENT *) a;
358
359
  *len= e->key_len;
360
  return (uchar*)e->db;
361
}
362
363
364
void free_table_ent(void* a)
365
{
366
  TABLE_RULE_ENT *e= (TABLE_RULE_ENT *) a;
367
  
368
  my_free((uchar*) e, MYF(0));
369
}
370
371
372
void 
373
Rpl_filter::init_table_rule_hash(HASH* h, bool* h_inited)
374
{
375
  hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0,
376
	    get_table_key, free_table_ent, 0);
377
  *h_inited = 1;
378
}
379
380
381
void 
382
Rpl_filter::init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited)
383
{
384
  my_init_dynamic_array(a, sizeof(TABLE_RULE_ENT*), TABLE_RULE_ARR_SIZE,
385
			TABLE_RULE_ARR_SIZE);
386
  *a_inited = 1;
387
}
388
389
390
TABLE_RULE_ENT* 
391
Rpl_filter::find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
392
{
393
  uint i;
394
  const char* key_end= key + len;
395
  
396
  for (i= 0; i < a->elements; i++)
397
  {
398
    TABLE_RULE_ENT* e ;
399
    get_dynamic(a, (uchar*)&e, i);
400
    if (!my_wildcmp(system_charset_info, key, key_end, 
401
		    (const char*)e->db,
402
		    (const char*)(e->db + e->key_len),
403
		    '\\',wild_one,wild_many))
404
      return e;
405
  }
406
  
407
  return 0;
408
}
409
410
411
void 
412
Rpl_filter::free_string_array(DYNAMIC_ARRAY *a)
413
{
414
  uint i;
415
  for (i= 0; i < a->elements; i++)
416
  {
417
    char* p;
418
    get_dynamic(a, (uchar*) &p, i);
419
    my_free(p, MYF(MY_WME));
420
  }
421
  delete_dynamic(a);
422
}
423
424
425
/*
426
  Builds a String from a HASH of TABLE_RULE_ENT. Cannot be used for any other 
427
  hash, as it assumes that the hash entries are TABLE_RULE_ENT.
428
429
  SYNOPSIS
430
    table_rule_ent_hash_to_str()
431
    s               pointer to the String to fill
432
    h               pointer to the HASH to read
433
434
  RETURN VALUES
435
    none
436
*/
437
438
void 
439
Rpl_filter::table_rule_ent_hash_to_str(String* s, HASH* h, bool inited)
440
{
441
  s->length(0);
442
  if (inited)
443
  {
444
    for (uint i= 0; i < h->records; i++)
445
    {
446
      TABLE_RULE_ENT* e= (TABLE_RULE_ENT*) hash_element(h, i);
447
      if (s->length())
448
        s->append(',');
449
      s->append(e->db,e->key_len);
450
    }
451
  }
452
}
453
454
455
void 
456
Rpl_filter::table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a,
457
                                                bool inited)
458
{
459
  s->length(0);
460
  if (inited)
461
  {
462
    for (uint i= 0; i < a->elements; i++)
463
    {
464
      TABLE_RULE_ENT* e;
465
      get_dynamic(a, (uchar*)&e, i);
466
      if (s->length())
467
        s->append(',');
468
      s->append(e->db,e->key_len);
469
    }
470
  }
471
}
472
473
474
void
475
Rpl_filter::get_do_table(String* str)
476
{
477
  table_rule_ent_hash_to_str(str, &do_table, do_table_inited);
478
}
479
480
481
void
482
Rpl_filter::get_ignore_table(String* str)
483
{
484
  table_rule_ent_hash_to_str(str, &ignore_table, ignore_table_inited);
485
}
486
487
488
void
489
Rpl_filter::get_wild_do_table(String* str)
490
{
491
  table_rule_ent_dynamic_array_to_str(str, &wild_do_table, wild_do_table_inited);
492
}
493
494
495
void
496
Rpl_filter::get_wild_ignore_table(String* str)
497
{
498
  table_rule_ent_dynamic_array_to_str(str, &wild_ignore_table, wild_ignore_table_inited);
499
}
500
501
502
const char*
503
Rpl_filter::get_rewrite_db(const char* db, size_t *new_len)
504
{
505
  if (rewrite_db.is_empty() || !db)
506
    return db;
507
  I_List_iterator<i_string_pair> it(rewrite_db);
508
  i_string_pair* tmp;
509
510
  while ((tmp=it++))
511
  {
512
    if (!strcmp(tmp->key, db))
513
    {
514
      *new_len= strlen(tmp->val);
515
      return tmp->val;
516
    }
517
  }
518
  return db;
519
}
520
521
522
I_List<i_string>*
523
Rpl_filter::get_do_db()
524
{
525
  return &do_db;
526
}
527
  
528
529
I_List<i_string>*
530
Rpl_filter::get_ignore_db()
531
{
532
  return &ignore_db;
533
}