--- orig/sql/sql_class.cc	2009-01-02 13:51:04.000000000 +0100
+++ byte/sql/sql_class.cc	2009-01-02 13:51:50.000000000 +0100
@@ -220,6 +220,8 @@
   bzero(ha_data, sizeof(ha_data));
   mysys_var=0;
   binlog_evt_union.do_union= FALSE;
+  busy_time = 0; //bbyte
+  updated_row_count = 0; //bbyte
 #ifndef DBUG_OFF
   dbug_sentry=THD_SENTRY_MAGIC;
 #endif
@@ -347,8 +349,57 @@
   total_warn_count= 0;
   update_charset();
   bzero((char *) &status_var, sizeof(status_var));
+  reset_stats(); //bbyte
 }
 
+// bbyte - begin
+// Resets stats in a THD.
+void THD::reset_stats(void) {
+  current_connect_time = time(NULL);
+  last_global_update_time = current_connect_time;
+  reset_diff_stats();
+}
+
+// Resets the 'diff' stats, which are used to update global stats.
+void THD::reset_diff_stats(void) {
+  diff_total_busy_time = 0;
+  diff_total_sent_rows = 0;
+  diff_total_updated_rows = 0;
+  diff_select_commands = 0;
+  diff_update_commands = 0;
+  diff_other_commands = 0;
+  //diff_commit_trans = 0;
+  //diff_rollback_trans = 0;
+}
+
+// Updates 'diff' stats of a THD.
+void THD::update_stats() {
+  diff_total_busy_time += busy_time;
+  diff_total_sent_rows += sent_row_count;
+  diff_total_updated_rows += updated_row_count;
+  // The replication thread has the COM_CONNECT command.
+  if ((old_command == COM_QUERY || command == COM_CONNECT) &&
+      (lex->sql_command >= 0 && lex->sql_command < SQLCOM_END)) {
+    // A SQL query.
+    if (lex->sql_command == SQLCOM_SELECT) {
+      if (lex->orig_sql_command == SQLCOM_END) {
+        diff_select_commands++;
+      } else {
+        // 'SHOW ' commands become SQLCOM_SELECT.
+        diff_other_commands++;
+        // 'SHOW ' commands shouldn't inflate total sent row count.
+        diff_total_sent_rows -= sent_row_count;
+      }
+    } else if (is_update_query(lex->sql_command)) {
+      diff_update_commands++;
+    } else {
+      diff_other_commands++;
+    }
+  }
+  // diff_commit_trans is updated in handler.cc.
+  // diff_rollback_trans is updated in handler.cc.
+}
+// bbyte - end
 
 /*
   Init THD for query processing.
--- orig/sql/sql_class.h	2009-01-02 13:51:04.000000000 +0100
+++ byte/sql/sql_class.h	2009-01-02 13:51:49.000000000 +0100
@@ -1241,6 +1241,11 @@
     first byte of the packet in do_command()
   */
   enum enum_server_command command;
+  // bbyte - begin
+  // Used to save the command, before it is set to COM_SLEEP.
+  enum enum_server_command old_command;
+  // bbyte - end
+ 
   uint32     server_id;
   uint32     file_id;			// for LOAD DATA INFILE
   /*
@@ -1355,6 +1360,7 @@
   longlong   row_count_func;	/* For the ROW_COUNT() function */
   ha_rows    cuted_fields,
              sent_row_count, examined_row_count;
+  ha_rows    updated_row_count; // bbyte
   /*
     The set of those tables whose fields are referenced in all subqueries
     of the query.
@@ -1482,6 +1488,31 @@
   */
   LOG_INFO*  current_linfo;
   NET*       slave_net;			// network connection from slave -> m.
+
+  //bbyte - begin 
+    /*
+       Used to update global user stats.  The global user stats are updated
+       occasionally with the 'diff' variables.  After the update, the 'diff'
+       variables are reset to 0.
+    */
+  // Time when the current thread connected to MySQL.
+  time_t current_connect_time;
+  // Last time when THD stats were updated in global_user_stats.
+  time_t last_global_update_time;
+  // Busy (non-idle) time for just one command.
+  double busy_time;
+  // Busy time not updated in global_user_stats yet.
+  double diff_total_busy_time;
+  // Number of rows not reflected in global_user_stats yet.
+  ha_rows diff_total_sent_rows, diff_total_updated_rows;
+  // Number of commands not reflected in global_user_stats yet.
+  ulonglong diff_select_commands, diff_update_commands, diff_other_commands;
+  // Number of transactions not reflected in global_user_stats yet.
+  //ulonglong diff_commit_trans, diff_rollback_trans;
+
+  // bbyte - end
+
+
   /* Used by the sys_var class to store temporary values */
   union
   {
@@ -1539,6 +1570,11 @@
     alloc_root.
   */
   void init_for_queries();
+  //bbyte - begin
+  void reset_stats(void);
+  void reset_diff_stats(void);
+  void update_stats(void);
+  //bbyte - end
   void change_user(void);
   void cleanup(void);
   void cleanup_after_query();
--- orig/sql/byte_stats.cc	1970-01-01 01:00:00.000000000 +0100
+++ byte/sql/byte_stats.cc	2009-01-02 13:51:50.000000000 +0100
@@ -0,0 +1,211 @@
+// bbyte - begin
+#include "byte_stats.h"
+
+pthread_mutex_t LOCK_global_user_stats;
+HASH global_user_stats;
+
+extern "C" byte *get_key_user_stats(USER_STATS *user_stats, uint *length,
+                                    my_bool not_used __attribute__((unused)))
+{
+  *length = strlen(user_stats->user);
+  return (byte*)user_stats->user;
+}
+
+extern "C" void free_user_stats(USER_STATS* user_stats)
+{
+  my_free((char*)user_stats, MYF(0));
+}
+
+void init_global_user_stats(void)
+{
+  if (hash_init(&global_user_stats, system_charset_info, max_connections,
+                0, 0, (hash_get_key)get_key_user_stats,
+                (hash_free_key)free_user_stats, 0)) {
+    sql_print_error("Initializing global_user_stats failed.");
+    exit(1);
+  }
+}
+
+void free_global_user_stats(void)
+{
+  hash_free(&global_user_stats);
+}
+
+
+// 'mysql_system_user' is used for when the user is not defined for a THD.
+static char mysql_system_user[] = "#mysql_system#";
+
+// Returns 'user' if it's not NULL.  Returns 'mysql_system_user' otherwise.
+static char* get_valid_user_string(char* user) {
+  return user ? user : mysql_system_user;
+}
+
+// Increments the global user stats connection count.  If 'use_lock' is true,
+// 'LOCK_global_user_stats' will be locked/unlocked.  Returns 0 on success,
+// 1 on error.
+int increment_connection_count(THD* thd, bool use_lock) {
+  char* user_string = get_valid_user_string(thd->main_security_ctx.user);
+
+  USER_STATS* user_stats;
+  int return_value = 0;
+
+  if (use_lock) pthread_mutex_lock(&LOCK_global_user_stats);
+  if (!(user_stats = (USER_STATS*)hash_search(&global_user_stats,
+                                              (byte*)user_string,
+                                              strlen(user_string)))) {
+    // First connection for this user.
+    if (!(user_stats = ((USER_STATS*)
+                        my_malloc(sizeof(USER_STATS), MYF(MY_WME))))) {
+      // Out of memory.
+      return_value = 1;
+      goto end;
+    }
+    strncpy(user_stats->user, user_string, sizeof(user_stats->user));
+    user_stats->total_connections = 0;
+    user_stats->concurrent_connections = 0;
+    user_stats->connected_time = 0;
+    user_stats->busy_time = 0;
+    user_stats->rows_fetched = 0;
+    user_stats->rows_updated = 0;
+    user_stats->select_commands = 0;
+    user_stats->update_commands = 0;
+    user_stats->other_commands = 0;
+    //user_stats->commit_trans = 0;
+    //user_stats->rollback_trans = 0;
+
+    if (my_hash_insert(&global_user_stats, (byte*)user_stats)) {
+      // Out of memory.
+      my_free((char*)user_stats, 0);
+      return_value = 1;
+      goto end;
+    }
+  }
+  user_stats->total_connections++;
+end:
+  if (use_lock) pthread_mutex_unlock(&LOCK_global_user_stats);
+  return return_value;
+}
+// Used to update the global user stats.
+static void update_global_user_stats_with_user(THD* thd,
+                                               USER_STATS* user_stats) {
+  time_t current_time = time(NULL);
+  user_stats->connected_time += current_time - thd->last_global_update_time;
+  thd->last_global_update_time = current_time;
+  user_stats->busy_time += thd->diff_total_busy_time;
+  user_stats->rows_fetched += thd->diff_total_sent_rows;
+  user_stats->rows_updated += thd->diff_total_updated_rows;
+  user_stats->select_commands += thd->diff_select_commands;
+  user_stats->update_commands += thd->diff_update_commands;
+  user_stats->other_commands += thd->diff_other_commands;
+  //user_stats->commit_trans += thd->diff_commit_trans;
+  //user_stats->rollback_trans += thd->diff_rollback_trans;
+}
+
+// Updates the global stats of a thread/user.
+void update_global_user_stats(THD* thd) {
+  char* user_string = get_valid_user_string(thd->main_security_ctx.user);
+
+  USER_STATS* user_stats;
+  pthread_mutex_lock(&LOCK_global_user_stats);
+  if ((user_stats = (USER_STATS*)hash_search(&global_user_stats,
+                                             (byte*)user_string,
+                                             strlen(user_string)))) {
+    // Found user.
+    update_global_user_stats_with_user(thd, user_stats);
+    thd->reset_diff_stats();
+  } else {
+    // The user name should exist.
+    increment_connection_count(thd, false);
+  }
+  pthread_mutex_unlock(&LOCK_global_user_stats);
+}
+
+// Determines the concurrent number of connections of current threads.
+void set_concurrent_connections_stats() {
+  USER_STATS* user_stats;
+
+  pthread_mutex_lock(&LOCK_global_user_stats);
+  pthread_mutex_lock(&LOCK_thread_count);
+
+  // Resets all concurrent connections to 0.
+  for (int i = 0; i < global_user_stats.records; ++i) {
+    user_stats = (USER_STATS*)hash_element(&global_user_stats, i);
+    user_stats->concurrent_connections = 0;
+  }
+
+  I_List_iterator<THD> it(threads);
+  THD* thd;
+  // Iterates through the current threads.
+  while ((thd = it++)) {
+    char* user_string = get_valid_user_string(thd->main_security_ctx.user);
+    if ((user_stats = (USER_STATS*)hash_search(&global_user_stats,
+                                               (byte*)user_string,
+                                               strlen(user_string)))) {
+      // Found user.
+      user_stats->concurrent_connections++;
+      update_global_user_stats_with_user(thd, user_stats);
+      thd->reset_diff_stats();
+    } else {
+      // The user name should exist.
+      increment_connection_count(thd, false);
+    }
+  }
+  pthread_mutex_unlock(&LOCK_thread_count);
+  pthread_mutex_unlock(&LOCK_global_user_stats);
+}
+
+// Sends the global user stats back to the client.
+int mysqld_show_user_stats(THD *thd, const char *wild) {
+  Protocol *protocol= thd->protocol;
+  List<Item> field_list;
+
+  DBUG_ENTER("mysqld_show_user_stats");
+  field_list.push_back(new Item_empty_string("User", USERNAME_LENGTH + 1));
+  field_list.push_back(new Item_int("Total_connections", 0));
+  field_list.push_back(new Item_int("Concurrent_connections", 0));
+  field_list.push_back(new Item_int("Connected_time", 0));
+  field_list.push_back(new Item_int("Busy_time", 0));
+  field_list.push_back(new Item_int("Rows_fetched", 0));
+  field_list.push_back(new Item_int("Rows_updated", 0));
+  field_list.push_back(new Item_int("Select_commands", 0));
+  field_list.push_back(new Item_int("Update_commands", 0));
+  field_list.push_back(new Item_int("Other_commands", 0));
+  //field_list.push_back(new Item_int("Commit_transactions", 0));
+  //field_list.push_back(new Item_int("Rollback_transactions", 0));
+  if (protocol->send_fields(&field_list,
+                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+    DBUG_RETURN(TRUE); /* purecov: inspected */
+
+  // Iterates through all the global stats and sends them to the client.
+  // Pattern matching on the username is supported.
+  pthread_mutex_lock(&LOCK_global_user_stats);
+  for (int i = 0; i < global_user_stats.records; ++i) {
+    USER_STATS *user_stats = (USER_STATS*)hash_element(&global_user_stats, i);
+    if (!(wild && wild[0] &&
+          wild_case_compare(system_charset_info, user_stats->user, wild))) {
+      protocol->prepare_for_resend();
+      protocol->store(user_stats->user, system_charset_info);
+      protocol->store((longlong)user_stats->total_connections);
+      protocol->store((longlong)user_stats->concurrent_connections);
+      protocol->store((longlong)user_stats->connected_time);
+      protocol->store((longlong)user_stats->busy_time);
+      protocol->store((longlong)user_stats->rows_fetched);
+      protocol->store((longlong)user_stats->rows_updated);
+      protocol->store((longlong)user_stats->select_commands);
+      protocol->store((longlong)user_stats->update_commands);
+      protocol->store((longlong)user_stats->other_commands);
+      //protocol->store((longlong)user_stats->commit_trans);
+      //protocol->store((longlong)user_stats->rollback_trans);
+      if (protocol->write())
+        goto err;                               /* purecov: inspected */
+    }
+  }
+  pthread_mutex_unlock(&LOCK_global_user_stats);
+  send_eof(thd);
+  DBUG_RETURN(FALSE);
+
+ err:
+  pthread_mutex_unlock(&LOCK_global_user_stats);
+  DBUG_RETURN(TRUE);
+}
+// bbyte - end
--- orig/sql/byte_stats.h	1970-01-01 01:00:00.000000000 +0100
+++ byte/sql/byte_stats.h	2009-01-02 13:51:50.000000000 +0100
@@ -0,0 +1,38 @@
+// bbyte - begin
+#ifndef __BYTE_STATS
+#define __BYTE_STATS
+#include "mysql_priv.h"
+#include "mysql_com.h"
+#include "hash.h"
+
+class THD;
+
+typedef struct st_user_stats {
+  char user[USERNAME_LENGTH + 1];
+  uint total_connections;
+  uint concurrent_connections;
+  time_t connected_time;  // in seconds
+  double busy_time;       // in seconds
+  ha_rows rows_fetched, rows_updated;
+  ulonglong select_commands, update_commands, other_commands;
+  //ulonglong commit_trans, rollback_trans;
+} USER_STATS;
+
+
+extern void free_global_user_stats(void);
+extern void init_global_user_stats(void);
+
+// Set stats for concurrent connections displayed by mysqld_show().
+extern void set_concurrent_connections_stats();
+// Increments connection count for user.
+extern int increment_connection_count(THD* thd, bool use_lock);
+// Uses the THD to update the global stats.
+extern void update_global_user_stats(THD* thd);
+
+int mysqld_show_user_stats(THD *thd, const char *wild);
+
+extern HASH global_user_stats;
+extern pthread_mutex_t LOCK_global_user_stats;
+
+#endif
+// bbyte - end
--- orig/sql/Makefile.am	2009-01-02 13:51:04.000000000 +0100
+++ byte/sql/Makefile.am	2009-01-02 13:51:50.000000000 +0100
@@ -69,7 +69,8 @@
 			sql_array.h sql_cursor.h \
 			examples/ha_example.h ha_archive.h \
 			examples/ha_tina.h ha_blackhole.h  \
-			ha_federated.h
+			ha_federated.h \
+			byte_stats.h # bbyte 
 mysqld_SOURCES =	sql_lex.cc sql_handler.cc \
 			item.cc item_sum.cc item_buff.cc item_func.cc \
 			item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
@@ -106,7 +107,8 @@
 			sp_cache.cc parse_file.cc sql_trigger.cc \
 			examples/ha_example.cc ha_archive.cc \
 			examples/ha_tina.cc ha_blackhole.cc \
-			ha_federated.cc
+			ha_federated.cc \
+			byte_stats.cc # bbyte
 
 gen_lex_hash_SOURCES =	gen_lex_hash.cc
 gen_lex_hash_LDADD =	$(LDADD) $(CXXLDFLAGS)
--- orig/sql/Makefile.in	2009-01-02 13:51:04.000000000 +0100
+++ byte/sql/Makefile.in	2009-01-02 13:51:50.000000000 +0100
@@ -152,7 +152,8 @@
 	sp_rcontext.$(OBJEXT) sp.$(OBJEXT) sp_cache.$(OBJEXT) \
 	parse_file.$(OBJEXT) sql_trigger.$(OBJEXT) \
 	ha_example.$(OBJEXT) ha_archive.$(OBJEXT) ha_tina.$(OBJEXT) \
-	ha_blackhole.$(OBJEXT) ha_federated.$(OBJEXT)
+	ha_blackhole.$(OBJEXT) ha_federated.$(OBJEXT) \
+	byte_stats.$(OBJEXT) # bbyte
 mysqld_OBJECTS = $(am_mysqld_OBJECTS)
 mysqld_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
 	$(am__DEPENDENCIES_2) $(am__DEPENDENCIES_2) \
@@ -512,7 +513,8 @@
 			sql_array.h sql_cursor.h \
 			examples/ha_example.h ha_archive.h \
 			examples/ha_tina.h ha_blackhole.h  \
-			ha_federated.h
+			ha_federated.h \
+			byte_stats.h # bbyte
 
 mysqld_SOURCES = sql_lex.cc sql_handler.cc \
 			item.cc item_sum.cc item_buff.cc item_func.cc \
@@ -550,7 +552,8 @@
 			sp_cache.cc parse_file.cc sql_trigger.cc \
 			examples/ha_example.cc ha_archive.cc \
 			examples/ha_tina.cc ha_blackhole.cc \
-			ha_federated.cc
+			ha_federated.cc \
+			byte_stats.cc # bbyte
 
 gen_lex_hash_SOURCES = gen_lex_hash.cc
 gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
--- orig/sql/lex.h	2009-01-02 13:51:04.000000000 +0100
+++ byte/sql/lex.h	2009-01-02 13:51:50.000000000 +0100
@@ -524,6 +524,7 @@
   { "USE",		SYM(USE_SYM)},
   { "USER",		SYM(USER)},
   { "USER_RESOURCES",	SYM(RESOURCES)},
+  { "USER_STATISTICS",	SYM(USER_STATS_SYM)}, /* bbyte */
   { "USE_FRM",		SYM(USE_FRM)},
   { "USING",		SYM(USING)},
   { "UTC_DATE",         SYM(UTC_DATE_SYM)},
--- orig/sql/mysqld.cc	2009-01-02 13:51:04.000000000 +0100
+++ byte/sql/mysqld.cc	2009-01-02 13:51:50.000000000 +0100
@@ -13,6 +13,7 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
+#include "byte_stats.h" // bbyte
 #include "mysql_priv.h"
 #include <m_ctype.h>
 #include <my_dir.h>
@@ -1170,6 +1171,7 @@
   x_free(opt_secure_file_priv);
   bitmap_free(&temp_pool);
   free_max_user_conn();
+  free_global_user_stats(); // bbyte
 #ifdef HAVE_REPLICATION
   end_slave_list();
   free_list(&replicate_do_db);
@@ -1284,6 +1286,7 @@
   (void) pthread_cond_destroy(&COND_thread_cache);
   (void) pthread_cond_destroy(&COND_flush_thread_cache);
   (void) pthread_cond_destroy(&COND_manager);
+  (void) pthread_mutex_destroy(&LOCK_global_user_stats); // bbyte
 }
 
 #endif /*EMBEDDED_LIBRARY*/
@@ -2983,6 +2986,7 @@
   (void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST);
   (void) pthread_cond_init(&COND_rpl_status, NULL);
 #endif
+  (void) pthread_mutex_init(&LOCK_global_user_stats, MY_MUTEX_INIT_FAST); // bbyte
   sp_cache_init();
   /* Parameter for threads created for connections */
   (void) pthread_attr_init(&connection_attrib);
@@ -3336,6 +3340,7 @@
 
   init_max_user_conn();
   init_update_queries();
+  init_global_user_stats(); // bbyte
   DBUG_RETURN(0);
 }
 
--- orig/sql/sql_lex.h	2009-01-02 13:51:04.000000000 +0100
+++ byte/sql/sql_lex.h	2009-01-02 13:51:50.000000000 +0100
@@ -100,6 +100,7 @@
     When a command is added here, be sure it's also added in mysqld.cc
     in "struct show_var_st status_vars[]= {" ...
   */
+  SQLCOM_SHOW_USER_STATS, // bbyte
   /* This should be the last !!! */
   SQLCOM_END
 };
--- orig/sql/sql_parse.cc	2009-01-02 13:51:04.000000000 +0100
+++ byte/sql/sql_parse.cc	2009-01-02 13:51:50.000000000 +0100
@@ -14,6 +14,7 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
 #define MYSQL_LEX 1
+#include "byte_stats.h" // bbyte
 #include "mysql_priv.h"
 #include "sql_repl.h"
 #include "repl_failsafe.h"
@@ -1089,6 +1090,7 @@
 
 pthread_handler_t handle_one_connection(void *arg)
 {
+  int aborted_connection = 0; //bbyte
   THD *thd=(THD*) arg;
   uint launch_time  =
     (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
@@ -1155,8 +1157,19 @@
 	my_sleep(1000);				/* must wait after eof() */
 #endif
       statistic_increment(aborted_connects,&LOCK_status);
+      aborted_connection = 1; //bbyte - do not increase statistics in end_thread
       goto end_thread;
     }
+
+    // bbyte - begin
+    thd->reset_stats();
+    // Updates global user connection stats.
+    if (increment_connection_count(thd, true)) {
+      net_send_error(thd, ER_OUTOFMEMORY);  // Out of memory
+      goto end_thread;
+    }
+    // bbyte - end
+
 #ifdef __NETWARE__
     netware_reg_user(sctx->ip, sctx->user, "MySQL");
 #endif
@@ -1218,6 +1231,12 @@
     
 end_thread:
     close_connection(thd, 0, 1);
+    //bbyte - begin
+    if (not aborted_connection){ 
+      //otherwise inexistent users that tried to login would appear in the stats
+      thd->update_stats(); 
+      update_global_user_stats(thd);
+    }//bbyte - end
     end_thread(thd,1);
     /*
       If end_thread returns, we are either running with --one-thread
@@ -1619,6 +1638,12 @@
   }
 
   thd->command=command;
+  // bbyte - begin
+  // To increment the corrent command counter for user stats, 'command' must
+  // be saved because it is set to COM_SLEEP at the end of this function.
+  thd->old_command = command;
+  // bbyte - end
+
   /*
     Commands which always take a long time are logged into
     the slow log only if opt_log_slow_admin_statements is set.
@@ -2802,6 +2827,17 @@
   }
 #endif
 
+  // bbyte - begin
+  case SQLCOM_SHOW_USER_STATS:
+  {
+    //allow only root to check statistics
+    if (check_global_access(thd, SUPER_ACL))
+      goto error;
+    set_concurrent_connections_stats();
+    res= mysqld_show_user_stats(thd, (lex->wild ? lex->wild->ptr() : NullS));
+    break;
+  }
+  // bbyte - end
   case SQLCOM_BACKUP_TABLE:
   {
     DBUG_ASSERT(first_table == all_tables && first_table != 0);
@@ -5870,6 +5906,8 @@
 #ifdef ENABLED_PROFILING
     thd->profiling.reset();
 #endif
+    thd->updated_row_count=0; // bbyte
+    thd->busy_time=0; // bbyte
   }
   DBUG_VOID_RETURN;
 }
@@ -6035,6 +6073,24 @@
 
   DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on(););
 
+  // bbyte - begin
+  int start_time_error = 0; 
+  int end_time_error = 0; 
+  struct timespec start_timespec,end_timespec;
+  double start_milisec = 0;
+  double end_milisec = 0;
+  
+  //Gets the start time, in order to measure how long this command takes.
+  if (!(start_time_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID,&start_timespec))) {
+    //start_timespec gives nanoseconds so divide to get msec
+    start_milisec = double(start_timespec.tv_sec)*1e3 + double(start_timespec.tv_nsec)/1e6; 
+  }
+  //if (strcasestr(inBuf,"select")){
+    //clock_getcpuclockid(getpid(),&clockid);
+    //fprintf(stderr,"%d:%d times %ld.%lds clock:%d\n",getpid(),pthread_self(),start_timespec.tv_sec,start_timespec.tv_nsec,clockid);
+  //}
+  // bbyte - end
+
   /*
     Warning.
     The purpose of query_cache_send_result_to_client() is to lookup the
@@ -6123,6 +6179,27 @@
     /* There are no multi queries in the cache. */
     *found_semicolon= NULL;
   }
+  // bbyte - begin
+  if (!(end_time_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID,&end_timespec))) {
+    //end_timespec gives nanoseconds so divide to get msec
+    end_milisec = double(end_timespec.tv_sec)*1e3 + double(end_timespec.tv_nsec)/1e6;
+  }
+  if (strcasestr(inBuf,"select")){
+    //clock_getcpuclockid(getpid(),&clockid);
+    //fprintf(stderr,"%d:%d times %ld.%lds clock:%d\n",getpid(),pthread_self(),end_timespec.tv_sec,end_timespec.tv_nsec,clockid);
+  }
+  if (end_milisec >= start_milisec && !start_time_error && !end_time_error) {
+    thd->busy_time = (end_milisec - start_milisec) ;
+  } else {
+    // end time went back in time, or gettimeofday() failed.
+    //statistic_increment(gettimeofday_errors, &LOCK_status);
+    thd->busy_time = 0;
+  }
+
+  // Updates THD stats and the global user stats.
+  thd->update_stats();
+  update_global_user_stats(thd);
+  // bbyte - end
 
   DBUG_VOID_RETURN;
 }
--- orig/sql/sql_yacc.yy	2009-01-02 13:51:04.000000000 +0100
+++ byte/sql/sql_yacc.yy	2009-01-02 13:51:49.000000000 +0100
@@ -989,6 +989,7 @@
 %token  UPGRADE_SYM
 %token  USAGE
 %token  USER
+%token	USER_STATS_SYM /* bbyte */
 %token  USE_FRM
 %token  USE_SYM
 %token  USING
@@ -7133,6 +7134,10 @@
           {
 	    Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
           }
+        | USER_STATS_SYM wild_and_where /* bbyte - begin */
+          {
+	    Lex->sql_command = SQLCOM_SHOW_USER_STATS;
+          } /* bbyte - end */
 	| CREATE PROCEDURE sp_name
 	  {
 	    LEX *lex= Lex;
--- orig/sql/sql_delete.cc	2009-01-02 13:51:04.000000000 +0100
+++ byte/sql/sql_delete.cc	2009-01-02 13:51:49.000000000 +0100
@@ -348,6 +348,7 @@
     send_ok(thd,deleted);
     DBUG_PRINT("info",("%ld records deleted",(long) deleted));
   }
+  thd->updated_row_count += deleted;// bbyte
   DBUG_RETURN(error >= 0 || thd->net.report_error);
 }
 
@@ -832,6 +833,7 @@
     thd->row_count_func= deleted;
     ::send_ok(thd, deleted);
   }
+  thd->updated_row_count += deleted;//bbyte
   return 0;
 }
 
--- orig/sql/sql_insert.cc	2009-01-02 13:51:04.000000000 +0100
+++ byte/sql/sql_insert.cc	2009-01-02 13:51:50.000000000 +0100
@@ -967,6 +967,7 @@
     thd->row_count_func= info.copied + info.deleted + updated;
     ::send_ok(thd, (ulong) thd->row_count_func, id, buff);
   }
+  thd->updated_row_count += thd->row_count_func; // bbyte
   thd->abort_on_warning= 0;
   DBUG_RETURN(FALSE);
 
@@ -2981,6 +2982,7 @@
                        ((thd->client_capabilities & CLIENT_FOUND_ROWS) ?
                         info.touched : info.updated);
   ::send_ok(thd, (ulong) thd->row_count_func, last_insert_id, buff);
+  thd->updated_row_count += thd->row_count_func; // bbyte
   DBUG_RETURN(0);
 }
 
--- orig/sql/sql_update.cc	2009-01-02 13:51:04.000000000 +0100
+++ byte/sql/sql_update.cc	2009-01-02 13:51:49.000000000 +0100
@@ -614,6 +614,7 @@
       (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
     send_ok(thd, (ulong) thd->row_count_func,
 	    thd->insert_id_used ? thd->last_insert_id : 0L,buff);
+    thd->updated_row_count += thd->row_count_func; // bbyte
     DBUG_PRINT("info",("%ld records updated", (long) updated));
   }
   thd->count_cuted_fields= CHECK_FIELD_IGNORE;		/* calc cuted fields */
@@ -1709,5 +1710,6 @@
     (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
   ::send_ok(thd, (ulong) thd->row_count_func,
 	    thd->insert_id_used ? thd->last_insert_id : 0L,buff);
+  thd->updated_row_count += thd->row_count_func; // bbyte
   return FALSE;
 }
--- orig/libmysqld/Makefile.am	2009-01-02 13:51:06.000000000 +0100
+++ byte/libmysqld/Makefile.am	2009-01-02 13:51:53.000000000 +0100
@@ -65,7 +65,8 @@
 	spatial.cc gstream.cc sql_help.cc tztime.cc sql_cursor.cc \
 	sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \
 	parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \
-	ha_blackhole.cc ha_archive.cc my_user.c
+	ha_blackhole.cc ha_archive.cc my_user.c \
+	byte_stats.cc
 
 libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources) $(sqlexamplessources)
 libmysqld_a_SOURCES=
--- orig/libmysqld/Makefile.in	2009-01-02 13:51:06.000000000 +0100
+++ byte/libmysqld/Makefile.in	2009-01-02 13:51:53.000000000 +0100
@@ -137,7 +137,8 @@
 	sp_head.$(OBJEXT) sp_pcontext.$(OBJEXT) sp.$(OBJEXT) \
 	sp_cache.$(OBJEXT) sp_rcontext.$(OBJEXT) parse_file.$(OBJEXT) \
 	sql_view.$(OBJEXT) sql_trigger.$(OBJEXT) my_decimal.$(OBJEXT) \
-	ha_blackhole.$(OBJEXT) ha_archive.$(OBJEXT) my_user.$(OBJEXT)
+	ha_blackhole.$(OBJEXT) ha_archive.$(OBJEXT) my_user.$(OBJEXT) \
+	byte_stats.$(OBJEXT)
 am__objects_4 = ha_example.$(OBJEXT) ha_tina.$(OBJEXT)
 am_libmysqld_int_a_OBJECTS = $(am__objects_1) $(am__objects_2) \
 	$(am__objects_3) $(am__objects_4)
@@ -482,7 +483,8 @@
 	spatial.cc gstream.cc sql_help.cc tztime.cc sql_cursor.cc \
 	sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \
 	parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \
-	ha_blackhole.cc ha_archive.cc my_user.c
+	ha_blackhole.cc ha_archive.cc my_user.c \
+	byte_stats.cc
 
 libmysqld_int_a_SOURCES = $(libmysqld_sources) $(libmysqlsources) $(sqlsources) $(sqlexamplessources)
 libmysqld_a_SOURCES = 
@@ -574,6 +576,7 @@
 distclean-compile:
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/byte_stats.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/derror.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/discover.Po@am__quote@

