1 /* Copyright (c) 2000, 2013, 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
14 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
15
16 #include "mariadb.h"
17 #include "sql_priv.h"
18 #include "mysqld.h" // system_charset_info
19 #include "rpl_filter.h"
20 #include "hash.h" // my_hash_free
21 #include "table.h" // TABLE_LIST
22
23 #define TABLE_RULE_HASH_SIZE 16
24 #define TABLE_RULE_ARR_SIZE 16
25
Rpl_filter()26 Rpl_filter::Rpl_filter() :
27 parallel_mode(SLAVE_PARALLEL_CONSERVATIVE),
28 table_rules_on(0),
29 do_table_inited(0), ignore_table_inited(0),
30 wild_do_table_inited(0), wild_ignore_table_inited(0)
31 {
32 do_db.empty();
33 ignore_db.empty();
34 rewrite_db.empty();
35 }
36
37
~Rpl_filter()38 Rpl_filter::~Rpl_filter()
39 {
40 if (do_table_inited)
41 my_hash_free(&do_table);
42 if (ignore_table_inited)
43 my_hash_free(&ignore_table);
44 if (wild_do_table_inited)
45 free_string_array(&wild_do_table);
46 if (wild_ignore_table_inited)
47 free_string_array(&wild_ignore_table);
48 free_string_list(&do_db);
49 free_string_list(&ignore_db);
50 free_list(&rewrite_db);
51 }
52
53
54 #ifndef MYSQL_CLIENT
55 /*
56 Returns true if table should be logged/replicated
57
58 SYNOPSIS
59 tables_ok()
60 db db to use if db in TABLE_LIST is undefined for a table
61 tables list of tables to check
62
63 NOTES
64 Changing table order in the list can lead to different results.
65
66 Note also order of precedence of do/ignore rules (see code). For
67 that reason, users should not set conflicting rules because they
68 may get unpredicted results (precedence order is explained in the
69 manual).
70
71 If no table in the list is marked "updating", then we always
72 return 0, because there is no reason to execute this statement on
73 slave if it updates nothing. (Currently, this can only happen if
74 statement is a multi-delete (SQLCOM_DELETE_MULTI) and "tables" are
75 the tables in the FROM):
76
77 In the case of SQLCOM_DELETE_MULTI, there will be a second call to
78 tables_ok(), with tables having "updating==TRUE" (those after the
79 DELETE), so this second call will make the decision (because
80 all_tables_not_ok() = !tables_ok(1st_list) &&
81 !tables_ok(2nd_list)).
82
83 TODO
84 "Include all tables like "abc.%" except "%.EFG"". (Can't be done now.)
85 If we supported Perl regexps, we could do it with pattern: /^abc\.(?!EFG)/
86 (I could not find an equivalent in the regex library MySQL uses).
87
88 RETURN VALUES
89 0 should not be logged/replicated
90 1 should be logged/replicated
91 */
92
93 bool
tables_ok(const char * db,TABLE_LIST * tables)94 Rpl_filter::tables_ok(const char* db, TABLE_LIST* tables)
95 {
96 bool some_tables_updating= 0;
97 DBUG_ENTER("Rpl_filter::tables_ok");
98
99 for (; tables; tables= tables->next_global)
100 {
101 char hash_key[SAFE_NAME_LEN*2+2];
102 char *end;
103 uint len;
104
105 if (!tables->updating)
106 continue;
107 some_tables_updating= 1;
108 end= strmov(hash_key, tables->db.str ? tables->db.str : db);
109 *end++= '.';
110 len= (uint) (strmov(end, tables->table_name.str) - hash_key);
111 if (do_table_inited) // if there are any do's
112 {
113 if (my_hash_search(&do_table, (uchar*) hash_key, len))
114 DBUG_RETURN(1);
115 }
116 if (ignore_table_inited) // if there are any ignores
117 {
118 if (my_hash_search(&ignore_table, (uchar*) hash_key, len))
119 DBUG_RETURN(0);
120 }
121 if (wild_do_table_inited &&
122 find_wild(&wild_do_table, hash_key, len))
123 DBUG_RETURN(1);
124 if (wild_ignore_table_inited &&
125 find_wild(&wild_ignore_table, hash_key, len))
126 DBUG_RETURN(0);
127 }
128
129 /*
130 If no table was to be updated, ignore statement (no reason we play it on
131 slave, slave is supposed to replicate _changes_ only).
132 If no explicit rule found and there was a do list, do not replicate.
133 If there was no do list, go ahead
134 */
135 DBUG_RETURN(some_tables_updating &&
136 !do_table_inited && !wild_do_table_inited);
137 }
138
139 #endif
140
141 /*
142 Checks whether a db matches some do_db and ignore_db rules
143
144 SYNOPSIS
145 db_ok()
146 db name of the db to check
147
148 RETURN VALUES
149 0 should not be logged/replicated
150 1 should be logged/replicated
151 */
152
153 bool
db_ok(const char * db)154 Rpl_filter::db_ok(const char* db)
155 {
156 DBUG_ENTER("Rpl_filter::db_ok");
157
158 if (do_db.is_empty() && ignore_db.is_empty())
159 DBUG_RETURN(1); // Ok to replicate if the user puts no constraints
160
161 /*
162 Previous behaviour "if the user has specified restrictions on which
163 databases to replicate and db was not selected, do not replicate" has
164 been replaced with "do replicate".
165 Since the filtering criteria is not equal to "NULL" the statement should
166 be logged into binlog.
167 */
168 if (!db)
169 DBUG_RETURN(1);
170
171 if (!do_db.is_empty()) // if the do's are not empty
172 {
173 I_List_iterator<i_string> it(do_db);
174 i_string* tmp;
175
176 while ((tmp=it++))
177 {
178 if (!strcmp(tmp->ptr, db))
179 DBUG_RETURN(1); // match
180 }
181 DBUG_PRINT("exit", ("Don't replicate"));
182 DBUG_RETURN(0);
183 }
184 else // there are some elements in the don't, otherwise we cannot get here
185 {
186 I_List_iterator<i_string> it(ignore_db);
187 i_string* tmp;
188
189 while ((tmp=it++))
190 {
191 if (!strcmp(tmp->ptr, db))
192 {
193 DBUG_PRINT("exit", ("Don't replicate"));
194 DBUG_RETURN(0); // match
195 }
196 }
197 DBUG_RETURN(1);
198 }
199 }
200
201
202 /*
203 Checks whether a db matches wild_do_table and wild_ignore_table
204 rules (for replication)
205
206 SYNOPSIS
207 db_ok_with_wild_table()
208 db name of the db to check.
209 Is tested with check_db_name() before calling this function.
210
211 NOTES
212 Here is the reason for this function.
213 We advise users who want to exclude a database 'db1' safely to do it
214 with replicate_wild_ignore_table='db1.%' instead of binlog_ignore_db or
215 replicate_ignore_db because the two lasts only check for the selected db,
216 which won't work in that case:
217 USE db2;
218 UPDATE db1.t SET ... #this will be replicated and should not
219 whereas replicate_wild_ignore_table will work in all cases.
220 With replicate_wild_ignore_table, we only check tables. When
221 one does 'DROP DATABASE db1', tables are not involved and the
222 statement will be replicated, while users could expect it would not (as it
223 rougly means 'DROP db1.first_table, DROP db1.second_table...').
224 In other words, we want to interpret 'db1.%' as "everything touching db1".
225 That is why we want to match 'db1' against 'db1.%' wild table rules.
226
227 RETURN VALUES
228 0 should not be logged/replicated
229 1 should be logged/replicated
230 */
231
232 bool
db_ok_with_wild_table(const char * db)233 Rpl_filter::db_ok_with_wild_table(const char *db)
234 {
235 DBUG_ENTER("Rpl_filter::db_ok_with_wild_table");
236
237 char hash_key[SAFE_NAME_LEN+2];
238 char *end;
239 int len;
240 end= strmov(hash_key, db);
241 *end++= '.';
242 len= (int)(end - hash_key);
243 if (wild_do_table_inited && find_wild(&wild_do_table, hash_key, len))
244 {
245 DBUG_PRINT("return",("1"));
246 DBUG_RETURN(1);
247 }
248 if (wild_ignore_table_inited && find_wild(&wild_ignore_table, hash_key, len))
249 {
250 DBUG_PRINT("return",("0"));
251 DBUG_RETURN(0);
252 }
253
254 /*
255 If no explicit rule found and there was a do list, do not replicate.
256 If there was no do list, go ahead
257 */
258 DBUG_PRINT("return",("db=%s,retval=%d", db, !wild_do_table_inited));
259 DBUG_RETURN(!wild_do_table_inited);
260 }
261
262
263 bool
is_on()264 Rpl_filter::is_on()
265 {
266 return table_rules_on;
267 }
268
269
270 /**
271 Parse and add the given comma-separated sequence of filter rules.
272
273 @param spec Comma-separated sequence of filter rules.
274 @param add Callback member function to add a filter rule.
275
276 @return true if error, false otherwise.
277 */
278
279 int
parse_filter_rule(const char * spec,Add_filter add)280 Rpl_filter::parse_filter_rule(const char* spec, Add_filter add)
281 {
282 int status= 0;
283 char *arg, *ptr, *pstr;
284
285 if (!spec)
286 return false;
287
288 if (! (ptr= my_strdup(spec, MYF(MY_WME))))
289 return true;
290
291 pstr= ptr;
292
293 while (pstr)
294 {
295 arg= pstr;
296
297 /* Parse token string. */
298 pstr= strpbrk(arg, ",");
299
300 /* NUL terminate the token string. */
301 if (pstr)
302 *pstr++= '\0';
303
304 /* Skip an empty token string. */
305 if (arg[0] == '\0')
306 continue;
307
308 /* Skip leading spaces. */
309 while (my_isspace(system_charset_info, *arg))
310 arg++;
311
312 status= (this->*add)(arg);
313
314 if (status)
315 break;
316 }
317
318 my_free(ptr);
319
320 return status;
321 }
322
323
324 int
add_do_table(const char * table_spec)325 Rpl_filter::add_do_table(const char* table_spec)
326 {
327 DBUG_ENTER("Rpl_filter::add_do_table");
328 if (!do_table_inited)
329 init_table_rule_hash(&do_table, &do_table_inited);
330 table_rules_on= 1;
331 DBUG_RETURN(add_table_rule(&do_table, table_spec));
332 }
333
334
335 int
add_ignore_table(const char * table_spec)336 Rpl_filter::add_ignore_table(const char* table_spec)
337 {
338 DBUG_ENTER("Rpl_filter::add_ignore_table");
339 if (!ignore_table_inited)
340 init_table_rule_hash(&ignore_table, &ignore_table_inited);
341 table_rules_on= 1;
342 DBUG_RETURN(add_table_rule(&ignore_table, table_spec));
343 }
344
345
346 int
set_do_table(const char * table_spec)347 Rpl_filter::set_do_table(const char* table_spec)
348 {
349 int status;
350
351 if (do_table_inited)
352 {
353 my_hash_free(&do_table);
354 do_table_inited= 0;
355 }
356
357 status= parse_filter_rule(table_spec, &Rpl_filter::add_do_table);
358
359 if (do_table_inited && status)
360 {
361 if (!do_table.records)
362 {
363 my_hash_free(&do_table);
364 do_table_inited= 0;
365 }
366 }
367
368 return status;
369 }
370
371
372 int
set_ignore_table(const char * table_spec)373 Rpl_filter::set_ignore_table(const char* table_spec)
374 {
375 int status;
376
377 if (ignore_table_inited)
378 {
379 my_hash_free(&ignore_table);
380 ignore_table_inited= 0;
381 }
382
383 status= parse_filter_rule(table_spec, &Rpl_filter::add_ignore_table);
384
385 if (ignore_table_inited && status)
386 {
387 if (!ignore_table.records)
388 {
389 my_hash_free(&ignore_table);
390 ignore_table_inited= 0;
391 }
392 }
393
394 return status;
395 }
396
397
398 int
add_wild_do_table(const char * table_spec)399 Rpl_filter::add_wild_do_table(const char* table_spec)
400 {
401 DBUG_ENTER("Rpl_filter::add_wild_do_table");
402 if (!wild_do_table_inited)
403 init_table_rule_array(&wild_do_table, &wild_do_table_inited);
404 table_rules_on= 1;
405 DBUG_RETURN(add_wild_table_rule(&wild_do_table, table_spec));
406 }
407
408
409 int
add_wild_ignore_table(const char * table_spec)410 Rpl_filter::add_wild_ignore_table(const char* table_spec)
411 {
412 DBUG_ENTER("Rpl_filter::add_wild_ignore_table");
413 if (!wild_ignore_table_inited)
414 init_table_rule_array(&wild_ignore_table, &wild_ignore_table_inited);
415 table_rules_on= 1;
416 DBUG_RETURN(add_wild_table_rule(&wild_ignore_table, table_spec));
417 }
418
419
420 int
set_wild_do_table(const char * table_spec)421 Rpl_filter::set_wild_do_table(const char* table_spec)
422 {
423 int status;
424
425 if (wild_do_table_inited)
426 {
427 free_string_array(&wild_do_table);
428 wild_do_table_inited= 0;
429 }
430
431 status= parse_filter_rule(table_spec, &Rpl_filter::add_wild_do_table);
432
433 if (wild_do_table_inited && status)
434 {
435 if (!wild_do_table.elements)
436 {
437 delete_dynamic(&wild_do_table);
438 wild_do_table_inited= 0;
439 }
440 }
441
442 return status;
443 }
444
445
446 int
set_wild_ignore_table(const char * table_spec)447 Rpl_filter::set_wild_ignore_table(const char* table_spec)
448 {
449 int status;
450
451 if (wild_ignore_table_inited)
452 {
453 free_string_array(&wild_ignore_table);
454 wild_ignore_table_inited= 0;
455 }
456
457 status= parse_filter_rule(table_spec, &Rpl_filter::add_wild_ignore_table);
458
459 if (wild_ignore_table_inited && status)
460 {
461 if (!wild_ignore_table.elements)
462 {
463 delete_dynamic(&wild_ignore_table);
464 wild_ignore_table_inited= 0;
465 }
466 }
467
468 return status;
469 }
470
471
472 void
add_db_rewrite(const char * from_db,const char * to_db)473 Rpl_filter::add_db_rewrite(const char* from_db, const char* to_db)
474 {
475 i_string_pair *db_pair = new i_string_pair(from_db, to_db);
476 rewrite_db.push_back(db_pair);
477 }
478
479
480 int
add_table_rule(HASH * h,const char * table_spec)481 Rpl_filter::add_table_rule(HASH* h, const char* table_spec)
482 {
483 const char* dot = strchr(table_spec, '.');
484 if (!dot) return 1;
485 // len is always > 0 because we know the there exists a '.'
486 uint len = (uint)strlen(table_spec);
487 TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
488 + len, MYF(MY_WME));
489 if (!e) return 1;
490 e->db= (char*)e + sizeof(TABLE_RULE_ENT);
491 e->tbl_name= e->db + (dot - table_spec) + 1;
492 e->key_len= len;
493 memcpy(e->db, table_spec, len);
494
495 return my_hash_insert(h, (uchar*)e);
496 }
497
498
499 /*
500 Add table expression with wildcards to dynamic array
501 */
502
503 int
add_wild_table_rule(DYNAMIC_ARRAY * a,const char * table_spec)504 Rpl_filter::add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
505 {
506 const char* dot = strchr(table_spec, '.');
507 if (!dot) return 1;
508 uint len = (uint)strlen(table_spec);
509 TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT)
510 + len, MYF(MY_WME));
511 if (!e) return 1;
512 e->db= (char*)e + sizeof(TABLE_RULE_ENT);
513 e->tbl_name= e->db + (dot - table_spec) + 1;
514 e->key_len= len;
515 memcpy(e->db, table_spec, len);
516 return insert_dynamic(a, (uchar*)&e);
517 }
518
519
520 int
add_string_list(I_List<i_string> * list,const char * spec)521 Rpl_filter::add_string_list(I_List<i_string> *list, const char* spec)
522 {
523 char *str;
524 i_string *node;
525
526 if (! (str= my_strdup(spec, MYF(MY_WME))))
527 return true;
528
529 if (! (node= new i_string(str)))
530 {
531 my_free(str);
532 return true;
533 }
534
535 list->push_back(node);
536
537 return false;
538 }
539
540
541 int
add_do_db(const char * table_spec)542 Rpl_filter::add_do_db(const char* table_spec)
543 {
544 DBUG_ENTER("Rpl_filter::add_do_db");
545 DBUG_RETURN(add_string_list(&do_db, table_spec));
546 }
547
548
549 int
add_ignore_db(const char * table_spec)550 Rpl_filter::add_ignore_db(const char* table_spec)
551 {
552 DBUG_ENTER("Rpl_filter::add_ignore_db");
553 DBUG_RETURN(add_string_list(&ignore_db, table_spec));
554 }
555
556
557 int
set_do_db(const char * db_spec)558 Rpl_filter::set_do_db(const char* db_spec)
559 {
560 free_string_list(&do_db);
561 return parse_filter_rule(db_spec, &Rpl_filter::add_do_db);
562 }
563
564
565 int
set_ignore_db(const char * db_spec)566 Rpl_filter::set_ignore_db(const char* db_spec)
567 {
568 free_string_list(&ignore_db);
569 return parse_filter_rule(db_spec, &Rpl_filter::add_ignore_db);
570 }
571
572
573 extern "C" uchar *get_table_key(const uchar *, size_t *, my_bool);
574 extern "C" void free_table_ent(void* a);
575
get_table_key(const uchar * a,size_t * len,my_bool)576 uchar *get_table_key(const uchar* a, size_t *len,
577 my_bool __attribute__((unused)))
578 {
579 TABLE_RULE_ENT *e= (TABLE_RULE_ENT *) a;
580
581 *len= e->key_len;
582 return (uchar*)e->db;
583 }
584
585
free_table_ent(void * a)586 void free_table_ent(void* a)
587 {
588 TABLE_RULE_ENT *e= (TABLE_RULE_ENT *) a;
589
590 my_free(e);
591 }
592
593
594 void
init_table_rule_hash(HASH * h,bool * h_inited)595 Rpl_filter::init_table_rule_hash(HASH* h, bool* h_inited)
596 {
597 my_hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0,
598 get_table_key, free_table_ent, 0);
599 *h_inited = 1;
600 }
601
602
603 void
init_table_rule_array(DYNAMIC_ARRAY * a,bool * a_inited)604 Rpl_filter::init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited)
605 {
606 my_init_dynamic_array(a, sizeof(TABLE_RULE_ENT*), TABLE_RULE_ARR_SIZE,
607 TABLE_RULE_ARR_SIZE, MYF(0));
608 *a_inited = 1;
609 }
610
611
612 TABLE_RULE_ENT*
find_wild(DYNAMIC_ARRAY * a,const char * key,int len)613 Rpl_filter::find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
614 {
615 uint i;
616 const char* key_end= key + len;
617
618 for (i= 0; i < a->elements; i++)
619 {
620 TABLE_RULE_ENT* e ;
621 get_dynamic(a, (uchar*)&e, i);
622 if (!my_wildcmp(system_charset_info, key, key_end,
623 (const char*)e->db,
624 (const char*)(e->db + e->key_len),
625 '\\',wild_one,wild_many))
626 return e;
627 }
628
629 return 0;
630 }
631
632
633 void
free_string_array(DYNAMIC_ARRAY * a)634 Rpl_filter::free_string_array(DYNAMIC_ARRAY *a)
635 {
636 uint i;
637 for (i= 0; i < a->elements; i++)
638 {
639 char* p;
640 get_dynamic(a, (uchar*) &p, i);
641 my_free(p);
642 }
643 delete_dynamic(a);
644 }
645
646
647 void
free_string_list(I_List<i_string> * l)648 Rpl_filter::free_string_list(I_List<i_string> *l)
649 {
650 void *ptr;
651 i_string *tmp;
652
653 while ((tmp= l->get()))
654 {
655 ptr= (void *) tmp->ptr;
656 my_free(ptr);
657 delete tmp;
658 }
659
660 l->empty();
661 }
662
663
664 /*
665 Builds a String from a HASH of TABLE_RULE_ENT. Cannot be used for any other
666 hash, as it assumes that the hash entries are TABLE_RULE_ENT.
667
668 SYNOPSIS
669 table_rule_ent_hash_to_str()
670 s pointer to the String to fill
671 h pointer to the HASH to read
672
673 RETURN VALUES
674 none
675 */
676
677 void
table_rule_ent_hash_to_str(String * s,HASH * h,bool inited)678 Rpl_filter::table_rule_ent_hash_to_str(String* s, HASH* h, bool inited)
679 {
680 s->length(0);
681 if (inited)
682 {
683 for (uint i= 0; i < h->records; i++)
684 {
685 TABLE_RULE_ENT* e= (TABLE_RULE_ENT*) my_hash_element(h, i);
686 if (s->length())
687 s->append(',');
688 s->append(e->db,e->key_len);
689 }
690 }
691 }
692
693
694 void
table_rule_ent_dynamic_array_to_str(String * s,DYNAMIC_ARRAY * a,bool inited)695 Rpl_filter::table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a,
696 bool inited)
697 {
698 s->length(0);
699 if (inited)
700 {
701 for (uint i= 0; i < a->elements; i++)
702 {
703 TABLE_RULE_ENT* e;
704 get_dynamic(a, (uchar*)&e, i);
705 if (s->length())
706 s->append(',');
707 s->append(e->db,e->key_len);
708 }
709 }
710 }
711
712
713 void
get_do_table(String * str)714 Rpl_filter::get_do_table(String* str)
715 {
716 table_rule_ent_hash_to_str(str, &do_table, do_table_inited);
717 }
718
719
720 void
get_ignore_table(String * str)721 Rpl_filter::get_ignore_table(String* str)
722 {
723 table_rule_ent_hash_to_str(str, &ignore_table, ignore_table_inited);
724 }
725
726
727 void
get_wild_do_table(String * str)728 Rpl_filter::get_wild_do_table(String* str)
729 {
730 table_rule_ent_dynamic_array_to_str(str, &wild_do_table, wild_do_table_inited);
731 }
732
733
734 void
get_wild_ignore_table(String * str)735 Rpl_filter::get_wild_ignore_table(String* str)
736 {
737 table_rule_ent_dynamic_array_to_str(str, &wild_ignore_table, wild_ignore_table_inited);
738 }
739
740
741 bool
rewrite_db_is_empty()742 Rpl_filter::rewrite_db_is_empty()
743 {
744 return rewrite_db.is_empty();
745 }
746
747
748 const char*
get_rewrite_db(const char * db,size_t * new_len)749 Rpl_filter::get_rewrite_db(const char* db, size_t *new_len)
750 {
751 if (rewrite_db.is_empty() || !db)
752 return db;
753 I_List_iterator<i_string_pair> it(rewrite_db);
754 i_string_pair* tmp;
755
756 while ((tmp=it++))
757 {
758 if (!strcmp(tmp->key, db))
759 {
760 *new_len= strlen(tmp->val);
761 return tmp->val;
762 }
763 }
764 return db;
765 }
766
767
768 void
copy_rewrite_db(Rpl_filter * from)769 Rpl_filter::copy_rewrite_db(Rpl_filter *from)
770 {
771 I_List_iterator<i_string_pair> it(from->rewrite_db);
772 i_string_pair* tmp;
773 DBUG_ASSERT(rewrite_db.is_empty());
774
775 /* TODO: Add memory checking here and in all add_xxxx functions ! */
776 while ((tmp=it++))
777 add_db_rewrite(tmp->key, tmp->val);
778 }
779
780 I_List<i_string>*
get_do_db()781 Rpl_filter::get_do_db()
782 {
783 return &do_db;
784 }
785
786
787 I_List<i_string>*
get_ignore_db()788 Rpl_filter::get_ignore_db()
789 {
790 return &ignore_db;
791 }
792
793
794 void
db_rule_ent_list_to_str(String * str,I_List<i_string> * list)795 Rpl_filter::db_rule_ent_list_to_str(String* str, I_List<i_string>* list)
796 {
797 I_List_iterator<i_string> it(*list);
798 i_string* s;
799
800 str->length(0);
801
802 while ((s= it++))
803 {
804 str->append(s->ptr);
805 str->append(',');
806 }
807
808 // Remove last ','
809 if (!str->is_empty())
810 str->chop();
811 }
812
813
814 void
get_do_db(String * str)815 Rpl_filter::get_do_db(String* str)
816 {
817 db_rule_ent_list_to_str(str, get_do_db());
818 }
819
820
821 void
get_ignore_db(String * str)822 Rpl_filter::get_ignore_db(String* str)
823 {
824 db_rule_ent_list_to_str(str, get_ignore_db());
825 }
826