Hello, everyone:

I recently had to recover some deleted data that was important enough to dig through the binlogs for and fish it out. To make my job easier, I fixed up mysqlbinlog to do a couple of extra tricks:

  * show only entries in a given timestamp range
  * exclude queries containing a certain substring
  * include only queries matching a certain substring
  * exclude queries done by a certain thread

Regexp search, and mutliple patterns still remain on the wish list - fortunately ( for me) and unfortunately for others I did not need them. But anyway, here is what I ended up with (patch against 4.0.18), let's hope some find it useful:

----------------------------start----------------------------------
--- ../../tmp/mysql-4.0.18/client/mysqlbinlog.cc        Tue Feb 10 11:15:56 2004
+++ mysqlbinlog.cc      Thu Mar 18 12:23:27 2004
@@ -27,6 +27,10 @@

#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)

+#define FILTER_MATCH 0
+#define FILTER_SAVE_INTVAR 1
+#define FILTER_NO_MATCH -1
+
 char server_version[SERVER_VERSION_LENGTH];
 ulong server_id = 0;

@@ -57,6 +61,12 @@
 static short binlog_flags = 0;
 static MYSQL* mysql = NULL;

+Intvar_log_event* save_insert_ev = 0, *save_last_insert_ev = 0;
+
+static time_t from_ts = 0, to_ts = 0;
+static const char* pattern = 0, *exclude_pattern = 0;
+static ulong exclude_thread_id = 0;
+
 static const char* dirname_for_local_load= 0;

 static int dump_local_log_entries(const char* logname);
@@ -66,6 +76,8 @@
 static void die(const char* fmt, ...);
 static MYSQL* safe_connect();

+static int filter_match(Log_event* ev, char* last_db);
+static void clear_saved_events();

 class Load_log_processor
 {
@@ -300,6 +312,78 @@

Load_log_processor load_processor;

+static void clear_saved_events()
+{
+  if (save_insert_ev)
+    {
+      delete save_insert_ev;
+      save_insert_ev = 0;
+    }
+  if (save_last_insert_ev)
+    {
+      delete save_last_insert_ev;
+      save_last_insert_ev = 0;
+    }
+}
+
+static int filter_match(Log_event* ev, char* last_db)
+{
+  if (from_ts && ev->when < from_ts)
+    return FILTER_NO_MATCH;
+  if (to_ts && ev->when > to_ts)
+    return FILTER_NO_MATCH;
+
+  if (exclude_pattern)
+  {
+    if (ev->get_type_code() == QUERY_EVENT)
+    {
+      Query_log_event* qev = (Query_log_event*)ev;
+      if (strstr(qev->query,exclude_pattern))
+        return FILTER_NO_MATCH;
+    }
+  }
+
+  if (pattern)
+  {
+    switch (ev->get_type_code())
+    {
+      case QUERY_EVENT:
+        {
+         Query_log_event* qev = (Query_log_event*)ev;
+         if (!strstr(qev->query,pattern))
+           return FILTER_NO_MATCH;
+         break;
+        }
+      case INTVAR_EVENT:
+        return FILTER_SAVE_INTVAR;
+      default:
+        return FILTER_NO_MATCH;
+    }
+  }
+
+  if (exclude_thread_id)
+  {
+    if (ev->get_type_code() == QUERY_EVENT)
+    {
+      Query_log_event* qev = (Query_log_event*)ev;
+      if (qev->thread_id == exclude_thread_id)
+        return FILTER_NO_MATCH;
+    }
+  }
+  if (save_insert_ev)
+    {
+      save_insert_ev->print(result_file,short_form,last_db);
+      delete save_insert_ev;
+      save_insert_ev = 0;
+    }
+  if (save_last_insert_ev)
+    {
+      save_last_insert_ev->print(result_file,short_form,last_db);
+      delete save_last_insert_ev;
+      save_last_insert_ev = 0;
+    }
+  return FILTER_MATCH;
+}

 int process_event(ulonglong *rec_count, char *last_db, Log_event *ev,
                  my_off_t pos, int old_format)
@@ -307,6 +391,37 @@
   char ll_buff[21];
   if ((*rec_count) >= offset)
   {
+    switch (filter_match(ev,last_db))
+    {
+      case FILTER_NO_MATCH:
+        delete ev;
+        clear_saved_events();
+        return 0;
+      case FILTER_SAVE_INTVAR:
+       {
+         Intvar_log_event* iev = (Intvar_log_event*)ev;
+         switch (iev->type)
+         {
+           case INSERT_ID_EVENT:
+              if (save_insert_ev)
+                delete save_insert_ev;
+              save_insert_ev = iev;
+              return 0;
+           case LAST_INSERT_ID_EVENT:
+              if (save_last_insert_ev)
+                delete save_last_insert_ev;
+              save_last_insert_ev = iev;
+              return 0;
+           default:
+              delete ev;
+              return 0;
+         }
+         break;
+       }
+      default:
+        break;
+    }
+
     if (!short_form)
       fprintf(result_file, "# at %s\n",llstr(pos,ll_buff));

@@ -395,6 +510,16 @@
   return 0;
 }

+enum mysqlbinlog_options
+ {
+   OPT_FROM_TS=256,
+   OPT_TO_TS,
+   OPT_EXCLUDE_THREAD,
+   OPT_PATTERN,
+   OPT_EXCLUDE_PATTERN
+ };
+
+

static struct my_option my_long_options[] =
{
@@ -439,6 +564,25 @@
{"local-load", 'l', "Prepare files for local load in directory.",
(gptr*) &dirname_for_local_load, (gptr*) &dirname_for_local_load, 0,
GET_STR_ALLOC, OPT_ARG, 0, 0, 0, 0, 0, 0},
+ {"from-ts", OPT_FROM_TS, "Print entries only after this timestamp",
+ (gptr*) &from_ts, (gptr*) &from_ts, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0,
+ 0, 0},
+ {"to-ts", OPT_TO_TS, "Print entries only prior to this timestamp",
+ (gptr*) &to_ts, (gptr*) &to_ts, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0,
+ 0, 0},
+ {"exclude-connection-id", OPT_EXCLUDE_THREAD,
+ "Do not print entries created by this connection",
+ (gptr*) &exclude_thread_id, (gptr*) &exclude_thread_id, 0, GET_ULONG,
+ REQUIRED_ARG, 0, 0, 0, 0,
+ 0, 0},
+ {"query-pattern", OPT_PATTERN,
+ "Print entries only containing this pattern in the query",
+ (gptr*) &pattern, (gptr*) &pattern, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0,
+ 0, 0},
+ {"exclude-query-pattern", OPT_EXCLUDE_PATTERN,
+ "Print entries only if they do not contain this pattern in the query",
+ (gptr*) &exclude_pattern, (gptr*) &exclude_pattern, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0,
+ 0, 0},
{"version", 'V', "Print version and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}



-----------------------------end-----------------------------------


A patched Linux binary is also available at http://www.surveyz.com/~sasha/mysqlbinlog

--
Sasha Pachev
Create online surveys at http://www.surveyz.com/

--
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:    http://lists.mysql.com/[EMAIL PROTECTED]



Reply via email to