MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Luis Soares Date:May 27 2009 3:37pm
Subject:bzr commit into mysql-5.1-bugteam branch (luis.soares:2874) Bug#42941
View as plain text  
#At file:///home/lsoares/Workspace/mysql-server/bugfix/b42941/5.1-bt/ based on revid:mats@stripped

 2874 Luis Soares	2009-05-27
      BUG#42941: --database paramater to mysqlbinlog fails with RBR
      
      mysqlbinlog --database parameter was being ignored when processing
      row events. As such no event filtering would take place.
      
      This patch addresses this by deploying a call to shall_skip_database
      when table_map_events are handled (as these contain also the name of
      the database). All other rows events referencing the table id for the
      filtered map event, will also be skipped.
     @ client/mysqlbinlog.cc
        Added shall_skip_database call to the part of the code that handles 
        Table_map_log_events. It inspects the database name and decides whether
        to filter the event or not. Furthermore, if table map event is filtered
        next events referencing the table id in the table map event, will also
        be filtered.
     @ mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_db_filter.test
        Test case that checks if row events are actually filtered out.
     @ sql/log_event.h
        Added a map for holding the currently ignored table map events.
        Table map events are inserted when they shall be skipped and removed
        once the last row event in the statement referencing this event is 
        processed.

    added:
      mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_db_filter.result
      mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_db_filter.test
    modified:
      client/mysqlbinlog.cc
      sql/log_event.h
=== modified file 'client/mysqlbinlog.cc'
--- a/client/mysqlbinlog.cc	2009-05-08 17:24:15 +0000
+++ b/client/mysqlbinlog.cc	2009-05-27 15:37:01 +0000
@@ -681,6 +681,7 @@ Exit_status process_event(PRINT_EVENT_IN
 {
   char ll_buff[21];
   Log_event_type ev_type= ev->get_type_code();
+  my_bool destroy_evt= TRUE;
   DBUG_ENTER("process_event");
   print_event_info->short_form= short_form;
   Exit_status retval= OK_CONTINUE;
@@ -871,12 +872,57 @@ Exit_status process_event(PRINT_EVENT_IN
       break;
     }
     case TABLE_MAP_EVENT:
+    {
+      Table_map_log_event *map= ((Table_map_log_event *)ev);
+      if (shall_skip_database(map->get_db_name()))
+      {
+        print_event_info->m_table_map_ignored.set_table(map->get_table_id(), map);
+        destroy_evt= FALSE;
+        goto end;
+      }
+    }
     case WRITE_ROWS_EVENT:
     case DELETE_ROWS_EVENT:
     case UPDATE_ROWS_EVENT:
     case PRE_GA_WRITE_ROWS_EVENT:
     case PRE_GA_DELETE_ROWS_EVENT:
     case PRE_GA_UPDATE_ROWS_EVENT:
+    {
+      if (ev_type != TABLE_MAP_EVENT)
+      {
+        Rows_log_event *e= (Rows_log_event*) ev;
+        Table_map_log_event *ignored= 
+          print_event_info->m_table_map_ignored.get_table(e->get_table_id());
+        if (ignored) /* map got filtered before, now filter rest of events */
+        {
+          /* 
+             one needs to take into account events that get filtered
+             but was last event in the statement. Cache still needs to
+             be written to file. (Especially needed on multi table updates
+             from different databases).
+           */
+          if (e->get_flags(Rows_log_event::STMT_END_F))
+          {
+            int error= 0;
+            error= (copy_event_cache_to_file_and_reinit(&print_event_info->head_cache, result_file) ||
+                    copy_event_cache_to_file_and_reinit(&print_event_info->body_cache, result_file));
+
+            /* clean up */
+            print_event_info->m_table_map_ignored.remove_table(e->get_table_id());
+
+            /* now is safe to destroy the original map event. */
+            if (remote_opt)
+              ignored->temp_buf= 0;
+            delete ignored;
+
+            if (error)
+              goto err;
+          }
+
+          /* filter event */
+          goto end;
+        }
+      }
       /*
         These events must be printed in base64 format, if printed.
         base64 format requires a FD event to be safe, so if no FD
@@ -900,6 +946,7 @@ Exit_status process_event(PRINT_EVENT_IN
         goto err;
       }
       /* FALL THROUGH */
+    }
     default:
       ev->print(result_file, print_event_info);
     }
@@ -915,7 +962,7 @@ end:
     Destroy the log_event object. If reading from a remote host,
     set the temp_buf to NULL so that memory isn't freed twice.
   */
-  if (ev)
+  if (ev && destroy_evt)
   {
     if (remote_opt)
       ev->temp_buf= 0;

=== added file 'mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_db_filter.result'
--- a/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_db_filter.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_db_filter.result	2009-05-27 15:37:01 +0000
@@ -0,0 +1,36 @@
+RESET MASTER;
+CREATE TABLE t1 (id int);
+CREATE TABLE t2 (id int);
+CREATE TABLE t3 (txt TEXT);
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t2 VALUES (1);
+INSERT INTO t2 VALUES (2);
+INSERT INTO t1 VALUES (3);
+LOAD DATA INFILE 'MYSQLTEST_VARDIR/std_data/words.dat' INTO TABLE t3;
+INSERT INTO t1 VALUES (4);
+CREATE DATABASE b42941;
+use b42941;
+CREATE TABLE t1 (id int);
+CREATE TABLE t2 (id int);
+CREATE TABLE t3 (txt TEXT);
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t2 VALUES (1);
+INSERT INTO t2 VALUES (2);
+INSERT INTO t1 VALUES (3);
+LOAD DATA INFILE 'MYSQLTEST_VARDIR/std_data/words.dat' INTO TABLE t3;
+INSERT INTO t1 VALUES (4);
+INSERT INTO test.t1 VALUES (5);
+FLUSH LOGS;
+UPDATE test.t1 t11, b42941.t1 t12 SET t11.id=10, t12.id=100;
+FLUSH LOGS;
+SET @b42941_output.1= LOAD_FILE('MYSQLTEST_VARDIR/tmp/b42941-mysqlbinlog.1');
+SET @b42941_output.2= LOAD_FILE('MYSQLTEST_VARDIR/tmp/b42941-mysqlbinlog.2');
+SET @b42941_output.1= LOAD_FILE('MYSQLTEST_VARDIR/tmp/b42941-mysqlbinlog.1');
+SET @b42941_output.2= LOAD_FILE('MYSQLTEST_VARDIR/tmp/b42941-mysqlbinlog.2');
+SET @b42941_output.1= LOAD_FILE('MYSQLTEST_VARDIR/tmp/b42941-mysqlbinlog.1');
+SET @b42941_output.2= LOAD_FILE('MYSQLTEST_VARDIR/tmp/b42941-mysqlbinlog.2');
+DROP DATABASE b42941;
+use test;
+DROP TABLE t1, t2, t3;

=== added file 'mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_db_filter.test'
--- a/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_db_filter.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_db_filter.test	2009-05-27 15:37:01 +0000
@@ -0,0 +1,134 @@
+# BUG#42941: --database paramater to mysqlbinlog fails with RBR
+#
+# WHAT
+# ====
+#
+#  This test aims at checking whether a rows log event is printed or
+#  not when --database parameter is used to filter events from one
+#  given database.
+#
+# HOW
+# ===
+#
+#  The test is implemented as follows: 
+#
+#    i) Some operations are done in two different databases:
+#       'test' and 'b42941';
+#   ii) mysqlbinlog is used to dump the contents of the binlog file
+#       filtering only events from 'b42941'. The result of the dump is
+#       stored in a temporary file. (This is done with and without
+#       --verbose/hexdump flag);
+#  iii) The contents of the dump are loaded into a session variable;
+#   iv) The variable contents are searched for 'test' and 'b42941';
+#    v) Should 'test' be found, an ERROR is reported. Should 'b42941' be
+#       absent, an ERROR is reported.
+
+-- source include/have_log_bin.inc
+-- source include/have_binlog_format_row.inc
+
+RESET MASTER;
+-- let $MYSQLD_DATADIR= `select @@datadir`
+
+CREATE TABLE t1 (id int);
+CREATE TABLE t2 (id int);
+CREATE TABLE t3 (txt TEXT);
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t2 VALUES (1);
+INSERT INTO t2 VALUES (2);
+INSERT INTO t1 VALUES (3);
+-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+-- eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/std_data/words.dat' INTO TABLE t3
+INSERT INTO t1 VALUES (4);
+
+CREATE DATABASE b42941;
+use b42941;
+CREATE TABLE t1 (id int);
+CREATE TABLE t2 (id int);
+CREATE TABLE t3 (txt TEXT);
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t2 VALUES (1);
+INSERT INTO t2 VALUES (2);
+INSERT INTO t1 VALUES (3);
+-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+-- eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/std_data/words.dat' INTO TABLE t3
+INSERT INTO t1 VALUES (4);
+
+INSERT INTO test.t1 VALUES (5);
+
+FLUSH LOGS;
+
+UPDATE test.t1 t11, b42941.t1 t12 SET t11.id=10, t12.id=100;
+
+FLUSH LOGS;
+
+-- let $log_file1= $MYSQLD_DATADIR/master-bin.000001
+-- let $log_file2= $MYSQLD_DATADIR/master-bin.000002
+-- let $outfile= $MYSQLTEST_VARDIR/tmp/b42941-mysqlbinlog
+-- let $cmd= $MYSQL_BINLOG
+
+let $i= 3;
+while($i)
+{
+  -- let $flags=--database=b42941
+
+  # construct CLI for mysqlbinlog
+  if(`SELECT $i=3`)
+  {
+    -- let $flags= $flags --verbose --hexdump
+  }
+
+  if(`SELECT $i=2`)
+  {
+    -- let $flags= $flags --verbose
+  }
+
+  if(`SELECT $i=0`)
+  {
+    # do nothing
+  }
+
+  # execute mysqlbinlog on the two available master binlog files
+  -- exec $cmd $flags $log_file1 > $outfile.1
+  -- exec $cmd $flags $log_file2 > $outfile.2
+
+  # load outputs into a variable
+  -- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+  -- eval SET @b42941_output.1= LOAD_FILE('$outfile.1')
+
+  -- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+  -- eval SET @b42941_output.2= LOAD_FILE('$outfile.2')
+
+  # remove unecessary files
+  -- remove_file $outfile.1
+  -- remove_file $outfile.2
+
+  # assertion: events for database test are filtered
+  if (`SELECT INSTR(@b42941_output.1, 'test')`)
+  {
+    -- echo **** ERROR **** Database name 'test' FOUND in mysqlbinlog output ($flags $outfile.1).
+  }
+
+  if (`SELECT INSTR(@b42941_output.2, 'test')`)
+  {
+    -- echo **** ERROR **** Database name 'test' FOUND in mysqlbinlog output ($flags $outfile.2).
+  }
+
+  # assertion: events for database b42941 are not filtered
+  if (!`SELECT INSTR(@b42941_output.1, 'b42941')`)
+  {
+    -- echo **** ERROR **** Database name 'b42941' NOT FOUND in mysqlbinlog output ($flags $outfile.1).
+  }
+
+  if (!`SELECT INSTR(@b42941_output.2, 'b42941')`)
+  {
+    -- echo **** ERROR **** Database name 'b42941' NOT FOUND in mysqlbinlog output ($flags $outfile.2).
+  }
+
+  dec $i;
+}
+
+DROP DATABASE b42941;
+use test;
+DROP TABLE t1, t2, t3;

=== modified file 'sql/log_event.h'
--- a/sql/log_event.h	2009-04-08 23:42:51 +0000
+++ b/sql/log_event.h	2009-05-27 15:37:01 +0000
@@ -676,6 +676,7 @@ typedef struct st_print_event_info
 #ifdef MYSQL_CLIENT
   uint verbose;
   table_mapping m_table_map;
+  table_mapping m_table_map_ignored;
 #endif
 
   /*


Attachment: [text/bzr-bundle] bzr/luis.soares@sun.com-20090527153701-s3gsj8ft488fxf1n.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (luis.soares:2874) Bug#42941Luis Soares27 May
  • Re: bzr commit into mysql-5.1-bugteam branch (luis.soares:2874)Bug#42941Alfranio Correia29 May
    • Re: bzr commit into mysql-5.1-bugteam branch (luis.soares:2874)Bug#42941Luís Soares5 Jun