diff -r ab59095a9cbf include/my_time.h
--- a/include/my_time.h	Tue Aug 14 12:28:04 2007 +0200
+++ b/include/my_time.h	Mon Apr 07 14:30:21 2008 +0200
@@ -140,7 +140,7 @@
 int my_date_to_str(const MYSQL_TIME *l_time, char *to);
 int my_datetime_to_str(const MYSQL_TIME *l_time, char *to);
 int my_TIME_to_str(const MYSQL_TIME *l_time, char *to);
-
+ulonglong my_timer(ulonglong *ltime, ulonglong frequency);
 C_MODE_END
 
 #endif /* _my_time_h_ */
diff -r ab59095a9cbf scripts/mysqldumpslow.sh
--- a/scripts/mysqldumpslow.sh	Tue Aug 14 12:28:04 2007 +0200
+++ b/scripts/mysqldumpslow.sh	Mon Apr 07 14:30:21 2008 +0200
@@ -83,8 +83,8 @@
     s/^#? Time: \d{6}\s+\d+:\d+:\d+.*\n//;
     my ($user,$host) = s/^#? User\@Host:\s+(\S+)\s+\@\s+(\S+).*\n// ? ($1,$2) : ('','');
 
-    s/^# Query_time: (\d+)  Lock_time: (\d+)  Rows_sent: (\d+).*\n//;
-    my ($t, $l, $r) = ($1, $2, $3);
+    s/^# Query_time: (\d+(\.\d+)?)  Lock_time: (\d+(\.\d+)?)  Rows_sent: (\d+(\.\d+)?).*\n//;
+    my ($t, $l, $r) = ($1, $3, $5);
     $t -= $l unless $opt{l};
 
     # remove fluff that mysqld writes to log when it (re)starts:
diff -r ab59095a9cbf sql-common/my_time.c
--- a/sql-common/my_time.c	Tue Aug 14 12:28:04 2007 +0200
+++ b/sql-common/my_time.c	Mon Apr 07 14:30:21 2008 +0200
@@ -1250,3 +1250,37 @@
   return 0;
 }
 
+/*
+ int my_timer(ulonglong *ltime, ulonglong frequency)
+
+ For performance measurement this function returns the number
+ of microseconds since the epoch (SVr4, BSD 4.3, POSIX 1003.1-2001)
+ or system start (Windows platforms).
+
+ For windows platforms frequency value (obtained via 
+ QueryPerformanceFrequency) has to be specified. The global frequency
+ value is set in mysqld.cc. 
+
+ If Windows platform doesn't support QueryPerformanceFrequency we will
+ obtain the time via GetClockCount, which supports microseconds only.
+*/
+
+ulonglong my_timer(ulonglong *ltime, ulonglong frequency)
+{
+  ulonglong newtime= 0;
+#ifdef __WIN__
+  if (frequency) 
+  {
+    QueryPerformanceCounter((LARGE_INTEGER *)&newtime);
+    newtime/= (frequency * 1000000);
+  } else
+    newtime= (GetTickCount() * 1000; /* GetTickCount only returns milliseconds */
+#else
+  struct timeval t;
+  gettimeofday(&t, NULL);
+  newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec;
+#endif
+  if (ltime)
+    *ltime= newtime;
+  return newtime;
+}
diff -r ab59095a9cbf sql/filesort.cc
--- a/sql/filesort.cc	Tue Aug 14 12:28:04 2007 +0200
+++ b/sql/filesort.cc	Mon Apr 07 14:30:21 2008 +0200
@@ -172,6 +172,7 @@
   {
     statistic_increment(thd->status_var.filesort_scan_count, &LOCK_status);
   }
+  thd->query_plan_flags|= QPLAN_FILESORT;
 #ifdef CAN_TRUST_RANGE
   if (select && select->quick && select->quick->records > 0L)
   {
@@ -238,6 +239,7 @@
   }
   else
   {
+    thd->query_plan_flags|= QPLAN_FILESORT_DISK;
     if (!table_sort.buffpek && table_sort.buffpek_len < maxbuffer &&
         !(table_sort.buffpek=
           (byte *) read_buffpek_from_file(&buffpek_pointers, maxbuffer)))
@@ -1058,6 +1060,7 @@
 
   statistic_increment(current_thd->status_var.filesort_merge_passes,
 		      &LOCK_status);
+  current_thd->query_plan_fsort_passes++;
   if (param->not_killable)
   {
     killed= &not_killable;
diff -r ab59095a9cbf sql/log.cc
--- a/sql/log.cc	Tue Aug 14 12:28:04 2007 +0200
+++ b/sql/log.cc	Mon Apr 07 14:30:21 2008 +0200
@@ -1930,10 +1930,11 @@
 */
 
 bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
-		      time_t query_start_arg)
+		      time_t query_start_arg, ulonglong query_start_timer)
 {
   bool error=0;
   time_t current_time;
+  ulonglong current_timer;
   if (!is_open())
     return 0;
   DBUG_ENTER("MYSQL_LOG::write");
@@ -1944,7 +1945,8 @@
     int tmp_errno=0;
     char buff[80],*end;
     end=buff;
-    if (!(thd->options & OPTION_UPDATE_LOG))
+    if (!(thd->options & OPTION_UPDATE_LOG) &&
+        !(thd->slave_thread && opt_log_slow_slave_statements))
     {
       VOID(pthread_mutex_unlock(&LOCK_log));
       DBUG_RETURN(0);
@@ -1974,22 +1976,69 @@
       if (my_b_printf(&log_file, "# User@Host: %s[%s] @ %s [%s]\n",
                       sctx->priv_user ?
                       sctx->priv_user : "",
-                      sctx->user ? sctx->user : "",
+                      sctx->user ? sctx->user : (thd->slave_thread ? "SQL_SLAVE" : ""),
                       sctx->host ? sctx->host : "",
                       sctx->ip ? sctx->ip : "") ==
           (uint) -1)
         tmp_errno=errno;
     }
-    if (query_start_arg)
+    if (query_start_timer)
     {
+      char buf[5][20];
+      ulonglong current_timer= my_timer(&current_timer, frequency);
+      sprintf(buf[0], "%.6f", (current_timer - query_start_timer) / 1000000.0);
+      sprintf(buf[1], "%.6f", (thd->timer_after_lock - query_start_timer) / 1000000.0);
+      if (!query_length)
+      {
+        thd->sent_row_count= thd->examined_row_count= 0;
+        thd->innodb_was_used= FALSE;
+        thd->query_plan_flags= QPLAN_NONE;
+        thd->query_plan_fsort_passes= 0;
+      }
+
       /* For slow query log */
       if (my_b_printf(&log_file,
-                      "# Query_time: %lu  Lock_time: %lu  Rows_sent: %lu  Rows_examined: %lu\n",
-                      (ulong) (current_time - query_start_arg),
-                      (ulong) (thd->time_after_lock - query_start_arg),
+                      "# Thread_id: %lu  Schema: %s\n" \
+                      "# Query_time: %s  Lock_time: %s  Rows_sent: %lu  Rows_examined: %lu\n", 
+                      (ulong) thd->thread_id, (thd->db ? thd->db : ""),
+                      buf[0], buf[1],
                       (ulong) thd->sent_row_count,
                       (ulong) thd->examined_row_count) == (uint) -1)
         tmp_errno=errno;
+      if ((thd->variables.log_slow_verbosity & SLOG_V_QUERY_PLAN) &&
+           my_b_printf(&log_file,
+                      "# QC_Hit: %s  Full_scan: %s  Full_join: %s  Tmp_table: %s  Tmp_table_on_disk: %s\n" \
+                      "# Filesort: %s  Filesort_on_disk: %s  Merge_passes: %lu\n",
+                      ((thd->query_plan_flags & QPLAN_QC) ? "Yes" : "No"),
+                      ((thd->query_plan_flags & QPLAN_FULL_SCAN) ? "Yes" : "No"),
+                      ((thd->query_plan_flags & QPLAN_FULL_JOIN) ? "Yes" : "No"),
+                      ((thd->query_plan_flags & QPLAN_TMP_TABLE) ? "Yes" : "No"),
+                      ((thd->query_plan_flags & QPLAN_TMP_DISK) ? "Yes" : "No"),
+                      ((thd->query_plan_flags & QPLAN_FILESORT) ? "Yes" : "No"),
+                      ((thd->query_plan_flags & QPLAN_FILESORT_DISK) ? "Yes" : "No"),
+                      thd->query_plan_fsort_passes) == (uint) -1)
+        tmp_errno=errno;
+      if ((thd->variables.log_slow_verbosity & SLOG_V_INNODB) && thd->innodb_was_used)
+      {
+        sprintf(buf[2], "%.6f", thd->innodb_io_reads_wait_timer / 1000000.0);
+        sprintf(buf[3], "%.6f", thd->innodb_lock_que_wait_timer / 1000000.0);
+        sprintf(buf[4], "%.6f", thd->innodb_innodb_que_wait_timer / 1000000.0);
+        if (my_b_printf(&log_file,
+                        "#   InnoDB_IO_r_ops: %lu  InnoDB_IO_r_bytes: %lu  InnoDB_IO_r_wait: %s\n" \
+                        "#   InnoDB_rec_lock_wait: %s  InnoDB_queue_wait: %s\n" \
+                        "#   InnoDB_pages_distinct: %lu\n",
+                        (ulong) thd->innodb_io_reads,
+                        (ulong) thd->innodb_io_read,
+                        buf[2], buf[3], buf[4],
+                        (ulong) thd->innodb_page_access) == (uint) -1)
+          tmp_errno=errno;
+      } 
+      else
+      {
+        if ((thd->variables.log_slow_verbosity & SLOG_V_INNODB) &&
+            my_b_printf(&log_file,"# No InnoDB statistics available for this query\n") == (uint) -1)
+          tmp_errno=errno;
+      }
     }
     if (thd->db && strcmp(thd->db,db))
     {						// Database changed
diff -r ab59095a9cbf sql/log_event.cc
--- a/sql/log_event.cc	Tue Aug 14 12:28:04 2007 +0200
+++ b/sql/log_event.cc	Mon Apr 07 14:30:21 2008 +0200
@@ -1900,6 +1900,7 @@
       /* Execute the query (note that we bypass dispatch_command()) */
       const char* found_semicolon= NULL;
       mysql_parse(thd, thd->query, thd->query_length, &found_semicolon);
+      log_slow_statement(thd);
 
     }
     else
diff -r ab59095a9cbf sql/my_time.c
--- a/sql/my_time.c	Tue Aug 14 12:28:04 2007 +0200
+++ b/sql/my_time.c	Mon Apr 07 14:30:21 2008 +0200
@@ -1250,3 +1250,37 @@
   return 0;
 }
 
+/*
+ int my_timer(ulonglong *ltime, ulonglong frequency)
+
+ For performance measurement this function returns the number
+ of microseconds since the epoch (SVr4, BSD 4.3, POSIX 1003.1-2001)
+ or system start (Windows platforms).
+
+ For windows platforms frequency value (obtained via 
+ QueryPerformanceFrequency) has to be specified. The global frequency
+ value is set in mysqld.cc. 
+
+ If Windows platform doesn't support QueryPerformanceFrequency we will
+ obtain the time via GetClockCount, which supports microseconds only.
+*/
+
+ulonglong my_timer(ulonglong *ltime, ulonglong frequency)
+{
+  ulonglong newtime= 0;
+#ifdef __WIN__
+  if (frequency) 
+  {
+    QueryPerformanceCounter((LARGE_INTEGER *)&newtime);
+    newtime/= (frequency / 1000000);
+  } else
+    newtime= (GetTickCount() * 1000); /* GetTickCount only returns milliseconds */
+#else
+  struct timeval t;
+  gettimeofday(&t, NULL);
+  newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec;
+#endif
+  if (ltime)
+    *ltime= newtime;
+  return newtime;
+}
diff -r ab59095a9cbf sql/mysql_priv.h
--- a/sql/mysql_priv.h	Tue Aug 14 12:28:04 2007 +0200
+++ b/sql/mysql_priv.h	Mon Apr 07 14:30:21 2008 +0200
@@ -482,6 +482,78 @@
 #define WEEK_FIRST_WEEKDAY   4
 
 #define STRING_BUFFER_USUAL_SIZE 80
+
+/* Slow log */
+
+struct msl_opts
+{
+  ulong val;
+  char *name;
+};
+
+#define SLOG_V_MICROTIME      1 << 0
+#define SLOG_V_QUERY_PLAN     1 << 1
+#define SLOG_V_INNODB         1 << 2
+/* ... */
+#define SLOG_V_INVALID        1 << 31
+#define SLOG_V_NONE           SLOG_V_MICROTIME
+
+static const struct msl_opts slog_verb[]=
+{
+  /* Basic flags */
+
+  { SLOG_V_MICROTIME, "microtime" },
+  { SLOG_V_QUERY_PLAN, "query_plan" },
+  { SLOG_V_INVALID, "innodb" },
+
+  /* End of baisc flags */
+   
+  { 0, "" },
+   
+  /* Complex flags */
+
+  { SLOG_V_MICROTIME, "minimal" },
+  { SLOG_V_MICROTIME|SLOG_V_QUERY_PLAN, "standard" },
+  { SLOG_V_INVALID, "full" },
+
+  /* End of complex flags */
+
+  { SLOG_V_INVALID, (char *)0 }
+};
+
+#define QPLAN_NONE            0
+#define QPLAN_QC              1 << 0
+#define QPLAN_QC_NO           1 << 1
+#define QPLAN_FULL_SCAN       1 << 2
+#define QPLAN_FULL_JOIN       1 << 3
+#define QPLAN_TMP_TABLE       1 << 4
+#define QPLAN_TMP_DISK        1 << 5
+#define QPLAN_FILESORT        1 << 6
+#define QPLAN_FILESORT_DISK   1 << 7
+/* ... */
+#define QPLAN_MAX             1 << 31
+
+#define SLOG_F_QC_NO          QPLAN_QC_NO
+#define SLOG_F_FULL_SCAN      QPLAN_FULL_SCAN
+#define SLOG_F_FULL_JOIN      QPLAN_FULL_JOIN
+#define SLOG_F_TMP_TABLE      QPLAN_TMP_TABLE
+#define SLOG_F_TMP_DISK       QPLAN_TMP_DISK
+#define SLOG_F_FILESORT       QPLAN_FILESORT
+#define SLOG_F_FILESORT_DISK  QPLAN_FILESORT_DISK
+#define SLOG_F_INVALID        1 << 31
+#define SLOG_F_NONE           0
+
+static const struct msl_opts slog_filter[]=
+{
+  { SLOG_F_QC_NO,         "qc_miss" },
+  { SLOG_F_FULL_SCAN,     "full_scan" },
+  { SLOG_F_FULL_JOIN,     "full_join" },
+  { SLOG_F_TMP_TABLE,     "tmp_table" },
+  { SLOG_F_TMP_DISK,      "tmp_table_on_disk" },
+  { SLOG_F_FILESORT,      "filesort" },
+  { SLOG_F_FILESORT_DISK, "filesort_on_disk" },
+  { SLOG_F_INVALID,       (char *)0 }
+};
 
 enum enum_parsing_place
 {
@@ -1323,7 +1395,7 @@
 extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs;
 extern my_bool opt_secure_auth;
 extern char* opt_secure_file_priv;
-extern my_bool opt_log_slow_admin_statements;
+extern my_bool opt_log_slow_admin_statements, opt_log_slow_slave_statements;
 extern my_bool sp_automatic_privileges, opt_noacl;
 extern my_bool opt_old_style_user_limits, trust_function_creators;
 extern uint opt_crash_binlog_innodb;
diff -r ab59095a9cbf sql/mysqld.cc
--- a/sql/mysqld.cc	Tue Aug 14 12:28:04 2007 +0200
+++ b/sql/mysqld.cc	Mon Apr 07 14:30:21 2008 +0200
@@ -169,7 +169,6 @@
 static void getvolumeID(BYTE *volumeName);
 #endif /* __NETWARE__ */
 
-
 #ifdef _AIX41
 int initgroups(const char *,unsigned int);
 #endif
@@ -213,6 +212,7 @@
 extern "C" int gethostname(char *name, int namelen);
 #endif
 
+ulonglong frequency= 0;
 
 /* Constants */
 
@@ -384,6 +384,7 @@
 my_bool opt_secure_auth= 0;
 char* opt_secure_file_priv= 0;
 my_bool opt_log_slow_admin_statements= 0;
+my_bool opt_log_slow_slave_statements= 0;
 my_bool lower_case_file_system= 0;
 my_bool opt_large_pages= 0;
 uint    opt_large_page_size= 0;
@@ -3490,6 +3491,8 @@
       unireg_abort(1);
     }
   }
+  if (!QueryPerformanceFrequency((LARGE_INTEGER *)&frequency))
+    frequency= 0;
 #endif /* __WIN__ */
 
   if (init_common_variables(MYSQL_CONFIG_NAME,
@@ -4724,7 +4727,7 @@
   OPT_INTERACTIVE_TIMEOUT, OPT_JOIN_BUFF_SIZE,
   OPT_KEY_BUFFER_SIZE, OPT_KEY_CACHE_BLOCK_SIZE,
   OPT_KEY_CACHE_DIVISION_LIMIT, OPT_KEY_CACHE_AGE_THRESHOLD,
-  OPT_LONG_QUERY_TIME,
+  OPT_LONG_QUERY_TIME, OPT_MIN_EXAMINED_ROW_LIMIT,
   OPT_LOWER_CASE_TABLE_NAMES, OPT_MAX_ALLOWED_PACKET,
   OPT_MAX_BINLOG_CACHE_SIZE, OPT_MAX_BINLOG_SIZE,
   OPT_MAX_CONNECTIONS, OPT_MAX_CONNECT_ERRORS,
@@ -4815,6 +4818,10 @@
   OPT_TIMED_MUTEXES,
   OPT_OLD_STYLE_USER_LIMITS,
   OPT_LOG_SLOW_ADMIN_STATEMENTS,
+  OPT_LOG_SLOW_SLAVE_STATEMENTS,
+  OPT_LOG_SLOW_RATE_LIMIT,
+  OPT_LOG_SLOW_VERBOSITY,
+  OPT_LOG_SLOW_FILTER,
   OPT_TABLE_LOCK_WAIT_TIMEOUT,
   OPT_PORT_OPEN_TIMEOUT,
   OPT_MERGE,
@@ -5195,6 +5202,11 @@
    "Log slow OPTIMIZE, ANALYZE, ALTER and other administrative statements to the slow log if it is open.",
    (gptr*) &opt_log_slow_admin_statements,
    (gptr*) &opt_log_slow_admin_statements,
+   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+  {"log-slow-slave-statements", OPT_LOG_SLOW_SLAVE_STATEMENTS,
+   "Log slow replicated statements to the slow log if it is open.",
+   (gptr*) &opt_log_slow_slave_statements,
+   (gptr*) &opt_log_slow_slave_statements,
    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
   {"log-slow-queries", OPT_SLOW_QUERY_LOG,
     "Log slow queries to this log file. Defaults logging to hostname-slow.log file. Must be enabled to activate other slow log options.",
@@ -5853,11 +5865,27 @@
    (gptr*) 0,
    0, (GET_ULONG | GET_ASK_ADDR) , REQUIRED_ARG, 100,
    1, 100, 0, 1, 0},
+  {"log_slow_filter", OPT_LOG_SLOW_FILTER,
+    "Log only the queries that followed certain execution plan. Multiple flags allowed in a comma-separated string. [qc_miss, full_scan, full_join, tmp_table, tmp_table_on_disk, filesort, filesort_on_disk]",
+    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, SLOG_F_NONE, 0, 0},
+  {"log_slow_rate_limit", OPT_LOG_SLOW_RATE_LIMIT,
+    "Rate limit statement writes to slow log to only those from every (1/log_slow_rate_limit) session.",
+    (gptr*) &global_system_variables.log_slow_rate_limit,
+    (gptr*) &max_system_variables.log_slow_rate_limit, 0, GET_ULONG,
+    REQUIRED_ARG, 0, 1, ~0L, 0, 1L, 0},
+  {"log_slow_verbosity", OPT_LOG_SLOW_VERBOSITY,
+    "Choose how verbose the messages to your slow log will be. Multiple flags allowed in a comma-separated string. [microtime, query_plan]",
+    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, SLOG_V_MICROTIME, 0, 0},
   {"long_query_time", OPT_LONG_QUERY_TIME,
    "Log all queries that have taken more than long_query_time seconds to execute to file.",
    (gptr*) &global_system_variables.long_query_time,
    (gptr*) &max_system_variables.long_query_time, 0, GET_ULONG,
-   REQUIRED_ARG, 10, 1, LONG_TIMEOUT, 0, 1, 0},
+    REQUIRED_ARG, 10000000, 0, LONG_TIMEOUT * 1000000, 0, 1, 0},
+  {"min_examined_row_limit", OPT_MIN_EXAMINED_ROW_LIMIT,
+    "Don't log queries which examine less than min_examined_row_limit rows to file.",
+    (gptr*) &global_system_variables.min_examined_row_limit,
+    (gptr*) &max_system_variables.min_examined_row_limit, 0, GET_ULONG,
+    REQUIRED_ARG, 0, 0, ~0L, 0, 1L, 0},
   {"lower_case_table_names", OPT_LOWER_CASE_TABLE_NAMES,
    "If set to 1 table names are stored in lowercase on disk and table names will be case-insensitive.  Should be set to 2 if you are using a case insensitive file system",
    (gptr*) &lower_case_table_names,
@@ -6623,7 +6651,9 @@
   global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR;
   max_system_variables.max_join_size=   (ulonglong) HA_POS_ERROR;
   global_system_variables.old_passwords= 0;
-
+  global_system_variables.log_slow_verbosity= SLOG_V_MICROTIME;
+  global_system_variables.log_slow_filter= SLOG_F_NONE;
+  
   /*
     Default behavior for 4.1 and 5.0 is to treat NULL values as unequal
     when collecting index statistics for MyISAM tables.
@@ -7084,6 +7114,24 @@
   case OPT_BOOTSTRAP:
     opt_noacl=opt_bootstrap=1;
     break;
+  case OPT_LOG_SLOW_FILTER:
+    if ((global_system_variables.log_slow_filter= 
+          msl_flag_resolve_by_name(slog_filter, argument,
+                                   SLOG_F_NONE, SLOG_F_INVALID)) == SLOG_F_INVALID)
+    {
+      fprintf(stderr,"Invalid argument to log_slow_filter\n");
+      exit(1);
+    }
+    break;
+  case OPT_LOG_SLOW_VERBOSITY:
+    if ((global_system_variables.log_slow_verbosity= 
+         msl_flag_resolve_by_name(slog_verb, argument,
+                                  SLOG_V_NONE, SLOG_V_INVALID)) == SLOG_V_INVALID)
+    {
+      fprintf(stderr,"Invalid argument to log_slow_verbosity\n");
+      exit(1);
+    }
+    break;
   case OPT_STORAGE_ENGINE:
   {
     if ((enum db_type)((global_system_variables.table_type=
@@ -7401,10 +7449,14 @@
   if (opt_bdb)
     sql_print_warning("this binary does not contain BDB storage engine");
 #endif
-  if ((opt_log_slow_admin_statements || opt_log_queries_not_using_indexes) &&
+  if ((opt_log_slow_admin_statements || opt_log_queries_not_using_indexes ||
+        opt_log_slow_slave_statements) &&
       !opt_slow_log)
-    sql_print_warning("options --log-slow-admin-statements and --log-queries-not-using-indexes have no effect if --log-slow-queries is not set");
-
+  {
+    sql_print_warning("options --log-slow-admin-statements, --log-slow-slave-statements and --log-queries-not-using-indexes have no effect if --log-slow-queries is not set");
+    opt_log_slow_slave_statements= FALSE;
+  }
+  
   if (argc > 0)
   {
     fprintf(stderr, "%s: Too many arguments (first extra is '%s').\nUse --help to get a list of available options\n", my_progname, *argv);
diff -r ab59095a9cbf sql/set_var.cc
--- a/sql/set_var.cc	Tue Aug 14 12:28:04 2007 +0200
+++ b/sql/set_var.cc	Mon Apr 07 14:30:21 2008 +0200
@@ -211,7 +211,7 @@
   sys_log_queries_not_using_indexes("log_queries_not_using_indexes",
                                     &opt_log_queries_not_using_indexes);
 sys_var_thd_ulong	sys_log_warnings("log_warnings", &SV::log_warnings);
-sys_var_thd_ulong	sys_long_query_time("long_query_time",
+sys_var_thd_ulonglong  sys_long_query_time("long_query_time",
 					     &SV::long_query_time);
 sys_var_thd_bool	sys_low_priority_updates("low_priority_updates",
 						 &SV::low_priority_updates,
@@ -276,6 +276,8 @@
 					   &SV::max_tmp_tables);
 sys_var_long_ptr	sys_max_write_lock_count("max_write_lock_count",
 						 &max_write_lock_count);
+sys_var_thd_ulong	sys_min_examined_row_limit("min_examined_row_limit",
+					     &SV::min_examined_row_limit);
 sys_var_thd_ulong       sys_multi_range_count("multi_range_count",
                                               &SV::multi_range_count);
 sys_var_long_ptr	sys_myisam_data_pointer_size("myisam_data_pointer_size",
@@ -319,6 +321,20 @@
 sys_var_bool_ptr	sys_relay_log_purge("relay_log_purge",
                                             &relay_log_purge);
 #endif
+sys_var_thd_ulong	sys_log_slow_rate_limit("log_slow_rate_limit",
+					     &SV::log_slow_rate_limit);
+sys_var_thd_msl_flag	sys_log_slow_filter("log_slow_filter",
+				       &SV::log_slow_filter,
+                                       SLOG_F_NONE,
+                                       SLOG_F_NONE,
+                                       SLOG_F_INVALID,
+                                       slog_filter);
+sys_var_thd_msl_flag	sys_log_slow_verbosity("log_slow_verbosity",
+				       &SV::log_slow_verbosity,
+                                       SLOG_V_NONE,
+                                       SLOG_V_MICROTIME,
+                                       SLOG_V_INVALID,
+                                       slog_verb);
 sys_var_long_ptr	sys_rpl_recovery_rank("rpl_recovery_rank",
 					      &rpl_recovery_rank);
 sys_var_long_ptr	sys_query_cache_size("query_cache_size",
@@ -669,6 +685,9 @@
   &sys_log_binlog,
   &sys_log_off,
   &sys_log_queries_not_using_indexes,
+  &sys_log_slow_filter,
+  &sys_log_slow_rate_limit,
+  &sys_log_slow_verbosity,
   &sys_log_update,
   &sys_log_warnings,
   &sys_long_query_time,
@@ -692,6 +711,7 @@
   &sys_max_tmp_tables,
   &sys_max_user_connections,
   &sys_max_write_lock_count,
+  &sys_min_examined_row_limit,
   &sys_multi_range_count,
   &sys_myisam_data_pointer_size,
   &sys_myisam_max_sort_file_size,
@@ -960,6 +980,8 @@
   {"log_slave_updates",       (char*) &opt_log_slave_updates,       SHOW_MY_BOOL},
 #endif
   {"log_slow_queries",        (char*) &opt_slow_log,                SHOW_BOOL},
+  {sys_log_slow_filter.name, (char*) &sys_log_slow_filter, SHOW_SYS},
+  {sys_log_slow_verbosity.name, (char*) &sys_log_slow_verbosity, SHOW_SYS},
   {sys_log_warnings.name,     (char*) &sys_log_warnings,	    SHOW_SYS},
   {sys_long_query_time.name,  (char*) &sys_long_query_time, 	    SHOW_SYS},
   {sys_low_priority_updates.name, (char*) &sys_low_priority_updates, SHOW_SYS},
@@ -988,6 +1010,7 @@
   {sys_max_tmp_tables.name,	(char*) &sys_max_tmp_tables,	    SHOW_SYS},
   {sys_max_user_connections.name,(char*) &sys_max_user_connections, SHOW_SYS},
   {sys_max_write_lock_count.name, (char*) &sys_max_write_lock_count,SHOW_SYS},
+  {sys_min_examined_row_limit.name, (char*) &sys_min_examined_row_limit, SHOW_SYS},
   {sys_multi_range_count.name,  (char*) &sys_multi_range_count,     SHOW_SYS},
   {sys_myisam_data_pointer_size.name, (char*) &sys_myisam_data_pointer_size, SHOW_SYS},
   {sys_myisam_max_sort_file_size.name, (char*) &sys_myisam_max_sort_file_size,
@@ -1044,6 +1067,7 @@
   {sys_query_prealloc_size.name, (char*) &sys_query_prealloc_size,  SHOW_SYS},
   {sys_range_alloc_block_size.name, (char*) &sys_range_alloc_block_size,
    SHOW_SYS},
+  {sys_log_slow_rate_limit.name, (char*) &sys_log_slow_rate_limit, SHOW_SYS},
   {sys_read_buff_size.name,   (char*) &sys_read_buff_size,	    SHOW_SYS},
   {sys_readonly.name,         (char*) &sys_readonly,                SHOW_SYS},
   {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size,	    SHOW_SYS},
@@ -1581,6 +1605,53 @@
   return (byte*) &(thd->variables.*offset);
 }
 
+void sys_var_thd_microtime::set_default(THD *thd, enum_var_type type)
+{
+  pthread_mutex_lock(&LOCK_global_system_variables);
+  global_system_variables.*offset= (ulonglong) option_limits->def_value;
+  pthread_mutex_unlock(&LOCK_global_system_variables);
+}
+
+bool sys_var_thd_microtime::check(THD *thd, set_var *var)
+{
+  if (var->value->result_type() == DECIMAL_RESULT)
+    var->save_result.ulonglong_value= (ulonglong)(var->value->val_real() * 1000000);
+  else 
+    var->save_result.ulonglong_value= (ulonglong)var->value->val_int() * 1000000;
+  return 0;
+}
+
+byte *sys_var_thd_microtime::value_ptr(THD *thd, enum_var_type type,
+				   LEX_STRING *base)
+{
+  if (type == OPT_GLOBAL)
+    return (byte*) &(global_system_variables.*offset);
+  return (byte*) &(thd->variables.*offset);
+}
+
+bool sys_var_thd_microtime::update(THD *thd,  set_var *var)
+{
+  ulonglong tmp= var->save_result.ulonglong_value;
+
+  if (tmp > max_system_variables.*offset)
+    tmp= max_system_variables.*offset;
+
+  if (option_limits)
+    tmp= getopt_ull_limit_value(tmp, option_limits);
+  
+  /* Lock is needed to make things safe on 32 bit systems */
+  if (var->type == OPT_GLOBAL)
+  {
+    /* Lock is needed to make things safe on 32 bit systems */
+    pthread_mutex_lock(&LOCK_global_system_variables);
+    global_system_variables.*offset= tmp;
+    pthread_mutex_unlock(&LOCK_global_system_variables);
+  }
+  else
+    thd->variables.*offset= (ulonglong) tmp;
+
+  return 0;
+}
 
 bool sys_var_thd_ha_rows::update(THD *thd, set_var *var)
 {
@@ -3392,6 +3463,191 @@
 #endif
 }
 
+/* Slow log stuff */
+
+ulong msl_option_resolve_by_name(const struct msl_opts *opts, const char *name, ulong len)
+{
+  ulong i;
+  
+  for (i=0; opts[i].name; i++)
+  {
+    if (!my_strnncoll(&my_charset_latin1,
+                      (const uchar *)name, len,
+                      (const uchar *)opts[i].name, strlen(opts[i].name)))
+      return opts[i].val;
+  }
+  return opts[i].val;
+}
+
+ulong msl_flag_resolve_by_name(const struct msl_opts *opts, const char *names_list, 
+                               const ulong none_val, const ulong invalid_val)
+{
+  const char *p, *e;
+  ulong val= none_val;
+  
+  if (!*names_list)
+    return val;
+  
+  for (p= e= names_list; ; e++)
+  {
+    ulong i;
+    
+    if (*e != ',' && *e)
+      continue;
+    for (i=0; opts[i].name; i++)
+    {
+      if (!my_strnncoll(&my_charset_latin1,
+                        (const uchar *)p, e - p,
+                        (const uchar *)opts[i].name, strlen(opts[i].name)))
+      {
+        val= val | opts[i].val;
+        break;
+      }
+    }
+    if (opts[i].val == invalid_val)
+      return invalid_val;
+    if (!*e)
+      break;
+    p= e + 1;
+  }
+  return val;
+}
+
+const char *msl_option_get_name(const struct msl_opts *opts, ulong val)
+{
+  for (ulong i=0; opts[i].name && opts[i].name[0]; i++)
+  {
+    if (opts[i].val == val)
+      return opts[i].name;
+  }
+  return "*INVALID*";
+}
+
+char *msl_flag_get_name(const struct msl_opts *opts, char *buf, ulong val)
+{
+  uint offset= 0;
+  
+  *buf= '\0';
+  for (ulong i=0; opts[i].name && opts[i].name[0]; i++)
+  {
+    if (opts[i].val & val)
+      offset+= snprintf(buf+offset, STRING_BUFFER_USUAL_SIZE - offset - 1,
+                        "%s%s", (offset ? "," : ""), opts[i].name);
+  }
+  return buf;
+}
+
+/****************************************************************************
+ Functions to handle log_slow_verbosity
+****************************************************************************/
+
+/* Based upon sys_var::check_enum() */
+
+bool sys_var_thd_msl_option::check(THD *thd, set_var *var)
+{
+  char buff[STRING_BUFFER_USUAL_SIZE];
+  String str(buff, sizeof(buff), &my_charset_latin1), *res;
+
+  if (var->value->result_type() == STRING_RESULT)
+  {
+    ulong verb= this->invalid_val;
+    if (!(res=var->value->val_str(&str)) ||
+	      (var->save_result.ulong_value=
+          (ulong) (verb= msl_option_resolve_by_name(this->opts, res->ptr(), res->length()))) == this->invalid_val)
+      goto err;
+    return 0;
+  }
+
+err:
+  my_error(ER_WRONG_ARGUMENTS, MYF(0), var->var->name);
+  return 1;
+}
+
+byte *sys_var_thd_msl_option::value_ptr(THD *thd, enum_var_type type,
+					LEX_STRING *base)
+{
+  ulong val;
+  val= ((type == OPT_GLOBAL) ? global_system_variables.*offset :
+        thd->variables.*offset);
+  const char *verbosity= msl_option_get_name(this->opts, val);
+  return (byte *) verbosity;
+}
+
+
+void sys_var_thd_msl_option::set_default(THD *thd, enum_var_type type)
+{
+  if (type == OPT_GLOBAL)
+    global_system_variables.*offset= (ulong) this->default_val;
+  else
+    thd->variables.*offset= (ulong) (global_system_variables.*offset);
+}
+
+
+bool sys_var_thd_msl_option::update(THD *thd, set_var *var)
+{
+  if (var->type == OPT_GLOBAL)
+    global_system_variables.*offset= var->save_result.ulong_value;
+  else
+    thd->variables.*offset= var->save_result.ulong_value;
+  return 0;
+}
+
+/****************************************************************************
+ Functions to handle log_slow_filter
+****************************************************************************/
+  
+/* Based upon sys_var::check_enum() */
+
+bool sys_var_thd_msl_flag::check(THD *thd, set_var *var)
+{
+  char buff[2 * STRING_BUFFER_USUAL_SIZE];
+  String str(buff, sizeof(buff), &my_charset_latin1), *res;
+
+  if (var->value->result_type() == STRING_RESULT)
+  {
+    ulong filter= this->none_val;
+    if (!(res=var->value->val_str(&str)) ||
+	 (var->save_result.ulong_value=
+          (ulong) (filter= msl_flag_resolve_by_name(this->flags, res->ptr(), this->none_val, 
+                                                    this->invalid_val))) == this->invalid_val)
+      goto err;
+    return 0;
+  }
+
+err:
+  my_error(ER_WRONG_ARGUMENTS, MYF(0), var->var->name);
+  return 1;
+}
+
+byte *sys_var_thd_msl_flag::value_ptr(THD *thd, enum_var_type type,
+					LEX_STRING *base)
+{
+  ulong val;
+  val= ((type == OPT_GLOBAL) ? global_system_variables.*offset :
+        thd->variables.*offset);
+  msl_flag_get_name(this->flags, this->flags_string, val);
+  return (byte *) this->flags_string;
+}
+
+
+void sys_var_thd_msl_flag::set_default(THD *thd, enum_var_type type)
+{
+  if (type == OPT_GLOBAL)
+    global_system_variables.*offset= (ulong) this->default_val;
+  else
+    thd->variables.*offset= (ulong) (global_system_variables.*offset);
+}
+
+
+bool sys_var_thd_msl_flag::update(THD *thd, set_var *var)
+{
+  if (var->type == OPT_GLOBAL)
+    global_system_variables.*offset= var->save_result.ulong_value;
+  else
+    thd->variables.*offset= var->save_result.ulong_value;
+  return 0;
+}
+
 /****************************************************************************
  Functions to handle table_type
 ****************************************************************************/
diff -r ab59095a9cbf sql/set_var.h
--- a/sql/set_var.h	Tue Aug 14 12:28:04 2007 +0200
+++ b/sql/set_var.h	Mon Apr 07 14:30:21 2008 +0200
@@ -123,6 +123,7 @@
 };
 
 
+
 class sys_var_ulonglong_ptr :public sys_var
 {
 public:
@@ -287,7 +288,6 @@
   }
 };
 
-
 class sys_var_thd_ulong :public sys_var_thd
 {
   sys_check_func check_func;
@@ -307,6 +307,23 @@
   byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
 };
 
+class sys_var_thd_microtime :public sys_var_thd
+{
+public:
+  ulonglong SV::*offset;
+  sys_var_thd_microtime(const char *name_arg, ulonglong SV::*offset_arg)
+    :sys_var_thd(name_arg), offset(offset_arg)
+  {}
+  bool update(THD *thd, set_var *var);
+  void set_default(THD *thd, enum_var_type type);
+  SHOW_TYPE type() { return SHOW_MICROTIME; }
+  byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+  bool check(THD *thd, set_var *var);
+  bool check_update_type(Item_result type)
+  { 
+    return type != INT_RESULT && type != DECIMAL_RESULT;
+  }
+};
 
 class sys_var_thd_ha_rows :public sys_var_thd
 {
@@ -324,7 +341,6 @@
   SHOW_TYPE show_type() { return SHOW_HA_ROWS; }
   byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
 };
-
 
 class sys_var_thd_ulonglong :public sys_var_thd
 {
@@ -353,7 +369,6 @@
   }
 };
 
-
 class sys_var_thd_bool :public sys_var_thd
 {
 public:
@@ -423,6 +438,66 @@
                                             ulong *length);
 };
 
+
+class sys_var_thd_msl_option :public sys_var_thd
+{
+protected:
+  ulong SV::*offset;
+  const ulong none_val;
+  const ulong default_val;
+  const ulong invalid_val;
+  const struct msl_opts *opts;
+public:
+  sys_var_thd_msl_option(const char *name_arg, ulong SV::*offset_arg,
+                         const ulong none_val_arg,
+                         const ulong default_val_arg,
+                         const ulong invalid_val_arg,
+                         const struct msl_opts *opts_arg)
+    :sys_var_thd(name_arg), offset(offset_arg), none_val(none_val_arg),
+     default_val(default_val_arg), invalid_val(invalid_val_arg), 
+     opts(opts_arg)
+  {}
+  bool check(THD *thd, set_var *var);
+  SHOW_TYPE show_type() { return SHOW_CHAR; }
+  bool check_update_type(Item_result type)
+  {
+    return type != STRING_RESULT;		/* Only accept strings */
+  }
+  void set_default(THD *thd, enum_var_type type);
+  bool update(THD *thd, set_var *var);
+  byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+};
+
+
+class sys_var_thd_msl_flag :public sys_var_thd
+{
+protected:
+  char flags_string[2 * STRING_BUFFER_USUAL_SIZE];
+  ulong SV::*offset;
+  const ulong none_val;
+  const ulong default_val;
+  const ulong invalid_val;
+  const struct msl_opts *flags;
+public:
+  sys_var_thd_msl_flag(const char *name_arg, ulong SV::*offset_arg, 
+                       const ulong none_val_arg, 
+                       const ulong default_val_arg, 
+                       const ulong invalid_val_arg,
+                       const struct msl_opts *flags_arg)
+    :sys_var_thd(name_arg), offset(offset_arg), none_val(none_val_arg),
+     default_val(default_val_arg), invalid_val(invalid_val_arg), 
+     flags(flags_arg)
+  {}
+  bool check(THD *thd, set_var *var);
+  SHOW_TYPE show_type() { return SHOW_CHAR; }
+  bool check_update_type(Item_result type)
+  {
+    return type != STRING_RESULT;		/* Only accept strings */
+  }
+  void set_default(THD *thd, enum_var_type type);
+  bool update(THD *thd, set_var *var);
+  byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+};
 
 class sys_var_thd_storage_engine :public sys_var_thd
 {
@@ -1018,3 +1093,11 @@
 bool process_key_caches(int (* func) (const char *name, KEY_CACHE *));
 void delete_elements(I_List<NAMED_LIST> *list,
 		     void (*free_element)(const char*, gptr));
+
+/* Slow log functions */
+
+ulong msl_option_resolve_by_name(const struct msl_opts *opts, const char *name, ulong len);
+ulong msl_flag_resolve_by_name(const struct msl_opts *opts, const char *names_list, 
+                               const ulong none_val, const ulong invalid_val);
+const char *msl_option_get_name(const struct msl_opts *opts, ulong val);
+char *msl_flag_get_name(const struct msl_opts *opts, char *buf, ulong val);
diff -r ab59095a9cbf sql/slave.cc
--- a/sql/slave.cc	Tue Aug 14 12:28:04 2007 +0200
+++ b/sql/slave.cc	Mon Apr 07 14:30:21 2008 +0200
@@ -2907,6 +2907,12 @@
     + MAX_LOG_EVENT_HEADER;  /* note, incr over the global not session var */
   thd->slave_thread = 1;
   set_slave_thread_options(thd);
+  if (opt_log_slow_slave_statements)
+  {
+    thd->enable_slow_log= TRUE;
+    /* Slave thread is excluded from rate limiting the slow log writes. */
+    thd->write_to_slow_log= TRUE;
+  }
   thd->client_capabilities = CLIENT_LOCAL_FILES;
   thd->real_id=pthread_self();
   pthread_mutex_lock(&LOCK_thread_count);
diff -r ab59095a9cbf sql/sql_cache.cc
--- a/sql/sql_cache.cc	Tue Aug 14 12:28:04 2007 +0200
+++ b/sql/sql_cache.cc	Mon Apr 07 14:30:21 2008 +0200
@@ -1297,6 +1297,7 @@
 
   thd->limit_found_rows = query->found_rows();
   thd->status_var.last_query_cost= 0.0;
+  thd->query_plan_flags|= QPLAN_QC;
 
   BLOCK_UNLOCK_RD(query_block);
   DBUG_RETURN(1);				// Result sent to client
@@ -1304,6 +1305,7 @@
 err_unlock:
   STRUCT_UNLOCK(&structure_guard_mutex);
 err:
+  thd->query_plan_flags|= QPLAN_QC_NO;
   DBUG_RETURN(0);				// Query was not cached
 }
 
diff -r ab59095a9cbf sql/sql_class.cc
--- a/sql/sql_class.cc	Tue Aug 14 12:28:04 2007 +0200
+++ b/sql/sql_class.cc	Mon Apr 07 14:30:21 2008 +0200
@@ -173,7 +173,7 @@
    Open_tables_state(refresh_version),
    lock_id(&main_lock_id),
    user_time(0), in_sub_stmt(0), global_read_lock(0), is_fatal_error(0),
-   rand_used(0), time_zone_used(0),
+   rand_used(0), time_zone_used(0), user_timer(0),
    last_insert_id_used(0), last_insert_id_used_bin_log(0), insert_id_used(0),
    clear_next_insert_id(0), in_lock_tables(0), bootstrap(0),
    derived_tables_processing(FALSE), spcont(NULL), m_lip(NULL)
@@ -2101,6 +2101,12 @@
   backup->cuted_fields=     cuted_fields;
   backup->client_capabilities= client_capabilities;
   backup->savepoints= transaction.savepoints;
+  backup->innodb_io_reads= innodb_io_reads;
+  backup->innodb_io_read= innodb_io_read;
+  backup->innodb_io_reads_wait_timer= innodb_io_reads_wait_timer;
+  backup->innodb_lock_que_wait_timer= innodb_lock_que_wait_timer;
+  backup->innodb_innodb_que_wait_timer= innodb_innodb_que_wait_timer;
+  backup->innodb_page_access= innodb_page_access;
 
   if (!lex->requires_prelocking() || is_update_query(lex->sql_command))
     options&= ~OPTION_BIN_LOG;
@@ -2117,7 +2123,13 @@
   sent_row_count= 0;
   cuted_fields= 0;
   transaction.savepoints= 0;
-
+  innodb_io_reads= 0;
+  innodb_io_read= 0;
+  innodb_io_reads_wait_timer= 0;
+  innodb_lock_que_wait_timer= 0;
+  innodb_innodb_que_wait_timer= 0;
+  innodb_page_access= 0;
+  
   /* Surpress OK packets in case if we will execute statements */
   net.no_send_ok= TRUE;
 }
@@ -2163,6 +2175,12 @@
   */
   examined_row_count+= backup->examined_row_count;
   cuted_fields+=       backup->cuted_fields;
+  innodb_io_reads+= backup->innodb_io_reads;
+  innodb_io_read+= backup->innodb_io_read;
+  innodb_io_reads_wait_timer+= backup->innodb_io_reads_wait_timer;
+  innodb_lock_que_wait_timer+= backup->innodb_lock_que_wait_timer;
+  innodb_innodb_que_wait_timer+= backup->innodb_innodb_que_wait_timer;
+  innodb_page_access+= backup->innodb_page_access;
 }
 
 
diff -r ab59095a9cbf sql/sql_class.h
--- a/sql/sql_class.h	Tue Aug 14 12:28:04 2007 +0200
+++ b/sql/sql_class.h	Mon Apr 07 14:30:21 2008 +0200
@@ -43,6 +43,13 @@
 extern char internal_table_name[2];
 extern char empty_c_string[1];
 extern const char **errmesg;
+#ifdef __cplusplus
+__BEGIN_DECLS
+#endif
+extern ulonglong frequency;
+#ifdef __cplusplus
+__END_DECLS
+#endif
 
 #define TC_LOG_PAGE_SIZE   8192
 #define TC_LOG_MIN_SIZE    (3*TC_LOG_PAGE_SIZE)
@@ -308,7 +315,7 @@
   bool write(THD *thd, enum enum_server_command command,
 	     const char *format, ...) ATTRIBUTE_FORMAT(printf, 4, 5);
   bool write(THD *thd, const char *query, uint query_length,
-	     time_t query_start=0);
+	     time_t query_start=0, ulonglong query_start_timer=0);
   bool write(Log_event* event_info); // binary log write
   bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event);
 
@@ -514,13 +521,14 @@
   ulong auto_increment_increment, auto_increment_offset;
   ulong bulk_insert_buff_size;
   ulong join_buff_size;
-  ulong long_query_time;
+  ulonglong long_query_time;
   ulong max_allowed_packet;
   ulong max_error_count;
   ulong max_length_for_sort_data;
   ulong max_sort_length;
   ulong max_tmp_tables;
   ulong max_insert_delayed_threads;
+  ulong min_examined_row_limit;
   ulong multi_range_count;
   ulong myisam_repair_threads;
   ulong myisam_sort_buff_size;
@@ -536,10 +544,13 @@
   ulong preload_buff_size;
   ulong profiling_history_size;
   ulong query_cache_type;
+  ulong log_slow_rate_limit;
   ulong read_buff_size;
   ulong read_rnd_buff_size;
   ulong div_precincrement;
   ulong sortbuff_size;
+  ulong log_slow_filter;
+  ulong log_slow_verbosity;
   ulong table_type;
   ulong tx_isolation;
   ulong completion_type;
@@ -1086,6 +1097,12 @@
   uint in_sub_stmt;
   bool enable_slow_log, insert_id_used, clear_next_insert_id;
   bool last_insert_id_used;
+  ulong      innodb_io_reads;
+  ulonglong  innodb_io_read;
+  ulong      innodb_io_reads_wait_timer;
+  ulong      innodb_lock_que_wait_timer;
+  ulong      innodb_innodb_que_wait_timer;
+  ulong      innodb_page_access;
   my_bool no_send_ok;
   SAVEPOINT *savepoints;
 };
@@ -1142,6 +1159,11 @@
 class THD :public Statement,
            public Open_tables_state
 {
+private:
+  inline ulonglong query_start_timer() { return start_timer; }
+  inline void set_timer()    { if (user_timer) start_timer=timer_after_lock=user_timer; else timer_after_lock=my_timer(&start_timer, frequency); }
+  inline void end_timer()    { my_timer(&start_timer, frequency); }
+  inline void lock_timer()   { my_timer(&timer_after_lock, frequency); }
 public:
   /*
     Constant for THD::where initialization in the beginning of every query.
@@ -1250,10 +1272,24 @@
   */
   const char *where;
   time_t     start_time,time_after_lock,user_time;
+  ulonglong start_timer,timer_after_lock, user_timer;
   time_t     connect_time,thr_create_time; // track down slow pthread_create
   thr_lock_type update_lock_default;
   Delayed_insert *di;
 
+  bool       write_to_slow_log;
+
+  bool       innodb_was_used;
+  ulong      innodb_io_reads;
+  ulonglong  innodb_io_read;
+  ulong      innodb_io_reads_wait_timer;
+  ulong      innodb_lock_que_wait_timer;
+  ulong      innodb_innodb_que_wait_timer;
+  ulong      innodb_page_access;
+
+  ulong      query_plan_flags;
+  ulong      query_plan_fsort_passes;
+  
   /* <> 0 if we are inside of trigger or stored function. */
   uint in_sub_stmt;
 
@@ -1589,11 +1625,11 @@
     proc_info = old_msg;
     pthread_mutex_unlock(&mysys_var->mutex);
   }
-  inline time_t query_start() { query_start_used=1; return start_time; }
-  inline void	set_time()    { if (user_time) start_time=time_after_lock=user_time; else time_after_lock=time(&start_time); }
-  inline void	end_time()    { time(&start_time); }
-  inline void	set_time(time_t t) { time_after_lock=start_time=user_time=t; }
-  inline void	lock_time()   { time(&time_after_lock); }
+  inline time_t query_start() { query_start_timer(); query_start_used=1; return start_time; }
+  inline void set_time()    { set_timer(); if (user_time) start_time=time_after_lock=user_time; else time_after_lock=time(&start_time); }
+  inline void	end_time()    { end_timer(); time(&start_time); }
+  inline void	set_time(time_t t) { set_timer(); time_after_lock=start_time=user_time=t; }
+  inline void	lock_time()   { lock_timer(); time(&time_after_lock); }
   inline void	insert_id(ulonglong id_arg)
   {
     last_insert_id= id_arg;
diff -r ab59095a9cbf sql/sql_parse.cc
--- a/sql/sql_parse.cc	Tue Aug 14 12:28:04 2007 +0200
+++ b/sql/sql_parse.cc	Mon Apr 07 14:30:21 2008 +0200
@@ -20,6 +20,7 @@
 #include <m_ctype.h>
 #include <myisam.h>
 #include <my_dir.h>
+#include <my_time.h>
 
 #ifdef HAVE_INNOBASE_DB
 #include "ha_innodb.h"
@@ -1190,6 +1191,15 @@
     my_net_set_read_timeout(net, thd->variables.net_read_timeout);
     my_net_set_write_timeout(net, thd->variables.net_write_timeout);
 
+    /*
+      If rate limiting of slow log writes is enabled, decide whether to log this
+      new thread's queries or not. Uses extremely simple algorithm. :)
+    */
+    thd->write_to_slow_log= FALSE;
+    if (thd->variables.log_slow_rate_limit <= 1 || 
+        (thd->thread_id % thd->variables.log_slow_rate_limit) == 0)
+         thd->write_to_slow_log= TRUE;
+
     while (!net->error && net->vio != 0 &&
            !(thd->killed == THD::KILL_CONNECTION))
     {
@@ -2193,27 +2203,52 @@
     return;                                     // Don't set time for sub stmt
 
   start_of_query= thd->start_time;
+  ulonglong start_of_query_timer= thd->start_timer;
   thd->end_time();				// Set start time
+
+  /* Follow the slow log filter configuration. */
+  if (thd->variables.log_slow_filter != SLOG_F_NONE && 
+      (!(thd->variables.log_slow_filter & thd->query_plan_flags) ||
+       ((thd->variables.log_slow_filter & SLOG_F_QC_NO) && 
+        (thd->query_plan_flags & QPLAN_QC))))
+  return;
+
+  /*
+    Low long_query_time value most likely means user is debugging stuff and even 
+    though some thread's queries are not supposed to be logged b/c of the rate 
+    limit, if one of them takes long enough (>= 1 second) it will be sensible 
+    to make an exception and write to slow log anyway.
+  */
+  if (thd->write_to_slow_log != TRUE && thd->variables.long_query_time < 1000000 &&
+      (ulong) (thd->start_timer - thd->timer_after_lock) >= 1000000)
+       thd->write_to_slow_log= TRUE;
+
+  /* Do not log this thread's queries due to rate limiting. */
+  if (thd->write_to_slow_log != TRUE)
+    return;
 
   /*
     Do not log administrative statements unless the appropriate option is
     set; do not log into slow log if reading from backup.
   */
-  if (thd->enable_slow_log && !thd->user_time)
+  if (thd->enable_slow_log &&
+      (!thd->user_time || (thd->slave_thread && opt_log_slow_slave_statements))
+     )
   {
     thd_proc_info(thd, "logging slow query");
 
-    if ((ulong) (thd->start_time - thd->time_after_lock) >
-	thd->variables.long_query_time ||
-        (thd->server_status &
-	  (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
-        (specialflag & SPECIAL_LOG_QUERIES_NOT_USING_INDEXES) &&
-        /* == SQLCOM_END unless this is a SHOW command */
-        thd->lex->orig_sql_command == SQLCOM_END)
+    if (((ulong) (thd->start_timer - thd->timer_after_lock) >=
+         thd->variables.long_query_time ||
+         (thd->server_status &
+              (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
+         (specialflag & SPECIAL_LOG_QUERIES_NOT_USING_INDEXES) &&
+         /* == SQLCOM_END unless this is a SHOW command */
+         thd->lex->orig_sql_command == SQLCOM_END) &&
+        thd->examined_row_count >= thd->variables.min_examined_row_limit)
     {
       thd_proc_info(thd, "logging slow query");
       thd->status_var.long_query_count++;
-      mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
+      mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query, start_of_query_timer);
     }
   }
 }
@@ -5867,6 +5902,16 @@
     thd->total_warn_count=0;			// Warnings for this query
     thd->rand_used= 0;
     thd->sent_row_count= thd->examined_row_count= 0;
+    thd->innodb_was_used= FALSE;
+    thd->innodb_io_reads= 0;
+    thd->innodb_io_read= 0;
+    thd->innodb_io_reads_wait_timer= 0;
+    thd->innodb_lock_que_wait_timer= 0;
+    thd->innodb_innodb_que_wait_timer= 0;
+    thd->innodb_page_access= 0;
+    thd->query_plan_flags= QPLAN_NONE;
+    thd->query_plan_fsort_passes= 0;
+    
 #ifdef ENABLED_PROFILING
     thd->profiling.reset();
 #endif
diff -r ab59095a9cbf sql/sql_select.cc
--- a/sql/sql_select.cc	Tue Aug 14 12:28:04 2007 +0200
+++ b/sql/sql_select.cc	Mon Apr 07 14:30:21 2008 +0200
@@ -6170,8 +6170,11 @@
 	  {
 	    join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
 	    if (statistics)
+	    {
 	      statistic_increment(join->thd->status_var.select_scan_count,
 				  &LOCK_status);
+				join->thd->query_plan_flags|= QPLAN_FULL_SCAN;
+      }
 	  }
 	}
 	else
@@ -6186,8 +6189,11 @@
 	  {
 	    join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
 	    if (statistics)
+	    {
 	      statistic_increment(join->thd->status_var.select_full_join_count,
 				  &LOCK_status);
+				join->thd->query_plan_flags|= QPLAN_FULL_JOIN;
+      }
 	  }
 	}
 	if (!table->no_keyread)
@@ -9201,6 +9207,7 @@
 		      (ulong) rows_limit,test(group)));
 
   statistic_increment(thd->status_var.created_tmp_tables, &LOCK_status);
+  thd->query_plan_flags|= QPLAN_TMP_TABLE;
 
   if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES))
     temp_pool_slot = bitmap_set_next(&temp_pool);
@@ -10064,6 +10071,7 @@
   }
   statistic_increment(table->in_use->status_var.created_tmp_disk_tables,
 		      &LOCK_status);
+	table->in_use->query_plan_flags|= QPLAN_TMP_DISK;
   table->s->db_record_offset= 1;
   DBUG_RETURN(0);
  err:
diff -r ab59095a9cbf sql/sql_show.cc
--- a/sql/sql_show.cc	Tue Aug 14 12:28:04 2007 +0200
+++ b/sql/sql_show.cc	Mon Apr 07 14:30:21 2008 +0200
@@ -1467,6 +1467,9 @@
           value= ((char *) status_var + (ulonglong) value);
         case SHOW_LONGLONG:
           end= longlong10_to_str(*(longlong*) value, buff, 10);
+          break;
+        case SHOW_MICROTIME:
+          end= buff + sprintf(buff, "%.6f", (*(ulonglong*)value) / 1000000.0);
           break;
         case SHOW_HA_ROWS:
           end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10);
diff -r ab59095a9cbf sql/structs.h
--- a/sql/structs.h	Tue Aug 14 12:28:04 2007 +0200
+++ b/sql/structs.h	Mon Apr 07 14:30:21 2008 +0200
@@ -168,8 +168,8 @@
 enum SHOW_TYPE
 {
   SHOW_UNDEF,
-  SHOW_LONG, SHOW_LONGLONG, SHOW_INT, SHOW_CHAR, SHOW_CHAR_PTR, 
-  SHOW_DOUBLE_STATUS,
+  SHOW_LONG, SHOW_LONGLONG, SHOW_MICROTIME, SHOW_INT, SHOW_CHAR, 
+  SHOW_CHAR_PTR, SHOW_DOUBLE_STATUS, 
   SHOW_BOOL, SHOW_MY_BOOL, SHOW_OPENTABLES, SHOW_STARTTIME, SHOW_QUESTION,
   SHOW_LONG_CONST, SHOW_INT_CONST, SHOW_HAVE, SHOW_SYS, SHOW_HA_ROWS,
   SHOW_VARS,

