List:Commits« Previous MessageNext Message »
From:Marc Alff Date:May 7 2011 12:41am
Subject:bzr push into mysql-trunk branch (marc.alff:3347 to 3348) WL#5378
View as plain text  
 3348 Marc Alff	2011-05-06
      WL#5378 PERFORMANCE SCHEMA SUMMARY BY USER / HOST
      
      Part 1 (Implementation only)

    added:
      storage/perfschema/cursor_by_account.cc
      storage/perfschema/cursor_by_account.h
      storage/perfschema/cursor_by_host.cc
      storage/perfschema/cursor_by_host.h
      storage/perfschema/cursor_by_thread.cc
      storage/perfschema/cursor_by_thread.h
      storage/perfschema/cursor_by_user.cc
      storage/perfschema/cursor_by_user.h
      storage/perfschema/pfs_account.cc
      storage/perfschema/pfs_account.h
      storage/perfschema/pfs_host.cc
      storage/perfschema/pfs_host.h
      storage/perfschema/pfs_user.cc
      storage/perfschema/pfs_user.h
      storage/perfschema/table_accounts.cc
      storage/perfschema/table_accounts.h
      storage/perfschema/table_esgs_by_account_by_event_name.cc
      storage/perfschema/table_esgs_by_account_by_event_name.h
      storage/perfschema/table_esgs_by_host_by_event_name.cc
      storage/perfschema/table_esgs_by_host_by_event_name.h
      storage/perfschema/table_esgs_by_user_by_event_name.cc
      storage/perfschema/table_esgs_by_user_by_event_name.h
      storage/perfschema/table_esms_by_account_by_event_name.cc
      storage/perfschema/table_esms_by_account_by_event_name.h
      storage/perfschema/table_esms_by_host_by_event_name.cc
      storage/perfschema/table_esms_by_host_by_event_name.h
      storage/perfschema/table_esms_by_user_by_event_name.cc
      storage/perfschema/table_esms_by_user_by_event_name.h
      storage/perfschema/table_ews_by_account_by_event_name.cc
      storage/perfschema/table_ews_by_account_by_event_name.h
      storage/perfschema/table_ews_by_host_by_event_name.cc
      storage/perfschema/table_ews_by_host_by_event_name.h
      storage/perfschema/table_ews_by_user_by_event_name.cc
      storage/perfschema/table_ews_by_user_by_event_name.h
      storage/perfschema/table_hosts.cc
      storage/perfschema/table_hosts.h
      storage/perfschema/table_users.cc
      storage/perfschema/table_users.h
    modified:
      scripts/mysql_system_tables.sql
      sql/sys_vars.cc
      storage/perfschema/CMakeLists.txt
      storage/perfschema/ha_perfschema.cc
      storage/perfschema/pfs.cc
      storage/perfschema/pfs_engine_table.cc
      storage/perfschema/pfs_events_stages.cc
      storage/perfschema/pfs_events_stages.h
      storage/perfschema/pfs_events_statements.cc
      storage/perfschema/pfs_events_statements.h
      storage/perfschema/pfs_events_waits.cc
      storage/perfschema/pfs_events_waits.h
      storage/perfschema/pfs_instr.cc
      storage/perfschema/pfs_instr.h
      storage/perfschema/pfs_instr_class.cc
      storage/perfschema/pfs_instr_class.h
      storage/perfschema/pfs_server.cc
      storage/perfschema/pfs_server.h
      storage/perfschema/pfs_setup_actor.cc
      storage/perfschema/pfs_setup_object.cc
      storage/perfschema/pfs_stat.h
      storage/perfschema/pfs_visitor.cc
      storage/perfschema/pfs_visitor.h
      storage/perfschema/table_esgs_global_by_event_name.cc
      storage/perfschema/table_esms_global_by_event_name.cc
      storage/perfschema/table_helper.cc
      storage/perfschema/table_helper.h
      storage/perfschema/table_threads.cc
      storage/perfschema/table_threads.h
 3347 Davi Arnaut	2011-04-29 [merge]
      Merge of mysql-5.5 into mysql-trunk.

    modified:
      config.h.cmake
      configure.cmake
      vio/viosocket.c
=== modified file 'scripts/mysql_system_tables.sql'
--- a/scripts/mysql_system_tables.sql	2011-03-18 22:51:17 +0000
+++ b/scripts/mysql_system_tables.sql	2011-05-07 00:40:25 +0000
@@ -293,6 +293,64 @@ EXECUTE stmt;
 DROP PREPARE stmt;
 
 --
+-- TABLE EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME
+--
+
+SET @cmd="CREATE TABLE performance_schema.events_waits_summary_by_host_by_event_name("
+  "HOST CHAR(60) collate utf8_bin default null,"
+  "EVENT_NAME VARCHAR(128) not null,"
+  "COUNT_STAR BIGINT unsigned not null,"
+  "SUM_TIMER_WAIT BIGINT unsigned not null,"
+  "MIN_TIMER_WAIT BIGINT unsigned not null,"
+  "AVG_TIMER_WAIT BIGINT unsigned not null,"
+  "MAX_TIMER_WAIT BIGINT unsigned not null"
+  ")ENGINE=PERFORMANCE_SCHEMA;";
+
+SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0');
+PREPARE stmt FROM @str;
+EXECUTE stmt;
+DROP PREPARE stmt;
+
+--
+-- TABLE EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME
+--
+
+SET @cmd="CREATE TABLE performance_schema.events_waits_summary_by_user_by_event_name("
+  "USER CHAR(16) collate utf8_bin default null,"
+  "EVENT_NAME VARCHAR(128) not null,"
+  "COUNT_STAR BIGINT unsigned not null,"
+  "SUM_TIMER_WAIT BIGINT unsigned not null,"
+  "MIN_TIMER_WAIT BIGINT unsigned not null,"
+  "AVG_TIMER_WAIT BIGINT unsigned not null,"
+  "MAX_TIMER_WAIT BIGINT unsigned not null"
+  ")ENGINE=PERFORMANCE_SCHEMA;";
+
+SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0');
+PREPARE stmt FROM @str;
+EXECUTE stmt;
+DROP PREPARE stmt;
+
+--
+-- TABLE EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME
+--
+
+SET @cmd="CREATE TABLE performance_schema.events_waits_summary_by_account_by_event_name("
+  "USER CHAR(16) collate utf8_bin default null,"
+  "HOST CHAR(60) collate utf8_bin default null,"
+  "EVENT_NAME VARCHAR(128) not null,"
+  "COUNT_STAR BIGINT unsigned not null,"
+  "SUM_TIMER_WAIT BIGINT unsigned not null,"
+  "MIN_TIMER_WAIT BIGINT unsigned not null,"
+  "AVG_TIMER_WAIT BIGINT unsigned not null,"
+  "MAX_TIMER_WAIT BIGINT unsigned not null"
+  ")ENGINE=PERFORMANCE_SCHEMA;";
+
+SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0');
+PREPARE stmt FROM @str;
+EXECUTE stmt;
+DROP PREPARE stmt;
+
+--
 -- TABLE EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME
 --
 
@@ -815,6 +873,64 @@ EXECUTE stmt;
 DROP PREPARE stmt;
 
 --
+-- TABLE EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME
+--
+
+SET @cmd="CREATE TABLE performance_schema.events_stages_summary_by_host_by_event_name("
+  "HOST CHAR(60) collate utf8_bin default null,"
+  "EVENT_NAME VARCHAR(128) not null,"
+  "COUNT_STAR BIGINT unsigned not null,"
+  "SUM_TIMER_WAIT BIGINT unsigned not null,"
+  "MIN_TIMER_WAIT BIGINT unsigned not null,"
+  "AVG_TIMER_WAIT BIGINT unsigned not null,"
+  "MAX_TIMER_WAIT BIGINT unsigned not null"
+  ")ENGINE=PERFORMANCE_SCHEMA;";
+
+SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0');
+PREPARE stmt FROM @str;
+EXECUTE stmt;
+DROP PREPARE stmt;
+
+--
+-- TABLE EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME
+--
+
+SET @cmd="CREATE TABLE performance_schema.events_stages_summary_by_user_by_event_name("
+  "USER CHAR(16) collate utf8_bin default null,"
+  "EVENT_NAME VARCHAR(128) not null,"
+  "COUNT_STAR BIGINT unsigned not null,"
+  "SUM_TIMER_WAIT BIGINT unsigned not null,"
+  "MIN_TIMER_WAIT BIGINT unsigned not null,"
+  "AVG_TIMER_WAIT BIGINT unsigned not null,"
+  "MAX_TIMER_WAIT BIGINT unsigned not null"
+  ")ENGINE=PERFORMANCE_SCHEMA;";
+
+SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0');
+PREPARE stmt FROM @str;
+EXECUTE stmt;
+DROP PREPARE stmt;
+
+--
+-- TABLE EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME
+--
+
+SET @cmd="CREATE TABLE performance_schema.events_stages_summary_by_account_by_event_name("
+  "USER CHAR(16) collate utf8_bin default null,"
+  "HOST CHAR(60) collate utf8_bin default null,"
+  "EVENT_NAME VARCHAR(128) not null,"
+  "COUNT_STAR BIGINT unsigned not null,"
+  "SUM_TIMER_WAIT BIGINT unsigned not null,"
+  "MIN_TIMER_WAIT BIGINT unsigned not null,"
+  "AVG_TIMER_WAIT BIGINT unsigned not null,"
+  "MAX_TIMER_WAIT BIGINT unsigned not null"
+  ")ENGINE=PERFORMANCE_SCHEMA;";
+
+SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0');
+PREPARE stmt FROM @str;
+EXECUTE stmt;
+DROP PREPARE stmt;
+
+--
 -- TABLE EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME
 --
 
@@ -1018,6 +1134,121 @@ EXECUTE stmt;
 DROP PREPARE stmt;
 
 --
+-- TABLE EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME
+--
+
+SET @cmd="CREATE TABLE performance_schema.events_statements_summary_by_host_by_event_name("
+  "HOST CHAR(60) collate utf8_bin default null,"
+  "EVENT_NAME VARCHAR(128) not null,"
+  "COUNT_STAR BIGINT unsigned not null,"
+  "SUM_TIMER_WAIT BIGINT unsigned not null,"
+  "MIN_TIMER_WAIT BIGINT unsigned not null,"
+  "AVG_TIMER_WAIT BIGINT unsigned not null,"
+  "MAX_TIMER_WAIT BIGINT unsigned not null,"
+  "SUM_LOCK_TIME BIGINT unsigned not null,"
+  "SUM_ERRORS BIGINT unsigned not null,"
+  "SUM_WARNINGS BIGINT unsigned not null,"
+  "SUM_ROWS_AFFECTED BIGINT unsigned not null,"
+  "SUM_ROWS_SENT BIGINT unsigned not null,"
+  "SUM_ROWS_EXAMINED BIGINT unsigned not null,"
+  "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null,"
+  "SUM_CREATED_TMP_TABLES BIGINT unsigned not null,"
+  "SUM_SELECT_FULL_JOIN BIGINT unsigned not null,"
+  "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null,"
+  "SUM_SELECT_RANGE BIGINT unsigned not null,"
+  "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null,"
+  "SUM_SELECT_SCAN BIGINT unsigned not null,"
+  "SUM_SORT_MERGE_PASSES BIGINT unsigned not null,"
+  "SUM_SORT_RANGE BIGINT unsigned not null,"
+  "SUM_SORT_ROWS BIGINT unsigned not null,"
+  "SUM_SORT_SCAN BIGINT unsigned not null,"
+  "SUM_NO_INDEX_USED BIGINT unsigned not null,"
+  "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null"
+  ")ENGINE=PERFORMANCE_SCHEMA;";
+
+SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0');
+PREPARE stmt FROM @str;
+EXECUTE stmt;
+DROP PREPARE stmt;
+
+--
+-- TABLE EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME
+--
+
+SET @cmd="CREATE TABLE performance_schema.events_statements_summary_by_user_by_event_name("
+  "USER CHAR(16) collate utf8_bin default null,"
+  "EVENT_NAME VARCHAR(128) not null,"
+  "COUNT_STAR BIGINT unsigned not null,"
+  "SUM_TIMER_WAIT BIGINT unsigned not null,"
+  "MIN_TIMER_WAIT BIGINT unsigned not null,"
+  "AVG_TIMER_WAIT BIGINT unsigned not null,"
+  "MAX_TIMER_WAIT BIGINT unsigned not null,"
+  "SUM_LOCK_TIME BIGINT unsigned not null,"
+  "SUM_ERRORS BIGINT unsigned not null,"
+  "SUM_WARNINGS BIGINT unsigned not null,"
+  "SUM_ROWS_AFFECTED BIGINT unsigned not null,"
+  "SUM_ROWS_SENT BIGINT unsigned not null,"
+  "SUM_ROWS_EXAMINED BIGINT unsigned not null,"
+  "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null,"
+  "SUM_CREATED_TMP_TABLES BIGINT unsigned not null,"
+  "SUM_SELECT_FULL_JOIN BIGINT unsigned not null,"
+  "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null,"
+  "SUM_SELECT_RANGE BIGINT unsigned not null,"
+  "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null,"
+  "SUM_SELECT_SCAN BIGINT unsigned not null,"
+  "SUM_SORT_MERGE_PASSES BIGINT unsigned not null,"
+  "SUM_SORT_RANGE BIGINT unsigned not null,"
+  "SUM_SORT_ROWS BIGINT unsigned not null,"
+  "SUM_SORT_SCAN BIGINT unsigned not null,"
+  "SUM_NO_INDEX_USED BIGINT unsigned not null,"
+  "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null"
+  ")ENGINE=PERFORMANCE_SCHEMA;";
+
+SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0');
+PREPARE stmt FROM @str;
+EXECUTE stmt;
+DROP PREPARE stmt;
+
+--
+-- TABLE EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME
+--
+
+SET @cmd="CREATE TABLE performance_schema.events_statements_summary_by_account_by_event_name("
+  "USER CHAR(16) collate utf8_bin default null,"
+  "HOST CHAR(60) collate utf8_bin default null,"
+  "EVENT_NAME VARCHAR(128) not null,"
+  "COUNT_STAR BIGINT unsigned not null,"
+  "SUM_TIMER_WAIT BIGINT unsigned not null,"
+  "MIN_TIMER_WAIT BIGINT unsigned not null,"
+  "AVG_TIMER_WAIT BIGINT unsigned not null,"
+  "MAX_TIMER_WAIT BIGINT unsigned not null,"
+  "SUM_LOCK_TIME BIGINT unsigned not null,"
+  "SUM_ERRORS BIGINT unsigned not null,"
+  "SUM_WARNINGS BIGINT unsigned not null,"
+  "SUM_ROWS_AFFECTED BIGINT unsigned not null,"
+  "SUM_ROWS_SENT BIGINT unsigned not null,"
+  "SUM_ROWS_EXAMINED BIGINT unsigned not null,"
+  "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null,"
+  "SUM_CREATED_TMP_TABLES BIGINT unsigned not null,"
+  "SUM_SELECT_FULL_JOIN BIGINT unsigned not null,"
+  "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null,"
+  "SUM_SELECT_RANGE BIGINT unsigned not null,"
+  "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null,"
+  "SUM_SELECT_SCAN BIGINT unsigned not null,"
+  "SUM_SORT_MERGE_PASSES BIGINT unsigned not null,"
+  "SUM_SORT_RANGE BIGINT unsigned not null,"
+  "SUM_SORT_ROWS BIGINT unsigned not null,"
+  "SUM_SORT_SCAN BIGINT unsigned not null,"
+  "SUM_NO_INDEX_USED BIGINT unsigned not null,"
+  "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null"
+  ")ENGINE=PERFORMANCE_SCHEMA;";
+
+SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0');
+PREPARE stmt FROM @str;
+EXECUTE stmt;
+DROP PREPARE stmt;
+
+--
 -- TABLE EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME
 --
 
@@ -1054,6 +1285,52 @@ PREPARE stmt FROM @str;
 EXECUTE stmt;
 DROP PREPARE stmt;
 
+--
+-- TABLE HOSTS
+--
+
+SET @cmd="CREATE TABLE performance_schema.hosts("
+  "HOST CHAR(60) collate utf8_bin default null,"
+  "CURRENT_CONNECTIONS bigint not null,"
+  "TOTAL_CONNECTIONS bigint not null"
+  ")ENGINE=PERFORMANCE_SCHEMA;";
+
+SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0');
+PREPARE stmt FROM @str;
+EXECUTE stmt;
+DROP PREPARE stmt;
+
+--
+-- TABLE USERS
+--
+
+SET @cmd="CREATE TABLE performance_schema.users("
+  "USER CHAR(16) collate utf8_bin default null,"
+  "CURRENT_CONNECTIONS bigint not null,"
+  "TOTAL_CONNECTIONS bigint not null"
+  ")ENGINE=PERFORMANCE_SCHEMA;";
+
+SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0');
+PREPARE stmt FROM @str;
+EXECUTE stmt;
+DROP PREPARE stmt;
+
+--
+-- TABLE ACCOUNTS
+--
+
+SET @cmd="CREATE TABLE performance_schema.accounts("
+  "USER CHAR(16) collate utf8_bin default null,"
+  "HOST CHAR(60) collate utf8_bin default null,"
+  "CURRENT_CONNECTIONS bigint not null,"
+  "TOTAL_CONNECTIONS bigint not null"
+  ")ENGINE=PERFORMANCE_SCHEMA;";
+
+SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0');
+PREPARE stmt FROM @str;
+EXECUTE stmt;
+DROP PREPARE stmt;
+
 
 CREATE TABLE IF NOT EXISTS proxies_priv (Host char(60) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, Proxied_host char(60) binary DEFAULT '' NOT NULL, Proxied_user char(16) binary DEFAULT '' NOT NULL, With_grant BOOL DEFAULT 0 NOT NULL, Grantor char(77) DEFAULT '' NOT NULL, Timestamp timestamp, PRIMARY KEY Host (Host,User,Proxied_host,Proxied_user), KEY Grantor (Grantor) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='User proxy privileges';
 

=== modified file 'sql/sys_vars.cc'
--- a/sql/sys_vars.cc	2011-04-11 10:28:36 +0000
+++ b/sql/sys_vars.cc	2011-05-07 00:40:25 +0000
@@ -216,6 +216,30 @@ static Sys_var_ulong Sys_pfs_setup_objec
        DEFAULT(PFS_MAX_SETUP_OBJECT),
        BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
 
+static Sys_var_ulong Sys_pfs_accounts_size(
+       "performance_schema_accounts_size",
+       "Maximum number of instrumented user@host accounts.",
+       READ_ONLY GLOBAL_VAR(pfs_param.m_account_sizing),
+       CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024),
+       DEFAULT(PFS_MAX_ACCOUNT),
+       BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
+static Sys_var_ulong Sys_pfs_hosts_size(
+       "performance_schema_hosts_size",
+       "Maximum number of instrumented hosts.",
+       READ_ONLY GLOBAL_VAR(pfs_param.m_host_sizing),
+       CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024),
+       DEFAULT(PFS_MAX_HOST),
+       BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
+static Sys_var_ulong Sys_pfs_users_size(
+       "performance_schema_users_size",
+       "Maximum number of instrumented users.",
+       READ_ONLY GLOBAL_VAR(pfs_param.m_user_sizing),
+       CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1024*1024),
+       DEFAULT(PFS_MAX_USER),
+       BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);
+
 static Sys_var_ulong Sys_pfs_max_stage_classes(
        "performance_schema_max_stage_classes",
        "Maximum number of stage instruments.",

=== modified file 'storage/perfschema/CMakeLists.txt'
--- a/storage/perfschema/CMakeLists.txt	2011-02-14 14:23:55 +0000
+++ b/storage/perfschema/CMakeLists.txt	2011-05-07 00:40:25 +0000
@@ -26,7 +26,12 @@ ADD_DEFINITIONS(-DMYSQL_SERVER)
 # Tip: ls -1 *.h, ls -1 *.cc
 #
 SET(PERFSCHEMA_SOURCES ha_perfschema.h
+cursor_by_account.h
+cursor_by_host.h
+cursor_by_thread.h
+cursor_by_user.h
 pfs.h
+pfs_account.h
 pfs_atomic.h
 pfs_column_types.h
 pfs_column_values.h
@@ -38,6 +43,7 @@ pfs_events_stages.h
 pfs_events_statements.h
 pfs_events_waits.h
 pfs_global.h
+pfs_host.h
 pfs_instr.h
 pfs_instr_class.h
 pfs_lock.h
@@ -46,21 +52,33 @@ pfs_setup_actor.h
 pfs_setup_object.h
 pfs_stat.h
 pfs_timer.h
+pfs_user.h
 pfs_visitor.h
+table_accounts.h
 table_all_instr.h
+table_esgs_by_account_by_event_name.h
+table_esgs_by_host_by_event_name.h
 table_esgs_by_thread_by_event_name.h
+table_esgs_by_user_by_event_name.h
 table_esgs_global_by_event_name.h
+table_esms_by_account_by_event_name.h
+table_esms_by_host_by_event_name.h
 table_esms_by_thread_by_event_name.h
+table_esms_by_user_by_event_name.h
 table_esms_global_by_event_name.h
 table_events_stages.h
 table_events_statements.h
 table_events_waits.h
 table_events_waits_summary.h
+table_ews_by_account_by_event_name.h
+table_ews_by_host_by_event_name.h
 table_ews_by_thread_by_event_name.h
+table_ews_by_user_by_event_name.h
 table_ews_global_by_event_name.h
 table_file_instances.h
 table_file_summary.h
 table_helper.h
+table_hosts.h
 table_os_global_by_type.h
 table_performance_timers.h
 table_setup_actors.h
@@ -73,8 +91,14 @@ table_threads.h
 table_tiws_by_index_usage.h
 table_tiws_by_table.h
 table_tlws_by_table.h
+table_users.h
+cursor_by_account.cc
+cursor_by_host.cc
+cursor_by_thread.cc
+cursor_by_user.cc
 ha_perfschema.cc
 pfs.cc
+pfs_account.cc
 pfs_atomic.cc
 pfs_check.cc
 pfs_column_values.cc
@@ -85,27 +109,40 @@ pfs_events_stages.cc
 pfs_events_statements.cc
 pfs_events_waits.cc
 pfs_global.cc
+pfs_host.cc
 pfs_instr.cc
 pfs_instr_class.cc
 pfs_server.cc
 pfs_setup_actor.cc
 pfs_setup_object.cc
 pfs_timer.cc
+pfs_user.cc
 pfs_visitor.cc
+table_accounts.cc
 table_all_instr.cc
+table_esgs_by_account_by_event_name.cc
+table_esgs_by_host_by_event_name.cc
 table_esgs_by_thread_by_event_name.cc
+table_esgs_by_user_by_event_name.cc
 table_esgs_global_by_event_name.cc
+table_esms_by_account_by_event_name.cc
+table_esms_by_host_by_event_name.cc
 table_esms_by_thread_by_event_name.cc
+table_esms_by_user_by_event_name.cc
 table_esms_global_by_event_name.cc
 table_events_stages.cc
 table_events_statements.cc
 table_events_waits.cc
 table_events_waits_summary.cc
+table_ews_by_account_by_event_name.cc
+table_ews_by_host_by_event_name.cc
 table_ews_by_thread_by_event_name.cc
+table_ews_by_user_by_event_name.cc
 table_ews_global_by_event_name.cc
 table_file_instances.cc
 table_file_summary.cc
 table_helper.cc
+table_hosts.cc
 table_os_global_by_type.cc
 table_performance_timers.cc
 table_setup_actors.cc
@@ -118,6 +155,7 @@ table_threads.cc
 table_tiws_by_index_usage.cc
 table_tiws_by_table.cc
 table_tlws_by_table.cc
+table_users.cc
 )
 
 MYSQL_ADD_PLUGIN(perfschema ${PERFSCHEMA_SOURCES} STORAGE_ENGINE DEFAULT STATIC_ONLY)

=== added file 'storage/perfschema/cursor_by_account.cc'
--- a/storage/perfschema/cursor_by_account.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/cursor_by_account.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,72 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file storage/perfschema/cursor_by_account.cc
+  Cursor CURSOR_BY_ACCOUNT (implementation).
+*/
+
+#include "my_global.h"
+#include "cursor_by_account.h"
+#include "pfs_user.h"
+
+cursor_by_account::cursor_by_account(const PFS_engine_table_share *share)
+  : PFS_engine_table(share, &m_pos),
+    m_pos(0), m_next_pos(0)
+{}
+
+void cursor_by_account::reset_position(void)
+{
+  m_pos.m_index= 0;
+  m_next_pos.m_index= 0;
+}
+
+int cursor_by_account::rnd_next(void)
+{
+  PFS_account *pfs;
+
+  for (m_pos.set_at(&m_next_pos);
+       m_pos.m_index < account_max;
+       m_pos.next())
+  {
+    pfs= &account_array[m_pos.m_index];
+    if (pfs->m_lock.is_populated())
+    {
+      make_row(pfs);
+      m_next_pos.set_after(&m_pos);
+      return 0;
+    }
+  }
+
+  return HA_ERR_END_OF_FILE;
+}
+
+int
+cursor_by_account::rnd_pos(const void *pos)
+{
+  PFS_account *pfs;
+
+  set_position(pos);
+  DBUG_ASSERT(m_pos.m_index < account_max);
+  pfs= &account_array[m_pos.m_index];
+  if (pfs->m_lock.is_populated())
+  {
+    make_row(pfs);
+    return 0;
+  }
+
+  return HA_ERR_RECORD_DELETED;
+}
+

=== added file 'storage/perfschema/cursor_by_account.h'
--- a/storage/perfschema/cursor_by_account.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/cursor_by_account.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,59 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef CURSOR_BY_ACCOUNT_H
+#define CURSOR_BY_ACCOUNT_H
+
+/**
+  @file storage/perfschema/cursor_by_account.h
+  Cursor CURSOR_BY_ACCOUNT (declarations).
+*/
+
+#include "pfs_engine_table.h"
+#include "pfs_account.h"
+#include "table_helper.h"
+
+/**
+  @addtogroup Performance_schema_tables
+  @{
+*/
+
+/** Cursor CURSOR_BY_ACCOUNT. */
+class cursor_by_account : public PFS_engine_table
+{
+public:
+  virtual int rnd_next();
+  virtual int rnd_pos(const void *pos);
+  virtual void reset_position(void);
+
+protected:
+  cursor_by_account(const PFS_engine_table_share *share);
+
+public:
+  ~cursor_by_account()
+  {}
+
+protected:
+  virtual void make_row(PFS_account *account)= 0;
+
+private:
+  /** Current position. */
+  PFS_simple_index m_pos;
+  /** Next position. */
+  PFS_simple_index m_next_pos;
+};
+
+/** @} */
+#endif

=== added file 'storage/perfschema/cursor_by_host.cc'
--- a/storage/perfschema/cursor_by_host.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/cursor_by_host.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,72 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file storage/perfschema/cursor_by_host.cc
+  Cursor CURSOR_BY_HOST (implementation).
+*/
+
+#include "my_global.h"
+#include "cursor_by_host.h"
+#include "pfs_host.h"
+
+cursor_by_host::cursor_by_host(const PFS_engine_table_share *share)
+  : PFS_engine_table(share, &m_pos),
+    m_pos(0), m_next_pos(0)
+{}
+
+void cursor_by_host::reset_position(void)
+{
+  m_pos.m_index= 0;
+  m_next_pos.m_index= 0;
+}
+
+int cursor_by_host::rnd_next(void)
+{
+  PFS_host *host;
+
+  for (m_pos.set_at(&m_next_pos);
+       m_pos.m_index < host_max;
+       m_pos.next())
+  {
+    host= & host_array[m_pos.m_index];
+    if (host->m_lock.is_populated())
+    {
+      make_row(host);
+      m_next_pos.set_after(&m_pos);
+      return 0;
+    }
+  }
+
+  return HA_ERR_END_OF_FILE;
+}
+
+int
+cursor_by_host::rnd_pos(const void *pos)
+{
+  PFS_host *pfs;
+
+  set_position(pos);
+  DBUG_ASSERT(m_pos.m_index < host_max);
+  pfs= &host_array[m_pos.m_index];
+  if (pfs->m_lock.is_populated())
+  {
+    make_row(pfs);
+    return 0;
+  }
+
+  return HA_ERR_RECORD_DELETED;
+}
+

=== added file 'storage/perfschema/cursor_by_host.h'
--- a/storage/perfschema/cursor_by_host.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/cursor_by_host.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,59 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef CURSOR_BY_HOST_H
+#define CURSOR_BY_HOST_H
+
+/**
+  @file storage/perfschema/cursor_by_host.h
+  Cursor CURSOR_BY_HOST (declarations).
+*/
+
+#include "pfs_engine_table.h"
+#include "pfs_host.h"
+#include "table_helper.h"
+
+/**
+  @addtogroup Performance_schema_tables
+  @{
+*/
+
+/** Cursor CURSOR_BY_HOST. */
+class cursor_by_host : public PFS_engine_table
+{
+public:
+  virtual int rnd_next();
+  virtual int rnd_pos(const void *pos);
+  virtual void reset_position(void);
+
+protected:
+  cursor_by_host(const PFS_engine_table_share *share);
+
+public:
+  ~cursor_by_host()
+  {}
+
+protected:
+  virtual void make_row(PFS_host *host)= 0;
+
+private:
+  /** Current position. */
+  PFS_simple_index m_pos;
+  /** Next position. */
+  PFS_simple_index m_next_pos;
+};
+
+/** @} */
+#endif

=== added file 'storage/perfschema/cursor_by_thread.cc'
--- a/storage/perfschema/cursor_by_thread.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/cursor_by_thread.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,72 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file storage/perfschema/cursor_by_thread.cc
+  Cursor CURSOR_BY_THREAD (implementation).
+*/
+
+#include "my_global.h"
+#include "cursor_by_thread.h"
+#include "pfs_instr.h"
+
+cursor_by_thread::cursor_by_thread(const PFS_engine_table_share *share)
+  : PFS_engine_table(share, &m_pos),
+    m_pos(0), m_next_pos(0)
+{}
+
+void cursor_by_thread::reset_position(void)
+{
+  m_pos.m_index= 0;
+  m_next_pos.m_index= 0;
+}
+
+int cursor_by_thread::rnd_next(void)
+{
+  PFS_thread *pfs;
+
+  for (m_pos.set_at(&m_next_pos);
+       m_pos.m_index < thread_max;
+       m_pos.next())
+  {
+    pfs= &thread_array[m_pos.m_index];
+    if (pfs->m_lock.is_populated())
+    {
+      make_row(pfs);
+      m_next_pos.set_after(&m_pos);
+      return 0;
+    }
+  }
+
+  return HA_ERR_END_OF_FILE;
+}
+
+int
+cursor_by_thread::rnd_pos(const void *pos)
+{
+  PFS_thread *pfs;
+
+  set_position(pos);
+  DBUG_ASSERT(m_pos.m_index < thread_max);
+  pfs= &thread_array[m_pos.m_index];
+  if (pfs->m_lock.is_populated())
+  {
+    make_row(pfs);
+    return 0;
+  }
+
+  return HA_ERR_RECORD_DELETED;
+}
+

=== added file 'storage/perfschema/cursor_by_thread.h'
--- a/storage/perfschema/cursor_by_thread.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/cursor_by_thread.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,59 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef CURSOR_BY_THREAD_H
+#define CURSOR_BY_THREAD_H
+
+/**
+  @file storage/perfschema/cursor_by_thread.h
+  Cursor CURSOR_BY_THREAD (declarations).
+*/
+
+#include "pfs_engine_table.h"
+#include "pfs_instr.h"
+#include "table_helper.h"
+
+/**
+  @addtogroup Performance_schema_tables
+  @{
+*/
+
+/** Cursor CURSOR_BY_THREAD. */
+class cursor_by_thread : public PFS_engine_table
+{
+public:
+  virtual int rnd_next();
+  virtual int rnd_pos(const void *pos);
+  virtual void reset_position(void);
+
+protected:
+  cursor_by_thread(const PFS_engine_table_share *share);
+
+public:
+  ~cursor_by_thread()
+  {}
+
+protected:
+  virtual void make_row(PFS_thread *thread)= 0;
+
+private:
+  /** Current position. */
+  PFS_simple_index m_pos;
+  /** Next position. */
+  PFS_simple_index m_next_pos;
+};
+
+/** @} */
+#endif

=== added file 'storage/perfschema/cursor_by_user.cc'
--- a/storage/perfschema/cursor_by_user.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/cursor_by_user.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,72 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file storage/perfschema/cursor_by_user.cc
+  Cursor CURSOR_BY_USER (implementation).
+*/
+
+#include "my_global.h"
+#include "cursor_by_user.h"
+#include "pfs_user.h"
+
+cursor_by_user::cursor_by_user(const PFS_engine_table_share *share)
+  : PFS_engine_table(share, &m_pos),
+    m_pos(0), m_next_pos(0)
+{}
+
+void cursor_by_user::reset_position(void)
+{
+  m_pos.m_index= 0;
+  m_next_pos.m_index= 0;
+}
+
+int cursor_by_user::rnd_next(void)
+{
+  PFS_user *pfs;
+
+  for (m_pos.set_at(&m_next_pos);
+       m_pos.m_index < user_max;
+       m_pos.next())
+  {
+    pfs= &user_array[m_pos.m_index];
+    if (pfs->m_lock.is_populated())
+    {
+      make_row(pfs);
+      m_next_pos.set_after(&m_pos);
+      return 0;
+    }
+  }
+
+  return HA_ERR_END_OF_FILE;
+}
+
+int
+cursor_by_user::rnd_pos(const void *pos)
+{
+  PFS_user *pfs;
+
+  set_position(pos);
+  DBUG_ASSERT(m_pos.m_index < user_max);
+  pfs= &user_array[m_pos.m_index];
+  if (pfs->m_lock.is_populated())
+  {
+    make_row(pfs);
+    return 0;
+  }
+
+  return HA_ERR_RECORD_DELETED;
+}
+

=== added file 'storage/perfschema/cursor_by_user.h'
--- a/storage/perfschema/cursor_by_user.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/cursor_by_user.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,59 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef CURSOR_BY_USER_H
+#define CURSOR_BY_USER_H
+
+/**
+  @file storage/perfschema/cursor_by_user.h
+  Cursor CURSOR_BY_USER (declarations).
+*/
+
+#include "pfs_engine_table.h"
+#include "pfs_user.h"
+#include "table_helper.h"
+
+/**
+  @addtogroup Performance_schema_tables
+  @{
+*/
+
+/** Cursor CURSOR_BY_USER. */
+class cursor_by_user : public PFS_engine_table
+{
+public:
+  virtual int rnd_next();
+  virtual int rnd_pos(const void *pos);
+  virtual void reset_position(void);
+
+protected:
+  cursor_by_user(const PFS_engine_table_share *share);
+
+public:
+  ~cursor_by_user()
+  {}
+
+protected:
+  virtual void make_row(PFS_user *user)= 0;
+
+private:
+  /** Current position. */
+  PFS_simple_index m_pos;
+  /** Next position. */
+  PFS_simple_index m_next_pos;
+};
+
+/** @} */
+#endif

=== modified file 'storage/perfschema/ha_perfschema.cc'
--- a/storage/perfschema/ha_perfschema.cc	2011-02-14 14:23:55 +0000
+++ b/storage/perfschema/ha_perfschema.cc	2011-05-07 00:40:25 +0000
@@ -28,6 +28,9 @@
 #include "pfs_column_values.h"
 #include "pfs_instr_class.h"
 #include "pfs_instr.h"
+#include "pfs_host.h"
+#include "pfs_user.h"
+#include "pfs_account.h"
 
 #ifdef MY_ATOMIC_MODE_DUMMY
 /*
@@ -146,6 +149,12 @@ static struct st_mysql_show_var pfs_stat
   /* table handles, can be flushed */
   {"Performance_schema_table_handles_lost",
     (char*) &table_lost, SHOW_LONG},
+  {"Performance_schema_hosts_lost",
+    (char*) &host_lost, SHOW_LONG},
+  {"Performance_schema_users_lost",
+    (char*) &user_lost, SHOW_LONG},
+  {"Performance_schema_accounts_lost",
+    (char*) &user_lost, SHOW_LONG},
   {"Performance_schema_stage_classes_lost",
     (char*) &stage_class_lost, SHOW_LONG},
   {"Performance_schema_statement_classes_lost",

=== modified file 'storage/perfschema/pfs.cc'
--- a/storage/perfschema/pfs.cc	2011-02-14 14:23:55 +0000
+++ b/storage/perfschema/pfs.cc	2011-05-07 00:40:25 +0000
@@ -21,11 +21,15 @@
 #include "my_global.h"
 #include "thr_lock.h"
 #include "mysql/psi/psi.h"
+#include "mysql/psi/mysql_thread.h"
 #include "my_pthread.h"
 #include "sql_const.h"
 #include "pfs.h"
 #include "pfs_instr_class.h"
 #include "pfs_instr.h"
+#include "pfs_host.h"
+#include "pfs_user.h"
+#include "pfs_account.h"
 #include "pfs_global.h"
 #include "pfs_column_values.h"
 #include "pfs_timer.h"
@@ -35,6 +39,7 @@
 #include "pfs_setup_actor.h"
 #include "pfs_setup_object.h"
 #include "sql_error.h"
+#include "sp_head.h"
 
 /**
   @page PAGE_PERFORMANCE_SCHEMA The Performance Schema main page
@@ -715,7 +720,7 @@ static inline int mysql_mutex_lock(...)
         |
         | [3]
         |
-     3a |-> pfs_user_host(U, H).event_name(M) =====>> [D], [E], [F]
+     3a |-> pfs_account(U, H).event_name(M) =====>> [D], [E], [F]
         |    |
         |    | [4]
         |    |
@@ -748,8 +753,8 @@ static inline int mysql_mutex_lock(...)
   Not implemented:
   - [3] thread disconnect
   - [4] user host disconnect
-  - [D] EVENTS_WAITS_SUMMARY_BY_USER_HOST_BY_EVENT_NAME,
-        table_ews_by_user_host_by_event_name::make_row()
+  - [D] EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME,
+        table_ews_by_account_by_event_name::make_row()
   - [E] EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME,
         table_ews_by_user_by_event_name::make_row()
   - [F] EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME,
@@ -898,7 +903,7 @@ static inline int mysql_mutex_lock(...)
    |    |
    |    | [2]
    |    |
-   |  a |-> pfs_user_host(U, H).event_name(S) =====>> [B], [C], [D], [E]
+   |  a |-> pfs_account(U, H).event_name(S) =====>> [B], [C], [D], [E]
    |    |    |
    |    |    | [3]
    |    |    |
@@ -924,8 +929,8 @@ static inline int mysql_mutex_lock(...)
   - [2a, 2b, 2c] @c delete_thread_v1() to aggregate to user/host buffers
   - [3] user disconnect
   - [4] host disconnect
-  - [B] EVENTS_STAGES_SUMMARY_BY_USER_HOST_BY_EVENT_NAME,
-        @c table_esgs_by_user_host_by_event_name::make_row()
+  - [B] EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME,
+        @c table_esgs_by_account_by_event_name::make_row()
   - [C] EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME,
         @c table_esgs_by_user_by_event_name::make_row()
   - [D] EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME,
@@ -942,7 +947,7 @@ static inline int mysql_mutex_lock(...)
    |    |
    |    | [2]
    |    |
-   |  a |-> pfs_user_host(U, H).event_name(S) =====>> [B], [C], [D], [E]
+   |  a |-> pfs_account(U, H).event_name(S) =====>> [B], [C], [D], [E]
    |    |    |
    |    |    | [3]
    |    |    |
@@ -968,8 +973,8 @@ static inline int mysql_mutex_lock(...)
   - [2a, 2b, 2c] @c delete_thread_v1() to aggregate to user/host buffers
   - [3] user disconnect
   - [4] host disconnect
-  - [B] EVENTS_STATEMENTS_SUMMARY_BY_USER_HOST_BY_EVENT_NAME,
-        @c table_esms_by_user_host_by_event_name::make_row()
+  - [B] EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME,
+        @c table_esms_by_account_by_event_name::make_row()
   - [C] EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME,
         @c table_esms_by_user_by_event_name::make_row()
   - [D] EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME,
@@ -1542,6 +1547,8 @@ void* pfs_spawn_thread(void *arg)
     {
       PFS_thread *parent= typed_arg->m_parent_thread;
 
+      clear_thread_account(pfs);
+
       pfs->m_parent_thread_internal_id= parent->m_thread_internal_id;
 
       memcpy(pfs->m_username, parent->m_username, sizeof(pfs->m_username));
@@ -1549,6 +1556,8 @@ void* pfs_spawn_thread(void *arg)
 
       memcpy(pfs->m_hostname, parent->m_hostname, sizeof(pfs->m_hostname));
       pfs->m_hostname_length= parent->m_hostname_length;
+
+      set_thread_account(pfs);
     }
   }
   else
@@ -1660,10 +1669,14 @@ static void set_thread_user_v1(const cha
 
   pfs->m_lock.allocated_to_dirty();
 
+  clear_thread_account(pfs);
+
   if (user_len > 0)
     memcpy(pfs->m_username, user, user_len);
   pfs->m_username_length= user_len;
 
+  set_thread_account(pfs);
+
   bool enabled= true;
   if (flag_thread_instrumentation)
   {
@@ -1689,9 +1702,9 @@ static void set_thread_user_v1(const cha
 
 /**
   Implementation of the thread instrumentation interface.
-  @sa PSI_v1::set_thread_user_host.
+  @sa PSI_v1::set_thread_account.
 */
-static void set_thread_user_host_v1(const char *user, int user_len,
+static void set_thread_account_v1(const char *user, int user_len,
                                     const char *host, int host_len)
 {
   PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
@@ -1708,6 +1721,8 @@ static void set_thread_user_host_v1(cons
 
   pfs->m_lock.allocated_to_dirty();
 
+  clear_thread_account(pfs);
+
   if (host_len > 0)
     memcpy(pfs->m_hostname, host, host_len);
   pfs->m_hostname_length= host_len;
@@ -1716,6 +1731,8 @@ static void set_thread_user_host_v1(cons
     memcpy(pfs->m_username, user, user_len);
   pfs->m_username_length= user_len;
 
+  set_thread_account(pfs);
+
   bool enabled= true;
   if (flag_thread_instrumentation)
   {
@@ -3597,7 +3614,6 @@ static void end_file_wait_v1(PSI_file_lo
   }
 }
 
-
 static void start_stage_v1(PSI_stage_key key, const char *src_file, int src_line)
 {
   ulonglong timer_value= 0;
@@ -4220,6 +4236,7 @@ static void end_statement_v1(PSI_stateme
       break;
   }
 }
+
 /**
   Implementation of the instrumentation interface.
   @sa PSI_v1.
@@ -4250,7 +4267,7 @@ PSI_v1 PFS_v1=
   set_thread_id_v1,
   get_thread_v1,
   set_thread_user_v1,
-  set_thread_user_host_v1,
+  set_thread_account_v1,
   set_thread_db_v1,
   set_thread_command_v1,
   set_thread_start_time_v1,

=== added file 'storage/perfschema/pfs_account.cc'
--- a/storage/perfschema/pfs_account.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/pfs_account.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,452 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file storage/perfschema/pfs_account.cc
+  Performance schema user@host (implementation).
+*/
+
+#include "my_global.h"
+#include "my_sys.h"
+#include "pfs.h"
+#include "pfs_stat.h"
+#include "pfs_instr.h"
+#include "pfs_setup_actor.h"
+#include "pfs_host.h"
+#include "pfs_host.h"
+#include "pfs_user.h"
+#include "pfs_account.h"
+#include "pfs_global.h"
+#include "pfs_instr_class.h"
+
+/**
+  @addtogroup Performance_schema_buffers
+  @{
+*/
+
+ulong account_max;
+ulong account_lost;
+
+PFS_account *account_array= NULL;
+
+static PFS_single_stat *account_instr_class_waits_array= NULL;
+static PFS_stage_stat *account_instr_class_stages_array= NULL;
+static PFS_statement_stat *account_instr_class_statements_array= NULL;
+
+static LF_HASH account_hash;
+static bool account_hash_inited= false;
+
+/**
+  Initialize the user buffers.
+  @param param                        sizing parameters
+  @return 0 on success
+*/
+int init_account(const PFS_global_param *param)
+{
+  uint index;
+
+  account_max= param->m_account_sizing;
+
+  account_array= NULL;
+  account_instr_class_waits_array= NULL;
+  account_instr_class_stages_array= NULL;
+  account_instr_class_statements_array= NULL;
+  uint waits_sizing= account_max * wait_class_max;
+  uint stages_sizing= account_max * stage_class_max;
+  uint statements_sizing= account_max * statement_class_max;
+
+  if (account_max > 0)
+  {
+    account_array= PFS_MALLOC_ARRAY(account_max, PFS_account,
+                                      MYF(MY_ZEROFILL));
+    if (unlikely(account_array == NULL))
+      return 1;
+  }
+
+  if (waits_sizing > 0)
+  {
+    account_instr_class_waits_array=
+      PFS_connection_slice::alloc_waits_slice(waits_sizing);
+    if (unlikely(account_instr_class_waits_array == NULL))
+      return 1;
+  }
+
+  if (stages_sizing > 0)
+  {
+    account_instr_class_stages_array=
+      PFS_connection_slice::alloc_stages_slice(stages_sizing);
+    if (unlikely(account_instr_class_stages_array == NULL))
+      return 1;
+  }
+
+  if (statements_sizing > 0)
+  {
+    account_instr_class_statements_array=
+      PFS_connection_slice::alloc_statements_slice(statements_sizing);
+    if (unlikely(account_instr_class_statements_array == NULL))
+      return 1;
+  }
+
+  for (index= 0; index < account_max; index++)
+  {
+    account_array[index].m_instr_class_waits_stats=
+      &account_instr_class_waits_array[index * wait_class_max];
+    account_array[index].m_instr_class_stages_stats=
+      &account_instr_class_stages_array[index * stage_class_max];
+    account_array[index].m_instr_class_statements_stats=
+      &account_instr_class_statements_array[index * statement_class_max];
+  }
+
+  return 0;
+}
+
+/** Cleanup all the user buffers. */
+void cleanup_account(void)
+{
+  pfs_free(account_array);
+  account_array= NULL;
+  pfs_free(account_instr_class_waits_array);
+  account_instr_class_waits_array= NULL;
+  account_max= 0;
+}
+
+static uchar *account_hash_get_key(const uchar *entry, size_t *length,
+                                my_bool)
+{
+  const PFS_account * const *typed_entry;
+  const PFS_account *account;
+  const void *result;
+  typed_entry= reinterpret_cast<const PFS_account* const *> (entry);
+  DBUG_ASSERT(typed_entry != NULL);
+  account= *typed_entry;
+  DBUG_ASSERT(account != NULL);
+  *length= account->m_key.m_key_length;
+  result= account->m_key.m_hash_key;
+  return const_cast<uchar*> (reinterpret_cast<const uchar*> (result));
+}
+
+/**
+  Initialize the user hash.
+  @return 0 on success
+*/
+int init_account_hash(void)
+{
+  if (! account_hash_inited)
+  {
+    lf_hash_init(&account_hash, sizeof(PFS_account*), LF_HASH_UNIQUE,
+                 0, 0, account_hash_get_key, &my_charset_bin);
+    account_hash_inited= true;
+  }
+  return 0;
+}
+
+/** Cleanup the user hash. */
+void cleanup_account_hash(void)
+{
+  if (account_hash_inited)
+  {
+    lf_hash_destroy(&account_hash);
+    account_hash_inited= false;
+  }
+}
+
+static LF_PINS* get_account_hash_pins(PFS_thread *thread)
+{
+  if (unlikely(thread->m_account_hash_pins == NULL))
+  {
+    if (! account_hash_inited)
+      return NULL;
+    thread->m_account_hash_pins= lf_hash_get_pins(&account_hash);
+  }
+  return thread->m_account_hash_pins;
+}
+
+static void set_account_key(PFS_account_key *key,
+                              const char *user, uint user_length,
+                              const char *host, uint host_length)
+{
+  DBUG_ASSERT(user_length <= USERNAME_LENGTH);
+  DBUG_ASSERT(host_length <= HOSTNAME_LENGTH);
+
+  char *ptr= &key->m_hash_key[0];
+  if (user_length > 0)
+  {
+    memcpy(ptr, user, user_length);
+    ptr+= user_length;
+  }
+  ptr[0]= 0;
+  ptr++;
+  if (host_length > 0)
+  {
+    memcpy(ptr, host, host_length);
+    ptr+= host_length;
+  }
+  ptr[0]= 0;
+  ptr++;
+  key->m_key_length= ptr - &key->m_hash_key[0];
+}
+
+PFS_account *
+find_or_create_account(PFS_thread *thread,
+                         const char *username, uint username_length,
+                         const char *hostname, uint hostname_length)
+{
+  if (account_max == 0)
+  {
+    account_lost++;
+    return NULL;
+  }
+
+  LF_PINS *pins= get_account_hash_pins(thread);
+  if (unlikely(pins == NULL))
+  {
+    account_lost++;
+    return NULL;
+  }
+
+  PFS_account_key key;
+  set_account_key(&key, username, username_length,
+                    hostname, hostname_length);
+
+  PFS_account **entry;
+  uint retry_count= 0;
+  const uint retry_max= 3;
+
+search:
+  entry= reinterpret_cast<PFS_account**>
+    (lf_hash_search(&account_hash, pins,
+                    key.m_hash_key, key.m_key_length));
+  if (entry && (entry != MY_ERRPTR))
+  {
+    PFS_account *pfs;
+    pfs= *entry;
+    pfs->inc_refcount();
+    lf_hash_search_unpin(pins);
+    return pfs;
+  }
+
+  PFS_scan scan;
+  uint random= randomized_index(username, account_max);
+
+  for (scan.init(random, account_max);
+       scan.has_pass();
+       scan.next_pass())
+  {
+    PFS_account *pfs= account_array + scan.first();
+    PFS_account *pfs_last= account_array + scan.last();
+    for ( ; pfs < pfs_last; pfs++)
+    {
+      if (pfs->m_lock.is_free())
+      {
+        if (pfs->m_lock.free_to_dirty())
+        {
+          pfs->m_key= key;
+          if (username_length > 0)
+            pfs->m_username= &pfs->m_key.m_hash_key[0];
+          else
+            pfs->m_username= NULL;
+          pfs->m_username_length= username_length;
+
+          if (hostname_length > 0)
+            pfs->m_hostname= &pfs->m_key.m_hash_key[username_length + 1];
+          else
+            pfs->m_hostname= NULL;
+          pfs->m_hostname_length= hostname_length;
+
+          pfs->m_user= find_or_create_user(thread, username, username_length);
+          pfs->m_host= find_or_create_host(thread, hostname, hostname_length);
+
+          pfs->init_refcount();
+          pfs->reset_stats();
+          pfs->m_disconnected_count= 0;
+
+          int res;
+          res= lf_hash_insert(&account_hash, pins, &pfs);
+          if (likely(res == 0))
+          {
+            pfs->m_lock.dirty_to_allocated();
+            return pfs;
+          }
+
+          if (pfs->m_user)
+          {
+            pfs->m_user->release();
+            pfs->m_user= NULL;
+          }
+          if (pfs->m_host)
+          {
+            pfs->m_host->release();
+            pfs->m_host= NULL;
+          }
+
+          pfs->m_lock.dirty_to_free();
+
+          if (res > 0)
+          {
+            if (++retry_count > retry_max)
+            {
+              account_lost++;
+              return NULL;
+            }
+            goto search;
+          }
+
+          account_lost++;
+          return NULL;
+        }
+      }
+    }
+  }
+
+  account_lost++;
+  return NULL;
+}
+
+void PFS_account::aggregate()
+{
+  aggregate_waits();
+
+  if (likely(m_user != NULL && m_host != NULL))
+  {
+    m_user->m_disconnected_count+= m_disconnected_count;
+    m_host->m_disconnected_count+= m_disconnected_count;
+    m_disconnected_count= 0;
+  }
+  else
+  {
+    if (m_user != NULL)
+    {
+      m_user->m_disconnected_count+= m_disconnected_count;
+      m_disconnected_count= 0;
+    }
+    else if (m_host != NULL)
+    {
+      m_host->m_disconnected_count+= m_disconnected_count;
+      m_disconnected_count= 0;
+    }
+  }
+}
+
+void PFS_account::aggregate_waits()
+{
+  if (likely(m_user != NULL && m_host != NULL))
+  {
+    /*
+      Aggregate EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
+      -  EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME
+      -  EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME
+      in parallel.
+    */
+    aggregate_all_event_names(m_instr_class_waits_stats,
+                              m_user->m_instr_class_waits_stats,
+                              m_host->m_instr_class_waits_stats);
+  }
+  else
+  {
+    if (m_user != NULL)
+    {
+      /*
+        Aggregate EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
+        -  EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME
+      */
+      aggregate_all_event_names(m_instr_class_waits_stats,
+                                m_user->m_instr_class_waits_stats);
+    }
+    else if (m_host != NULL)
+    {
+      /*
+        Aggregate EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
+        -  EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME
+      */
+      aggregate_all_event_names(m_instr_class_waits_stats,
+                                m_host->m_instr_class_waits_stats);
+    }
+  }
+}
+
+void PFS_account::release()
+{
+  dec_refcount();
+}
+
+PFS_account *sanitize_account(PFS_account *unsafe)
+{
+  if ((&account_array[0] <= unsafe) &&
+      (unsafe < &account_array[account_max]))
+    return unsafe;
+  return NULL;
+}
+
+void purge_account(PFS_thread *thread, PFS_account *account)
+{
+  account->aggregate();
+
+  LF_PINS *pins= get_account_hash_pins(thread);
+  if (unlikely(pins == NULL))
+    return;
+
+  PFS_account **entry;
+  entry= reinterpret_cast<PFS_account**>
+    (lf_hash_search(&account_hash, pins,
+                    account->m_key.m_hash_key,
+                    account->m_key.m_key_length));
+  if (entry && (entry != MY_ERRPTR))
+  {
+    PFS_account *pfs;
+    pfs= *entry;
+    DBUG_ASSERT(pfs == account);
+    if (account->get_refcount() == 0)
+    {
+      lf_hash_delete(&account_hash, pins,
+                     account->m_key.m_hash_key,
+                     account->m_key.m_key_length);
+      if (account->m_user != NULL)
+      {
+        account->m_user->release();
+        account->m_user= NULL;
+      }
+      if (account->m_host != NULL)
+      {
+        account->m_host->release();
+        account->m_host= NULL;
+      }
+      account->m_lock.allocated_to_free();
+    }
+    lf_hash_search_unpin(pins);
+  }
+}
+
+/** Purge non connected user@host, reset stats of connected user@host. */
+void purge_all_account(void)
+{
+  PFS_thread *thread= PFS_thread::get_current_thread();
+  if (unlikely(thread == NULL))
+    return;
+
+  PFS_account *pfs= account_array;
+  PFS_account *pfs_last= account_array + account_max;
+
+  for ( ; pfs < pfs_last; pfs++)
+  {
+    if (pfs->m_lock.is_populated())
+    {
+      pfs->m_disconnected_count= 0;
+      if (pfs->get_refcount() == 0)
+        purge_account(thread, pfs);
+    }
+  }
+}
+
+/** @} */

=== added file 'storage/perfschema/pfs_account.h'
--- a/storage/perfschema/pfs_account.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/pfs_account.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,117 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef PFS_ACCOUNT_H
+#define PFS_ACCOUNT_H
+
+/**
+  @file storage/perfschema/pfs_account.h
+  Performance schema user@host (declarations).
+*/
+
+#include "pfs_lock.h"
+#include "lf.h"
+#include "pfs_con_slice.h"
+
+struct PFS_global_param;
+struct PFS_user;
+struct PFS_host;
+struct PFS_thread;
+
+/**
+  @addtogroup Performance_schema_buffers
+  @{
+*/
+
+struct PFS_account_key
+{
+  /**
+    Hash search key.
+    This has to be a string for LF_HASH,
+    the format is "<username><0x00><hostname><0x00>"
+  */
+  char m_hash_key[USERNAME_LENGTH + 1 + HOSTNAME_LENGTH + 1];
+  uint m_key_length;
+};
+
+struct PFS_account : PFS_connection_slice
+{
+public:
+  inline void init_refcount(void)
+  {
+    PFS_atomic::store_32(& m_refcount, 1);
+  }
+
+  inline int get_refcount(void)
+  {
+    return PFS_atomic::load_32(& m_refcount);
+  }
+
+  inline void inc_refcount(void)
+  {
+    PFS_atomic::add_32(& m_refcount, 1);
+  }
+
+  inline void dec_refcount(void)
+  {
+    PFS_atomic::add_32(& m_refcount, -1);
+  }
+
+  void aggregate(void);
+  void aggregate_waits(void);
+  void release(void);
+
+  /** Internal lock. */
+  pfs_lock m_lock;
+  PFS_account_key m_key;
+  const char *m_username;
+  uint m_username_length;
+  const char *m_hostname;
+  uint m_hostname_length;
+  PFS_user *m_user;
+  PFS_host *m_host;
+
+  ulonglong m_disconnected_count;
+
+private:
+  int m_refcount;
+};
+
+int init_account(const PFS_global_param *param);
+void cleanup_account(void);
+int init_account_hash(void);
+void cleanup_account_hash(void);
+
+PFS_account *
+find_or_create_account(PFS_thread *thread,
+                         const char *username, uint username_length,
+                         const char *hostname, uint hostname_length);
+
+PFS_account *sanitize_account(PFS_account *unsafe);
+void purge_all_account(void);
+
+
+/* For iterators and show status. */
+
+extern ulong account_max;
+extern ulong account_lost;
+
+/* Exposing the data directly, for iterators. */
+
+extern PFS_account *account_array;
+
+/** @} */
+#endif
+

=== modified file 'storage/perfschema/pfs_engine_table.cc'
--- a/storage/perfschema/pfs_engine_table.cc	2011-02-15 14:31:13 +0000
+++ b/storage/perfschema/pfs_engine_table.cc	2011-05-07 00:40:25 +0000
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -18,6 +18,8 @@
   Performance schema tables (implementation).
 */
 
+#include "my_global.h"
+#include "my_pthread.h"
 #include "pfs_engine_table.h"
 
 #include "table_events_waits.h"
@@ -35,18 +37,32 @@
 #include "table_file_instances.h"
 #include "table_file_summary.h"
 #include "table_threads.h"
+
+#include "table_ews_by_host_by_event_name.h"
+#include "table_ews_by_user_by_event_name.h"
+#include "table_ews_by_account_by_event_name.h"
 #include "table_tiws_by_index_usage.h"
 #include "table_tiws_by_table.h"
 #include "table_tlws_by_table.h"
 
 #include "table_events_stages.h"
 #include "table_esgs_by_thread_by_event_name.h"
+#include "table_esgs_by_host_by_event_name.h"
+#include "table_esgs_by_user_by_event_name.h"
+#include "table_esgs_by_account_by_event_name.h"
 #include "table_esgs_global_by_event_name.h"
 
 #include "table_events_statements.h"
 #include "table_esms_by_thread_by_event_name.h"
+#include "table_esms_by_host_by_event_name.h"
+#include "table_esms_by_user_by_event_name.h"
+#include "table_esms_by_account_by_event_name.h"
 #include "table_esms_global_by_event_name.h"
 
+#include "table_users.h"
+#include "table_accounts.h"
+#include "table_hosts.h"
+
 /* For show status */
 #include "pfs_column_values.h"
 #include "pfs_instr.h"
@@ -66,10 +82,13 @@ static PFS_engine_table_share *all_share
 {
   &table_cond_instances::m_share,
   &table_events_waits_current::m_share,
-  &table_events_waits_history_long::m_share,
   &table_events_waits_history::m_share,
+  &table_events_waits_history_long::m_share,
+  &table_ews_by_host_by_event_name::m_share,
   &table_events_waits_summary_by_instance::m_share,
   &table_ews_by_thread_by_event_name::m_share,
+  &table_ews_by_user_by_event_name::m_share,
+  &table_ews_by_account_by_event_name::m_share,
   &table_ews_global_by_event_name::m_share,
   &table_file_instances::m_share,
   &table_file_summary_by_event_name::m_share,
@@ -83,23 +102,32 @@ static PFS_engine_table_share *all_share
   &table_setup_instruments::m_share,
   &table_setup_objects::m_share,
   &table_setup_timers::m_share,
-  &table_threads::m_share,
   &table_tiws_by_index_usage::m_share,
   &table_tiws_by_table::m_share,
   &table_tlws_by_table::m_share,
+  &table_threads::m_share,
 
   &table_events_stages_current::m_share,
   &table_events_stages_history::m_share,
   &table_events_stages_history_long::m_share,
   &table_esgs_by_thread_by_event_name::m_share,
+  &table_esgs_by_account_by_event_name::m_share,
+  &table_esgs_by_user_by_event_name::m_share,
+  &table_esgs_by_host_by_event_name::m_share,
   &table_esgs_global_by_event_name::m_share,
 
   &table_events_statements_current::m_share,
   &table_events_statements_history::m_share,
   &table_events_statements_history_long::m_share,
   &table_esms_by_thread_by_event_name::m_share,
+  &table_esms_by_account_by_event_name::m_share,
+  &table_esms_by_user_by_event_name::m_share,
+  &table_esms_by_host_by_event_name::m_share,
   &table_esms_global_by_event_name::m_share,
 
+  &table_users::m_share,
+  &table_accounts::m_share,
+  &table_hosts::m_share,
   NULL
 };
 
@@ -114,7 +142,7 @@ void PFS_engine_table_share::check_all_t
   DBUG_EXECUTE_IF("tampered_perfschema_table1",
                   {
                     /* Hack SETUP_INSTRUMENT, incompatible change. */
-                    all_shares[16]->m_field_def->count++;
+                    all_shares[24]->m_field_def->count++;
                   });
 
   for (current= &all_shares[0]; (*current) != NULL; current++)
@@ -926,146 +954,302 @@ bool pfs_show_status(handlerton *hton, T
       total_memory+= size;
       break;
     case 59:
+      name= "(pfs_account).row_size";
+      size= sizeof(PFS_account);
+      break;
+    case 60:
+      name= "(pfs_account).row_count";
+      size= account_max;
+      break;
+    case 61:
+      name= "(pfs_account).memory";
+      size= account_max * sizeof(PFS_account);
+      total_memory+= size;
+      break;
+    case 62:
+      name= "events_waits_summary_by_account_by_event_name.row_size";
+      size= sizeof(PFS_single_stat);
+      break;
+    case 63:
+      name= "events_waits_summary_by_account_by_event_name.row_count";
+      size= account_max * wait_class_max;
+      break;
+    case 64:
+      name= "events_waits_summary_by_account_by_event_name.memory";
+      size= account_max * wait_class_max * sizeof(PFS_single_stat);
+      total_memory+= size;
+      break;
+    case 65:
+      name= "events_waits_summary_by_user_by_event_name.row_size";
+      size= sizeof(PFS_single_stat);
+      break;
+    case 66:
+      name= "events_waits_summary_by_user_by_event_name.row_count";
+      size= user_max * wait_class_max;
+      break;
+    case 67:
+      name= "events_waits_summary_by_user_by_event_name.memory";
+      size= user_max * wait_class_max * sizeof(PFS_single_stat);
+      total_memory+= size;
+      break;
+    case 68:
+      name= "events_waits_summary_by_host_by_event_name.row_size";
+      size= sizeof(PFS_single_stat);
+      break;
+    case 69:
+      name= "events_waits_summary_by_host_by_event_name.row_count";
+      size= host_max * wait_class_max;
+      break;
+    case 70:
+      name= "events_waits_summary_by_host_by_event_name.memory";
+      size= host_max * wait_class_max * sizeof(PFS_single_stat);
+      total_memory+= size;
+      break;
+    case 71:
+      name= "(pfs_user).row_size";
+      size= sizeof(PFS_user);
+      break;
+    case 72:
+      name= "(pfs_user).row_count";
+      size= user_max;
+      break;
+    case 73:
+      name= "(pfs_user).memory";
+      size= user_max * sizeof(PFS_user);
+      total_memory+= size;
+      break;
+    case 74:
+      name= "(pfs_host).row_size";
+      size= sizeof(PFS_host);
+      break;
+    case 75:
+      name= "(pfs_host).row_count";
+      size= host_max;
+      break;
+    case 76:
+      name= "(pfs_host).memory";
+      size= host_max * sizeof(PFS_host);
+      total_memory+= size;
+      break;
+    case 77:
       name= "(pfs_stage_class).row_size";
       size= sizeof(PFS_stage_class);
       break;
-    case 60:
+    case 78:
       name= "(pfs_stage_class).row_count";
       size= stage_class_max;
       break;
-    case 61:
+    case 79:
       name= "(pfs_stage_class).memory";
       size= stage_class_max * sizeof(PFS_stage_class);
       total_memory+= size;
       break;
-    case 62:
+    case 80:
       name= "events_stages_history.row_size";
       size= sizeof(PFS_events_stages);
       break;
-    case 63:
+    case 81:
       name= "events_stages_history.row_count";
       size= events_stages_history_per_thread * thread_max;
       break;
-    case 64:
+    case 82:
       name= "events_stages_history.memory";
       size= events_stages_history_per_thread * thread_max
         * sizeof(PFS_events_stages);
       total_memory+= size;
       break;
-    case 65:
+    case 83:
       name= "events_stages_history_long.row_size";
       size= sizeof(PFS_events_stages);
       break;
-    case 66:
+    case 84:
       name= "events_stages_history_long.row_count";
       size= events_stages_history_long_size;
       break;
-    case 67:
+    case 85:
       name= "events_stages_history_long.memory";
       size= events_stages_history_long_size * sizeof(PFS_events_stages);
       total_memory+= size;
       break;
-    case 68:
+    case 86:
       name= "events_stages_summary_by_thread_by_event_name.row_size";
       size= sizeof(PFS_stage_stat);
       break;
-    case 69:
+    case 87:
       name= "events_stages_summary_by_thread_by_event_name.row_count";
       size= thread_max * stage_class_max;
       break;
-    case 70:
+    case 88:
       name= "events_stages_summary_by_thread_by_event_name.memory";
       size= thread_max * stage_class_max * sizeof(PFS_stage_stat);
       total_memory+= size;
       break;
-    case 71:
+    case 89:
       name= "events_stages_summary_global_by_event_name.row_size";
       size= sizeof(PFS_stage_stat);
       break;
-    case 72:
+    case 90:
       name= "events_stages_summary_global_by_event_name.row_count";
       size= stage_class_max;
       break;
-    case 73:
+    case 91:
       name= "events_stages_summary_global_by_event_name.memory";
       size= stage_class_max * sizeof(PFS_stage_stat);
       total_memory+= size;
       break;
-    case 74:
+    case 92:
+      name= "events_stages_summary_by_account_by_event_name.row_size";
+      size= sizeof(PFS_stage_stat);
+      break;
+    case 93:
+      name= "events_stages_summary_by_account_by_event_name.row_count";
+      size= account_max * stage_class_max;
+      break;
+    case 94:
+      name= "events_stages_summary_by_account_by_event_name.memory";
+      size= account_max * stage_class_max * sizeof(PFS_stage_stat);
+      total_memory+= size;
+      break;
+    case 95:
+      name= "events_stages_summary_by_user_by_event_name.row_size";
+      size= sizeof(PFS_stage_stat);
+      break;
+    case 96:
+      name= "events_stages_summary_by_user_by_event_name.row_count";
+      size= user_max * stage_class_max;
+      break;
+    case 97:
+      name= "events_stages_summary_by_user_by_event_name.memory";
+      size= user_max * stage_class_max * sizeof(PFS_stage_stat);
+      total_memory+= size;
+      break;
+    case 98:
+      name= "events_stages_summary_by_host_by_event_name.row_size";
+      size= sizeof(PFS_stage_stat);
+      break;
+    case 99:
+      name= "events_stages_summary_by_host_by_event_name.row_count";
+      size= host_max * stage_class_max;
+      break;
+    case 100:
+      name= "events_stages_summary_by_host_by_event_name.memory";
+      size= host_max * stage_class_max * sizeof(PFS_stage_stat);
+      total_memory+= size;
+      break;
+    case 101:
       name= "(pfs_statement_class).row_size";
       size= sizeof(PFS_statement_class);
       break;
-    case 75:
+    case 102:
       name= "(pfs_statement_class).row_count";
       size= statement_class_max;
       break;
-    case 76:
+    case 103:
       name= "(pfs_statement_class).memory";
       size= statement_class_max * sizeof(PFS_statement_class);
       total_memory+= size;
       break;
-    case 77:
+    case 104:
       name= "events_statements_history.row_size";
       size= sizeof(PFS_events_statements);
       break;
-    case 78:
+    case 105:
       name= "events_statements_history.row_count";
       size= events_statements_history_per_thread * thread_max;
       break;
-    case 79:
+    case 106:
       name= "events_statements_history.memory";
       size= events_statements_history_per_thread * thread_max
         * sizeof(PFS_events_statements);
       total_memory+= size;
       break;
-    case 80:
+    case 107:
       name= "events_statements_history_long.row_size";
       size= sizeof(PFS_events_statements);
       break;
-    case 81:
+    case 108:
       name= "events_statements_history_long.row_count";
       size= events_statements_history_long_size;
       break;
-    case 82:
+    case 109:
       name= "events_statements_history_long.memory";
       size= events_statements_history_long_size * sizeof(PFS_events_statements);
       total_memory+= size;
       break;
-    case 83:
+    case 110:
       name= "events_statements_summary_by_thread_by_event_name.row_size";
       size= sizeof(PFS_statement_stat);
       break;
-    case 84:
+    case 111:
       name= "events_statements_summary_by_thread_by_event_name.row_count";
       size= thread_max * statement_class_max;
       break;
-    case 85:
+    case 112:
       name= "events_statements_summary_by_thread_by_event_name.memory";
       size= thread_max * statement_class_max * sizeof(PFS_statement_stat);
       total_memory+= size;
       break;
-    case 86:
+    case 113:
       name= "events_statements_summary_global_by_event_name.row_size";
       size= sizeof(PFS_statement_stat);
       break;
-    case 87:
+    case 114:
       name= "events_statements_summary_global_by_event_name.row_count";
       size= statement_class_max;
       break;
-    case 88:
+    case 115:
       name= "events_statements_summary_global_by_event_name.memory";
       size= statement_class_max * sizeof(PFS_statement_stat);
       total_memory+= size;
       break;
-    case 89:
+    case 116:
+      name= "events_statements_summary_by_account_by_event_name.row_size";
+      size= sizeof(PFS_statement_stat);
+      break;
+    case 117:
+      name= "events_statements_summary_by_account_by_event_name.row_count";
+      size= account_max * statement_class_max;
+      break;
+    case 118:
+      name= "events_statements_summary_by_account_by_event_name.memory";
+      size= account_max * statement_class_max * sizeof(PFS_statement_stat);
+      total_memory+= size;
+      break;
+    case 119:
+      name= "events_statements_summary_by_user_by_event_name.row_size";
+      size= sizeof(PFS_statement_stat);
+      break;
+    case 120:
+      name= "events_statements_summary_by_user_by_event_name.row_count";
+      size= user_max * statement_class_max;
+      break;
+    case 121:
+      name= "events_statements_summary_by_user_by_event_name.memory";
+      size= user_max * statement_class_max * sizeof(PFS_statement_stat);
+      total_memory+= size;
+      break;
+    case 122:
+      name= "events_statements_summary_by_host_by_event_name.row_size";
+      size= sizeof(PFS_statement_stat);
+      break;
+    case 123:
+      name= "events_statements_summary_by_host_by_event_name.row_count";
+      size= host_max * statement_class_max;
+      break;
+    case 124:
+      name= "events_statements_summary_by_host_by_event_name.memory";
+      size= host_max * statement_class_max * sizeof(PFS_statement_stat);
+      total_memory+= size;
+      break;
+    case 125:
       name= "events_statements_current.row_size";
       size= sizeof(PFS_events_statements);
       break;
-    case 90:
+    case 126:
       name= "events_statements_current.row_count";
       size= thread_max * statement_stack_max;
       break;
-    case 91:
+    case 127:
       name= "events_statements_current.memory";
       size= thread_max * statement_stack_max * sizeof(PFS_events_statements);
       total_memory+= size;
@@ -1074,7 +1258,7 @@ bool pfs_show_status(handlerton *hton, T
       This case must be last,
       for aggregation in total_memory.
     */
-    case 92:
+    case 128:
       name= "performance_schema.memory";
       size= total_memory;
       /* This will fail if something is not advertised here */

=== modified file 'storage/perfschema/pfs_events_stages.cc'
--- a/storage/perfschema/pfs_events_stages.cc	2011-02-17 18:10:56 +0000
+++ b/storage/perfschema/pfs_events_stages.cc	2011-05-07 00:40:25 +0000
@@ -184,12 +184,12 @@ void reset_events_stages_by_thread()
   }
 }
 
-/** Reset table EVENTS_STAGES_SUMMARY_BY_USER_HOST_BY_EVENT_NAME data. */
-void reset_events_stages_by_user_host()
+/** Reset table EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME data. */
+void reset_events_stages_by_account()
 {
 #ifdef LATER
-  PFS_user_host *pfs= user_host_array;
-  PFS_user_host *pfs_last= user_host_array + user_host_max;
+  PFS_account *pfs= account_array;
+  PFS_account *pfs_last= account_array + account_max;
 
   for ( ; pfs < pfs_last; pfs++)
   {

=== modified file 'storage/perfschema/pfs_events_stages.h'
--- a/storage/perfschema/pfs_events_stages.h	2011-02-14 14:23:55 +0000
+++ b/storage/perfschema/pfs_events_stages.h	2011-05-07 00:40:25 +0000
@@ -24,7 +24,7 @@
 #include "pfs_events.h"
 
 struct PFS_thread;
-struct PFS_user_host;
+struct PFS_account;
 struct PFS_user;
 struct PFS_host;
 
@@ -53,11 +53,11 @@ void reset_events_stages_current();
 void reset_events_stages_history();
 void reset_events_stages_history_long();
 void reset_events_stages_by_thread();
-void reset_events_stages_by_user_host();
+void reset_events_stages_by_account();
 void reset_events_stages_by_user();
 void reset_events_stages_by_host();
 void reset_events_stages_global();
-void aggregate_user_host_stages(PFS_user_host *user_host);
+void aggregate_account_stages(PFS_account *account);
 void aggregate_user_stages(PFS_user *user);
 void aggregate_host_stages(PFS_host *host);
 

=== modified file 'storage/perfschema/pfs_events_statements.cc'
--- a/storage/perfschema/pfs_events_statements.cc	2011-02-17 18:10:56 +0000
+++ b/storage/perfschema/pfs_events_statements.cc	2011-05-07 00:40:25 +0000
@@ -188,12 +188,12 @@ void reset_events_statements_by_thread()
   }
 }
 
-/** Reset table EVENTS_STATEMENTS_SUMMARY_BY_USER_HOST_BY_EVENT_NAME data. */
-void reset_events_statements_by_user_host()
+/** Reset table EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME data. */
+void reset_events_statements_by_account()
 {
 #ifdef LATER
-  PFS_user_host *pfs= user_host_array;
-  PFS_user_host *pfs_last= user_host_array + user_host_max;
+  PFS_account *pfs= account_array;
+  PFS_account *pfs_last= account_array + account_max;
 
   for ( ; pfs < pfs_last; pfs++)
   {

=== modified file 'storage/perfschema/pfs_events_statements.h'
--- a/storage/perfschema/pfs_events_statements.h	2011-04-04 14:34:42 +0000
+++ b/storage/perfschema/pfs_events_statements.h	2011-05-07 00:40:25 +0000
@@ -25,7 +25,7 @@
 #include "pfs_events.h"
 
 struct PFS_thread;
-struct PFS_user_host;
+struct PFS_account;
 struct PFS_user;
 struct PFS_host;
 
@@ -108,11 +108,11 @@ void reset_events_statements_current();
 void reset_events_statements_history();
 void reset_events_statements_history_long();
 void reset_events_statements_by_thread();
-void reset_events_statements_by_user_host();
+void reset_events_statements_by_account();
 void reset_events_statements_by_user();
 void reset_events_statements_by_host();
 void reset_events_statements_global();
-void aggregate_user_host_statements(PFS_user_host *user_host);
+void aggregate_account_statements(PFS_account *account);
 void aggregate_user_statements(PFS_user *user);
 void aggregate_host_statements(PFS_host *host);
 

=== modified file 'storage/perfschema/pfs_events_waits.cc'
--- a/storage/perfschema/pfs_events_waits.cc	2011-02-14 14:23:55 +0000
+++ b/storage/perfschema/pfs_events_waits.cc	2011-05-07 00:40:25 +0000
@@ -21,7 +21,11 @@
 #include "my_global.h"
 #include "my_sys.h"
 #include "pfs_global.h"
+#include "pfs_instr_class.h"
 #include "pfs_instr.h"
+#include "pfs_user.h"
+#include "pfs_host.h"
+#include "pfs_account.h"
 #include "pfs_events_waits.h"
 #include "pfs_atomic.h"
 #include "m_string.h"
@@ -181,6 +185,45 @@ void reset_events_waits_by_thread()
   }
 }
 
+/** Reset table EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME data. */
+void reset_events_waits_by_account()
+{
+  PFS_account *pfs= account_array;
+  PFS_account *pfs_last= account_array + account_max;
+
+  for ( ; pfs < pfs_last; pfs++)
+  {
+    if (pfs->m_lock.is_populated())
+      pfs->aggregate_waits();
+  }
+}
+
+/** Reset table EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME data. */
+void reset_events_waits_by_user()
+{
+  PFS_user *pfs= user_array;
+  PFS_user *pfs_last= user_array + user_max;
+
+  for ( ; pfs < pfs_last; pfs++)
+  {
+    if (pfs->m_lock.is_populated())
+      pfs->aggregate_waits();
+  }
+}
+
+/** Reset table EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME data. */
+void reset_events_waits_by_host()
+{
+  PFS_host *pfs= host_array;
+  PFS_host *pfs_last= host_array + host_max;
+
+  for ( ; pfs < pfs_last; pfs++)
+  {
+    if (pfs->m_lock.is_populated())
+      pfs->aggregate_waits();
+  }
+}
+
 /** Reset table EVENTS_WAITS_GLOBAL_BY_EVENT_NAME data. */
 void reset_events_waits_global()
 {

=== modified file 'storage/perfschema/pfs_events_waits.h'
--- a/storage/perfschema/pfs_events_waits.h	2011-02-14 14:23:55 +0000
+++ b/storage/perfschema/pfs_events_waits.h	2011-05-07 00:40:25 +0000
@@ -33,6 +33,9 @@ struct PFS_file;
 struct PFS_thread;
 struct PFS_instr_class;
 struct PFS_table_share;
+struct PFS_account;
+struct PFS_user;
+struct PFS_host;
 
 /** Class of a wait event. */
 enum events_waits_class
@@ -110,7 +113,13 @@ void reset_events_waits_current();
 void reset_events_waits_history();
 void reset_events_waits_history_long();
 void reset_events_waits_by_thread();
+void reset_events_waits_by_account();
+void reset_events_waits_by_user();
+void reset_events_waits_by_host();
 void reset_events_waits_global();
+void aggregate_account_waits(PFS_account *account);
+void aggregate_user_waits(PFS_user *user);
+void aggregate_host_waits(PFS_host *host);
 
 void reset_table_waits_by_table();
 void reset_table_io_waits_by_table();

=== added file 'storage/perfschema/pfs_host.cc'
--- a/storage/perfschema/pfs_host.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/pfs_host.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,354 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file storage/perfschema/pfs_host.cc
+  Performance schema host (implementation).
+*/
+
+#include "my_global.h"
+#include "my_sys.h"
+#include "pfs.h"
+#include "pfs_stat.h"
+#include "pfs_instr.h"
+#include "pfs_setup_actor.h"
+#include "pfs_host.h"
+#include "pfs_global.h"
+#include "pfs_instr_class.h"
+
+/**
+  @addtogroup Performance_schema_buffers
+  @{
+*/
+
+ulong host_max;
+ulong host_lost;
+
+PFS_host *host_array= NULL;
+
+static PFS_single_stat *host_instr_class_waits_array= NULL;
+static PFS_stage_stat *host_instr_class_stages_array= NULL;
+static PFS_statement_stat *host_instr_class_statements_array= NULL;
+
+static LF_HASH host_hash;
+static bool host_hash_inited= false;
+
+/**
+  Initialize the host buffers.
+  @param param                        sizing parameters
+  @return 0 on success
+*/
+int init_host(const PFS_global_param *param)
+{
+  uint index;
+
+  host_max= param->m_host_sizing;
+
+  host_array= NULL;
+  host_instr_class_waits_array= NULL;
+  host_instr_class_stages_array= NULL;
+  host_instr_class_statements_array= NULL;
+  uint waits_sizing= host_max * wait_class_max;
+  uint stages_sizing= host_max * stage_class_max;
+  uint statements_sizing= host_max * statement_class_max;
+
+  if (host_max > 0)
+  {
+    host_array= PFS_MALLOC_ARRAY(host_max, PFS_host,
+                                 MYF(MY_ZEROFILL));
+    if (unlikely(host_array == NULL))
+      return 1;
+  }
+
+  if (waits_sizing > 0)
+  {
+    host_instr_class_waits_array=
+      PFS_connection_slice::alloc_waits_slice(waits_sizing);
+    if (unlikely(host_instr_class_waits_array == NULL))
+      return 1;
+  }
+
+  if (stages_sizing > 0)
+  {
+    host_instr_class_stages_array=
+      PFS_connection_slice::alloc_stages_slice(stages_sizing);
+    if (unlikely(host_instr_class_stages_array == NULL))
+      return 1;
+  }
+
+  if (statements_sizing > 0)
+  {
+    host_instr_class_statements_array=
+      PFS_connection_slice::alloc_statements_slice(statements_sizing);
+    if (unlikely(host_instr_class_statements_array == NULL))
+      return 1;
+  }
+
+  for (index= 0; index < host_max; index++)
+  {
+    host_array[index].m_instr_class_waits_stats=
+      &host_instr_class_waits_array[index * wait_class_max];
+    host_array[index].m_instr_class_stages_stats=
+      &host_instr_class_stages_array[index * stage_class_max];
+    host_array[index].m_instr_class_statements_stats=
+      &host_instr_class_statements_array[index * statement_class_max];
+  }
+
+  return 0;
+}
+
+/** Cleanup all the host buffers. */
+void cleanup_host(void)
+{
+  pfs_free(host_array);
+  host_array= NULL;
+  pfs_free(host_instr_class_waits_array);
+  host_instr_class_waits_array= NULL;
+  pfs_free(host_instr_class_stages_array);
+  host_instr_class_stages_array= NULL;
+  pfs_free(host_instr_class_statements_array);
+  host_instr_class_statements_array= NULL;
+  host_max= 0;
+}
+
+static uchar *host_hash_get_key(const uchar *entry, size_t *length,
+                                my_bool)
+{
+  const PFS_host * const *typed_entry;
+  const PFS_host *host;
+  const void *result;
+  typed_entry= reinterpret_cast<const PFS_host* const *> (entry);
+  DBUG_ASSERT(typed_entry != NULL);
+  host= *typed_entry;
+  DBUG_ASSERT(host != NULL);
+  *length= host->m_key.m_key_length;
+  result= host->m_key.m_hash_key;
+  return const_cast<uchar*> (reinterpret_cast<const uchar*> (result));
+}
+
+/**
+  Initialize the host hash.
+  @return 0 on success
+*/
+int init_host_hash(void)
+{
+  if (! host_hash_inited)
+  {
+    lf_hash_init(&host_hash, sizeof(PFS_host*), LF_HASH_UNIQUE,
+                 0, 0, host_hash_get_key, &my_charset_bin);
+    host_hash_inited= true;
+  }
+  return 0;
+}
+
+/** Cleanup the host hash. */
+void cleanup_host_hash(void)
+{
+  if (host_hash_inited)
+  {
+    lf_hash_destroy(&host_hash);
+    host_hash_inited= false;
+  }
+}
+
+static LF_PINS* get_host_hash_pins(PFS_thread *thread)
+{
+  if (unlikely(thread->m_host_hash_pins == NULL))
+  {
+    if (! host_hash_inited)
+      return NULL;
+    thread->m_host_hash_pins= lf_hash_get_pins(&host_hash);
+  }
+  return thread->m_host_hash_pins;
+}
+
+static void set_host_key(PFS_host_key *key,
+                         const char *host, uint host_length)
+{
+  DBUG_ASSERT(host_length <= HOSTNAME_LENGTH);
+
+  char *ptr= &key->m_hash_key[0];
+  if (host_length > 0)
+  {
+    memcpy(ptr, host, host_length);
+    ptr+= host_length;
+  }
+  ptr[0]= 0;
+  ptr++;
+  key->m_key_length= ptr - &key->m_hash_key[0];
+}
+
+PFS_host *find_or_create_host(PFS_thread *thread,
+                              const char *hostname, uint hostname_length)
+{
+  if (host_max == 0)
+  {
+    host_lost++;
+    return NULL;
+  }
+
+  LF_PINS *pins= get_host_hash_pins(thread);
+  if (unlikely(pins == NULL))
+  {
+    host_lost++;
+    return NULL;
+  }
+
+  PFS_host_key key;
+  set_host_key(&key, hostname, hostname_length);
+
+  PFS_host **entry;
+  uint retry_count= 0;
+  const uint retry_max= 3;
+
+search:
+  entry= reinterpret_cast<PFS_host**>
+    (lf_hash_search(&host_hash, pins,
+                    key.m_hash_key, key.m_key_length));
+  if (entry && (entry != MY_ERRPTR))
+  {
+    PFS_host *pfs;
+    pfs= *entry;
+    pfs->inc_refcount();
+    lf_hash_search_unpin(pins);
+    return pfs;
+  }
+
+  PFS_scan scan;
+  uint random= randomized_index(hostname, host_max);
+
+  for (scan.init(random, host_max);
+       scan.has_pass();
+       scan.next_pass())
+  {
+    PFS_host *pfs= host_array + scan.first();
+    PFS_host *pfs_last= host_array + scan.last();
+    for ( ; pfs < pfs_last; pfs++)
+    {
+      if (pfs->m_lock.is_free())
+      {
+        if (pfs->m_lock.free_to_dirty())
+        {
+          pfs->m_key= key;
+          if (hostname_length > 0)
+            pfs->m_hostname= &pfs->m_key.m_hash_key[0];
+          else
+            pfs->m_hostname= NULL;
+          pfs->m_hostname_length= hostname_length;
+
+          pfs->init_refcount();
+          pfs->reset_stats();
+          pfs->m_disconnected_count= 0;
+
+          int res;
+          res= lf_hash_insert(&host_hash, pins, &pfs);
+          if (likely(res == 0))
+          {
+            pfs->m_lock.dirty_to_allocated();
+            return pfs;
+          }
+
+          pfs->m_lock.dirty_to_free();
+
+          if (res > 0)
+          {
+            if (++retry_count > retry_max)
+            {
+              host_lost++;
+              return NULL;
+            }
+            goto search;
+          }
+
+          host_lost++;
+          return NULL;
+        }
+      }
+    }
+  }
+
+  host_lost++;
+  return NULL;
+}
+
+void PFS_host::aggregate()
+{
+  aggregate_waits();
+}
+
+void PFS_host::aggregate_waits()
+{
+  /* No parent to aggregate to (for waits only), clean the stats */
+
+  PFS_single_stat *stat= m_instr_class_waits_stats;
+  PFS_single_stat *stat_last= stat + wait_class_max;
+  for ( ; stat < stat_last; stat++)
+    stat->reset();
+}
+
+void PFS_host::release()
+{
+  dec_refcount();
+}
+
+void purge_host(PFS_thread *thread, PFS_host *host)
+{
+  host->aggregate();
+
+  LF_PINS *pins= get_host_hash_pins(thread);
+  if (unlikely(pins == NULL))
+    return;
+
+  PFS_host **entry;
+  entry= reinterpret_cast<PFS_host**>
+    (lf_hash_search(&host_hash, pins,
+                    host->m_key.m_hash_key, host->m_key.m_key_length));
+  if (entry && (entry != MY_ERRPTR))
+  {
+    PFS_host *pfs;
+    pfs= *entry;
+    DBUG_ASSERT(pfs == host);
+    if (host->get_refcount() == 0)
+    {
+      lf_hash_delete(&host_hash, pins,
+                     host->m_key.m_hash_key, host->m_key.m_key_length);
+      host->m_lock.allocated_to_free();
+    }
+    lf_hash_search_unpin(pins);
+  }
+}
+
+/** Purge non connected hosts, reset stats of connected hosts. */
+void purge_all_host(void)
+{
+  PFS_thread *thread= PFS_thread::get_current_thread();
+  if (unlikely(thread == NULL))
+    return;
+
+  PFS_host *pfs= host_array;
+  PFS_host *pfs_last= host_array + host_max;
+
+  for ( ; pfs < pfs_last; pfs++)
+  {
+    if (pfs->m_lock.is_populated())
+    {
+      pfs->m_disconnected_count= 0;
+      if (pfs->get_refcount() == 0)
+        purge_host(thread, pfs);
+    }
+  }
+}
+
+/** @} */

=== added file 'storage/perfschema/pfs_host.h'
--- a/storage/perfschema/pfs_host.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/pfs_host.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,107 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef PFS_HOST_H
+#define PFS_HOST_H
+
+/**
+  @file storage/perfschema/pfs_host.h
+  Performance schema host (declarations).
+*/
+
+#include "pfs_lock.h"
+#include "lf.h"
+#include "pfs_con_slice.h"
+
+struct PFS_global_param;
+struct PFS_thread;
+
+/**
+  @addtogroup Performance_schema_buffers
+  @{
+*/
+
+struct PFS_host_key
+{
+  /**
+    Hash search key.
+    This has to be a string for LF_HASH,
+    the format is "<hostname><0x00>"
+  */
+  char m_hash_key[HOSTNAME_LENGTH + 1];
+  uint m_key_length;
+};
+
+struct PFS_host : PFS_connection_slice
+{
+public:
+  inline void init_refcount(void)
+  {
+    PFS_atomic::store_32(& m_refcount, 1);
+  }
+
+  inline int get_refcount(void)
+  {
+    return PFS_atomic::load_32(& m_refcount);
+  }
+
+  inline void inc_refcount(void)
+  {
+    PFS_atomic::add_32(& m_refcount, 1);
+  }
+
+  inline void dec_refcount(void)
+  {
+    PFS_atomic::add_32(& m_refcount, -1);
+  }
+
+  void aggregate(void);
+  void aggregate_waits(void);
+  void release(void);
+
+  /* Internal lock. */
+  pfs_lock m_lock;
+  PFS_host_key m_key;
+  const char *m_hostname;
+  uint m_hostname_length;
+
+  ulonglong m_disconnected_count;
+
+private:
+  int m_refcount;
+};
+
+int init_host(const PFS_global_param *param);
+void cleanup_host(void);
+int init_host_hash(void);
+void cleanup_host_hash(void);
+
+PFS_host *find_or_create_host(PFS_thread *thread,
+                              const char *hostname, uint hostname_length);
+
+void purge_all_host(void);
+
+/* For iterators and show status. */
+
+extern ulong host_max;
+extern ulong host_lost;
+
+/* Exposing the data directly, for iterators. */
+
+extern PFS_host *host_array;
+
+/** @} */
+#endif
+

=== modified file 'storage/perfschema/pfs_instr.cc'
--- a/storage/perfschema/pfs_instr.cc	2011-02-15 14:31:13 +0000
+++ b/storage/perfschema/pfs_instr.cc	2011-05-07 00:40:25 +0000
@@ -25,6 +25,9 @@
 #include "pfs.h"
 #include "pfs_stat.h"
 #include "pfs_instr.h"
+#include "pfs_host.h"
+#include "pfs_user.h"
+#include "pfs_account.h"
 #include "pfs_global.h"
 #include "pfs_instr_class.h"
 
@@ -199,7 +202,7 @@ int init_instruments(const PFS_global_pa
   thread_statements_history_sizing= param->m_thread_sizing
     * events_statements_history_per_thread;
 
-  statement_stack_max= 1; /* No nested statements yet */
+  statement_stack_max= 1;
   thread_statements_stack_sizing= param->m_thread_sizing * statement_stack_max;
 
   thread_instr_class_stages_sizing= param->m_thread_sizing
@@ -790,6 +793,9 @@ PFS_thread* create_thread(PFS_thread_cla
           pfs->m_table_share_hash_pins= NULL;
           pfs->m_setup_actor_hash_pins= NULL;
           pfs->m_setup_object_hash_pins= NULL;
+          pfs->m_user_hash_pins= NULL;
+          pfs->m_account_hash_pins= NULL;
+          pfs->m_host_hash_pins= NULL;
 
           pfs->m_username_length= 0;
           pfs->m_hostname_length= 0;
@@ -799,6 +805,11 @@ PFS_thread* create_thread(PFS_thread_cla
           pfs->m_processlist_state_length= 0;
           pfs->m_processlist_info_length= 0;
 
+          pfs->m_host= NULL;
+          pfs->m_user= NULL;
+          pfs->m_account= NULL;
+          set_thread_account(pfs);
+
           PFS_events_waits *child_wait;
           for (index= 0; index < WAIT_STACK_SIZE; index++)
           {
@@ -932,6 +943,26 @@ PFS_file *sanitize_file(PFS_file *unsafe
 void destroy_thread(PFS_thread *pfs)
 {
   DBUG_ASSERT(pfs != NULL);
+  if (pfs->m_account != NULL)
+  {
+    pfs->m_account->release();
+    pfs->m_account= NULL;
+    DBUG_ASSERT(pfs->m_user == NULL);
+    DBUG_ASSERT(pfs->m_host == NULL);
+  }
+  else
+  {
+    if (pfs->m_user != NULL)
+    {
+      pfs->m_user->release();
+      pfs->m_user= NULL;
+    }
+    if (pfs->m_host != NULL)
+    {
+      pfs->m_host->release();
+      pfs->m_host= NULL;
+    }
+  }
   if (pfs->m_filename_hash_pins)
   {
     lf_hash_put_pins(pfs->m_filename_hash_pins);
@@ -952,10 +983,41 @@ void destroy_thread(PFS_thread *pfs)
     lf_hash_put_pins(pfs->m_setup_object_hash_pins);
     pfs->m_setup_object_hash_pins= NULL;
   }
+  if (pfs->m_user_hash_pins)
+  {
+    lf_hash_put_pins(pfs->m_user_hash_pins);
+    pfs->m_user_hash_pins= NULL;
+  }
+  if (pfs->m_account_hash_pins)
+  {
+    lf_hash_put_pins(pfs->m_account_hash_pins);
+    pfs->m_account_hash_pins= NULL;
+  }
+  if (pfs->m_host_hash_pins)
+  {
+    lf_hash_put_pins(pfs->m_host_hash_pins);
+    pfs->m_host_hash_pins= NULL;
+  }
   pfs->m_lock.allocated_to_free();
 }
 
 /**
+  Get the hash pins for @filename_hash.
+  @param thread The running thread.
+  @returns The LF_HASH pins for the thread.
+*/
+LF_PINS* get_filename_hash_pins(PFS_thread *thread)
+{
+  if (unlikely(thread->m_filename_hash_pins == NULL))
+  {
+    if (! filename_hash_inited)
+      return NULL;
+    thread->m_filename_hash_pins= lf_hash_get_pins(&filename_hash);
+  }
+  return thread->m_filename_hash_pins;
+}
+
+/**
   Find or create instrumentation for a file instance by file name.
   @param thread                       the executing instrumented thread
   @param klass                        the file class
@@ -970,23 +1032,13 @@ find_or_create_file(PFS_thread *thread, 
   PFS_file *pfs;
   PFS_scan scan;
 
-  if (! filename_hash_inited)
+  LF_PINS *pins= get_filename_hash_pins(thread);
+  if (unlikely(pins == NULL))
   {
-    /* File instrumentation can be turned off. */
     file_lost++;
     return NULL;
   }
 
-  if (unlikely(thread->m_filename_hash_pins == NULL))
-  {
-    thread->m_filename_hash_pins= lf_hash_get_pins(&filename_hash);
-    if (unlikely(thread->m_filename_hash_pins == NULL))
-    {
-      file_lost++;
-      return NULL;
-    }
-  }
-
   char safe_buffer[FN_REFLEN];
   const char *safe_filename;
 
@@ -1072,13 +1124,13 @@ find_or_create_file(PFS_thread *thread, 
   const uint retry_max= 3;
 search:
   entry= reinterpret_cast<PFS_file**>
-    (lf_hash_search(&filename_hash, thread->m_filename_hash_pins,
+    (lf_hash_search(&filename_hash, pins,
                     normalized_filename, normalized_length));
   if (entry && (entry != MY_ERRPTR))
   {
     pfs= *entry;
     pfs->m_file_stat.m_open_count++;
-    lf_hash_search_unpin(thread->m_filename_hash_pins);
+    lf_hash_search_unpin(pins);
     return pfs;
   }
 
@@ -1106,7 +1158,7 @@ search:
           pfs->m_file_stat.m_io_stat.reset();
 
           int res;
-          res= lf_hash_insert(&filename_hash, thread->m_filename_hash_pins,
+          res= lf_hash_insert(&filename_hash, pins,
                               &pfs);
           if (likely(res == 0))
           {
@@ -1160,7 +1212,6 @@ void release_file(PFS_file *pfs)
 void destroy_file(PFS_thread *thread, PFS_file *pfs)
 {
   DBUG_ASSERT(thread != NULL);
-  DBUG_ASSERT(thread->m_filename_hash_pins != NULL);
   DBUG_ASSERT(pfs != NULL);
   PFS_file_class *klass= pfs->m_class;
 
@@ -1173,7 +1224,13 @@ void destroy_file(PFS_thread *thread, PF
   klass->m_file_stat.m_io_stat.aggregate(& pfs->m_file_stat.m_io_stat);
   pfs->m_file_stat.m_io_stat.reset();
 
-  lf_hash_delete(&filename_hash, thread->m_filename_hash_pins,
+  if (klass->is_singleton())
+    klass->m_singleton= NULL;
+
+  LF_PINS *pins= get_filename_hash_pins(thread);
+  DBUG_ASSERT(pins != NULL);
+
+  lf_hash_delete(&filename_hash, pins,
                  pfs->m_filename, pfs->m_filename_length);
   if (klass->is_singleton())
     klass->m_singleton= NULL;
@@ -1489,16 +1546,92 @@ void aggregate_all_statements(PFS_statem
   }
 }
 
+void aggregate_thread_stats(PFS_thread *thread)
+{
+  if (likely(thread->m_account != NULL))
+  {
+    thread->m_account->m_disconnected_count++;
+  }
+  else
+  {
+    if (thread->m_user != NULL)
+      thread->m_user->m_disconnected_count++;
+
+    if (thread->m_host != NULL)
+      thread->m_host->m_disconnected_count++;
+  }
+}
+
 void aggregate_thread(PFS_thread *thread)
 {
   aggregate_thread_waits(thread);
   aggregate_thread_stages(thread);
   aggregate_thread_statements(thread);
+  aggregate_thread_stats(thread);
 }
 
-
 void aggregate_thread_waits(PFS_thread *thread)
 {
+  if (likely(thread->m_account != NULL))
+  {
+    DBUG_ASSERT(thread->m_user == NULL);
+    DBUG_ASSERT(thread->m_host == NULL);
+    DBUG_ASSERT(thread->m_account->get_refcount() > 0);
+
+    /*
+      Aggregate EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME
+      to EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME.
+    */
+    aggregate_all_event_names(thread->m_instr_class_waits_stats,
+                              thread->m_account->m_instr_class_waits_stats);
+
+    return;
+  }
+
+  if ((thread->m_user != NULL) && (thread->m_host != NULL))
+  {
+    DBUG_ASSERT(thread->m_user->get_refcount() > 0);
+    DBUG_ASSERT(thread->m_host->get_refcount() > 0);
+
+    /*
+      Aggregate EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME to:
+      -  EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME
+      -  EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME
+      in parallel.
+    */
+    aggregate_all_event_names(thread->m_instr_class_waits_stats,
+                              thread->m_user->m_instr_class_waits_stats,
+                              thread->m_host->m_instr_class_waits_stats);
+    return;
+  }
+
+  if (thread->m_user != NULL)
+  {
+    DBUG_ASSERT(thread->m_user->get_refcount() > 0);
+
+    /*
+      Aggregate EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME
+      to EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME, directly.
+    */
+    aggregate_all_event_names(thread->m_instr_class_waits_stats,
+                              thread->m_user->m_instr_class_waits_stats);
+    return;
+  }
+
+  if (thread->m_host != NULL)
+  {
+    DBUG_ASSERT(thread->m_host->get_refcount() > 0);
+
+    /*
+      Aggregate EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME
+      to EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME, directly.
+    */
+    aggregate_all_event_names(thread->m_instr_class_waits_stats,
+                              thread->m_host->m_instr_class_waits_stats);
+    return;
+  }
+
+  /* Orphan thread, clean the stats */
   PFS_single_stat *stat= thread->m_instr_class_waits_stats;
   PFS_single_stat *stat_last= stat + wait_class_max;
   for ( ; stat < stat_last; stat++)
@@ -1525,4 +1658,48 @@ void aggregate_thread_statements(PFS_thr
                            global_instr_class_statements_array);
 }
 
+void clear_thread_account(PFS_thread *thread)
+{
+  if (thread->m_account != NULL)
+  {
+    thread->m_account->release();
+    thread->m_account= NULL;
+  }
+
+  if (thread->m_user != NULL)
+  {
+    thread->m_user->release();
+    thread->m_user= NULL;
+  }
+
+  if (thread->m_host != NULL)
+  {
+    thread->m_host->release();
+    thread->m_host= NULL;
+  }
+}
+
+void set_thread_account(PFS_thread *thread)
+{
+  DBUG_ASSERT(thread->m_account == NULL);
+  DBUG_ASSERT(thread->m_user == NULL);
+  DBUG_ASSERT(thread->m_host == NULL);
+
+  thread->m_account= find_or_create_account(thread,
+                                                thread->m_username,
+                                                thread->m_username_length,
+                                                thread->m_hostname,
+                                                thread->m_hostname_length);
+
+  if ((thread->m_account == NULL) && (thread->m_username_length > 0))
+    thread->m_user= find_or_create_user(thread,
+                                        thread->m_username,
+                                        thread->m_username_length);
+
+  if ((thread->m_account == NULL) && (thread->m_hostname_length > 0))
+    thread->m_host= find_or_create_host(thread,
+                                        thread->m_hostname,
+                                        thread->m_hostname_length);
+}
+
 /** @} */

=== modified file 'storage/perfschema/pfs_instr.h'
--- a/storage/perfschema/pfs_instr.h	2011-04-04 14:34:42 +0000
+++ b/storage/perfschema/pfs_instr.h	2011-05-07 00:40:25 +0000
@@ -44,6 +44,9 @@ struct PFS_thread_class;
 */
 
 struct PFS_thread;
+struct PFS_host;
+struct PFS_user;
+struct PFS_account;
 
 /** Base structure for wait instruments. */
 struct PFS_instr
@@ -288,6 +291,12 @@ struct PFS_thread : PFS_connection_slice
   LF_PINS *m_setup_actor_hash_pins;
   /** Pins for setup_object_hash. */
   LF_PINS *m_setup_object_hash_pins;
+  /** Pins for host_hash. */
+  LF_PINS *m_host_hash_pins;
+  /** Pins for user_hash. */
+  LF_PINS *m_user_hash_pins;
+  /** Pins for account_hash. */
+  LF_PINS *m_account_hash_pins;
   /** Event ID counter */
   ulonglong m_event_id;
   /** Thread instrumentation flag. */
@@ -395,6 +404,10 @@ struct PFS_thread : PFS_connection_slice
   /** Size of @c m_events_statements_stack. */
   uint m_events_statements_count;
   PFS_events_statements *m_statement_stack;
+
+  PFS_host *m_host;
+  PFS_user *m_user;
+  PFS_account *m_account;
 };
 
 extern PFS_single_stat *global_instr_class_waits_array;
@@ -484,6 +497,8 @@ void aggregate_thread(PFS_thread *thread
 void aggregate_thread_waits(PFS_thread *thread);
 void aggregate_thread_stages(PFS_thread *thread);
 void aggregate_thread_statements(PFS_thread *thread);
+void clear_thread_account(PFS_thread *thread);
+void set_thread_account(PFS_thread *thread);
 
 /** @} */
 #endif

=== modified file 'storage/perfschema/pfs_instr_class.cc'
--- a/storage/perfschema/pfs_instr_class.cc	2011-02-14 14:23:55 +0000
+++ b/storage/perfschema/pfs_instr_class.cc	2011-05-07 00:40:25 +0000
@@ -92,9 +92,9 @@ ulong table_share_max= 0;
 /** Number of table share lost. @sa table_share_array */
 ulong table_share_lost= 0;
 
-static PFS_mutex_class *mutex_class_array= NULL;
-static PFS_rwlock_class *rwlock_class_array= NULL;
-static PFS_cond_class *cond_class_array= NULL;
+PFS_mutex_class *mutex_class_array= NULL;
+PFS_rwlock_class *rwlock_class_array= NULL;
+PFS_cond_class *cond_class_array= NULL;
 
 /**
   Current number or elements in thread_class_array.
@@ -139,7 +139,7 @@ C_MODE_END
 static volatile uint32 file_class_dirty_count= 0;
 static volatile uint32 file_class_allocated_count= 0;
 
-static PFS_file_class *file_class_array= NULL;
+PFS_file_class *file_class_array= NULL;
 
 static volatile uint32 stage_class_dirty_count= 0;
 static volatile uint32 stage_class_allocated_count= 0;

=== modified file 'storage/perfschema/pfs_instr_class.h'
--- a/storage/perfschema/pfs_instr_class.h	2011-02-14 14:23:55 +0000
+++ b/storage/perfschema/pfs_instr_class.h	2011-05-07 00:40:25 +0000
@@ -390,6 +390,13 @@ extern ulong statement_class_max;
 extern ulong statement_class_lost;
 extern ulong table_share_max;
 extern ulong table_share_lost;
+
+/* Exposing the data directly, for iterators. */
+
+extern PFS_mutex_class *mutex_class_array;
+extern PFS_rwlock_class *rwlock_class_array;
+extern PFS_cond_class *cond_class_array;
+extern PFS_file_class *file_class_array;
 extern PFS_table_share *table_share_array;
 
 void reset_file_class_io();

=== modified file 'storage/perfschema/pfs_server.cc'
--- a/storage/perfschema/pfs_server.cc	2011-02-14 14:23:55 +0000
+++ b/storage/perfschema/pfs_server.cc	2011-05-07 00:40:25 +0000
@@ -32,6 +32,9 @@
 #include "pfs_timer.h"
 #include "pfs_setup_actor.h"
 #include "pfs_setup_object.h"
+#include "pfs_host.h"
+#include "pfs_user.h"
+#include "pfs_account.h"
 #include "pfs_defaults.h"
 
 PFS_global_param pfs_param;
@@ -85,7 +88,13 @@ initialize_performance_schema(const PFS_
       init_setup_actor(param) ||
       init_setup_actor_hash() ||
       init_setup_object(param) ||
-      init_setup_object_hash())
+      init_setup_object_hash() ||
+      init_host(param) ||
+      init_host_hash() ||
+      init_user(param) ||
+      init_user_hash() ||
+      init_account(param) ||
+      init_account_hash())
   {
     /*
       The performance schema initialization failed.
@@ -137,6 +146,12 @@ static void cleanup_performance_schema(v
   cleanup_setup_actor_hash();
   cleanup_setup_object();
   cleanup_setup_object_hash();
+  cleanup_host();
+  cleanup_host_hash();
+  cleanup_user();
+  cleanup_user_hash();
+  cleanup_account();
+  cleanup_account_hash();
   PFS_atomic::cleanup();
 }
 
@@ -156,3 +171,4 @@ void shutdown_performance_schema(void)
   }
 }
 
+

=== modified file 'storage/perfschema/pfs_server.h'
--- a/storage/perfschema/pfs_server.h	2011-04-04 14:34:42 +0000
+++ b/storage/perfschema/pfs_server.h	2011-05-07 00:40:25 +0000
@@ -72,6 +72,15 @@
 #ifndef PFS_MAX_SETUP_OBJECT
   #define PFS_MAX_SETUP_OBJECT 100
 #endif
+#ifndef PFS_MAX_HOST
+  #define PFS_MAX_HOST 100
+#endif
+#ifndef PFS_MAX_USER
+  #define PFS_MAX_USER 100
+#endif
+#ifndef PFS_MAX_ACCOUNT
+  #define PFS_MAX_ACCOUNT 100
+#endif
 #ifndef PFS_MAX_STAGE_CLASS
   #define PFS_MAX_STAGE_CLASS 100
 #endif
@@ -169,6 +178,12 @@ struct PFS_global_param
   ulong m_setup_actor_sizing;
   /** Maximum number of rows in table SETUP_OBJECTS. */
   ulong m_setup_object_sizing;
+  /** Maximum number of rows in table HOSTS. */
+  ulong m_host_sizing;
+  /** Maximum number of rows in table USERS. */
+  ulong m_user_sizing;
+  /** Maximum number of rows in table ACCOUNTS. */
+  ulong m_account_sizing;
   /**
     Maximum number of instrumented stage classes.
     @sa stage_class_lost.

=== modified file 'storage/perfschema/pfs_setup_actor.cc'
--- a/storage/perfschema/pfs_setup_actor.cc	2011-04-04 14:34:42 +0000
+++ b/storage/perfschema/pfs_setup_actor.cc	2011-05-07 00:40:25 +0000
@@ -119,10 +119,12 @@ void cleanup_setup_actor_hash(void)
 
 static LF_PINS* get_setup_actor_hash_pins(PFS_thread *thread)
 {
-  if (! setup_actor_hash_inited)
-    return NULL;
   if (unlikely(thread->m_setup_actor_hash_pins == NULL))
+  {
+    if (! setup_actor_hash_inited)
+      return NULL;
     thread->m_setup_actor_hash_pins= lf_hash_get_pins(&setup_actor_hash);
+  }
   return thread->m_setup_actor_hash_pins;
 }
 

=== modified file 'storage/perfschema/pfs_setup_object.cc'
--- a/storage/perfschema/pfs_setup_object.cc	2010-09-24 21:04:59 +0000
+++ b/storage/perfschema/pfs_setup_object.cc	2011-05-07 00:40:25 +0000
@@ -114,10 +114,12 @@ void cleanup_setup_object_hash(void)
 
 static LF_PINS* get_setup_object_hash_pins(PFS_thread *thread)
 {
-  if (! setup_object_hash_inited)
-    return NULL;
   if (unlikely(thread->m_setup_object_hash_pins == NULL))
+  {
+    if (! setup_object_hash_inited)
+      return NULL;
     thread->m_setup_object_hash_pins= lf_hash_get_pins(&setup_object_hash);
+  }
   return thread->m_setup_object_hash_pins;
 }
 

=== modified file 'storage/perfschema/pfs_stat.h'
--- a/storage/perfschema/pfs_stat.h	2011-02-14 14:23:55 +0000
+++ b/storage/perfschema/pfs_stat.h	2011-05-07 00:40:25 +0000
@@ -428,6 +428,28 @@ struct PFS_table_stat
   }
 };
 
+struct PFS_connection_stat
+{
+  PFS_connection_stat()
+  : m_current_connections(0),
+    m_total_connections(0)
+  {}
+
+  ulonglong m_current_connections;
+  ulonglong m_total_connections;
+
+  inline void aggregate_active(ulonglong active)
+  {
+    m_current_connections+= active;
+    m_total_connections+= active;
+  }
+
+  inline void aggregate_disconnected(ulonglong disconnected)
+  {
+    m_total_connections+= disconnected;
+  }
+};
+
 /** @} */
 #endif
 

=== added file 'storage/perfschema/pfs_user.cc'
--- a/storage/perfschema/pfs_user.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/pfs_user.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,363 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file storage/perfschema/pfs_user.cc
+  Performance schema user (implementation).
+*/
+
+#include "my_global.h"
+#include "my_sys.h"
+#include "pfs.h"
+#include "pfs_stat.h"
+#include "pfs_instr.h"
+#include "pfs_setup_actor.h"
+#include "pfs_user.h"
+#include "pfs_global.h"
+#include "pfs_instr_class.h"
+
+/**
+  @addtogroup Performance_schema_buffers
+  @{
+*/
+
+ulong user_max;
+ulong user_lost;
+
+PFS_user *user_array= NULL;
+
+static PFS_single_stat *user_instr_class_waits_array= NULL;
+static PFS_stage_stat *user_instr_class_stages_array= NULL;
+static PFS_statement_stat *user_instr_class_statements_array= NULL;
+
+static LF_HASH user_hash;
+static bool user_hash_inited= false;
+
+/**
+  Initialize the user buffers.
+  @param param                        sizing parameters
+  @return 0 on success
+*/
+int init_user(const PFS_global_param *param)
+{
+  uint index;
+
+  user_max= param->m_user_sizing;
+
+  user_array= NULL;
+  user_instr_class_waits_array= NULL;
+  user_instr_class_stages_array= NULL;
+  user_instr_class_statements_array= NULL;
+  uint waits_sizing= user_max * wait_class_max;
+  uint stages_sizing= user_max * stage_class_max;
+  uint statements_sizing= user_max * statement_class_max;
+
+  if (user_max > 0)
+  {
+    user_array= PFS_MALLOC_ARRAY(user_max, PFS_user,
+                                 MYF(MY_ZEROFILL));
+    if (unlikely(user_array == NULL))
+      return 1;
+  }
+
+  if (waits_sizing > 0)
+  {
+    user_instr_class_waits_array=
+      PFS_connection_slice::alloc_waits_slice(waits_sizing);
+    if (unlikely(user_instr_class_waits_array == NULL))
+      return 1;
+  }
+
+  if (stages_sizing > 0)
+  {
+    user_instr_class_stages_array=
+      PFS_connection_slice::alloc_stages_slice(stages_sizing);
+    if (unlikely(user_instr_class_stages_array == NULL))
+      return 1;
+  }
+
+  if (statements_sizing > 0)
+  {
+    user_instr_class_statements_array=
+      PFS_connection_slice::alloc_statements_slice(statements_sizing);
+    if (unlikely(user_instr_class_statements_array == NULL))
+      return 1;
+  }
+
+  for (index= 0; index < user_max; index++)
+  {
+    user_array[index].m_instr_class_waits_stats=
+      &user_instr_class_waits_array[index * wait_class_max];
+    user_array[index].m_instr_class_stages_stats=
+      &user_instr_class_stages_array[index * stage_class_max];
+    user_array[index].m_instr_class_statements_stats=
+      &user_instr_class_statements_array[index * statement_class_max];
+  }
+
+  return 0;
+}
+
+/** Cleanup all the user buffers. */
+void cleanup_user(void)
+{
+  pfs_free(user_array);
+  user_array= NULL;
+  pfs_free(user_instr_class_waits_array);
+  user_instr_class_waits_array= NULL;
+  pfs_free(user_instr_class_stages_array);
+  user_instr_class_stages_array= NULL;
+  pfs_free(user_instr_class_statements_array);
+  user_instr_class_statements_array= NULL;
+  user_max= 0;
+}
+
+static uchar *user_hash_get_key(const uchar *entry, size_t *length,
+                                my_bool)
+{
+  const PFS_user * const *typed_entry;
+  const PFS_user *user;
+  const void *result;
+  typed_entry= reinterpret_cast<const PFS_user* const *> (entry);
+  DBUG_ASSERT(typed_entry != NULL);
+  user= *typed_entry;
+  DBUG_ASSERT(user != NULL);
+  *length= user->m_key.m_key_length;
+  result= user->m_key.m_hash_key;
+  return const_cast<uchar*> (reinterpret_cast<const uchar*> (result));
+}
+
+/**
+  Initialize the user hash.
+  @return 0 on success
+*/
+int init_user_hash(void)
+{
+  if (! user_hash_inited)
+  {
+    lf_hash_init(&user_hash, sizeof(PFS_user*), LF_HASH_UNIQUE,
+                 0, 0, user_hash_get_key, &my_charset_bin);
+    user_hash_inited= true;
+  }
+  return 0;
+}
+
+/** Cleanup the user hash. */
+void cleanup_user_hash(void)
+{
+  if (user_hash_inited)
+  {
+    lf_hash_destroy(&user_hash);
+    user_hash_inited= false;
+  }
+}
+
+static LF_PINS* get_user_hash_pins(PFS_thread *thread)
+{
+  if (unlikely(thread->m_user_hash_pins == NULL))
+  {
+    if (! user_hash_inited)
+      return NULL;
+    thread->m_user_hash_pins= lf_hash_get_pins(&user_hash);
+  }
+  return thread->m_user_hash_pins;
+}
+
+static void set_user_key(PFS_user_key *key,
+                         const char *user, uint user_length)
+{
+  DBUG_ASSERT(user_length <= USERNAME_LENGTH);
+
+  char *ptr= &key->m_hash_key[0];
+  if (user_length > 0)
+  {
+    memcpy(ptr, user, user_length);
+    ptr+= user_length;
+  }
+  ptr[0]= 0;
+  ptr++;
+  key->m_key_length= ptr - &key->m_hash_key[0];
+}
+
+PFS_user *
+find_or_create_user(PFS_thread *thread,
+                    const char *username, uint username_length)
+{
+  if (user_max == 0)
+  {
+    user_lost++;
+    return NULL;
+  }
+
+  LF_PINS *pins= get_user_hash_pins(thread);
+  if (unlikely(pins == NULL))
+  {
+    user_lost++;
+    return NULL;
+  }
+
+  PFS_user_key key;
+  set_user_key(&key, username, username_length);
+
+  PFS_user **entry;
+  uint retry_count= 0;
+  const uint retry_max= 3;
+
+search:
+  entry= reinterpret_cast<PFS_user**>
+    (lf_hash_search(&user_hash, pins,
+                    key.m_hash_key, key.m_key_length));
+  if (entry && (entry != MY_ERRPTR))
+  {
+    PFS_user *pfs;
+    pfs= *entry;
+    pfs->inc_refcount();
+    lf_hash_search_unpin(pins);
+    return pfs;
+  }
+
+  PFS_scan scan;
+  uint random= randomized_index(username, user_max);
+
+  for (scan.init(random, user_max);
+       scan.has_pass();
+       scan.next_pass())
+  {
+    PFS_user *pfs= user_array + scan.first();
+    PFS_user *pfs_last= user_array + scan.last();
+    for ( ; pfs < pfs_last; pfs++)
+    {
+      if (pfs->m_lock.is_free())
+      {
+        if (pfs->m_lock.free_to_dirty())
+        {
+          pfs->m_key= key;
+          if (username_length > 0)
+            pfs->m_username= &pfs->m_key.m_hash_key[0];
+          else
+            pfs->m_username= NULL;
+          pfs->m_username_length= username_length;
+
+          pfs->init_refcount();
+          pfs->reset_stats();
+          pfs->m_disconnected_count= 0;
+
+          int res;
+          res= lf_hash_insert(&user_hash, pins, &pfs);
+          if (likely(res == 0))
+          {
+            pfs->m_lock.dirty_to_allocated();
+            return pfs;
+          }
+
+          pfs->m_lock.dirty_to_free();
+
+          if (res > 0)
+          {
+            if (++retry_count > retry_max)
+            {
+              user_lost++;
+              return NULL;
+            }
+            goto search;
+          }
+
+          user_lost++;
+          return NULL;
+        }
+      }
+    }
+  }
+
+  user_lost++;
+  return NULL;
+}
+
+void PFS_user::aggregate()
+{
+  aggregate_waits();
+}
+
+void PFS_user::aggregate_waits()
+{
+  /* No parent to aggregate to, clean the stats */
+
+  PFS_single_stat *stat= m_instr_class_waits_stats;
+  PFS_single_stat *stat_last= stat + wait_class_max;
+  for ( ; stat < stat_last; stat++)
+    stat->reset();
+}
+
+void PFS_user::release()
+{
+  dec_refcount();
+}
+
+PFS_user *sanitize_user(PFS_user *unsafe)
+{
+  if ((&user_array[0] <= unsafe) &&
+      (unsafe < &user_array[user_max]))
+    return unsafe;
+  return NULL;
+}
+
+void purge_user(PFS_thread *thread, PFS_user *user)
+{
+  user->aggregate();
+
+  LF_PINS *pins= get_user_hash_pins(thread);
+  if (unlikely(pins == NULL))
+    return;
+
+  PFS_user **entry;
+  entry= reinterpret_cast<PFS_user**>
+    (lf_hash_search(&user_hash, pins,
+                    user->m_key.m_hash_key, user->m_key.m_key_length));
+  if (entry && (entry != MY_ERRPTR))
+  {
+    PFS_user *pfs;
+    pfs= *entry;
+    DBUG_ASSERT(pfs == user);
+    if (user->get_refcount() == 0)
+    {
+      lf_hash_delete(&user_hash, pins,
+                     user->m_key.m_hash_key, user->m_key.m_key_length);
+      user->m_lock.allocated_to_free();
+    }
+    lf_hash_search_unpin(pins);
+  }
+}
+
+/** Purge non connected users, reset stats of connected users. */
+void purge_all_user(void)
+{
+  PFS_thread *thread= PFS_thread::get_current_thread();
+  if (unlikely(thread == NULL))
+    return;
+
+  PFS_user *pfs= user_array;
+  PFS_user *pfs_last= user_array + user_max;
+
+  for ( ; pfs < pfs_last; pfs++)
+  {
+    if (pfs->m_lock.is_populated())
+    {
+      pfs->m_disconnected_count= 0;
+      if (pfs->get_refcount() == 0)
+        purge_user(thread, pfs);
+    }
+  }
+}
+
+/** @} */

=== added file 'storage/perfschema/pfs_user.h'
--- a/storage/perfschema/pfs_user.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/pfs_user.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,110 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef PFS_USER_H
+#define PFS_USER_H
+
+/**
+  @file storage/perfschema/pfs_user.h
+  Performance schema user (declarations).
+*/
+
+#include "pfs_lock.h"
+#include "lf.h"
+#include "pfs_con_slice.h"
+
+struct PFS_global_param;
+struct PFS_thread;
+
+/**
+  @addtogroup Performance_schema_buffers
+  @{
+*/
+
+struct PFS_user_key
+{
+  /**
+    Hash search key.
+    This has to be a string for LF_HASH,
+    the format is "<username><0x00>"
+  */
+  char m_hash_key[USERNAME_LENGTH + 1];
+  uint m_key_length;
+};
+
+struct PFS_user : public PFS_connection_slice
+{
+public:
+  inline void init_refcount(void)
+  {
+    PFS_atomic::store_32(& m_refcount, 1);
+  }
+
+  inline int get_refcount(void)
+  {
+    return PFS_atomic::load_32(& m_refcount);
+  }
+
+  inline void inc_refcount(void)
+  {
+    PFS_atomic::add_32(& m_refcount, 1);
+  }
+
+  inline void dec_refcount(void)
+  {
+    PFS_atomic::add_32(& m_refcount, -1);
+  }
+
+  void aggregate(void);
+  void aggregate_waits(void);
+  void release(void);
+
+  /** Internal lock. */
+  pfs_lock m_lock;
+  PFS_user_key m_key;
+  const char *m_username;
+  uint m_username_length;
+
+  ulonglong m_disconnected_count;
+
+private:
+  int m_refcount;
+};
+
+int init_user(const PFS_global_param *param);
+void cleanup_user(void);
+int init_user_hash(void);
+void cleanup_user_hash(void);
+
+PFS_user *
+find_or_create_user(PFS_thread *thread,
+                    const char *username, uint username_length);
+
+PFS_user *sanitize_user(PFS_user *unsafe);
+void purge_all_user(void);
+
+
+/* For iterators and show status. */
+
+extern ulong user_max;
+extern ulong user_lost;
+
+/* Exposing the data directly, for iterators. */
+
+extern PFS_user *user_array;
+
+/** @} */
+#endif
+

=== modified file 'storage/perfschema/pfs_visitor.cc'
--- a/storage/perfschema/pfs_visitor.cc	2011-02-14 14:23:55 +0000
+++ b/storage/perfschema/pfs_visitor.cc	2011-05-07 00:40:25 +0000
@@ -17,6 +17,9 @@
 #include "my_sys.h"
 #include "pfs_visitor.h"
 #include "pfs_instr.h"
+#include "pfs_user.h"
+#include "pfs_host.h"
+#include "pfs_account.h"
 
 /**
   @file storage/perfschema/pfs_visitor.cc
@@ -28,13 +31,47 @@
   @{
 */
 
-void PFS_connection_iterator::visit_global(bool with_threads,
+void PFS_connection_iterator::visit_global(bool with_hosts, bool with_users,
+                                           bool with_accounts, bool with_threads,
                                            PFS_connection_visitor *visitor)
 {
   DBUG_ASSERT(visitor != NULL);
 
   visitor->visit_global();
 
+  if (with_hosts)
+  {
+    PFS_host *pfs= host_array;
+    PFS_host *pfs_last= pfs + host_max;
+    for ( ; pfs < pfs_last; pfs++)
+    {
+      if (pfs->m_lock.is_populated())
+        visitor->visit_host(pfs);
+    }
+  }
+
+  if (with_users)
+  {
+    PFS_user *pfs= user_array;
+    PFS_user *pfs_last= pfs + user_max;
+    for ( ; pfs < pfs_last; pfs++)
+    {
+      if (pfs->m_lock.is_populated())
+        visitor->visit_user(pfs);
+    }
+  }
+
+  if (with_accounts)
+  {
+    PFS_account *pfs= account_array;
+    PFS_account *pfs_last= pfs + account_max;
+    for ( ; pfs < pfs_last; pfs++)
+    {
+      if (pfs->m_lock.is_populated())
+        visitor->visit_account(pfs);
+    }
+  }
+
   if (with_threads)
   {
     PFS_thread *pfs= thread_array;
@@ -47,6 +84,266 @@ void PFS_connection_iterator::visit_glob
   }
 }
 
+void PFS_connection_iterator::visit_host(PFS_host *host,
+                                         bool with_accounts, bool with_threads,
+                                         PFS_connection_visitor *visitor)
+{
+  DBUG_ASSERT(visitor != NULL);
+
+  visitor->visit_host(host);
+
+  if (with_accounts)
+  {
+    PFS_account *pfs= account_array;
+    PFS_account *pfs_last= pfs + account_max;
+    for ( ; pfs < pfs_last; pfs++)
+    {
+      if ((pfs->m_host == host) && pfs->m_lock.is_populated())
+      {
+        visitor->visit_account(pfs);
+      }
+    }
+  }
+
+  if (with_threads)
+  {
+    PFS_thread *pfs= thread_array;
+    PFS_thread *pfs_last= pfs + thread_max;
+    for ( ; pfs < pfs_last; pfs++)
+    {
+      if (pfs->m_lock.is_populated())
+      {
+        PFS_account *safe_account= sanitize_account(pfs->m_account);
+        if ((safe_account != NULL) && (safe_account->m_host == host))
+        {
+          /*
+            If the thread belongs to a known user@host that belongs to this host,
+            process it.
+          */
+          visitor->visit_thread(pfs);
+        }
+        else if (pfs->m_host == host)
+        {
+          /*
+            If the thread belongs to a 'lost' user@host that belong to this host,
+            process it.
+          */
+          visitor->visit_thread(pfs);
+        }
+      }
+    }
+  }
+}
+
+void PFS_connection_iterator::visit_user(PFS_user *user,
+                                         bool with_accounts, bool with_threads,
+                                         PFS_connection_visitor *visitor)
+{
+  DBUG_ASSERT(visitor != NULL);
+
+  visitor->visit_user(user);
+
+  if (with_accounts)
+  {
+    PFS_account *pfs= account_array;
+    PFS_account *pfs_last= pfs + account_max;
+    for ( ; pfs < pfs_last; pfs++)
+    {
+      if ((pfs->m_user == user) && pfs->m_lock.is_populated())
+      {
+        visitor->visit_account(pfs);
+      }
+    }
+  }
+
+  if (with_threads)
+  {
+    PFS_thread *pfs= thread_array;
+    PFS_thread *pfs_last= pfs + thread_max;
+    for ( ; pfs < pfs_last; pfs++)
+    {
+      if (pfs->m_lock.is_populated())
+      {
+        PFS_account *safe_account= sanitize_account(pfs->m_account);
+        if ((safe_account != NULL) && (safe_account->m_user == user))
+        {
+          /*
+            If the thread belongs to a known user@host that belongs to this user,
+            process it.
+          */
+          visitor->visit_thread(pfs);
+        }
+        else if (pfs->m_user == user)
+        {
+          /*
+            If the thread belongs to a 'lost' user@host that belong to this user,
+            process it.
+          */
+          visitor->visit_thread(pfs);
+        }
+      }
+    }
+  }
+}
+
+void PFS_connection_iterator::visit_account(PFS_account *account,
+                                              bool with_threads,
+                                              PFS_connection_visitor *visitor)
+{
+  DBUG_ASSERT(visitor != NULL);
+
+  visitor->visit_account(account);
+
+  if (with_threads)
+  {
+    PFS_thread *pfs= thread_array;
+    PFS_thread *pfs_last= pfs + thread_max;
+    for ( ; pfs < pfs_last; pfs++)
+    {
+      if ((pfs->m_account == account) && pfs->m_lock.is_populated())
+      {
+        visitor->visit_thread(pfs);
+      }
+    }
+  }
+}
+
+void PFS_instance_iterator::visit_all(PFS_instance_visitor *visitor)
+{
+  visit_all_mutex(visitor);
+  visit_all_rwlock(visitor);
+  visit_all_cond(visitor);
+  visit_all_file(visitor);
+}
+
+void PFS_instance_iterator::visit_all_mutex(PFS_instance_visitor *visitor)
+{
+  visit_all_mutex_classes(visitor);
+  visit_all_mutex_instances(visitor);
+}
+
+void PFS_instance_iterator::visit_all_mutex_classes(PFS_instance_visitor *visitor)
+{
+  PFS_mutex_class *pfs= mutex_class_array;
+  PFS_mutex_class *pfs_last= pfs + mutex_class_max;
+  for ( ; pfs < pfs_last; pfs++)
+  {
+    if (pfs->m_name_length != 0)
+    {
+      visitor->visit_mutex_class(pfs);
+    }
+  }
+}
+
+void PFS_instance_iterator::visit_all_mutex_instances(PFS_instance_visitor *visitor)
+{
+  PFS_mutex *pfs= mutex_array;
+  PFS_mutex *pfs_last= pfs + mutex_max;
+  for ( ; pfs < pfs_last; pfs++)
+  {
+    if (pfs->m_lock.is_populated())
+    {
+      visitor->visit_mutex(pfs);
+    }
+  }
+}
+
+void PFS_instance_iterator::visit_all_rwlock(PFS_instance_visitor *visitor)
+{
+  visit_all_rwlock_classes(visitor);
+  visit_all_rwlock_instances(visitor);
+}
+
+void PFS_instance_iterator::visit_all_rwlock_classes(PFS_instance_visitor *visitor)
+{
+  PFS_rwlock_class *pfs= rwlock_class_array;
+  PFS_rwlock_class *pfs_last= pfs + rwlock_class_max;
+  for ( ; pfs < pfs_last; pfs++)
+  {
+    if (pfs->m_name_length != 0)
+    {
+      visitor->visit_rwlock_class(pfs);
+    }
+  }
+}
+
+void PFS_instance_iterator::visit_all_rwlock_instances(PFS_instance_visitor *visitor)
+{
+  PFS_rwlock *pfs= rwlock_array;
+  PFS_rwlock *pfs_last= pfs + rwlock_max;
+  for ( ; pfs < pfs_last; pfs++)
+  {
+    if (pfs->m_lock.is_populated())
+    {
+      visitor->visit_rwlock(pfs);
+    }
+  }
+}
+
+void PFS_instance_iterator::visit_all_cond(PFS_instance_visitor *visitor)
+{
+  visit_all_cond_classes(visitor);
+  visit_all_cond_instances(visitor);
+}
+
+void PFS_instance_iterator::visit_all_cond_classes(PFS_instance_visitor *visitor)
+{
+  PFS_cond_class *pfs= cond_class_array;
+  PFS_cond_class *pfs_last= pfs + cond_class_max;
+  for ( ; pfs < pfs_last; pfs++)
+  {
+    if (pfs->m_name_length != 0)
+    {
+      visitor->visit_cond_class(pfs);
+    }
+  }
+}
+
+void PFS_instance_iterator::visit_all_cond_instances(PFS_instance_visitor *visitor)
+{
+  PFS_cond *pfs= cond_array;
+  PFS_cond *pfs_last= pfs + cond_max;
+  for ( ; pfs < pfs_last; pfs++)
+  {
+    if (pfs->m_lock.is_populated())
+    {
+      visitor->visit_cond(pfs);
+    }
+  }
+}
+
+void PFS_instance_iterator::visit_all_file(PFS_instance_visitor *visitor)
+{
+  visit_all_file_classes(visitor);
+  visit_all_file_instances(visitor);
+}
+
+void PFS_instance_iterator::visit_all_file_classes(PFS_instance_visitor *visitor)
+{
+  PFS_file_class *pfs= file_class_array;
+  PFS_file_class *pfs_last= pfs + file_class_max;
+  for ( ; pfs < pfs_last; pfs++)
+  {
+    if (pfs->m_name_length != 0)
+    {
+      visitor->visit_file_class(pfs);
+    }
+  }
+}
+
+void PFS_instance_iterator::visit_all_file_instances(PFS_instance_visitor *visitor)
+{
+  PFS_file *pfs= file_array;
+  PFS_file *pfs_last= pfs + file_max;
+  for ( ; pfs < pfs_last; pfs++)
+  {
+    if (pfs->m_lock.is_populated())
+    {
+      visitor->visit_file(pfs);
+    }
+  }
+}
+
 void PFS_instance_iterator::visit_mutex_instances(PFS_mutex_class *klass,
                                                   PFS_instance_visitor *visitor)
 {
@@ -175,6 +472,11 @@ void PFS_instance_iterator::visit_file_i
   }
 }
 
+void PFS_object_iterator::visit_all(PFS_object_visitor *visitor)
+{
+  visit_all_tables(visitor);
+}
+
 void PFS_object_iterator::visit_all_tables(PFS_object_visitor *visitor)
 {
   DBUG_ASSERT(visitor != NULL);
@@ -258,11 +560,69 @@ void PFS_connection_wait_visitor::visit_
   DBUG_ASSERT(false);
 }
 
+void PFS_connection_wait_visitor::visit_host(PFS_host *pfs)
+{
+  m_stat.aggregate(& pfs->m_instr_class_waits_stats[m_index]);
+}
+
+void PFS_connection_wait_visitor::visit_user(PFS_user *pfs)
+{
+  m_stat.aggregate(& pfs->m_instr_class_waits_stats[m_index]);
+}
+
+void PFS_connection_wait_visitor::visit_account(PFS_account *pfs)
+{
+  m_stat.aggregate(& pfs->m_instr_class_waits_stats[m_index]);
+}
+
 void PFS_connection_wait_visitor::visit_thread(PFS_thread *pfs)
 {
   m_stat.aggregate(& pfs->m_instr_class_waits_stats[m_index]);
 }
 
+PFS_connection_all_wait_visitor
+::PFS_connection_all_wait_visitor()
+{}
+
+PFS_connection_all_wait_visitor::~PFS_connection_all_wait_visitor()
+{}
+
+void PFS_connection_all_wait_visitor::visit_global()
+{
+  /* Sum by instances, not by connection */
+  DBUG_ASSERT(false);
+}
+
+void PFS_connection_all_wait_visitor::visit_connection_slice(PFS_connection_slice *pfs)
+{
+  PFS_single_stat *stat= pfs->m_instr_class_waits_stats;
+  PFS_single_stat *stat_last= stat + wait_class_max;
+  for ( ; stat < stat_last; stat++)
+  {
+    m_stat.aggregate(stat);
+  }
+}
+
+void PFS_connection_all_wait_visitor::visit_host(PFS_host *pfs)
+{
+  visit_connection_slice(pfs);
+}
+
+void PFS_connection_all_wait_visitor::visit_user(PFS_user *pfs)
+{
+  visit_connection_slice(pfs);
+}
+
+void PFS_connection_all_wait_visitor::visit_account(PFS_account *pfs)
+{
+  visit_connection_slice(pfs);
+}
+
+void PFS_connection_all_wait_visitor::visit_thread(PFS_thread *pfs)
+{
+  visit_connection_slice(pfs);
+}
+
 PFS_connection_stage_visitor::PFS_connection_stage_visitor(PFS_stage_class *klass)
 {
   m_index= klass->m_event_name_index;
@@ -276,6 +636,21 @@ void PFS_connection_stage_visitor::visit
   m_stat.aggregate(& global_instr_class_stages_array[m_index]);
 }
 
+void PFS_connection_stage_visitor::visit_host(PFS_host *pfs)
+{
+  m_stat.aggregate(& pfs->m_instr_class_stages_stats[m_index]);
+}
+
+void PFS_connection_stage_visitor::visit_user(PFS_user *pfs)
+{
+  m_stat.aggregate(& pfs->m_instr_class_stages_stats[m_index]);
+}
+
+void PFS_connection_stage_visitor::visit_account(PFS_account *pfs)
+{
+  m_stat.aggregate(& pfs->m_instr_class_stages_stats[m_index]);
+}
+
 void PFS_connection_stage_visitor::visit_thread(PFS_thread *pfs)
 {
   m_stat.aggregate(& pfs->m_instr_class_stages_stats[m_index]);
@@ -295,11 +670,102 @@ void PFS_connection_statement_visitor::v
   m_stat.aggregate(& global_instr_class_statements_array[m_index]);
 }
 
+void PFS_connection_statement_visitor::visit_host(PFS_host *pfs)
+{
+  m_stat.aggregate(& pfs->m_instr_class_statements_stats[m_index]);
+}
+
+void PFS_connection_statement_visitor::visit_user(PFS_user *pfs)
+{
+  m_stat.aggregate(& pfs->m_instr_class_statements_stats[m_index]);
+}
+
+void PFS_connection_statement_visitor::visit_account(PFS_account *pfs)
+{
+  m_stat.aggregate(& pfs->m_instr_class_statements_stats[m_index]);
+}
+
 void PFS_connection_statement_visitor::visit_thread(PFS_thread *pfs)
 {
   m_stat.aggregate(& pfs->m_instr_class_statements_stats[m_index]);
 }
 
+PFS_connection_all_statement_visitor
+::PFS_connection_all_statement_visitor()
+{}
+
+PFS_connection_all_statement_visitor::~PFS_connection_all_statement_visitor()
+{}
+
+void PFS_connection_all_statement_visitor::visit_global()
+{
+  PFS_statement_stat *stat= global_instr_class_statements_array;
+  PFS_statement_stat *stat_last= stat + statement_class_max;
+  for ( ; stat < stat_last; stat++)
+  {
+    m_stat.aggregate(stat);
+  }
+}
+
+void PFS_connection_all_statement_visitor::visit_connection_slice(PFS_connection_slice *pfs)
+{
+  PFS_statement_stat *stat= pfs->m_instr_class_statements_stats;
+  PFS_statement_stat *stat_last= stat + statement_class_max;
+  for ( ; stat < stat_last; stat++)
+  {
+    m_stat.aggregate(stat);
+  }
+}
+
+void PFS_connection_all_statement_visitor::visit_host(PFS_host *pfs)
+{
+  visit_connection_slice(pfs);
+}
+
+void PFS_connection_all_statement_visitor::visit_user(PFS_user *pfs)
+{
+  visit_connection_slice(pfs);
+}
+
+void PFS_connection_all_statement_visitor::visit_account(PFS_account *pfs)
+{
+  visit_connection_slice(pfs);
+}
+
+void PFS_connection_all_statement_visitor::visit_thread(PFS_thread *pfs)
+{
+  visit_connection_slice(pfs);
+}
+
+PFS_connection_stat_visitor::PFS_connection_stat_visitor()
+{}
+
+PFS_connection_stat_visitor::~PFS_connection_stat_visitor()
+{}
+
+void PFS_connection_stat_visitor::visit_global()
+{}
+
+void PFS_connection_stat_visitor::visit_host(PFS_host *pfs)
+{
+  m_stat.aggregate_disconnected(pfs->m_disconnected_count);
+}
+
+void PFS_connection_stat_visitor::visit_user(PFS_user *pfs)
+{
+  m_stat.aggregate_disconnected(pfs->m_disconnected_count);
+}
+
+void PFS_connection_stat_visitor::visit_account(PFS_account *pfs)
+{
+  m_stat.aggregate_disconnected(pfs->m_disconnected_count);
+}
+
+void PFS_connection_stat_visitor::visit_thread(PFS_thread *)
+{
+  m_stat.aggregate_active(1);
+}
+
 PFS_instance_wait_visitor::PFS_instance_wait_visitor()
 {
 }
@@ -351,6 +817,33 @@ void PFS_instance_wait_visitor::visit_fi
   m_stat.aggregate(& pfs->m_wait_stat);
 }
 
+PFS_object_wait_visitor::PFS_object_wait_visitor()
+{}
+
+PFS_object_wait_visitor::~PFS_object_wait_visitor()
+{}
+
+void PFS_object_wait_visitor::visit_global()
+{
+  uint index;
+
+  index= global_table_io_class.m_event_name_index;
+  m_stat.aggregate(& global_instr_class_waits_array[index]);
+
+  index= global_table_lock_class.m_event_name_index;
+  m_stat.aggregate(& global_instr_class_waits_array[index]);
+}
+
+void PFS_object_wait_visitor::visit_table_share(PFS_table_share *pfs)
+{
+  pfs->m_table_stat.sum(& m_stat);
+}
+
+void PFS_object_wait_visitor::visit_table(PFS_table *pfs)
+{
+  pfs->m_table_stat.sum(& m_stat);
+}
+
 PFS_table_io_wait_visitor::PFS_table_io_wait_visitor()
 {}
 

=== modified file 'storage/perfschema/pfs_visitor.h'
--- a/storage/perfschema/pfs_visitor.h	2011-02-14 14:23:55 +0000
+++ b/storage/perfschema/pfs_visitor.h	2011-05-07 00:40:25 +0000
@@ -28,6 +28,9 @@
   @{
 */
 
+struct PFS_user;
+struct PFS_account;
+struct PFS_host;
 struct PFS_thread;
 struct PFS_instr_class;
 struct PFS_mutex_class;
@@ -42,6 +45,7 @@ struct PFS_file;
 struct PFS_table;
 struct PFS_stage_class;
 struct PFS_statement_class;
+struct PFS_connection_slice;
 
 /**
   Interface class to visit groups of connections.
@@ -54,6 +58,12 @@ public:
   virtual ~PFS_connection_visitor() {}
   /** Visit all connections. */
   virtual void visit_global() {}
+  /** Visit all connections of a host. */
+  virtual void visit_host(PFS_host *pfs) {}
+  /** Visit all connections of a user+host. */
+  virtual void visit_account(PFS_account *pfs) {}
+  /** Visit all connections of a user. */
+  virtual void visit_user(PFS_user *pfs) {}
   /** Visit all a thread. */
   virtual void visit_thread(PFS_thread *pfs) {}
 };
@@ -67,12 +77,42 @@ class PFS_connection_iterator
 public:
   /**
     Visit all connections.
+    @param with_hosts when true, visit also all hosts.
+    @param with_users when true, visit also all users.
+    @param with_accounts when true, visit also all user+host.
     @param with_threads when true, visit also all threads.
     @param visitor the visitor to call
   */
-  static void visit_global(bool with_threads,
+  static void visit_global(bool with_hosts, bool with_users,
+                           bool with_accounts, bool with_threads,
                            PFS_connection_visitor *visitor);
   /**
+    Visit all connections of a host.
+    @param host the host to visit.
+    @param with_accounts when true, visit also all related user+host.
+    @param with_threads when true, visit also all related threads.
+    @param visitor the visitor to call
+  */
+  static void visit_host(PFS_host *host, bool with_accounts, bool with_threads,
+                         PFS_connection_visitor *visitor);
+  /**
+    Visit all connections of a user.
+    @param user the user to visit.
+    @param with_accounts when true, visit also all related user+host.
+    @param with_threads when true, visit also all related threads.
+    @param visitor the visitor to call
+  */
+  static void visit_user(PFS_user *user, bool with_accounts, bool with_threads,
+                         PFS_connection_visitor *visitor);
+  /**
+    Visit all connections of a user+host.
+    @param account the user+host to visit.
+    @param with_threads when true, visit also all related threads.
+    @param visitor the visitor to call
+  */
+  static void visit_account(PFS_account *account, bool with_threads,
+                              PFS_connection_visitor *visitor);
+  /**
     Visit a thread or connection.
     @param thread the thread to visit.
     @param visitor the visitor to call
@@ -116,6 +156,20 @@ public:
 class PFS_instance_iterator
 {
 public:
+  static void visit_all(PFS_instance_visitor *visitor);
+  static void visit_all_mutex(PFS_instance_visitor *visitor);
+  static void visit_all_mutex_classes(PFS_instance_visitor *visitor);
+  static void visit_all_mutex_instances(PFS_instance_visitor *visitor);
+  static void visit_all_rwlock(PFS_instance_visitor *visitor);
+  static void visit_all_rwlock_classes(PFS_instance_visitor *visitor);
+  static void visit_all_rwlock_instances(PFS_instance_visitor *visitor);
+  static void visit_all_cond(PFS_instance_visitor *visitor);
+  static void visit_all_cond_classes(PFS_instance_visitor *visitor);
+  static void visit_all_cond_instances(PFS_instance_visitor *visitor);
+  static void visit_all_file(PFS_instance_visitor *visitor);
+  static void visit_all_file_classes(PFS_instance_visitor *visitor);
+  static void visit_all_file_instances(PFS_instance_visitor *visitor);
+
   /**
     Visit a mutex class and related instances.
     @param klass the klass to visit.
@@ -174,6 +228,8 @@ public:
 class PFS_object_iterator
 {
 public:
+  /** Visit all objects. */
+  static void visit_all(PFS_object_visitor *visitor);
   /** Visit all tables and related handles. */
   static void visit_all_tables(PFS_object_visitor *visitor);
   /** Visit a table and related table handles. */
@@ -187,7 +243,7 @@ public:
 
 /**
   A concrete connection visitor that aggregates
-  wait statistics.
+  wait statistics for a given event_name.
 */
 class PFS_connection_wait_visitor : public PFS_connection_visitor
 {
@@ -196,6 +252,9 @@ public:
   PFS_connection_wait_visitor(PFS_instr_class *klass);
   virtual ~PFS_connection_wait_visitor();
   virtual void visit_global();
+  virtual void visit_host(PFS_host *pfs);
+  virtual void visit_account(PFS_account *pfs);
+  virtual void visit_user(PFS_user *pfs);
   virtual void visit_thread(PFS_thread *pfs);
 
   /** EVENT_NAME instrument index. */
@@ -206,6 +265,29 @@ public:
 
 /**
   A concrete connection visitor that aggregates
+  wait statistics for all events.
+*/
+class PFS_connection_all_wait_visitor : public PFS_connection_visitor
+{
+public:
+  /** Constructor. */
+  PFS_connection_all_wait_visitor();
+  virtual ~PFS_connection_all_wait_visitor();
+  virtual void visit_global();
+  virtual void visit_host(PFS_host *pfs);
+  virtual void visit_account(PFS_account *pfs);
+  virtual void visit_user(PFS_user *pfs);
+  virtual void visit_thread(PFS_thread *pfs);
+
+  /** Wait statistic collected. */
+  PFS_single_stat m_stat;
+
+private:
+  void visit_connection_slice(PFS_connection_slice *pfs);
+};
+
+/**
+  A concrete connection visitor that aggregates
   stage statistics.
 */
 class PFS_connection_stage_visitor : public PFS_connection_visitor
@@ -215,6 +297,9 @@ public:
   PFS_connection_stage_visitor(PFS_stage_class *klass);
   virtual ~PFS_connection_stage_visitor();
   virtual void visit_global();
+  virtual void visit_host(PFS_host *pfs);
+  virtual void visit_account(PFS_account *pfs);
+  virtual void visit_user(PFS_user *pfs);
   virtual void visit_thread(PFS_thread *pfs);
 
   /** EVENT_NAME instrument index. */
@@ -225,7 +310,7 @@ public:
 
 /**
   A concrete connection visitor that aggregates
-  statement statistics.
+  statement statistics for a given event_name.
 */
 class PFS_connection_statement_visitor : public PFS_connection_visitor
 {
@@ -234,6 +319,9 @@ public:
   PFS_connection_statement_visitor(PFS_statement_class *klass);
   virtual ~PFS_connection_statement_visitor();
   virtual void visit_global();
+  virtual void visit_host(PFS_host *pfs);
+  virtual void visit_account(PFS_account *pfs);
+  virtual void visit_user(PFS_user *pfs);
   virtual void visit_thread(PFS_thread *pfs);
 
   /** EVENT_NAME instrument index. */
@@ -243,6 +331,49 @@ public:
 };
 
 /**
+  A concrete connection visitor that aggregates
+  statement statistics for all events.
+*/
+class PFS_connection_all_statement_visitor : public PFS_connection_visitor
+{
+public:
+  /** Constructor. */
+  PFS_connection_all_statement_visitor();
+  virtual ~PFS_connection_all_statement_visitor();
+  virtual void visit_global();
+  virtual void visit_host(PFS_host *pfs);
+  virtual void visit_account(PFS_account *pfs);
+  virtual void visit_user(PFS_user *pfs);
+  virtual void visit_thread(PFS_thread *pfs);
+
+  /** Statement statistic collected. */
+  PFS_statement_stat m_stat;
+
+private:
+  void visit_connection_slice(PFS_connection_slice *pfs);
+};
+
+/**
+  A concrete connection visitor that aggregates
+  connection statistics.
+*/
+class PFS_connection_stat_visitor : public PFS_connection_visitor
+{
+public:
+  /** Constructor. */
+  PFS_connection_stat_visitor();
+  virtual ~PFS_connection_stat_visitor();
+  virtual void visit_global();
+  virtual void visit_host(PFS_host *pfs);
+  virtual void visit_account(PFS_account *pfs);
+  virtual void visit_user(PFS_user *pfs);
+  virtual void visit_thread(PFS_thread *pfs);
+
+  /** Connection statistic collected. */
+  PFS_connection_stat m_stat;
+};
+
+/**
   A concrete instance visitor that aggregates
   wait statistics.
 */
@@ -266,6 +397,23 @@ public:
 
 /**
   A concrete object visitor that aggregates
+  object wait statistics.
+*/
+class PFS_object_wait_visitor : public PFS_object_visitor
+{
+public:
+  PFS_object_wait_visitor();
+  virtual ~PFS_object_wait_visitor();
+  virtual void visit_global();
+  virtual void visit_table_share(PFS_table_share *pfs);
+  virtual void visit_table(PFS_table *pfs);
+
+  /** Object wait statistic collected. */
+  PFS_single_stat m_stat;
+};
+
+/**
+  A concrete object visitor that aggregates
   table io wait statistics.
 */
 class PFS_table_io_wait_visitor : public PFS_object_visitor

=== added file 'storage/perfschema/table_accounts.cc'
--- a/storage/perfschema/table_accounts.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_accounts.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,148 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software Foundation,
+  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "table_accounts.h"
+#include "pfs_instr_class.h"
+#include "pfs_instr.h"
+#include "pfs_account.h"
+#include "pfs_visitor.h"
+
+THR_LOCK table_accounts::m_table_lock;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+  {
+    { C_STRING_WITH_LEN("USER") },
+    { C_STRING_WITH_LEN("char(16)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("HOST") },
+    { C_STRING_WITH_LEN("char(60)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("CURRENT_CONNECTIONS") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("TOTAL_CONNECTIONS") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  }
+};
+
+TABLE_FIELD_DEF
+table_accounts::m_field_def=
+{ 4, field_types };
+
+PFS_engine_table_share
+table_accounts::m_share=
+{
+  { C_STRING_WITH_LEN("accounts") },
+  &pfs_truncatable_acl,
+  &table_accounts::create,
+  NULL, /* write_row */
+  table_accounts::delete_all_rows,
+  NULL, /* get_row_count */
+  1000, /* records */
+  sizeof(PFS_simple_index), /* ref length */
+  &m_table_lock,
+  &m_field_def,
+  false /* checked */
+};
+
+PFS_engine_table* table_accounts::create()
+{
+  return new table_accounts();
+}
+
+int
+table_accounts::delete_all_rows(void)
+{
+  reset_events_waits_by_thread();
+  reset_events_waits_by_account();
+  reset_events_stages_by_thread();
+  reset_events_stages_by_account();
+  reset_events_statements_by_thread();
+  reset_events_statements_by_account();
+  purge_all_account();
+  return 0;
+}
+
+table_accounts::table_accounts()
+  : cursor_by_account(& m_share),
+  m_row_exists(false)
+{}
+
+void table_accounts::make_row(PFS_account *pfs)
+{
+  pfs_lock lock;
+
+  m_row_exists= false;
+  pfs->m_lock.begin_optimistic_lock(&lock);
+
+  if (m_row.m_account.make_row(pfs))
+    return;
+
+  PFS_connection_stat_visitor visitor;
+  PFS_connection_iterator::visit_account(pfs, true, & visitor);
+
+  if (! pfs->m_lock.end_optimistic_lock(& lock))
+    return;
+
+  m_row.m_connection_stat.set(& visitor.m_stat);
+  m_row_exists= true;
+}
+
+int table_accounts::read_row_values(TABLE *table,
+                                      unsigned char *buf,
+                                      Field **fields,
+                                      bool read_all)
+{
+  Field *f;
+
+  if (unlikely(! m_row_exists))
+    return HA_ERR_RECORD_DELETED;
+
+  /* Set the null bits */
+  DBUG_ASSERT(table->s->null_bytes == 1);
+  buf[0]= 0;
+
+  for (; (f= *fields) ; fields++)
+  {
+    if (read_all || bitmap_is_set(table->read_set, f->field_index))
+    {
+      switch(f->field_index)
+      {
+      case 0: /* USER */
+      case 1: /* HOST */
+        m_row.m_account.set_field(f->field_index, f);
+        break;
+      case 2: /* CURRENT_CONNECTIONS */
+      case 3: /* TOTAL_CONNECTIONS */
+        m_row.m_connection_stat.set_field(f->field_index - 2, f);
+        break;
+      default:
+        DBUG_ASSERT(false);
+      }
+    }
+  }
+  return 0;
+}
+

=== added file 'storage/perfschema/table_accounts.h'
--- a/storage/perfschema/table_accounts.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_accounts.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,80 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software Foundation,
+  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#ifndef TABLE_ACCOUNTS_H
+#define TABLE_ACCOUNTS_H
+
+#include "pfs_column_types.h"
+#include "cursor_by_account.h"
+#include "table_helper.h"
+
+struct PFS_account;
+
+/**
+  \addtogroup Performance_schema_tables
+  @{
+*/
+
+/**
+  A row of PERFORMANCE_SCHEMA.ACCOUNTS.
+*/
+struct row_accounts
+{
+  /** Column USER, HOST. */
+  PFS_account_row m_account;
+  /** Columns CURRENT_CONNECTIONS, TOTAL_CONNECTIONS. */
+  PFS_connection_stat_row m_connection_stat;
+};
+
+/** Table PERFORMANCE_SCHEMA.ACCOUNTS. */
+class table_accounts : public cursor_by_account
+{
+public:
+  /** Table share */
+  static PFS_engine_table_share m_share;
+  /** Table builder */
+  static PFS_engine_table* create();
+  static int delete_all_rows();
+
+protected:
+  virtual int read_row_values(TABLE *table,
+                              unsigned char *buf,
+                              Field **fields,
+                              bool read_all);
+
+
+protected:
+  table_accounts();
+
+public:
+  ~table_accounts()
+  {}
+
+private:
+  virtual void make_row(PFS_account *pfs);
+
+  /** Table share lock. */
+  static THR_LOCK m_table_lock;
+  /** Fields definition. */
+  static TABLE_FIELD_DEF m_field_def;
+
+  /** Current row. */
+  row_accounts m_row;
+  /** True if the current row exists. */
+  bool m_row_exists;
+};
+
+/** @} */
+#endif

=== added file 'storage/perfschema/table_esgs_by_account_by_event_name.cc'
--- a/storage/perfschema/table_esgs_by_account_by_event_name.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_esgs_by_account_by_event_name.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,229 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file storage/perfschema/table_esgs_by_account_by_event_name.cc
+  Table EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME (implementation).
+*/
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "pfs_instr_class.h"
+#include "pfs_column_types.h"
+#include "pfs_column_values.h"
+#include "table_esgs_by_account_by_event_name.h"
+#include "pfs_global.h"
+#include "pfs_visitor.h"
+
+THR_LOCK table_esgs_by_account_by_event_name::m_table_lock;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+  {
+    { C_STRING_WITH_LEN("USER") },
+    { C_STRING_WITH_LEN("char(16)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("HOST") },
+    { C_STRING_WITH_LEN("char(60)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("EVENT_NAME") },
+    { C_STRING_WITH_LEN("varchar(128)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("COUNT_STAR") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MIN_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("AVG_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MAX_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  }
+};
+
+TABLE_FIELD_DEF
+table_esgs_by_account_by_event_name::m_field_def=
+{ 8, field_types };
+
+PFS_engine_table_share
+table_esgs_by_account_by_event_name::m_share=
+{
+  { C_STRING_WITH_LEN("events_stages_summary_by_account_by_event_name") },
+  &pfs_truncatable_acl,
+  table_esgs_by_account_by_event_name::create,
+  NULL, /* write_row */
+  table_esgs_by_account_by_event_name::delete_all_rows,
+  NULL, /* get_row_count */
+  1000, /* records */
+  sizeof(pos_esgs_by_account_by_event_name),
+  &m_table_lock,
+  &m_field_def,
+  false /* checked */
+};
+
+PFS_engine_table*
+table_esgs_by_account_by_event_name::create(void)
+{
+  return new table_esgs_by_account_by_event_name();
+}
+
+int
+table_esgs_by_account_by_event_name::delete_all_rows(void)
+{
+  reset_events_stages_by_thread();
+  reset_events_stages_by_account();
+  return 0;
+}
+
+table_esgs_by_account_by_event_name::table_esgs_by_account_by_event_name()
+  : PFS_engine_table(&m_share, &m_pos),
+    m_row_exists(false), m_pos(), m_next_pos()
+{}
+
+void table_esgs_by_account_by_event_name::reset_position(void)
+{
+  m_pos.reset();
+  m_next_pos.reset();
+}
+
+int table_esgs_by_account_by_event_name::rnd_next(void)
+{
+  PFS_account *account;
+  PFS_stage_class *stage_class;
+
+  for (m_pos.set_at(&m_next_pos);
+       m_pos.has_more_account();
+       m_pos.next_account())
+  {
+    account= &account_array[m_pos.m_index_1];
+    if (account->m_lock.is_populated())
+    {
+      stage_class= find_stage_class(m_pos.m_index_2);
+      if (stage_class)
+      {
+        make_row(account, stage_class);
+        m_next_pos.set_after(&m_pos);
+        return 0;
+      }
+    }
+  }
+
+  return HA_ERR_END_OF_FILE;
+}
+
+int
+table_esgs_by_account_by_event_name::rnd_pos(const void *pos)
+{
+  PFS_account *account;
+  PFS_stage_class *stage_class;
+
+  set_position(pos);
+  DBUG_ASSERT(m_pos.m_index_1 < account_max);
+
+  account= &account_array[m_pos.m_index_1];
+  if (! account->m_lock.is_populated())
+    return HA_ERR_RECORD_DELETED;
+
+  stage_class= find_stage_class(m_pos.m_index_2);
+  if (stage_class)
+  {
+    make_row(account, stage_class);
+    return 0;
+  }
+
+  return HA_ERR_RECORD_DELETED;
+}
+
+void table_esgs_by_account_by_event_name
+::make_row(PFS_account *account, PFS_stage_class *klass)
+{
+  pfs_lock lock;
+  m_row_exists= false;
+
+  account->m_lock.begin_optimistic_lock(&lock);
+
+  if (m_row.m_account.make_row(account))
+    return;
+
+  m_row.m_event_name.make_row(klass);
+
+  PFS_connection_stage_visitor visitor(klass);
+  PFS_connection_iterator::visit_account(account, true, & visitor);
+
+  if (! account->m_lock.end_optimistic_lock(&lock))
+    return;
+
+  m_row_exists= true;
+
+  time_normalizer *normalizer= time_normalizer::get(stage_timer);
+  m_row.m_stat.set(normalizer, & visitor.m_stat);
+}
+
+int table_esgs_by_account_by_event_name
+::read_row_values(TABLE *table, unsigned char *buf, Field **fields,
+                  bool read_all)
+{
+  Field *f;
+
+  if (unlikely(! m_row_exists))
+    return HA_ERR_RECORD_DELETED;
+
+  /* Set the null bits */
+  DBUG_ASSERT(table->s->null_bytes == 1);
+  buf[0]= 0;
+
+  for (; (f= *fields) ; fields++)
+  {
+    if (read_all || bitmap_is_set(table->read_set, f->field_index))
+    {
+      switch(f->field_index)
+      {
+      case 0: /* USER */
+      case 1: /* HOST */
+        m_row.m_account.set_field(f->field_index, f);
+        break;
+      case 2: /* EVENT_NAME */
+        m_row.m_event_name.set_field(f);
+        break;
+      default: /* 3, ... COUNT/SUM/MIN/AVG/MAX */
+        m_row.m_stat.set_field(f->field_index - 3, f);
+        break;
+      }
+    }
+  }
+
+  return 0;
+}
+

=== added file 'storage/perfschema/table_esgs_by_account_by_event_name.h'
--- a/storage/perfschema/table_esgs_by_account_by_event_name.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_esgs_by_account_by_event_name.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,124 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef TABLE_ESGS_BY_ACCOUNT_BY_EVENT_NAME_H
+#define TABLE_ESGS_BY_ACCOUNT_BY_EVENT_NAME_H
+
+/**
+  @file storage/perfschema/table_esgs_by_account_by_event_name.h
+  Table EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME (declarations).
+*/
+
+#include "pfs_column_types.h"
+#include "pfs_engine_table.h"
+#include "pfs_instr_class.h"
+#include "pfs_instr.h"
+#include "pfs_account.h"
+#include "table_helper.h"
+
+/**
+  @addtogroup Performance_schema_tables
+  @{
+*/
+
+/**
+  A row of table
+  PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME.
+*/
+struct row_esgs_by_account_by_event_name
+{
+  /** Column USER, HOST. */
+  PFS_account_row m_account;
+  /** Column EVENT_NAME. */
+  PFS_event_name_row m_event_name;
+  /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */
+  PFS_stage_stat_row m_stat;
+};
+
+/**
+  Position of a cursor on
+  PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME.
+  Index 1 on user@host (0 based)
+  Index 2 on stage class (1 based)
+*/
+struct pos_esgs_by_account_by_event_name
+: public PFS_double_index
+{
+  pos_esgs_by_account_by_event_name()
+    : PFS_double_index(0, 1)
+  {}
+
+  inline void reset(void)
+  {
+    m_index_1= 0;
+    m_index_2= 1;
+  }
+
+  inline bool has_more_account(void)
+  { return (m_index_1 < account_max); }
+
+  inline void next_account(void)
+  {
+    m_index_1++;
+    m_index_2= 1;
+  }
+};
+
+/** Table PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. */
+class table_esgs_by_account_by_event_name : public PFS_engine_table
+{
+public:
+  /** Table share */
+  static PFS_engine_table_share m_share;
+  static PFS_engine_table* create();
+  static int delete_all_rows();
+
+  virtual int rnd_next();
+  virtual int rnd_pos(const void *pos);
+  virtual void reset_position(void);
+
+protected:
+  virtual int read_row_values(TABLE *table,
+                              unsigned char *buf,
+                              Field **fields,
+                              bool read_all);
+
+  table_esgs_by_account_by_event_name();
+
+public:
+  ~table_esgs_by_account_by_event_name()
+  {}
+
+protected:
+  void make_row(PFS_account *account, PFS_stage_class *klass);
+
+private:
+  /** Table share lock. */
+  static THR_LOCK m_table_lock;
+  /** Fields definition. */
+  static TABLE_FIELD_DEF m_field_def;
+
+  /** Current row. */
+  row_esgs_by_account_by_event_name m_row;
+  /** True is the current row exists. */
+  bool m_row_exists;
+  /** Current position. */
+  pos_esgs_by_account_by_event_name m_pos;
+  /** Next position. */
+  pos_esgs_by_account_by_event_name m_next_pos;
+};
+
+/** @} */
+#endif

=== added file 'storage/perfschema/table_esgs_by_host_by_event_name.cc'
--- a/storage/perfschema/table_esgs_by_host_by_event_name.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_esgs_by_host_by_event_name.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,225 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file storage/perfschema/table_esgs_by_host_by_event_name.cc
+  Table EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME (implementation).
+*/
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "pfs_instr_class.h"
+#include "pfs_column_types.h"
+#include "pfs_column_values.h"
+#include "table_esgs_by_host_by_event_name.h"
+#include "pfs_global.h"
+#include "pfs_account.h"
+#include "pfs_visitor.h"
+
+THR_LOCK table_esgs_by_host_by_event_name::m_table_lock;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+  {
+    { C_STRING_WITH_LEN("HOST") },
+    { C_STRING_WITH_LEN("char(60)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("EVENT_NAME") },
+    { C_STRING_WITH_LEN("varchar(128)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("COUNT_STAR") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MIN_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("AVG_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MAX_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  }
+};
+
+TABLE_FIELD_DEF
+table_esgs_by_host_by_event_name::m_field_def=
+{ 7, field_types };
+
+PFS_engine_table_share
+table_esgs_by_host_by_event_name::m_share=
+{
+  { C_STRING_WITH_LEN("events_stages_summary_by_host_by_event_name") },
+  &pfs_truncatable_acl,
+  table_esgs_by_host_by_event_name::create,
+  NULL, /* write_row */
+  table_esgs_by_host_by_event_name::delete_all_rows,
+  NULL, /* get_row_count */
+  1000, /* records */
+  sizeof(pos_esgs_by_host_by_event_name),
+  &m_table_lock,
+  &m_field_def,
+  false /* checked */
+};
+
+PFS_engine_table*
+table_esgs_by_host_by_event_name::create(void)
+{
+  return new table_esgs_by_host_by_event_name();
+}
+
+int
+table_esgs_by_host_by_event_name::delete_all_rows(void)
+{
+  reset_events_stages_by_thread();
+  reset_events_stages_by_account();
+  reset_events_stages_by_host();
+  return 0;
+}
+
+table_esgs_by_host_by_event_name::table_esgs_by_host_by_event_name()
+  : PFS_engine_table(&m_share, &m_pos),
+    m_row_exists(false), m_pos(), m_next_pos()
+{}
+
+void table_esgs_by_host_by_event_name::reset_position(void)
+{
+  m_pos.reset();
+  m_next_pos.reset();
+}
+
+int table_esgs_by_host_by_event_name::rnd_next(void)
+{
+  PFS_host *host;
+  PFS_stage_class *stage_class;
+
+  for (m_pos.set_at(&m_next_pos);
+       m_pos.has_more_host();
+       m_pos.next_host())
+  {
+    host= &host_array[m_pos.m_index_1];
+    if (host->m_lock.is_populated())
+    {
+      stage_class= find_stage_class(m_pos.m_index_2);
+      if (stage_class)
+      {
+        make_row(host, stage_class);
+        m_next_pos.set_after(&m_pos);
+        return 0;
+      }
+    }
+  }
+
+  return HA_ERR_END_OF_FILE;
+}
+
+int
+table_esgs_by_host_by_event_name::rnd_pos(const void *pos)
+{
+  PFS_host *host;
+  PFS_stage_class *stage_class;
+
+  set_position(pos);
+  DBUG_ASSERT(m_pos.m_index_1 < host_max);
+
+  host= &host_array[m_pos.m_index_1];
+  if (! host->m_lock.is_populated())
+    return HA_ERR_RECORD_DELETED;
+
+  stage_class= find_stage_class(m_pos.m_index_2);
+  if (stage_class)
+  {
+    make_row(host, stage_class);
+    return 0;
+  }
+
+  return HA_ERR_RECORD_DELETED;
+}
+
+void table_esgs_by_host_by_event_name
+::make_row(PFS_host *host, PFS_stage_class *klass)
+{
+  pfs_lock lock;
+  m_row_exists= false;
+
+  host->m_lock.begin_optimistic_lock(&lock);
+
+  if (m_row.m_host.make_row(host))
+    return;
+
+  m_row.m_event_name.make_row(klass);
+
+  PFS_connection_stage_visitor visitor(klass);
+  PFS_connection_iterator::visit_host(host, true, true, & visitor);
+
+  if (! host->m_lock.end_optimistic_lock(&lock))
+    return;
+
+  m_row_exists= true;
+
+  time_normalizer *normalizer= time_normalizer::get(stage_timer);
+  m_row.m_stat.set(normalizer, & visitor.m_stat);
+}
+
+int table_esgs_by_host_by_event_name
+::read_row_values(TABLE *table, unsigned char *buf, Field **fields,
+                  bool read_all)
+{
+  Field *f;
+
+  if (unlikely(! m_row_exists))
+    return HA_ERR_RECORD_DELETED;
+
+  /* Set the null bits */
+  DBUG_ASSERT(table->s->null_bytes == 1);
+  buf[0]= 0;
+
+  for (; (f= *fields) ; fields++)
+  {
+    if (read_all || bitmap_is_set(table->read_set, f->field_index))
+    {
+      switch(f->field_index)
+      {
+      case 0: /* HOST */
+        m_row.m_host.set_field(f);
+        break;
+      case 1: /* EVENT_NAME */
+        m_row.m_event_name.set_field(f);
+        break;
+      default: /* 2, ... COUNT/SUM/MIN/AVG/MAX */
+        m_row.m_stat.set_field(f->field_index - 2, f);
+        break;
+      }
+    }
+  }
+
+  return 0;
+}
+

=== added file 'storage/perfschema/table_esgs_by_host_by_event_name.h'
--- a/storage/perfschema/table_esgs_by_host_by_event_name.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_esgs_by_host_by_event_name.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,124 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef TABLE_ESGS_BY_HOST_BY_EVENT_NAME_H
+#define TABLE_ESGS_BY_HOST_BY_EVENT_NAME_H
+
+/**
+  @file storage/perfschema/table_esgs_by_host_by_event_name.h
+  Table EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME (declarations).
+*/
+
+#include "pfs_column_types.h"
+#include "pfs_engine_table.h"
+#include "pfs_instr_class.h"
+#include "pfs_instr.h"
+#include "pfs_host.h"
+#include "table_helper.h"
+
+/**
+  @addtogroup Performance_schema_tables
+  @{
+*/
+
+/**
+  A row of table
+  PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME.
+*/
+struct row_esgs_by_host_by_event_name
+{
+  /** Column HOST. */
+  PFS_host_row m_host;
+  /** Column EVENT_NAME. */
+  PFS_event_name_row m_event_name;
+  /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */
+  PFS_stage_stat_row m_stat;
+};
+
+/**
+  Position of a cursor on
+  PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME.
+  Index 1 on host (0 based)
+  Index 2 on stage class (1 based).
+*/
+struct pos_esgs_by_host_by_event_name
+: public PFS_double_index
+{
+  pos_esgs_by_host_by_event_name()
+    : PFS_double_index(0, 1)
+  {}
+
+  inline void reset(void)
+  {
+    m_index_1= 0;
+    m_index_2= 1;
+  }
+
+  inline bool has_more_host(void)
+  { return (m_index_1 < host_max); }
+
+  inline void next_host(void)
+  {
+    m_index_1++;
+    m_index_2= 1;
+  }
+};
+
+/** Table PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME. */
+class table_esgs_by_host_by_event_name : public PFS_engine_table
+{
+public:
+  /** Table share */
+  static PFS_engine_table_share m_share;
+  static PFS_engine_table* create();
+  static int delete_all_rows();
+
+  virtual int rnd_next();
+  virtual int rnd_pos(const void *pos);
+  virtual void reset_position(void);
+
+protected:
+  virtual int read_row_values(TABLE *table,
+                              unsigned char *buf,
+                              Field **fields,
+                              bool read_all);
+
+  table_esgs_by_host_by_event_name();
+
+public:
+  ~table_esgs_by_host_by_event_name()
+  {}
+
+protected:
+  void make_row(PFS_host *host, PFS_stage_class *klass);
+
+private:
+  /** Table share lock. */
+  static THR_LOCK m_table_lock;
+  /** Fields definition. */
+  static TABLE_FIELD_DEF m_field_def;
+
+  /** Current row. */
+  row_esgs_by_host_by_event_name m_row;
+  /** True is the current row exists. */
+  bool m_row_exists;
+  /** Current position. */
+  pos_esgs_by_host_by_event_name m_pos;
+  /** Next position. */
+  pos_esgs_by_host_by_event_name m_next_pos;
+};
+
+/** @} */
+#endif

=== added file 'storage/perfschema/table_esgs_by_user_by_event_name.cc'
--- a/storage/perfschema/table_esgs_by_user_by_event_name.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_esgs_by_user_by_event_name.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,225 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file storage/perfschema/table_esgs_by_user_by_event_name.cc
+  Table EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME (implementation).
+*/
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "pfs_instr_class.h"
+#include "pfs_column_types.h"
+#include "pfs_column_values.h"
+#include "table_esgs_by_user_by_event_name.h"
+#include "pfs_global.h"
+#include "pfs_account.h"
+#include "pfs_visitor.h"
+
+THR_LOCK table_esgs_by_user_by_event_name::m_table_lock;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+  {
+    { C_STRING_WITH_LEN("USER") },
+    { C_STRING_WITH_LEN("char(16)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("EVENT_NAME") },
+    { C_STRING_WITH_LEN("varchar(128)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("COUNT_STAR") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MIN_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("AVG_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MAX_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  }
+};
+
+TABLE_FIELD_DEF
+table_esgs_by_user_by_event_name::m_field_def=
+{ 7, field_types };
+
+PFS_engine_table_share
+table_esgs_by_user_by_event_name::m_share=
+{
+  { C_STRING_WITH_LEN("events_stages_summary_by_user_by_event_name") },
+  &pfs_truncatable_acl,
+  table_esgs_by_user_by_event_name::create,
+  NULL, /* write_row */
+  table_esgs_by_user_by_event_name::delete_all_rows,
+  NULL, /* get_row_count */
+  1000, /* records */
+  sizeof(pos_esgs_by_user_by_event_name),
+  &m_table_lock,
+  &m_field_def,
+  false /* checked */
+};
+
+PFS_engine_table*
+table_esgs_by_user_by_event_name::create(void)
+{
+  return new table_esgs_by_user_by_event_name();
+}
+
+int
+table_esgs_by_user_by_event_name::delete_all_rows(void)
+{
+  reset_events_stages_by_thread();
+  reset_events_stages_by_account();
+  reset_events_stages_by_user();
+  return 0;
+}
+
+table_esgs_by_user_by_event_name::table_esgs_by_user_by_event_name()
+  : PFS_engine_table(&m_share, &m_pos),
+    m_row_exists(false), m_pos(), m_next_pos()
+{}
+
+void table_esgs_by_user_by_event_name::reset_position(void)
+{
+  m_pos.reset();
+  m_next_pos.reset();
+}
+
+int table_esgs_by_user_by_event_name::rnd_next(void)
+{
+  PFS_user *user;
+  PFS_stage_class *stage_class;
+
+  for (m_pos.set_at(&m_next_pos);
+       m_pos.has_more_user();
+       m_pos.next_user())
+  {
+    user= &user_array[m_pos.m_index_1];
+    if (user->m_lock.is_populated())
+    {
+      stage_class= find_stage_class(m_pos.m_index_2);
+      if (stage_class)
+      {
+        make_row(user, stage_class);
+        m_next_pos.set_after(&m_pos);
+        return 0;
+      }
+    }
+  }
+
+  return HA_ERR_END_OF_FILE;
+}
+
+int
+table_esgs_by_user_by_event_name::rnd_pos(const void *pos)
+{
+  PFS_user *user;
+  PFS_stage_class *stage_class;
+
+  set_position(pos);
+  DBUG_ASSERT(m_pos.m_index_1 < user_max);
+
+  user= &user_array[m_pos.m_index_1];
+  if (! user->m_lock.is_populated())
+    return HA_ERR_RECORD_DELETED;
+
+  stage_class= find_stage_class(m_pos.m_index_2);
+  if (stage_class)
+  {
+    make_row(user, stage_class);
+    return 0;
+  }
+
+  return HA_ERR_RECORD_DELETED;
+}
+
+void table_esgs_by_user_by_event_name
+::make_row(PFS_user *user, PFS_stage_class *klass)
+{
+  pfs_lock lock;
+  m_row_exists= false;
+
+  user->m_lock.begin_optimistic_lock(&lock);
+
+  if (m_row.m_user.make_row(user))
+    return;
+
+  m_row.m_event_name.make_row(klass);
+
+  PFS_connection_stage_visitor visitor(klass);
+  PFS_connection_iterator::visit_user(user, true, true, & visitor);
+
+  if (! user->m_lock.end_optimistic_lock(&lock))
+    return;
+
+  m_row_exists= true;
+
+  time_normalizer *normalizer= time_normalizer::get(stage_timer);
+  m_row.m_stat.set(normalizer, & visitor.m_stat);
+}
+
+int table_esgs_by_user_by_event_name
+::read_row_values(TABLE *table, unsigned char *buf, Field **fields,
+                  bool read_all)
+{
+  Field *f;
+
+  if (unlikely(! m_row_exists))
+    return HA_ERR_RECORD_DELETED;
+
+  /* Set the null bits */
+  DBUG_ASSERT(table->s->null_bytes == 1);
+  buf[0]= 0;
+
+  for (; (f= *fields) ; fields++)
+  {
+    if (read_all || bitmap_is_set(table->read_set, f->field_index))
+    {
+      switch(f->field_index)
+      {
+      case 0: /* USER */
+        m_row.m_user.set_field(f);
+        break;
+      case 1: /* EVENT_NAME */
+        m_row.m_event_name.set_field(f);
+        break;
+      default: /* 2, ... COUNT/SUM/MIN/AVG/MAX */
+        m_row.m_stat.set_field(f->field_index - 2, f);
+        break;
+      }
+    }
+  }
+
+  return 0;
+}
+

=== added file 'storage/perfschema/table_esgs_by_user_by_event_name.h'
--- a/storage/perfschema/table_esgs_by_user_by_event_name.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_esgs_by_user_by_event_name.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,129 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef TABLE_ESGS_BY_USER_BY_EVENT_NAME_H
+#define TABLE_ESGS_BY_USER_BY_EVENT_NAME_H
+
+/**
+  @file storage/perfschema/table_esgs_by_user_by_event_name.h
+  Table EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME (declarations).
+*/
+
+#include "pfs_column_types.h"
+#include "pfs_engine_table.h"
+#include "pfs_instr_class.h"
+#include "pfs_instr.h"
+#include "pfs_user.h"
+#include "table_helper.h"
+
+/**
+  @addtogroup Performance_schema_tables
+  @{
+*/
+
+/**
+  A row of table
+  PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME.
+*/
+struct row_esgs_by_user_by_event_name
+{
+  /** Column USER. */
+  PFS_user_row m_user;
+  /** Column EVENT_NAME. */
+  PFS_event_name_row m_event_name;
+  /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */
+  PFS_stage_stat_row m_stat;
+};
+
+/**
+  Position of a cursor on
+  PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME.
+  Index 1 on user (0 based)
+  Index 2 on stage class (1 based)
+*/
+struct pos_esgs_by_user_by_event_name
+: public PFS_double_index
+{
+  pos_esgs_by_user_by_event_name()
+    : PFS_double_index(0, 1)
+  {}
+
+  inline void reset(void)
+  {
+    m_index_1= 0;
+    m_index_2= 1;
+  }
+
+  inline bool has_more_user(void)
+  { return (m_index_1 < user_max); }
+
+  inline void next_user(void)
+  {
+    m_index_1++;
+    m_index_2= 1;
+  }
+
+  inline void next_stage(void)
+  {
+    m_index_2++;
+  }
+};
+
+/** Table PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME. */
+class table_esgs_by_user_by_event_name : public PFS_engine_table
+{
+public:
+  /** Table share */
+  static PFS_engine_table_share m_share;
+  static PFS_engine_table* create();
+  static int delete_all_rows();
+
+  virtual int rnd_next();
+  virtual int rnd_pos(const void *pos);
+  virtual void reset_position(void);
+
+protected:
+  virtual int read_row_values(TABLE *table,
+                              unsigned char *buf,
+                              Field **fields,
+                              bool read_all);
+
+  table_esgs_by_user_by_event_name();
+
+public:
+  ~table_esgs_by_user_by_event_name()
+  {}
+
+protected:
+  void make_row(PFS_user *user, PFS_stage_class *klass);
+
+private:
+  /** Table share lock. */
+  static THR_LOCK m_table_lock;
+  /** Fields definition. */
+  static TABLE_FIELD_DEF m_field_def;
+
+  /** Current row. */
+  row_esgs_by_user_by_event_name m_row;
+  /** True is the current row exists. */
+  bool m_row_exists;
+  /** Current position. */
+  pos_esgs_by_user_by_event_name m_pos;
+  /** Next position. */
+  pos_esgs_by_user_by_event_name m_next_pos;
+};
+
+/** @} */
+#endif

=== modified file 'storage/perfschema/table_esgs_global_by_event_name.cc'
--- a/storage/perfschema/table_esgs_global_by_event_name.cc	2011-02-14 14:23:55 +0000
+++ b/storage/perfschema/table_esgs_global_by_event_name.cc	2011-05-07 00:40:25 +0000
@@ -157,7 +157,9 @@ void table_esgs_global_by_event_name
   m_row.m_event_name.make_row(klass);
 
   PFS_connection_stage_visitor visitor(klass);
-  PFS_connection_iterator::visit_global(true, & visitor);
+  PFS_connection_iterator::visit_global(true, /* hosts */
+                                        false, /* users */
+                                        true, true, & visitor);
 
   time_normalizer *normalizer= time_normalizer::get(stage_timer);
   m_row.m_stat.set(normalizer, & visitor.m_stat);

=== added file 'storage/perfschema/table_esms_by_account_by_event_name.cc'
--- a/storage/perfschema/table_esms_by_account_by_event_name.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_esms_by_account_by_event_name.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,324 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file storage/perfschema/table_esms_by_account_by_event_name.cc
+  Table EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME (implementation).
+*/
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "pfs_instr_class.h"
+#include "pfs_column_types.h"
+#include "pfs_column_values.h"
+#include "table_esms_by_account_by_event_name.h"
+#include "pfs_global.h"
+#include "pfs_visitor.h"
+
+THR_LOCK table_esms_by_account_by_event_name::m_table_lock;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+  {
+    { C_STRING_WITH_LEN("USER") },
+    { C_STRING_WITH_LEN("char(16)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("HOST") },
+    { C_STRING_WITH_LEN("char(60)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("EVENT_NAME") },
+    { C_STRING_WITH_LEN("varchar(128)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("COUNT_STAR") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MIN_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("AVG_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MAX_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_LOCK_TIME") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_ERRORS") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_WARNINGS") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_ROWS_AFFECTED") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_ROWS_SENT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_ROWS_EXAMINED") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_CREATED_TMP_DISK_TABLES") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_CREATED_TMP_TABLES") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SELECT_FULL_JOIN") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SELECT_FULL_RANGE_JOIN") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SELECT_RANGE") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SELECT_RANGE_CHECK") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SELECT_SCAN") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SORT_MERGE_PASSES") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SORT_RANGE") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SORT_ROWS") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SORT_SCAN") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_NO_INDEX_USED") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_NO_GOOD_INDEX_USED") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  }
+};
+
+TABLE_FIELD_DEF
+table_esms_by_account_by_event_name::m_field_def=
+{ 27, field_types };
+
+PFS_engine_table_share
+table_esms_by_account_by_event_name::m_share=
+{
+  { C_STRING_WITH_LEN("events_statements_summary_by_account_by_event_name") },
+  &pfs_truncatable_acl,
+  table_esms_by_account_by_event_name::create,
+  NULL, /* write_row */
+  table_esms_by_account_by_event_name::delete_all_rows,
+  NULL, /* get_row_count */
+  1000, /* records */
+  sizeof(pos_esms_by_account_by_event_name),
+  &m_table_lock,
+  &m_field_def,
+  false /* checked */
+};
+
+PFS_engine_table*
+table_esms_by_account_by_event_name::create(void)
+{
+  return new table_esms_by_account_by_event_name();
+}
+
+int
+table_esms_by_account_by_event_name::delete_all_rows(void)
+{
+  reset_events_statements_by_thread();
+  reset_events_statements_by_account();
+  return 0;
+}
+
+table_esms_by_account_by_event_name::table_esms_by_account_by_event_name()
+  : PFS_engine_table(&m_share, &m_pos),
+    m_row_exists(false), m_pos(), m_next_pos()
+{}
+
+void table_esms_by_account_by_event_name::reset_position(void)
+{
+  m_pos.reset();
+  m_next_pos.reset();
+}
+
+int table_esms_by_account_by_event_name::rnd_next(void)
+{
+  PFS_account *account;
+  PFS_statement_class *statement_class;
+
+  for (m_pos.set_at(&m_next_pos);
+       m_pos.has_more_account();
+       m_pos.next_account())
+  {
+    account= &account_array[m_pos.m_index_1];
+    if (account->m_lock.is_populated())
+    {
+      statement_class= find_statement_class(m_pos.m_index_2);
+      if (statement_class)
+      {
+        make_row(account, statement_class);
+        m_next_pos.set_after(&m_pos);
+        return 0;
+      }
+    }
+  }
+
+  return HA_ERR_END_OF_FILE;
+}
+
+int
+table_esms_by_account_by_event_name::rnd_pos(const void *pos)
+{
+  PFS_account *account;
+  PFS_statement_class *statement_class;
+
+  set_position(pos);
+  DBUG_ASSERT(m_pos.m_index_1 < account_max);
+
+  account= &account_array[m_pos.m_index_1];
+  if (! account->m_lock.is_populated())
+    return HA_ERR_RECORD_DELETED;
+
+  statement_class= find_statement_class(m_pos.m_index_2);
+  if (statement_class)
+  {
+    make_row(account, statement_class);
+    return 0;
+  }
+
+  return HA_ERR_RECORD_DELETED;
+}
+
+void table_esms_by_account_by_event_name
+::make_row(PFS_account *account, PFS_statement_class *klass)
+{
+  pfs_lock lock;
+  m_row_exists= false;
+
+  account->m_lock.begin_optimistic_lock(&lock);
+
+  if (m_row.m_account.make_row(account))
+    return;
+
+  m_row.m_event_name.make_row(klass);
+
+  PFS_connection_statement_visitor visitor(klass);
+  PFS_connection_iterator::visit_account(account, true, & visitor);
+
+  if (! account->m_lock.end_optimistic_lock(&lock))
+    return;
+
+  m_row_exists= true;
+
+  time_normalizer *normalizer= time_normalizer::get(statement_timer);
+  m_row.m_stat.set(normalizer, & visitor.m_stat);
+}
+
+int table_esms_by_account_by_event_name
+::read_row_values(TABLE *table, unsigned char *buf, Field **fields,
+                  bool read_all)
+{
+  Field *f;
+
+  if (unlikely(! m_row_exists))
+    return HA_ERR_RECORD_DELETED;
+
+  /* Set the null bits */
+  DBUG_ASSERT(table->s->null_bytes == 1);
+  buf[0]= 0;
+
+  for (; (f= *fields) ; fields++)
+  {
+    if (read_all || bitmap_is_set(table->read_set, f->field_index))
+    {
+      switch(f->field_index)
+      {
+      case 0: /* USER */
+      case 1: /* HOST */
+        m_row.m_account.set_field(f->field_index, f);
+        break;
+      case 2: /* EVENT_NAME */
+        m_row.m_event_name.set_field(f);
+        break;
+      default: /* 3, ... COUNT/SUM/MIN/AVG/MAX */
+        m_row.m_stat.set_field(f->field_index - 3, f);
+        break;
+      }
+    }
+  }
+
+  return 0;
+}
+

=== added file 'storage/perfschema/table_esms_by_account_by_event_name.h'
--- a/storage/perfschema/table_esms_by_account_by_event_name.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_esms_by_account_by_event_name.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,124 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef TABLE_ESMS_BY_ACCOUNT_BY_EVENT_NAME_H
+#define TABLE_ESMS_BY_ACCOUNT_BY_EVENT_NAME_H
+
+/**
+  @file storage/perfschema/table_esms_by_account_by_event_name.h
+  Table EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME (declarations).
+*/
+
+#include "pfs_column_types.h"
+#include "pfs_engine_table.h"
+#include "pfs_instr_class.h"
+#include "pfs_instr.h"
+#include "pfs_account.h"
+#include "table_helper.h"
+
+/**
+  @addtogroup Performance_schema_tables
+  @{
+*/
+
+/**
+  A row of table
+  PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME.
+*/
+struct row_esms_by_account_by_event_name
+{
+  /** Column USER, HOST. */
+  PFS_account_row m_account;
+  /** Column EVENT_NAME. */
+  PFS_event_name_row m_event_name;
+  /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */
+  PFS_statement_stat_row m_stat;
+};
+
+/**
+  Position of a cursor on
+  PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME.
+  Index 1 on user@host (0 based)
+  Index 2 on statement class (1 based)
+*/
+struct pos_esms_by_account_by_event_name
+: public PFS_double_index
+{
+  pos_esms_by_account_by_event_name()
+    : PFS_double_index(0, 1)
+  {}
+
+  inline void reset(void)
+  {
+    m_index_1= 0;
+    m_index_2= 1;
+  }
+
+  inline bool has_more_account(void)
+  { return (m_index_1 < account_max); }
+
+  inline void next_account(void)
+  {
+    m_index_1++;
+    m_index_2= 1;
+  }
+};
+
+/** Table PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. */
+class table_esms_by_account_by_event_name : public PFS_engine_table
+{
+public:
+  /** Table share */
+  static PFS_engine_table_share m_share;
+  static PFS_engine_table* create();
+  static int delete_all_rows();
+
+  virtual int rnd_next();
+  virtual int rnd_pos(const void *pos);
+  virtual void reset_position(void);
+
+protected:
+  virtual int read_row_values(TABLE *table,
+                              unsigned char *buf,
+                              Field **fields,
+                              bool read_all);
+
+  table_esms_by_account_by_event_name();
+
+public:
+  ~table_esms_by_account_by_event_name()
+  {}
+
+protected:
+  void make_row(PFS_account *account, PFS_statement_class *klass);
+
+private:
+  /** Table share lock. */
+  static THR_LOCK m_table_lock;
+  /** Fields definition. */
+  static TABLE_FIELD_DEF m_field_def;
+
+  /** Current row. */
+  row_esms_by_account_by_event_name m_row;
+  /** True is the current row exists. */
+  bool m_row_exists;
+  /** Current position. */
+  pos_esms_by_account_by_event_name m_pos;
+  /** Next position. */
+  pos_esms_by_account_by_event_name m_next_pos;
+};
+
+/** @} */
+#endif

=== added file 'storage/perfschema/table_esms_by_host_by_event_name.cc'
--- a/storage/perfschema/table_esms_by_host_by_event_name.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_esms_by_host_by_event_name.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,320 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file storage/perfschema/table_esms_by_host_by_event_name.cc
+  Table EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME (implementation).
+*/
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "pfs_instr_class.h"
+#include "pfs_column_types.h"
+#include "pfs_column_values.h"
+#include "table_esms_by_host_by_event_name.h"
+#include "pfs_global.h"
+#include "pfs_account.h"
+#include "pfs_visitor.h"
+
+THR_LOCK table_esms_by_host_by_event_name::m_table_lock;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+  {
+    { C_STRING_WITH_LEN("HOST") },
+    { C_STRING_WITH_LEN("char(60)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("EVENT_NAME") },
+    { C_STRING_WITH_LEN("varchar(128)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("COUNT_STAR") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MIN_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("AVG_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MAX_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_LOCK_TIME") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_ERRORS") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_WARNINGS") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_ROWS_AFFECTED") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_ROWS_SENT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_ROWS_EXAMINED") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_CREATED_TMP_DISK_TABLES") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_CREATED_TMP_TABLES") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SELECT_FULL_JOIN") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SELECT_FULL_RANGE_JOIN") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SELECT_RANGE") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SELECT_RANGE_CHECK") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SELECT_SCAN") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SORT_MERGE_PASSES") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SORT_RANGE") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SORT_ROWS") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SORT_SCAN") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_NO_INDEX_USED") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_NO_GOOD_INDEX_USED") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  }
+};
+
+TABLE_FIELD_DEF
+table_esms_by_host_by_event_name::m_field_def=
+{ 26, field_types };
+
+PFS_engine_table_share
+table_esms_by_host_by_event_name::m_share=
+{
+  { C_STRING_WITH_LEN("events_statements_summary_by_host_by_event_name") },
+  &pfs_truncatable_acl,
+  table_esms_by_host_by_event_name::create,
+  NULL, /* write_row */
+  table_esms_by_host_by_event_name::delete_all_rows,
+  NULL, /* get_row_count */
+  1000, /* records */
+  sizeof(pos_esms_by_host_by_event_name),
+  &m_table_lock,
+  &m_field_def,
+  false /* checked */
+};
+
+PFS_engine_table*
+table_esms_by_host_by_event_name::create(void)
+{
+  return new table_esms_by_host_by_event_name();
+}
+
+int
+table_esms_by_host_by_event_name::delete_all_rows(void)
+{
+  reset_events_statements_by_thread();
+  reset_events_statements_by_account();
+  reset_events_statements_by_host();
+  return 0;
+}
+
+table_esms_by_host_by_event_name::table_esms_by_host_by_event_name()
+  : PFS_engine_table(&m_share, &m_pos),
+    m_row_exists(false), m_pos(), m_next_pos()
+{}
+
+void table_esms_by_host_by_event_name::reset_position(void)
+{
+  m_pos.reset();
+  m_next_pos.reset();
+}
+
+int table_esms_by_host_by_event_name::rnd_next(void)
+{
+  PFS_host *host;
+  PFS_statement_class *statement_class;
+
+  for (m_pos.set_at(&m_next_pos);
+       m_pos.has_more_host();
+       m_pos.next_host())
+  {
+    host= &host_array[m_pos.m_index_1];
+    if (host->m_lock.is_populated())
+    {
+      statement_class= find_statement_class(m_pos.m_index_2);
+      if (statement_class)
+      {
+        make_row(host, statement_class);
+        m_next_pos.set_after(&m_pos);
+        return 0;
+      }
+    }
+  }
+
+  return HA_ERR_END_OF_FILE;
+}
+
+int
+table_esms_by_host_by_event_name::rnd_pos(const void *pos)
+{
+  PFS_host *host;
+  PFS_statement_class *statement_class;
+
+  set_position(pos);
+  DBUG_ASSERT(m_pos.m_index_1 < host_max);
+
+  host= &host_array[m_pos.m_index_1];
+  if (! host->m_lock.is_populated())
+    return HA_ERR_RECORD_DELETED;
+
+  statement_class= find_statement_class(m_pos.m_index_2);
+  if (statement_class)
+  {
+    make_row(host, statement_class);
+    return 0;
+  }
+
+  return HA_ERR_RECORD_DELETED;
+}
+
+void table_esms_by_host_by_event_name
+::make_row(PFS_host *host, PFS_statement_class *klass)
+{
+  pfs_lock lock;
+  m_row_exists= false;
+
+  host->m_lock.begin_optimistic_lock(&lock);
+
+  if (m_row.m_host.make_row(host))
+    return;
+
+  m_row.m_event_name.make_row(klass);
+
+  PFS_connection_statement_visitor visitor(klass);
+  PFS_connection_iterator::visit_host(host, true, true, & visitor);
+
+  if (! host->m_lock.end_optimistic_lock(&lock))
+    return;
+
+  m_row_exists= true;
+
+  time_normalizer *normalizer= time_normalizer::get(statement_timer);
+  m_row.m_stat.set(normalizer, & visitor.m_stat);
+}
+
+int table_esms_by_host_by_event_name
+::read_row_values(TABLE *table, unsigned char *buf, Field **fields,
+                  bool read_all)
+{
+  Field *f;
+
+  if (unlikely(! m_row_exists))
+    return HA_ERR_RECORD_DELETED;
+
+  /* Set the null bits */
+  DBUG_ASSERT(table->s->null_bytes == 1);
+  buf[0]= 0;
+
+  for (; (f= *fields) ; fields++)
+  {
+    if (read_all || bitmap_is_set(table->read_set, f->field_index))
+    {
+      switch(f->field_index)
+      {
+      case 0: /* HOST */
+        m_row.m_host.set_field(f);
+        break;
+      case 1: /* EVENT_NAME */
+        m_row.m_event_name.set_field(f);
+        break;
+      default: /* 2, ... COUNT/SUM/MIN/AVG/MAX */
+        m_row.m_stat.set_field(f->field_index - 2, f);
+        break;
+      }
+    }
+  }
+
+  return 0;
+}
+

=== added file 'storage/perfschema/table_esms_by_host_by_event_name.h'
--- a/storage/perfschema/table_esms_by_host_by_event_name.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_esms_by_host_by_event_name.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,124 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef TABLE_ESMS_BY_HOST_BY_EVENT_NAME_H
+#define TABLE_ESMS_BY_HOST_BY_EVENT_NAME_H
+
+/**
+  @file storage/perfschema/table_esms_by_host_by_event_name.h
+  Table EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME (declarations).
+*/
+
+#include "pfs_column_types.h"
+#include "pfs_engine_table.h"
+#include "pfs_instr_class.h"
+#include "pfs_instr.h"
+#include "pfs_host.h"
+#include "table_helper.h"
+
+/**
+  @addtogroup Performance_schema_tables
+  @{
+*/
+
+/**
+  A row of table
+  PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME.
+*/
+struct row_esms_by_host_by_event_name
+{
+  /** Column HOST */
+  PFS_host_row m_host;
+  /** Column EVENT_NAME */
+  PFS_event_name_row m_event_name;
+  /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */
+  PFS_statement_stat_row m_stat;
+};
+
+/**
+  Position of a cursor on
+  PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME.
+  Index 1 on host (0 based)
+  Index 2 on statement class (1 based)
+*/
+struct pos_esms_by_host_by_event_name
+: public PFS_double_index
+{
+  pos_esms_by_host_by_event_name()
+    : PFS_double_index(0, 1)
+  {}
+
+  inline void reset(void)
+  {
+    m_index_1= 0;
+    m_index_2= 1;
+  }
+
+  inline bool has_more_host(void)
+  { return (m_index_1 < host_max); }
+
+  inline void next_host(void)
+  {
+    m_index_1++;
+    m_index_2= 1;
+  }
+};
+
+/** Table PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME. */
+class table_esms_by_host_by_event_name : public PFS_engine_table
+{
+public:
+  /** Table share */
+  static PFS_engine_table_share m_share;
+  static PFS_engine_table* create();
+  static int delete_all_rows();
+
+  virtual int rnd_next();
+  virtual int rnd_pos(const void *pos);
+  virtual void reset_position(void);
+
+protected:
+  virtual int read_row_values(TABLE *table,
+                              unsigned char *buf,
+                              Field **fields,
+                              bool read_all);
+
+  table_esms_by_host_by_event_name();
+
+public:
+  ~table_esms_by_host_by_event_name()
+  {}
+
+protected:
+  void make_row(PFS_host *host, PFS_statement_class *klass);
+
+private:
+  /** Table share lock. */
+  static THR_LOCK m_table_lock;
+  /** Fields definition. */
+  static TABLE_FIELD_DEF m_field_def;
+
+  /** Current row. */
+  row_esms_by_host_by_event_name m_row;
+  /** True is the current row exists. */
+  bool m_row_exists;
+  /** Current position. */
+  pos_esms_by_host_by_event_name m_pos;
+  /** Next position. */
+  pos_esms_by_host_by_event_name m_next_pos;
+};
+
+/** @} */
+#endif

=== added file 'storage/perfschema/table_esms_by_user_by_event_name.cc'
--- a/storage/perfschema/table_esms_by_user_by_event_name.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_esms_by_user_by_event_name.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,320 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file storage/perfschema/table_esms_by_user_by_event_name.cc
+  Table EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME (implementation).
+*/
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "pfs_instr_class.h"
+#include "pfs_column_types.h"
+#include "pfs_column_values.h"
+#include "table_esms_by_user_by_event_name.h"
+#include "pfs_global.h"
+#include "pfs_account.h"
+#include "pfs_visitor.h"
+
+THR_LOCK table_esms_by_user_by_event_name::m_table_lock;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+  {
+    { C_STRING_WITH_LEN("USER") },
+    { C_STRING_WITH_LEN("char(16)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("EVENT_NAME") },
+    { C_STRING_WITH_LEN("varchar(128)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("COUNT_STAR") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MIN_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("AVG_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MAX_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_LOCK_TIME") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_ERRORS") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_WARNINGS") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_ROWS_AFFECTED") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_ROWS_SENT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_ROWS_EXAMINED") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_CREATED_TMP_DISK_TABLES") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_CREATED_TMP_TABLES") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SELECT_FULL_JOIN") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SELECT_FULL_RANGE_JOIN") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SELECT_RANGE") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SELECT_RANGE_CHECK") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SELECT_SCAN") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SORT_MERGE_PASSES") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SORT_RANGE") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SORT_ROWS") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_SORT_SCAN") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_NO_INDEX_USED") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_NO_GOOD_INDEX_USED") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  }
+};
+
+TABLE_FIELD_DEF
+table_esms_by_user_by_event_name::m_field_def=
+{ 26, field_types };
+
+PFS_engine_table_share
+table_esms_by_user_by_event_name::m_share=
+{
+  { C_STRING_WITH_LEN("events_statements_summary_by_user_by_event_name") },
+  &pfs_truncatable_acl,
+  table_esms_by_user_by_event_name::create,
+  NULL, /* write_row */
+  table_esms_by_user_by_event_name::delete_all_rows,
+  NULL, /* get_row_count */
+  1000, /* records */
+  sizeof(pos_esms_by_user_by_event_name),
+  &m_table_lock,
+  &m_field_def,
+  false /* checked */
+};
+
+PFS_engine_table*
+table_esms_by_user_by_event_name::create(void)
+{
+  return new table_esms_by_user_by_event_name();
+}
+
+int
+table_esms_by_user_by_event_name::delete_all_rows(void)
+{
+  reset_events_statements_by_thread();
+  reset_events_statements_by_account();
+  reset_events_statements_by_user();
+  return 0;
+}
+
+table_esms_by_user_by_event_name::table_esms_by_user_by_event_name()
+  : PFS_engine_table(&m_share, &m_pos),
+    m_row_exists(false), m_pos(), m_next_pos()
+{}
+
+void table_esms_by_user_by_event_name::reset_position(void)
+{
+  m_pos.reset();
+  m_next_pos.reset();
+}
+
+int table_esms_by_user_by_event_name::rnd_next(void)
+{
+  PFS_user *user;
+  PFS_statement_class *statement_class;
+
+  for (m_pos.set_at(&m_next_pos);
+       m_pos.has_more_user();
+       m_pos.next_user())
+  {
+    user= &user_array[m_pos.m_index_1];
+    if (user->m_lock.is_populated())
+    {
+      statement_class= find_statement_class(m_pos.m_index_2);
+      if (statement_class)
+      {
+        make_row(user, statement_class);
+        m_next_pos.set_after(&m_pos);
+        return 0;
+      }
+    }
+  }
+
+  return HA_ERR_END_OF_FILE;
+}
+
+int
+table_esms_by_user_by_event_name::rnd_pos(const void *pos)
+{
+  PFS_user *user;
+  PFS_statement_class *statement_class;
+
+  set_position(pos);
+  DBUG_ASSERT(m_pos.m_index_1 < user_max);
+
+  user= &user_array[m_pos.m_index_1];
+  if (! user->m_lock.is_populated())
+    return HA_ERR_RECORD_DELETED;
+
+  statement_class= find_statement_class(m_pos.m_index_2);
+  if (statement_class)
+  {
+    make_row(user, statement_class);
+    return 0;
+  }
+
+  return HA_ERR_RECORD_DELETED;
+}
+
+void table_esms_by_user_by_event_name
+::make_row(PFS_user *user, PFS_statement_class *klass)
+{
+  pfs_lock lock;
+  m_row_exists= false;
+
+  user->m_lock.begin_optimistic_lock(&lock);
+
+  if (m_row.m_user.make_row(user))
+    return;
+
+  m_row.m_event_name.make_row(klass);
+
+  PFS_connection_statement_visitor visitor(klass);
+  PFS_connection_iterator::visit_user(user, true, true, & visitor);
+
+  if (! user->m_lock.end_optimistic_lock(&lock))
+    return;
+
+  m_row_exists= true;
+
+  time_normalizer *normalizer= time_normalizer::get(statement_timer);
+  m_row.m_stat.set(normalizer, & visitor.m_stat);
+}
+
+int table_esms_by_user_by_event_name
+::read_row_values(TABLE *table, unsigned char *buf, Field **fields,
+                  bool read_all)
+{
+  Field *f;
+
+  if (unlikely(! m_row_exists))
+    return HA_ERR_RECORD_DELETED;
+
+  /* Set the null bits */
+  DBUG_ASSERT(table->s->null_bytes == 1);
+  buf[0]= 0;
+
+  for (; (f= *fields) ; fields++)
+  {
+    if (read_all || bitmap_is_set(table->read_set, f->field_index))
+    {
+      switch(f->field_index)
+      {
+      case 0: /* USER */
+        m_row.m_user.set_field(f);
+        break;
+      case 1: /* EVENT_NAME */
+        m_row.m_event_name.set_field(f);
+        break;
+      default: /* 2, ... COUNT/SUM/MIN/AVG/MAX */
+        m_row.m_stat.set_field(f->field_index - 2, f);
+        break;
+      }
+    }
+  }
+
+  return 0;
+}
+

=== added file 'storage/perfschema/table_esms_by_user_by_event_name.h'
--- a/storage/perfschema/table_esms_by_user_by_event_name.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_esms_by_user_by_event_name.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,124 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef TABLE_ESMS_BY_USER_BY_EVENT_NAME_H
+#define TABLE_ESMS_BY_USER_BY_EVENT_NAME_H
+
+/**
+  @file storage/perfschema/table_esms_by_user_by_event_name.h
+  Table EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME (declarations).
+*/
+
+#include "pfs_column_types.h"
+#include "pfs_engine_table.h"
+#include "pfs_instr_class.h"
+#include "pfs_instr.h"
+#include "pfs_user.h"
+#include "table_helper.h"
+
+/**
+  @addtogroup Performance_schema_tables
+  @{
+*/
+
+/**
+  A row of table
+  PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME.
+*/
+struct row_esms_by_user_by_event_name
+{
+  /** Column USER. */
+  PFS_user_row m_user;
+  /** Column EVENT_NAME. */
+  PFS_event_name_row m_event_name;
+  /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */
+  PFS_statement_stat_row m_stat;
+};
+
+/**
+  Position of a cursor on
+  PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME.
+  Index 1 on user (0 based)
+  Index 2 on statement class (1 based)
+*/
+struct pos_esms_by_user_by_event_name
+: public PFS_double_index
+{
+  pos_esms_by_user_by_event_name()
+    : PFS_double_index(0, 1)
+  {}
+
+  inline void reset(void)
+  {
+    m_index_1= 0;
+    m_index_2= 1;
+  }
+
+  inline bool has_more_user(void)
+  { return (m_index_1 < user_max); }
+
+  inline void next_user(void)
+  {
+    m_index_1++;
+    m_index_2= 1;
+  }
+};
+
+/** Table PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME. */
+class table_esms_by_user_by_event_name : public PFS_engine_table
+{
+public:
+  /** Table share */
+  static PFS_engine_table_share m_share;
+  static PFS_engine_table* create();
+  static int delete_all_rows();
+
+  virtual int rnd_next();
+  virtual int rnd_pos(const void *pos);
+  virtual void reset_position(void);
+
+protected:
+  virtual int read_row_values(TABLE *table,
+                              unsigned char *buf,
+                              Field **fields,
+                              bool read_all);
+
+  table_esms_by_user_by_event_name();
+
+public:
+  ~table_esms_by_user_by_event_name()
+  {}
+
+protected:
+  void make_row(PFS_user *user, PFS_statement_class *klass);
+
+private:
+  /** Table share lock. */
+  static THR_LOCK m_table_lock;
+  /** Fields definition. */
+  static TABLE_FIELD_DEF m_field_def;
+
+  /** Current row. */
+  row_esms_by_user_by_event_name m_row;
+  /** True is the current row exists. */
+  bool m_row_exists;
+  /** Current position. */
+  pos_esms_by_user_by_event_name m_pos;
+  /** Next position. */
+  pos_esms_by_user_by_event_name m_next_pos;
+};
+
+/** @} */
+#endif

=== modified file 'storage/perfschema/table_esms_global_by_event_name.cc'
--- a/storage/perfschema/table_esms_global_by_event_name.cc	2011-02-14 14:23:55 +0000
+++ b/storage/perfschema/table_esms_global_by_event_name.cc	2011-05-07 00:40:25 +0000
@@ -252,7 +252,9 @@ void table_esms_global_by_event_name
   m_row.m_event_name.make_row(klass);
 
   PFS_connection_statement_visitor visitor(klass);
-  PFS_connection_iterator::visit_global(true, & visitor);
+  PFS_connection_iterator::visit_global(true, /* hosts */
+                                        false, /* users */
+                                        true, true, & visitor);
 
   time_normalizer *normalizer= time_normalizer::get(statement_timer);
   m_row.m_stat.set(normalizer, & visitor.m_stat);

=== added file 'storage/perfschema/table_ews_by_account_by_event_name.cc'
--- a/storage/perfschema/table_ews_by_account_by_event_name.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_ews_by_account_by_event_name.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,276 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file storage/perfschema/table_ews_by_account_by_event_name.cc
+  Table EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME (implementation).
+*/
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "pfs_instr_class.h"
+#include "pfs_column_types.h"
+#include "pfs_column_values.h"
+#include "table_ews_by_account_by_event_name.h"
+#include "pfs_global.h"
+#include "pfs_visitor.h"
+
+THR_LOCK table_ews_by_account_by_event_name::m_table_lock;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+  {
+    { C_STRING_WITH_LEN("USER") },
+    { C_STRING_WITH_LEN("char(16)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("HOST") },
+    { C_STRING_WITH_LEN("char(60)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("EVENT_NAME") },
+    { C_STRING_WITH_LEN("varchar(128)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("COUNT_STAR") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MIN_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("AVG_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MAX_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  }
+};
+
+TABLE_FIELD_DEF
+table_ews_by_account_by_event_name::m_field_def=
+{ 8, field_types };
+
+PFS_engine_table_share
+table_ews_by_account_by_event_name::m_share=
+{
+  { C_STRING_WITH_LEN("events_waits_summary_by_account_by_event_name") },
+  &pfs_truncatable_acl,
+  table_ews_by_account_by_event_name::create,
+  NULL, /* write_row */
+  table_ews_by_account_by_event_name::delete_all_rows,
+  NULL, /* get_row_count */
+  1000, /* records */
+  sizeof(pos_ews_by_account_by_event_name),
+  &m_table_lock,
+  &m_field_def,
+  false /* checked */
+};
+
+PFS_engine_table*
+table_ews_by_account_by_event_name::create(void)
+{
+  return new table_ews_by_account_by_event_name();
+}
+
+int
+table_ews_by_account_by_event_name::delete_all_rows(void)
+{
+  reset_events_waits_by_thread();
+  reset_events_waits_by_account();
+  return 0;
+}
+
+table_ews_by_account_by_event_name::table_ews_by_account_by_event_name()
+  : PFS_engine_table(&m_share, &m_pos),
+    m_row_exists(false), m_pos(), m_next_pos()
+{}
+
+void table_ews_by_account_by_event_name::reset_position(void)
+{
+  m_pos.reset();
+  m_next_pos.reset();
+}
+
+int table_ews_by_account_by_event_name::rnd_next(void)
+{
+  PFS_account *account;
+  PFS_instr_class *instr_class;
+
+  for (m_pos.set_at(&m_next_pos);
+       m_pos.has_more_account();
+       m_pos.next_account())
+  {
+    account= &account_array[m_pos.m_index_1];
+    if (account->m_lock.is_populated())
+    {
+      for ( ;
+           m_pos.has_more_view();
+           m_pos.next_view())
+      {
+        switch (m_pos.m_index_2)
+        {
+        case pos_ews_by_account_by_event_name::VIEW_MUTEX:
+          instr_class= find_mutex_class(m_pos.m_index_3);
+          break;
+        case pos_ews_by_account_by_event_name::VIEW_RWLOCK:
+          instr_class= find_rwlock_class(m_pos.m_index_3);
+          break;
+        case pos_ews_by_account_by_event_name::VIEW_COND:
+          instr_class= find_cond_class(m_pos.m_index_3);
+          break;
+        case pos_ews_by_account_by_event_name::VIEW_FILE:
+          instr_class= find_file_class(m_pos.m_index_3);
+          break;
+        case pos_ews_by_account_by_event_name::VIEW_TABLE:
+          instr_class= find_table_class(m_pos.m_index_3);
+          break;
+        default:
+          instr_class= NULL;
+          DBUG_ASSERT(false);
+          break;
+        }
+
+        if (instr_class)
+        {
+          make_row(account, instr_class);
+          m_next_pos.set_after(&m_pos);
+          return 0;
+        }
+      }
+    }
+  }
+
+  return HA_ERR_END_OF_FILE;
+}
+
+int
+table_ews_by_account_by_event_name::rnd_pos(const void *pos)
+{
+  PFS_account *account;
+  PFS_instr_class *instr_class;
+
+  set_position(pos);
+  DBUG_ASSERT(m_pos.m_index_1 < account_max);
+
+  account= &account_array[m_pos.m_index_1];
+  if (! account->m_lock.is_populated())
+    return HA_ERR_RECORD_DELETED;
+
+  switch (m_pos.m_index_2)
+  {
+  case pos_ews_by_account_by_event_name::VIEW_MUTEX:
+    instr_class= find_mutex_class(m_pos.m_index_3);
+    break;
+  case pos_ews_by_account_by_event_name::VIEW_RWLOCK:
+    instr_class= find_rwlock_class(m_pos.m_index_3);
+    break;
+  case pos_ews_by_account_by_event_name::VIEW_COND:
+    instr_class= find_cond_class(m_pos.m_index_3);
+    break;
+  case pos_ews_by_account_by_event_name::VIEW_FILE:
+    instr_class= find_file_class(m_pos.m_index_3);
+    break;
+  case pos_ews_by_account_by_event_name::VIEW_TABLE:
+    instr_class= find_table_class(m_pos.m_index_3);
+    break;
+  default:
+    instr_class= NULL;
+    DBUG_ASSERT(false);
+  }
+  if (instr_class)
+  {
+    make_row(account, instr_class);
+    return 0;
+  }
+
+  return HA_ERR_RECORD_DELETED;
+}
+
+void table_ews_by_account_by_event_name
+::make_row(PFS_account *account, PFS_instr_class *klass)
+{
+  pfs_lock lock;
+  m_row_exists= false;
+
+  account->m_lock.begin_optimistic_lock(&lock);
+
+  if (m_row.m_account.make_row(account))
+    return;
+
+  m_row.m_event_name.make_row(klass);
+
+  PFS_connection_wait_visitor visitor(klass);
+  PFS_connection_iterator::visit_account(account, true, & visitor);
+
+  if (! account->m_lock.end_optimistic_lock(&lock))
+    return;
+
+  m_row_exists= true;
+
+  time_normalizer *normalizer= time_normalizer::get(wait_timer);
+  m_row.m_stat.set(normalizer, & visitor.m_stat);
+}
+
+int table_ews_by_account_by_event_name
+::read_row_values(TABLE *table, unsigned char *buf, Field **fields,
+                  bool read_all)
+{
+  Field *f;
+
+  if (unlikely(! m_row_exists))
+    return HA_ERR_RECORD_DELETED;
+
+  /* Set the null bits */
+  DBUG_ASSERT(table->s->null_bytes == 1);
+  buf[0]= 0;
+
+  for (; (f= *fields) ; fields++)
+  {
+    if (read_all || bitmap_is_set(table->read_set, f->field_index))
+    {
+      switch(f->field_index)
+      {
+      case 0: /* USER */
+      case 1: /* HOST */
+        m_row.m_account.set_field(f->field_index, f);
+        break;
+      case 2: /* EVENT_NAME */
+        m_row.m_event_name.set_field(f);
+        break;
+      default: /* 3, ... COUNT/SUM/MIN/AVG/MAX */
+        m_row.m_stat.set_field(f->field_index - 3, f);
+        break;
+      }
+    }
+  }
+
+  return 0;
+}
+

=== added file 'storage/perfschema/table_ews_by_account_by_event_name.h'
--- a/storage/perfschema/table_ews_by_account_by_event_name.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_ews_by_account_by_event_name.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,136 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef TABLE_EWS_BY_ACCOUNT_BY_EVENT_NAME_H
+#define TABLE_EWS_BY_ACCOUNT_BY_EVENT_NAME_H
+
+/**
+  @file storage/perfschema/table_ews_by_account_by_event_name.h
+  Table EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME (declarations).
+*/
+
+#include "pfs_column_types.h"
+#include "pfs_engine_table.h"
+#include "pfs_instr_class.h"
+#include "pfs_instr.h"
+#include "pfs_account.h"
+#include "table_helper.h"
+
+/**
+  @addtogroup Performance_schema_tables
+  @{
+*/
+
+/**
+  A row of table
+  PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME.
+*/
+struct row_ews_by_account_by_event_name
+{
+  /** Column USER, HOST. */
+  PFS_account_row m_account;
+  /** Column EVENT_NAME. */
+  PFS_event_name_row m_event_name;
+  /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */
+  PFS_stat_row m_stat;
+};
+
+/**
+  Position of a cursor on
+  PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME.
+  Index 1 on user@host (0 based)
+  Index 2 on instrument view
+  Index 3 on instrument class (1 based)
+*/
+struct pos_ews_by_account_by_event_name
+: public PFS_triple_index, public PFS_instrument_view_constants
+{
+  pos_ews_by_account_by_event_name()
+    : PFS_triple_index(0, FIRST_VIEW, 1)
+  {}
+
+  inline void reset(void)
+  {
+    m_index_1= 0;
+    m_index_2= VIEW_MUTEX;
+    m_index_3= 1;
+  }
+
+  inline bool has_more_account(void)
+  { return (m_index_1 < account_max); }
+
+  inline void next_account(void)
+  {
+    m_index_1++;
+    m_index_2= FIRST_VIEW;
+    m_index_3= 1;
+  }
+
+  inline bool has_more_view(void)
+  { return (m_index_2 <= LAST_VIEW); }
+
+  inline void next_view(void)
+  {
+    m_index_2++;
+    m_index_3= 1;
+  }
+};
+
+/** Table PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. */
+class table_ews_by_account_by_event_name : public PFS_engine_table
+{
+public:
+  /** Table share */
+  static PFS_engine_table_share m_share;
+  static PFS_engine_table* create();
+  static int delete_all_rows();
+
+  virtual int rnd_next();
+  virtual int rnd_pos(const void *pos);
+  virtual void reset_position(void);
+
+protected:
+  virtual int read_row_values(TABLE *table,
+                              unsigned char *buf,
+                              Field **fields,
+                              bool read_all);
+
+  table_ews_by_account_by_event_name();
+
+public:
+  ~table_ews_by_account_by_event_name()
+  {}
+
+protected:
+  void make_row(PFS_account *account, PFS_instr_class *klass);
+
+private:
+  /** Table share lock. */
+  static THR_LOCK m_table_lock;
+  /** Fields definition. */
+  static TABLE_FIELD_DEF m_field_def;
+
+  /** Current row. */
+  row_ews_by_account_by_event_name m_row;
+  /** True is the current row exists. */
+  bool m_row_exists;
+  /** Current position. */
+  pos_ews_by_account_by_event_name m_pos;
+  /** Next position. */
+  pos_ews_by_account_by_event_name m_next_pos;
+};
+
+/** @} */
+#endif

=== added file 'storage/perfschema/table_ews_by_host_by_event_name.cc'
--- a/storage/perfschema/table_ews_by_host_by_event_name.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_ews_by_host_by_event_name.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,273 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file storage/perfschema/table_ews_by_host_by_event_name.cc
+  Table EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME (implementation).
+*/
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "pfs_instr_class.h"
+#include "pfs_column_types.h"
+#include "pfs_column_values.h"
+#include "table_ews_by_host_by_event_name.h"
+#include "pfs_global.h"
+#include "pfs_account.h"
+#include "pfs_visitor.h"
+
+THR_LOCK table_ews_by_host_by_event_name::m_table_lock;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+  {
+    { C_STRING_WITH_LEN("HOST") },
+    { C_STRING_WITH_LEN("char(60)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("EVENT_NAME") },
+    { C_STRING_WITH_LEN("varchar(128)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("COUNT_STAR") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MIN_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("AVG_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MAX_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  }
+};
+
+TABLE_FIELD_DEF
+table_ews_by_host_by_event_name::m_field_def=
+{ 7, field_types };
+
+PFS_engine_table_share
+table_ews_by_host_by_event_name::m_share=
+{
+  { C_STRING_WITH_LEN("events_waits_summary_by_host_by_event_name") },
+  &pfs_truncatable_acl,
+  table_ews_by_host_by_event_name::create,
+  NULL, /* write_row */
+  table_ews_by_host_by_event_name::delete_all_rows,
+  NULL, /* get_row_count */
+  1000, /* records */
+  sizeof(pos_ews_by_host_by_event_name),
+  &m_table_lock,
+  &m_field_def,
+  false /* checked */
+};
+
+PFS_engine_table*
+table_ews_by_host_by_event_name::create(void)
+{
+  return new table_ews_by_host_by_event_name();
+}
+
+int
+table_ews_by_host_by_event_name::delete_all_rows(void)
+{
+  reset_events_waits_by_thread();
+  reset_events_waits_by_account();
+  reset_events_waits_by_host();
+  return 0;
+}
+
+table_ews_by_host_by_event_name::table_ews_by_host_by_event_name()
+  : PFS_engine_table(&m_share, &m_pos),
+    m_row_exists(false), m_pos(), m_next_pos()
+{}
+
+void table_ews_by_host_by_event_name::reset_position(void)
+{
+  m_pos.reset();
+  m_next_pos.reset();
+}
+
+int table_ews_by_host_by_event_name::rnd_next(void)
+{
+  PFS_host *host;
+  PFS_instr_class *instr_class;
+
+  for (m_pos.set_at(&m_next_pos);
+       m_pos.has_more_host();
+       m_pos.next_host())
+  {
+    host= &host_array[m_pos.m_index_1];
+    if (host->m_lock.is_populated())
+    {
+      for ( ;
+           m_pos.has_more_view();
+           m_pos.next_view())
+      {
+        switch (m_pos.m_index_2)
+        {
+        case pos_ews_by_host_by_event_name::VIEW_MUTEX:
+          instr_class= find_mutex_class(m_pos.m_index_3);
+          break;
+        case pos_ews_by_host_by_event_name::VIEW_RWLOCK:
+          instr_class= find_rwlock_class(m_pos.m_index_3);
+          break;
+        case pos_ews_by_host_by_event_name::VIEW_COND:
+          instr_class= find_cond_class(m_pos.m_index_3);
+          break;
+        case pos_ews_by_host_by_event_name::VIEW_FILE:
+          instr_class= find_file_class(m_pos.m_index_3);
+          break;
+        case pos_ews_by_host_by_event_name::VIEW_TABLE:
+          instr_class= find_table_class(m_pos.m_index_3);
+          break;
+        default:
+          instr_class= NULL;
+          DBUG_ASSERT(false);
+          break;
+        }
+
+        if (instr_class)
+        {
+          make_row(host, instr_class);
+          m_next_pos.set_after(&m_pos);
+          return 0;
+        }
+      }
+    }
+  }
+
+  return HA_ERR_END_OF_FILE;
+}
+
+int
+table_ews_by_host_by_event_name::rnd_pos(const void *pos)
+{
+  PFS_host *host;
+  PFS_instr_class *instr_class;
+
+  set_position(pos);
+  DBUG_ASSERT(m_pos.m_index_1 < host_max);
+
+  host= &host_array[m_pos.m_index_1];
+  if (! host->m_lock.is_populated())
+    return HA_ERR_RECORD_DELETED;
+
+  switch (m_pos.m_index_2)
+  {
+  case pos_ews_by_host_by_event_name::VIEW_MUTEX:
+    instr_class= find_mutex_class(m_pos.m_index_3);
+    break;
+  case pos_ews_by_host_by_event_name::VIEW_RWLOCK:
+    instr_class= find_rwlock_class(m_pos.m_index_3);
+    break;
+  case pos_ews_by_host_by_event_name::VIEW_COND:
+    instr_class= find_cond_class(m_pos.m_index_3);
+    break;
+  case pos_ews_by_host_by_event_name::VIEW_FILE:
+    instr_class= find_file_class(m_pos.m_index_3);
+    break;
+  case pos_ews_by_host_by_event_name::VIEW_TABLE:
+    instr_class= find_table_class(m_pos.m_index_3);
+    break;
+  default:
+    instr_class= NULL;
+    DBUG_ASSERT(false);
+    break;
+  }
+  if (instr_class)
+  {
+    make_row(host, instr_class);
+    return 0;
+  }
+
+  return HA_ERR_RECORD_DELETED;
+}
+
+void table_ews_by_host_by_event_name
+::make_row(PFS_host *host, PFS_instr_class *klass)
+{
+  pfs_lock lock;
+  m_row_exists= false;
+
+  host->m_lock.begin_optimistic_lock(&lock);
+
+  if (m_row.m_host.make_row(host))
+    return;
+
+  m_row.m_event_name.make_row(klass);
+
+  PFS_connection_wait_visitor visitor(klass);
+  PFS_connection_iterator::visit_host(host, true, true, & visitor);
+
+  if (! host->m_lock.end_optimistic_lock(&lock))
+    return;
+
+  m_row_exists= true;
+
+  time_normalizer *normalizer= time_normalizer::get(wait_timer);
+  m_row.m_stat.set(normalizer, & visitor.m_stat);
+}
+
+int table_ews_by_host_by_event_name
+::read_row_values(TABLE *table, unsigned char *buf, Field **fields,
+                  bool read_all)
+{
+  Field *f;
+
+  if (unlikely(! m_row_exists))
+    return HA_ERR_RECORD_DELETED;
+
+  /* Set the null bits */
+  DBUG_ASSERT(table->s->null_bytes == 1);
+  buf[0]= 0;
+
+  for (; (f= *fields) ; fields++)
+  {
+    if (read_all || bitmap_is_set(table->read_set, f->field_index))
+    {
+      switch(f->field_index)
+      {
+      case 0: /* HOST */
+        m_row.m_host.set_field(f);
+        break;
+      case 1: /* EVENT_NAME */
+        m_row.m_event_name.set_field(f);
+        break;
+      default: /* 2, ... COUNT/SUM/MIN/AVG/MAX */
+        m_row.m_stat.set_field(f->field_index - 2, f);
+        break;
+      }
+    }
+  }
+
+  return 0;
+}
+

=== added file 'storage/perfschema/table_ews_by_host_by_event_name.h'
--- a/storage/perfschema/table_ews_by_host_by_event_name.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_ews_by_host_by_event_name.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,136 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef TABLE_EWS_BY_HOST_BY_EVENT_NAME_H
+#define TABLE_EWS_BY_HOST_BY_EVENT_NAME_H
+
+/**
+  @file storage/perfschema/table_ews_by_host_by_event_name.h
+  Table EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME (declarations).
+*/
+
+#include "pfs_column_types.h"
+#include "pfs_engine_table.h"
+#include "pfs_instr_class.h"
+#include "pfs_instr.h"
+#include "pfs_host.h"
+#include "table_helper.h"
+
+/**
+  @addtogroup Performance_schema_tables
+  @{
+*/
+
+/**
+  A row of table
+  PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME.
+*/
+struct row_ews_by_host_by_event_name
+{
+  /** Column HOST. */
+  PFS_host_row m_host;
+  /** Column EVENT_NAME. */
+  PFS_event_name_row m_event_name;
+  /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */
+  PFS_stat_row m_stat;
+};
+
+/**
+  Position of a cursor on
+  PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME.
+  Index 1 on host (0 based)
+  Index 2 on instrument view
+  Index 3 on instrument class (1 based)
+*/
+struct pos_ews_by_host_by_event_name
+: public PFS_triple_index, public PFS_instrument_view_constants
+{
+  pos_ews_by_host_by_event_name()
+    : PFS_triple_index(0, FIRST_VIEW, 1)
+  {}
+
+  inline void reset(void)
+  {
+    m_index_1= 0;
+    m_index_2= FIRST_VIEW;
+    m_index_3= 1;
+  }
+
+  inline bool has_more_host(void)
+  { return (m_index_1 < host_max); }
+
+  inline void next_host(void)
+  {
+    m_index_1++;
+    m_index_2= FIRST_VIEW;
+    m_index_3= 1;
+  }
+
+  inline bool has_more_view(void)
+  { return (m_index_2 <= LAST_VIEW); }
+
+  inline void next_view(void)
+  {
+    m_index_2++;
+    m_index_3= 1;
+  }
+};
+
+/** Table PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME. */
+class table_ews_by_host_by_event_name : public PFS_engine_table
+{
+public:
+  /** Table share */
+  static PFS_engine_table_share m_share;
+  static PFS_engine_table* create();
+  static int delete_all_rows();
+
+  virtual int rnd_next();
+  virtual int rnd_pos(const void *pos);
+  virtual void reset_position(void);
+
+protected:
+  virtual int read_row_values(TABLE *table,
+                              unsigned char *buf,
+                              Field **fields,
+                              bool read_all);
+
+  table_ews_by_host_by_event_name();
+
+public:
+  ~table_ews_by_host_by_event_name()
+  {}
+
+protected:
+  void make_row(PFS_host *host, PFS_instr_class *klass);
+
+private:
+  /** Table share lock. */
+  static THR_LOCK m_table_lock;
+  /** Fields definition. */
+  static TABLE_FIELD_DEF m_field_def;
+
+  /** Current row. */
+  row_ews_by_host_by_event_name m_row;
+  /** True is the current row exists. */
+  bool m_row_exists;
+  /** Current position. */
+  pos_ews_by_host_by_event_name m_pos;
+  /** Next position. */
+  pos_ews_by_host_by_event_name m_next_pos;
+};
+
+/** @} */
+#endif

=== added file 'storage/perfschema/table_ews_by_user_by_event_name.cc'
--- a/storage/perfschema/table_ews_by_user_by_event_name.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_ews_by_user_by_event_name.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,273 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file storage/perfschema/table_ews_by_user_by_event_name.cc
+  Table EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME (implementation).
+*/
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "pfs_instr_class.h"
+#include "pfs_column_types.h"
+#include "pfs_column_values.h"
+#include "table_ews_by_user_by_event_name.h"
+#include "pfs_global.h"
+#include "pfs_account.h"
+#include "pfs_visitor.h"
+
+THR_LOCK table_ews_by_user_by_event_name::m_table_lock;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+  {
+    { C_STRING_WITH_LEN("USER") },
+    { C_STRING_WITH_LEN("char(16)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("EVENT_NAME") },
+    { C_STRING_WITH_LEN("varchar(128)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("COUNT_STAR") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("SUM_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MIN_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("AVG_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("MAX_TIMER_WAIT") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  }
+};
+
+TABLE_FIELD_DEF
+table_ews_by_user_by_event_name::m_field_def=
+{ 7, field_types };
+
+PFS_engine_table_share
+table_ews_by_user_by_event_name::m_share=
+{
+  { C_STRING_WITH_LEN("events_waits_summary_by_user_by_event_name") },
+  &pfs_truncatable_acl,
+  table_ews_by_user_by_event_name::create,
+  NULL, /* write_row */
+  table_ews_by_user_by_event_name::delete_all_rows,
+  NULL, /* get_row_count */
+  1000, /* records */
+  sizeof(pos_ews_by_user_by_event_name),
+  &m_table_lock,
+  &m_field_def,
+  false /* checked */
+};
+
+PFS_engine_table*
+table_ews_by_user_by_event_name::create(void)
+{
+  return new table_ews_by_user_by_event_name();
+}
+
+int
+table_ews_by_user_by_event_name::delete_all_rows(void)
+{
+  reset_events_waits_by_thread();
+  reset_events_waits_by_account();
+  reset_events_waits_by_user();
+  return 0;
+}
+
+table_ews_by_user_by_event_name::table_ews_by_user_by_event_name()
+  : PFS_engine_table(&m_share, &m_pos),
+    m_row_exists(false), m_pos(), m_next_pos()
+{}
+
+void table_ews_by_user_by_event_name::reset_position(void)
+{
+  m_pos.reset();
+  m_next_pos.reset();
+}
+
+int table_ews_by_user_by_event_name::rnd_next(void)
+{
+  PFS_user *user;
+  PFS_instr_class *instr_class;
+
+  for (m_pos.set_at(&m_next_pos);
+       m_pos.has_more_user();
+       m_pos.next_user())
+  {
+    user= &user_array[m_pos.m_index_1];
+    if (user->m_lock.is_populated())
+    {
+      for ( ;
+           m_pos.has_more_view();
+           m_pos.next_view())
+      {
+        switch (m_pos.m_index_2)
+        {
+        case pos_ews_by_user_by_event_name::VIEW_MUTEX:
+          instr_class= find_mutex_class(m_pos.m_index_3);
+          break;
+        case pos_ews_by_user_by_event_name::VIEW_RWLOCK:
+          instr_class= find_rwlock_class(m_pos.m_index_3);
+          break;
+        case pos_ews_by_user_by_event_name::VIEW_COND:
+          instr_class= find_cond_class(m_pos.m_index_3);
+          break;
+        case pos_ews_by_user_by_event_name::VIEW_FILE:
+          instr_class= find_file_class(m_pos.m_index_3);
+          break;
+        case pos_ews_by_user_by_event_name::VIEW_TABLE:
+          instr_class= find_table_class(m_pos.m_index_3);
+          break;
+        default:
+          instr_class= NULL;
+          DBUG_ASSERT(false);
+          break;
+        }
+
+        if (instr_class)
+        {
+          make_row(user, instr_class);
+          m_next_pos.set_after(&m_pos);
+          return 0;
+        }
+      }
+    }
+  }
+
+  return HA_ERR_END_OF_FILE;
+}
+
+int
+table_ews_by_user_by_event_name::rnd_pos(const void *pos)
+{
+  PFS_user *user;
+  PFS_instr_class *instr_class;
+
+  set_position(pos);
+  DBUG_ASSERT(m_pos.m_index_1 < user_max);
+
+  user= &user_array[m_pos.m_index_1];
+  if (! user->m_lock.is_populated())
+    return HA_ERR_RECORD_DELETED;
+
+  switch (m_pos.m_index_2)
+  {
+  case pos_ews_by_user_by_event_name::VIEW_MUTEX:
+    instr_class= find_mutex_class(m_pos.m_index_3);
+    break;
+  case pos_ews_by_user_by_event_name::VIEW_RWLOCK:
+    instr_class= find_rwlock_class(m_pos.m_index_3);
+    break;
+  case pos_ews_by_user_by_event_name::VIEW_COND:
+    instr_class= find_cond_class(m_pos.m_index_3);
+    break;
+  case pos_ews_by_user_by_event_name::VIEW_FILE:
+    instr_class= find_file_class(m_pos.m_index_3);
+    break;
+  case pos_ews_by_user_by_event_name::VIEW_TABLE:
+    instr_class= find_table_class(m_pos.m_index_3);
+    break;
+  default:
+    instr_class= NULL;
+    DBUG_ASSERT(false);
+    break;
+  }
+  if (instr_class)
+  {
+    make_row(user, instr_class);
+    return 0;
+  }
+
+  return HA_ERR_RECORD_DELETED;
+}
+
+void table_ews_by_user_by_event_name
+::make_row(PFS_user *user, PFS_instr_class *klass)
+{
+  pfs_lock lock;
+  m_row_exists= false;
+
+  user->m_lock.begin_optimistic_lock(&lock);
+
+  if (m_row.m_user.make_row(user))
+    return;
+
+  m_row.m_event_name.make_row(klass);
+
+  PFS_connection_wait_visitor visitor(klass);
+  PFS_connection_iterator::visit_user(user, true, true, & visitor);
+
+  if (! user->m_lock.end_optimistic_lock(&lock))
+    return;
+
+  m_row_exists= true;
+
+  time_normalizer *normalizer= time_normalizer::get(wait_timer);
+  m_row.m_stat.set(normalizer, & visitor.m_stat);
+}
+
+int table_ews_by_user_by_event_name
+::read_row_values(TABLE *table, unsigned char *buf, Field **fields,
+                  bool read_all)
+{
+  Field *f;
+
+  if (unlikely(! m_row_exists))
+    return HA_ERR_RECORD_DELETED;
+
+  /* Set the null bits */
+  DBUG_ASSERT(table->s->null_bytes == 1);
+  buf[0]= 0;
+
+  for (; (f= *fields) ; fields++)
+  {
+    if (read_all || bitmap_is_set(table->read_set, f->field_index))
+    {
+      switch(f->field_index)
+      {
+      case 0: /* USER */
+        m_row.m_user.set_field(f);
+        break;
+      case 1: /* EVENT_NAME */
+        m_row.m_event_name.set_field(f);
+        break;
+      default: /* 2, ... COUNT/SUM/MIN/AVG/MAX */
+        m_row.m_stat.set_field(f->field_index - 2, f);
+        break;
+      }
+    }
+  }
+
+  return 0;
+}
+

=== added file 'storage/perfschema/table_ews_by_user_by_event_name.h'
--- a/storage/perfschema/table_ews_by_user_by_event_name.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_ews_by_user_by_event_name.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,136 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef TABLE_EWS_BY_USER_BY_EVENT_NAME_H
+#define TABLE_EWS_BY_USER_BY_EVENT_NAME_H
+
+/**
+  @file storage/perfschema/table_ews_by_user_by_event_name.h
+  Table EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME (declarations).
+*/
+
+#include "pfs_column_types.h"
+#include "pfs_engine_table.h"
+#include "pfs_instr_class.h"
+#include "pfs_instr.h"
+#include "pfs_user.h"
+#include "table_helper.h"
+
+/**
+  @addtogroup Performance_schema_tables
+  @{
+*/
+
+/**
+  A row of table
+  PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME.
+*/
+struct row_ews_by_user_by_event_name
+{
+  /** Column USER. */
+  PFS_user_row m_user;
+  /** Column EVENT_NAME. */
+  PFS_event_name_row m_event_name;
+  /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */
+  PFS_stat_row m_stat;
+};
+
+/**
+  Position of a cursor on
+  PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME.
+  Index 1 on user (0 based)
+  Index 2 on instrument view
+  Index 3 on instrument class (1 based)
+*/
+struct pos_ews_by_user_by_event_name
+: public PFS_triple_index, public PFS_instrument_view_constants
+{
+  pos_ews_by_user_by_event_name()
+    : PFS_triple_index(0, FIRST_VIEW, 1)
+  {}
+
+  inline void reset(void)
+  {
+    m_index_1= 0;
+    m_index_2= FIRST_VIEW;
+    m_index_3= 1;
+  }
+
+  inline bool has_more_user(void)
+  { return (m_index_1 < user_max); }
+
+  inline void next_user(void)
+  {
+    m_index_1++;
+    m_index_2= FIRST_VIEW;
+    m_index_3= 1;
+  }
+
+  inline bool has_more_view(void)
+  { return (m_index_2 <= LAST_VIEW); }
+
+  inline void next_view(void)
+  {
+    m_index_2++;
+    m_index_3= 1;
+  }
+};
+
+/** Table PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME. */
+class table_ews_by_user_by_event_name : public PFS_engine_table
+{
+public:
+  /** Table share */
+  static PFS_engine_table_share m_share;
+  static PFS_engine_table* create();
+  static int delete_all_rows();
+
+  virtual int rnd_next();
+  virtual int rnd_pos(const void *pos);
+  virtual void reset_position(void);
+
+protected:
+  virtual int read_row_values(TABLE *table,
+                              unsigned char *buf,
+                              Field **fields,
+                              bool read_all);
+
+  table_ews_by_user_by_event_name();
+
+public:
+  ~table_ews_by_user_by_event_name()
+  {}
+
+protected:
+  void make_row(PFS_user *user, PFS_instr_class *klass);
+
+private:
+  /** Table share lock. */
+  static THR_LOCK m_table_lock;
+  /** Fields definition. */
+  static TABLE_FIELD_DEF m_field_def;
+
+  /** Current row. */
+  row_ews_by_user_by_event_name m_row;
+  /** True is the current row exists. */
+  bool m_row_exists;
+  /** Current position. */
+  pos_ews_by_user_by_event_name m_pos;
+  /** Next position. */
+  pos_ews_by_user_by_event_name m_next_pos;
+};
+
+/** @} */
+#endif

=== modified file 'storage/perfschema/table_helper.cc'
--- a/storage/perfschema/table_helper.cc	2011-02-14 14:23:55 +0000
+++ b/storage/perfschema/table_helper.cc	2011-05-07 00:40:25 +0000
@@ -22,6 +22,84 @@
 #include "my_pthread.h"
 #include "pfs_engine_table.h"
 #include "table_helper.h"
+#include "pfs_host.h"
+#include "pfs_user.h"
+#include "pfs_account.h"
+
+int PFS_host_row::make_row(PFS_host *pfs)
+{
+  m_hostname_length= pfs->m_hostname_length;
+  if (m_hostname_length > sizeof(m_hostname))
+    return 1;
+  if (m_hostname_length > 0)
+    memcpy(m_hostname, pfs->m_hostname, sizeof(m_hostname));
+  return 0;
+}
+
+void PFS_host_row::set_field(Field *f)
+{
+  if (m_hostname_length > 0)
+    PFS_engine_table::set_field_char_utf8(f, m_hostname, m_hostname_length);
+  else
+    f->set_null();
+}
+
+int PFS_user_row::make_row(PFS_user *pfs)
+{
+  m_username_length= pfs->m_username_length;
+  if (m_username_length > sizeof(m_username))
+    return 1;
+  if (m_username_length > 0)
+    memcpy(m_username, pfs->m_username, sizeof(m_username));
+  return 0;
+}
+
+void PFS_user_row::set_field(Field *f)
+{
+  if (m_username_length > 0)
+    PFS_engine_table::set_field_char_utf8(f, m_username, m_username_length);
+  else
+    f->set_null();
+}
+
+int PFS_account_row::make_row(PFS_account *pfs)
+{
+  m_username_length= pfs->m_username_length;
+  if (m_username_length > sizeof(m_username))
+    return 1;
+  if (m_username_length > 0)
+    memcpy(m_username, pfs->m_username, sizeof(m_username));
+
+  m_hostname_length= pfs->m_hostname_length;
+  if (m_hostname_length > sizeof(m_hostname))
+    return 1;
+  if (m_hostname_length > 0)
+    memcpy(m_hostname, pfs->m_hostname, sizeof(m_hostname));
+
+  return 0;
+}
+
+void PFS_account_row::set_field(uint index, Field *f)
+{
+  switch (index)
+  {
+    case 0: /* USER */
+      if (m_username_length > 0)
+        PFS_engine_table::set_field_char_utf8(f, m_username, m_username_length);
+      else
+        f->set_null();
+      break;
+    case 1: /* HOST */
+      if (m_hostname_length > 0)
+        PFS_engine_table::set_field_char_utf8(f, m_hostname, m_hostname_length);
+      else
+        f->set_null();
+      break;
+    default:
+      DBUG_ASSERT(false);
+      break;
+  }
+}
 
 int PFS_object_row::make_row(PFS_table_share *pfs)
 {
@@ -173,6 +251,22 @@ void PFS_statement_stat_row::set_field(u
   }
 }
 
+void PFS_connection_stat_row::set_field(uint index, Field *f)
+{
+  switch (index)
+  {
+    case 0: /* CURRENT_CONNECTIONS */
+      PFS_engine_table::set_field_ulonglong(f, m_current_connections);
+      break;
+    case 1: /* TOTAL_CONNECTIONS */
+      PFS_engine_table::set_field_ulonglong(f, m_total_connections);
+      break;
+    default:
+      DBUG_ASSERT(false);
+      break;
+  }
+}
+
 void set_field_object_type(Field *f, enum_object_type object_type)
 {
   switch (object_type)

=== modified file 'storage/perfschema/table_helper.h'
--- a/storage/perfschema/table_helper.h	2011-02-14 14:23:55 +0000
+++ b/storage/perfschema/table_helper.h	2011-05-07 00:40:25 +0000
@@ -22,6 +22,10 @@
 #include "pfs_engine_table.h"
 #include "pfs_instr_class.h"
 
+struct PFS_host;
+struct PFS_user;
+struct PFS_account;
+
 /**
   @file storage/perfschema/table_helper.h
   Performance schema table helpers (declarations).
@@ -57,6 +61,52 @@ struct PFS_object_view_constants
   static const uint VIEW_FUNCTION= 4;
 };
 
+/** Row fragment for column HOST. */
+struct PFS_host_row
+{
+  /** Column HOST. */
+  char m_hostname[HOSTNAME_LENGTH];
+  /** Length in bytes of @c m_hostname. */
+  uint m_hostname_length;
+
+  /** Build a row from a memory buffer. */
+  int make_row(PFS_host *pfs);
+  /** Set a table field from the row. */
+  void set_field(Field *f);
+};
+
+/** Row fragment for column USER. */
+struct PFS_user_row
+{
+  /** Column USER. */
+  char m_username[USERNAME_LENGTH];
+  /** Length in bytes of @c m_username. */
+  uint m_username_length;
+
+  /** Build a row from a memory buffer. */
+  int make_row(PFS_user *pfs);
+  /** Set a table field from the row. */
+  void set_field(Field *f);
+};
+
+/** Row fragment for columns USER, HOST. */
+struct PFS_account_row
+{
+  /** Column USER. */
+  char m_username[USERNAME_LENGTH];
+  /** Length in bytes of @c m_username. */
+  uint m_username_length;
+  /** Column HOST. */
+  char m_hostname[HOSTNAME_LENGTH];
+  /** Length in bytes of @c m_hostname. */
+  uint m_hostname_length;
+
+  /** Build a row from a memory buffer. */
+  int make_row(PFS_account *pfs);
+  /** Set a table field from the row. */
+  void set_field(uint index, Field *f);
+};
+
 /** Row fragment for column EVENT_NAME. */
 struct PFS_event_name_row
 {
@@ -346,6 +396,21 @@ struct PFS_statement_stat_row
   void set_field(uint index, Field *f);
 };
 
+struct PFS_connection_stat_row
+{
+  ulonglong m_current_connections;
+  ulonglong m_total_connections;
+
+  inline void set(const PFS_connection_stat *stat)
+  {
+    m_current_connections= stat->m_current_connections;
+    m_total_connections= stat->m_total_connections;
+  }
+
+  /** Set a table field from the row. */
+  void set_field(uint index, Field *f);
+};
+
 void set_field_object_type(Field *f, enum_object_type object_type);
 
 /** @} */

=== added file 'storage/perfschema/table_hosts.cc'
--- a/storage/perfschema/table_hosts.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_hosts.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,145 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software Foundation,
+  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "table_hosts.h"
+#include "pfs_instr_class.h"
+#include "pfs_instr.h"
+#include "pfs_host.h"
+#include "pfs_visitor.h"
+
+THR_LOCK table_hosts::m_table_lock;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+  {
+    { C_STRING_WITH_LEN("HOST") },
+    { C_STRING_WITH_LEN("char(60)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("CURRENT_CONNECTIONS") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("TOTAL_CONNECTIONS") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  }
+};
+
+TABLE_FIELD_DEF
+table_hosts::m_field_def=
+{ 3, field_types };
+
+PFS_engine_table_share
+table_hosts::m_share=
+{
+  { C_STRING_WITH_LEN("hosts") },
+  &pfs_truncatable_acl,
+  &table_hosts::create,
+  NULL, /* write_row */
+  table_hosts::delete_all_rows,
+  NULL, /* get_row_count */
+  1000, /* records */
+  sizeof(PFS_simple_index), /* ref length */
+  &m_table_lock,
+  &m_field_def,
+  false /* checked */
+};
+
+PFS_engine_table* table_hosts::create()
+{
+  return new table_hosts();
+}
+
+int
+table_hosts::delete_all_rows(void)
+{
+  reset_events_waits_by_thread();
+  reset_events_waits_by_account();
+  reset_events_waits_by_host();
+  reset_events_stages_by_thread();
+  reset_events_stages_by_account();
+  reset_events_stages_by_host();
+  reset_events_statements_by_thread();
+  reset_events_statements_by_account();
+  reset_events_statements_by_host();
+  purge_all_host();
+  return 0;
+}
+
+table_hosts::table_hosts()
+  : cursor_by_host(& m_share),
+  m_row_exists(false)
+{}
+
+void table_hosts::make_row(PFS_host *pfs)
+{
+  pfs_lock lock;
+
+  m_row_exists= false;
+  pfs->m_lock.begin_optimistic_lock(&lock);
+
+  if (m_row.m_host.make_row(pfs))
+    return;
+
+  PFS_connection_stat_visitor visitor;
+  PFS_connection_iterator::visit_host(pfs, true, true, & visitor);
+
+  if (! pfs->m_lock.end_optimistic_lock(& lock))
+    return;
+
+  m_row.m_connection_stat.set(& visitor.m_stat);
+  m_row_exists= true;
+}
+
+int table_hosts::read_row_values(TABLE *table,
+                                 unsigned char *buf,
+                                 Field **fields,
+                                 bool read_all)
+{
+  Field *f;
+
+  if (unlikely(! m_row_exists))
+    return HA_ERR_RECORD_DELETED;
+
+  /* Set the null bits */
+  DBUG_ASSERT(table->s->null_bytes == 1);
+  buf[0]= 0;
+
+  for (; (f= *fields) ; fields++)
+  {
+    if (read_all || bitmap_is_set(table->read_set, f->field_index))
+    {
+      switch(f->field_index)
+      {
+      case 0: /* HOST */
+        m_row.m_host.set_field(f);
+        break;
+      case 1: /* CURRENT_CONNECTIONS */
+      case 2: /* TOTAL_CONNECTIONS */
+        m_row.m_connection_stat.set_field(f->field_index - 1, f);
+        break;
+      default:
+        DBUG_ASSERT(false);
+      }
+    }
+  }
+  return 0;
+}
+

=== added file 'storage/perfschema/table_hosts.h'
--- a/storage/perfschema/table_hosts.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_hosts.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,80 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software Foundation,
+  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#ifndef TABLE_HOSTS_H
+#define TABLE_HOSTS_H
+
+#include "pfs_column_types.h"
+#include "cursor_by_host.h"
+#include "table_helper.h"
+
+struct PFS_host;
+
+/**
+  \addtogroup Performance_schema_tables
+  @{
+*/
+
+/**
+  A row of PERFORMANCE_SCHEMA.HOSTS.
+*/
+struct row_hosts
+{
+  /** Column HOST. */
+  PFS_host_row m_host;
+  /** Columns CURRENT_CONNECTIONS, TOTAL_CONNECTIONS. */
+  PFS_connection_stat_row m_connection_stat;
+};
+
+/** Table PERFORMANCE_SCHEMA.THREADS. */
+class table_hosts : public cursor_by_host
+{
+public:
+  /** Table share */
+  static PFS_engine_table_share m_share;
+  /** Table builder */
+  static PFS_engine_table* create();
+  static int delete_all_rows();
+
+protected:
+  virtual int read_row_values(TABLE *table,
+                              unsigned char *buf,
+                              Field **fields,
+                              bool read_all);
+
+
+protected:
+  table_hosts();
+
+public:
+  ~table_hosts()
+  {}
+
+private:
+  virtual void make_row(PFS_host *pfs);
+
+  /** Table share lock. */
+  static THR_LOCK m_table_lock;
+  /** Fields definition. */
+  static TABLE_FIELD_DEF m_field_def;
+
+  /** Current row. */
+  row_hosts m_row;
+  /** True if the current row exists. */
+  bool m_row_exists;
+};
+
+/** @} */
+#endif

=== modified file 'storage/perfschema/table_threads.cc'
--- a/storage/perfschema/table_threads.cc	2010-12-02 08:07:06 +0000
+++ b/storage/perfschema/table_threads.cc	2011-05-07 00:40:25 +0000
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -122,52 +122,10 @@ PFS_engine_table* table_threads::create(
 }
 
 table_threads::table_threads()
-  : PFS_engine_table(& m_share, & m_pos),
-  m_row_exists(false), m_pos(0), m_next_pos(0)
+  : cursor_by_thread(& m_share),
+  m_row_exists(false)
 {}
 
-void table_threads::reset_position(void)
-{
-  m_pos.m_index= 0;
-  m_next_pos.m_index= 0;
-}
-
-int table_threads::rnd_next()
-{
-  PFS_thread *pfs;
-
-  for (m_pos.set_at(&m_next_pos);
-       m_pos.m_index < thread_max;
-       m_pos.next())
-  {
-    pfs= &thread_array[m_pos.m_index];
-    if (pfs->m_lock.is_populated())
-    {
-      make_row(pfs);
-      m_next_pos.set_after(&m_pos);
-      return 0;
-    }
-  }
-
-  return HA_ERR_END_OF_FILE;
-}
-
-int table_threads::rnd_pos(const void *pos)
-{
-  PFS_thread *pfs;
-
-  set_position(pos);
-  DBUG_ASSERT(m_pos.m_index < thread_max);
-  pfs= &thread_array[m_pos.m_index];
-  if (pfs->m_lock.is_populated())
-  {
-    make_row(pfs);
-    return 0;
-  }
-
-  return HA_ERR_RECORD_DELETED;
-}
-
 void table_threads::make_row(PFS_thread *pfs)
 {
   pfs_lock lock;

=== modified file 'storage/perfschema/table_threads.h'
--- a/storage/perfschema/table_threads.h	2010-07-21 19:06:21 +0000
+++ b/storage/perfschema/table_threads.h	2011-05-07 00:40:25 +0000
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
 #define TABLE_THREADS_H
 
 #include "pfs_column_types.h"
-#include "pfs_engine_table.h"
+#include "cursor_by_thread.h"
 
 struct PFS_thread;
 
@@ -70,7 +70,7 @@ struct row_threads
 };
 
 /** Table PERFORMANCE_SCHEMA.THREADS. */
-class table_threads : public PFS_engine_table
+class table_threads : public cursor_by_thread
 {
 public:
   /** Table share */
@@ -78,10 +78,6 @@ public:
   /** Table builder */
   static PFS_engine_table* create();
 
-  virtual int rnd_next();
-  virtual int rnd_pos(const void *pos);
-  virtual void reset_position(void);
-
 protected:
   virtual int read_row_values(TABLE *table,
                               unsigned char *buf,
@@ -102,7 +98,7 @@ public:
   {}
 
 private:
-  void make_row(PFS_thread *pfs);
+  virtual void make_row(PFS_thread *pfs);
 
   /** Table share lock. */
   static THR_LOCK m_table_lock;
@@ -113,10 +109,6 @@ private:
   row_threads m_row;
   /** True if the current row exists. */
   bool m_row_exists;
-  /** Current position. */
-  PFS_simple_index m_pos;
-  /** Next position. */
-  PFS_simple_index m_next_pos;
 };
 
 /** @} */

=== added file 'storage/perfschema/table_users.cc'
--- a/storage/perfschema/table_users.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_users.cc	2011-05-07 00:40:25 +0000
@@ -0,0 +1,145 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software Foundation,
+  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "table_users.h"
+#include "pfs_instr_class.h"
+#include "pfs_instr.h"
+#include "pfs_user.h"
+#include "pfs_visitor.h"
+
+THR_LOCK table_users::m_table_lock;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+  {
+    { C_STRING_WITH_LEN("USER") },
+    { C_STRING_WITH_LEN("char(16)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("CURRENT_CONNECTIONS") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  },
+  {
+    { C_STRING_WITH_LEN("TOTAL_CONNECTIONS") },
+    { C_STRING_WITH_LEN("bigint(20)") },
+    { NULL, 0}
+  }
+};
+
+TABLE_FIELD_DEF
+table_users::m_field_def=
+{ 3, field_types };
+
+PFS_engine_table_share
+table_users::m_share=
+{
+  { C_STRING_WITH_LEN("users") },
+  &pfs_truncatable_acl,
+  &table_users::create,
+  NULL, /* write_row */
+  table_users::delete_all_rows,
+  NULL, /* get_row_count */
+  1000, /* records */
+  sizeof(PFS_simple_index), /* ref length */
+  &m_table_lock,
+  &m_field_def,
+  false /* checked */
+};
+
+PFS_engine_table* table_users::create()
+{
+  return new table_users();
+}
+
+int
+table_users::delete_all_rows(void)
+{
+  reset_events_waits_by_thread();
+  reset_events_waits_by_account();
+  reset_events_waits_by_user();
+  reset_events_stages_by_thread();
+  reset_events_stages_by_account();
+  reset_events_stages_by_user();
+  reset_events_statements_by_thread();
+  reset_events_statements_by_account();
+  reset_events_statements_by_user();
+  purge_all_user();
+  return 0;
+}
+
+table_users::table_users()
+  : cursor_by_user(& m_share),
+  m_row_exists(false)
+{}
+
+void table_users::make_row(PFS_user *pfs)
+{
+  pfs_lock lock;
+
+  m_row_exists= false;
+  pfs->m_lock.begin_optimistic_lock(&lock);
+
+  if (m_row.m_user.make_row(pfs))
+    return;
+
+  PFS_connection_stat_visitor visitor;
+  PFS_connection_iterator::visit_user(pfs, true, true, & visitor);
+
+  if (! pfs->m_lock.end_optimistic_lock(& lock))
+    return;
+
+  m_row.m_connection_stat.set(& visitor.m_stat);
+  m_row_exists= true;
+}
+
+int table_users::read_row_values(TABLE *table,
+                                 unsigned char *buf,
+                                 Field **fields,
+                                 bool read_all)
+{
+  Field *f;
+
+  if (unlikely(! m_row_exists))
+    return HA_ERR_RECORD_DELETED;
+
+  /* Set the null bits */
+  DBUG_ASSERT(table->s->null_bytes == 1);
+  buf[0]= 0;
+
+  for (; (f= *fields) ; fields++)
+  {
+    if (read_all || bitmap_is_set(table->read_set, f->field_index))
+    {
+      switch(f->field_index)
+      {
+      case 0: /* USER */
+        m_row.m_user.set_field(f);
+        break;
+      case 1: /* CURRENT_CONNECTIONS */
+      case 2: /* TOTAL_CONNECTIONS */
+        m_row.m_connection_stat.set_field(f->field_index - 1, f);
+        break;
+      default:
+        DBUG_ASSERT(false);
+      }
+    }
+  }
+  return 0;
+}
+

=== added file 'storage/perfschema/table_users.h'
--- a/storage/perfschema/table_users.h	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_users.h	2011-05-07 00:40:25 +0000
@@ -0,0 +1,80 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software Foundation,
+  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#ifndef TABLE_USERS_H
+#define TABLE_USERS_H
+
+#include "pfs_column_types.h"
+#include "cursor_by_user.h"
+#include "table_helper.h"
+
+struct PFS_user;
+
+/**
+  \addtogroup Performance_schema_tables
+  @{
+*/
+
+/**
+  A row of PERFORMANCE_SCHEMA.USERS.
+*/
+struct row_users
+{
+  /** Column USER. */
+  PFS_user_row m_user;
+  /** Columns CURRENT_CONNECTIONS, TOTAL_CONNECTIONS. */
+  PFS_connection_stat_row m_connection_stat;
+};
+
+/** Table PERFORMANCE_SCHEMA.USERS. */
+class table_users : public cursor_by_user
+{
+public:
+  /** Table share */
+  static PFS_engine_table_share m_share;
+  /** Table builder */
+  static PFS_engine_table* create();
+  static int delete_all_rows();
+
+protected:
+  virtual int read_row_values(TABLE *table,
+                              unsigned char *buf,
+                              Field **fields,
+                              bool read_all);
+
+
+protected:
+  table_users();
+
+public:
+  ~table_users()
+  {}
+
+private:
+  virtual void make_row(PFS_user *pfs);
+
+  /** Table share lock. */
+  static THR_LOCK m_table_lock;
+  /** Fields definition. */
+  static TABLE_FIELD_DEF m_field_def;
+
+  /** Current row. */
+  row_users m_row;
+  /** True if the current row exists. */
+  bool m_row_exists;
+};
+
+/** @} */
+#endif

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (marc.alff:3347 to 3348) WL#5378Marc Alff7 May