]> git.pld-linux.org Git - packages/mysql.git/blame - userstat.patch
- not all chunks needed to patch
[packages/mysql.git] / userstat.patch
CommitLineData
d4e9320e
AM
1# name : userstat.patch
2# introduced : 11 or before
b4e1fa2c 3# maintainer : Oleg
d4e9320e
AM
4#
5#!!! notice !!!
6# Any small change to this file in the main branch
7# should be done or reviewed by the maintainer!
d4e9320e 8diff -ruN a/include/mysql/plugin.h b/include/mysql/plugin.h
b4e1fa2c
AM
9--- a/include/mysql/plugin.h 2010-12-03 20:58:24.000000000 +0300
10+++ b/include/mysql/plugin.h 2010-12-31 06:06:43.000000000 +0300
11@@ -547,6 +547,9 @@
d4e9320e
AM
12 unsigned long thd_log_slow_verbosity(const MYSQL_THD thd);
13 int thd_opt_slow_log();
14 #define EXTENDED_SLOWLOG
15+
16+#define EXTENDED_FOR_USERSTAT
17+
18 /**
19 Create a temporary file.
20
21diff -ruN a/include/mysql_com.h b/include/mysql_com.h
b4e1fa2c
AM
22--- a/include/mysql_com.h 2010-12-03 20:58:24.000000000 +0300
23+++ b/include/mysql_com.h 2010-12-31 06:12:05.000000000 +0300
24@@ -31,6 +31,7 @@
d4e9320e
AM
25
26 #define SERVER_VERSION_LENGTH 60
27 #define SQLSTATE_LENGTH 5
28+#define LIST_PROCESS_HOST_LEN 64
29
30 /*
b4e1fa2c
AM
31 Maximum length of comments
32@@ -142,6 +143,11 @@
33 #define REFRESH_DES_KEY_FILE 0x40000L
34 #define REFRESH_USER_RESOURCES 0x80000L
35 #define REFRESH_QUERY_RESPONSE_TIME 0x100000L /* response time distibution */
36+#define REFRESH_TABLE_STATS 0x200000L /* Refresh table stats my_hash table */
37+#define REFRESH_INDEX_STATS 0x400000L /* Refresh index stats my_hash table */
38+#define REFRESH_USER_STATS 0x800000L /* Refresh user stats my_hash table */
39+#define REFRESH_CLIENT_STATS 0x1000000L /* Refresh client stats my_hash table */
40+#define REFRESH_THREAD_STATS 0x2000000L /* Refresh thread stats my_hash table */
41
42 #define CLIENT_LONG_PASSWORD 1 /* new more secure passwords */
43 #define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */
44diff -ruN a/patch_info/userstats.patch b/patch_info/userstats.patch
45--- a/patch_info/userstats.patch 1970-01-01 03:00:00.000000000 +0300
46+++ b/patch_info/userstats.patch 2010-12-30 00:45:46.000000000 +0300
a9ee80b9 47@@ -0,0 +1,17 @@
d4e9320e
AM
48+File=userstats.patch
49+Name=SHOW USER/TABLE/INDEX statistics
50+Version=V2
51+Author=Google
52+License=GPL
53+Comment=Added INFORMATION_SCHEMA.*_STATISTICS
54+2008-12-01
55+YK: fix behavior for prepared statements
56+
57+2008-11-26
a9ee80b9 58+YK: add switch variable "userstat" to control INFORMATION_SCHEMA.*_STATISTICS (default:OFF)
b4e1fa2c
AM
59+2010-12-31
60+Ported to 5.5.8
61+2011-1-5
62+Fix porting
a9ee80b9
ER
63+2011-02
64+Rename variable USERSTAT_RUNNING => USERSTAT
d4e9320e 65diff -ruN a/sql/handler.cc b/sql/handler.cc
b4e1fa2c
AM
66--- a/sql/handler.cc 2010-12-03 20:58:26.000000000 +0300
67+++ b/sql/handler.cc 2010-12-30 00:59:23.000000000 +0300
d8778560
AM
68@@ -1243,6 +1243,8 @@
69 goto end;
70 }
7023c87b 71 DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
d4e9320e
AM
72+ if (is_real_trans)
73+ thd->diff_commit_trans++;
b4e1fa2c 74 RUN_HOOK(transaction, after_commit, (thd, FALSE));
d4e9320e 75 end:
b4e1fa2c 76 if (rw_trans && mdl_request.ticket)
d8778560 77@@ -1397,6 +1399,8 @@
b4e1fa2c 78 /* Always cleanup. Even if nht==0. There may be savepoints. */
d4e9320e
AM
79 if (is_real_trans)
80 thd->transaction.cleanup();
81+
82+ thd->diff_rollback_trans++;
d4e9320e
AM
83 if (all)
84 thd->transaction_rollback_request= FALSE;
b4e1fa2c 85
d8778560 86@@ -1800,6 +1804,7 @@
d4e9320e
AM
87 ha_info->reset(); /* keep it conveniently zero-filled */
88 }
89 trans->ha_list= sv->ha_list;
90+ thd->diff_rollback_trans++;
91 DBUG_RETURN(error);
92 }
93
d8778560 94@@ -2169,6 +2174,8 @@
d4e9320e
AM
95 dup_ref=ref+ALIGN_SIZE(ref_length);
96 cached_table_flags= table_flags();
97 }
b4e1fa2c 98+ rows_read= rows_changed= 0;
d4e9320e
AM
99+ memset(index_rows_read, 0, sizeof(index_rows_read));
100 DBUG_RETURN(error);
101 }
102
d8778560 103@@ -3614,6 +3621,127 @@
d4e9320e
AM
104 return;
105 }
106
107+// Updates the global table stats with the TABLE this handler represents.
b4e1fa2c
AM
108+void handler::update_global_table_stats()
109+{
a9ee80b9 110+ if (!opt_userstat)
b4e1fa2c
AM
111+ {
112+ rows_read= rows_changed= 0;
d4e9320e
AM
113+ return;
114+ }
115+
b4e1fa2c
AM
116+ if (!rows_read && !rows_changed)
117+ return; // Nothing to update.
d4e9320e 118+ // table_cache_key is db_name + '\0' + table_name + '\0'.
b4e1fa2c
AM
119+ if (!table->s || !table->s->table_cache_key.str || !table->s->table_name.str)
120+ return;
d4e9320e
AM
121+
122+ TABLE_STATS* table_stats;
123+ char key[NAME_LEN * 2 + 2];
124+ // [db] + '.' + [table]
125+ sprintf(key, "%s.%s", table->s->table_cache_key.str, table->s->table_name.str);
126+
b4e1fa2c 127+ mysql_mutex_lock(&LOCK_global_table_stats);
d4e9320e 128+ // Gets the global table stats, creating one if necessary.
b4e1fa2c
AM
129+ if (!(table_stats = (TABLE_STATS *) my_hash_search(&global_table_stats,
130+ (uchar*)key,
131+ strlen(key))))
132+ {
133+ if (!(table_stats = ((TABLE_STATS *)
134+ my_malloc(sizeof(TABLE_STATS), MYF(MY_WME | MY_ZEROFILL)))))
135+ {
d4e9320e
AM
136+ // Out of memory.
137+ sql_print_error("Allocating table stats failed.");
138+ goto end;
139+ }
140+ strncpy(table_stats->table, key, sizeof(table_stats->table));
b4e1fa2c
AM
141+ table_stats->rows_read= 0;
142+ table_stats->rows_changed= 0;
143+ table_stats->rows_changed_x_indexes= 0;
144+ table_stats->engine_type= (int) ht->db_type;
d4e9320e 145+
b4e1fa2c
AM
146+ if (my_hash_insert(&global_table_stats, (uchar *) table_stats))
147+ {
d4e9320e
AM
148+ // Out of memory.
149+ sql_print_error("Inserting table stats failed.");
b4e1fa2c 150+ my_free((char *) table_stats);
d4e9320e
AM
151+ goto end;
152+ }
153+ }
154+ // Updates the global table stats.
b4e1fa2c
AM
155+ table_stats->rows_read+= rows_read;
156+ table_stats->rows_changed+= rows_changed;
157+ table_stats->rows_changed_x_indexes+=
158+ rows_changed * (table->s->keys ? table->s->keys : 1);
159+ current_thd->diff_total_read_rows+= rows_read;
160+ rows_read= rows_changed= 0;
d4e9320e 161+end:
b4e1fa2c 162+ mysql_mutex_unlock(&LOCK_global_table_stats);
d4e9320e
AM
163+}
164+
165+// Updates the global index stats with this handler's accumulated index reads.
b4e1fa2c
AM
166+void handler::update_global_index_stats()
167+{
d4e9320e 168+ // table_cache_key is db_name + '\0' + table_name + '\0'.
b4e1fa2c
AM
169+ if (!table->s || !table->s->table_cache_key.str || !table->s->table_name.str)
170+ return;
d4e9320e 171+
a9ee80b9 172+ if (!opt_userstat)
b4e1fa2c
AM
173+ {
174+ for (uint x= 0; x < table->s->keys; ++x)
175+ {
176+ index_rows_read[x]= 0;
d4e9320e
AM
177+ }
178+ return;
179+ }
180+
b4e1fa2c
AM
181+ for (uint x = 0; x < table->s->keys; ++x)
182+ {
183+ if (index_rows_read[x])
184+ {
d4e9320e
AM
185+ // Rows were read using this index.
186+ KEY* key_info = &table->key_info[x];
187+
188+ if (!key_info->name) continue;
189+
190+ INDEX_STATS* index_stats;
191+ char key[NAME_LEN * 3 + 3];
192+ // [db] + '.' + [table] + '.' + [index]
193+ sprintf(key, "%s.%s.%s", table->s->table_cache_key.str,
194+ table->s->table_name.str, key_info->name);
195+
b4e1fa2c 196+ mysql_mutex_lock(&LOCK_global_index_stats);
d4e9320e 197+ // Gets the global index stats, creating one if necessary.
b4e1fa2c
AM
198+ if (!(index_stats = (INDEX_STATS *) my_hash_search(&global_index_stats,
199+ (uchar *) key,
200+ strlen(key))))
201+ {
202+ if (!(index_stats = ((INDEX_STATS *)
203+ my_malloc(sizeof(INDEX_STATS), MYF(MY_WME | MY_ZEROFILL)))))
204+ {
d4e9320e
AM
205+ // Out of memory.
206+ sql_print_error("Allocating index stats failed.");
207+ goto end;
208+ }
209+ strncpy(index_stats->index, key, sizeof(index_stats->index));
b4e1fa2c 210+ index_stats->rows_read= 0;
d4e9320e 211+
b4e1fa2c
AM
212+ if (my_hash_insert(&global_index_stats, (uchar *) index_stats))
213+ {
d4e9320e
AM
214+ // Out of memory.
215+ sql_print_error("Inserting index stats failed.");
b4e1fa2c 216+ my_free((char *) index_stats);
d4e9320e
AM
217+ goto end;
218+ }
219+ }
220+ // Updates the global index stats.
b4e1fa2c
AM
221+ index_stats->rows_read+= index_rows_read[x];
222+ index_rows_read[x]= 0;
223+ end:
224+ mysql_mutex_unlock(&LOCK_global_index_stats);
d4e9320e
AM
225+ }
226+ }
227+}
228
229 /****************************************************************************
230 ** Some general functions that isn't in the handler class
231diff -ruN a/sql/handler.h b/sql/handler.h
b4e1fa2c
AM
232--- a/sql/handler.h 2010-12-03 20:58:26.000000000 +0300
233+++ b/sql/handler.h 2010-12-31 05:10:00.000000000 +0300
234@@ -33,6 +33,10 @@
235 #include <ft_global.h>
236 #include <keycache.h>
d4e9320e
AM
237
238+#if MAX_KEY > 128
239+#error MAX_KEY is too large. Values up to 128 are supported.
240+#endif
241+
242 // the following is for checking tables
243
244 #define HA_ADMIN_ALREADY_DONE 1
b4e1fa2c
AM
245@@ -561,10 +565,12 @@
246 enum enum_schema_tables
247 {
248 SCH_CHARSETS= 0,
249+ SCH_CLIENT_STATS,
250 SCH_COLLATIONS,
251 SCH_COLLATION_CHARACTER_SET_APPLICABILITY,
252 SCH_COLUMNS,
253 SCH_COLUMN_PRIVILEGES,
254+ SCH_INDEX_STATS,
255 SCH_ENGINES,
256 SCH_EVENTS,
257 SCH_FILES,
258@@ -592,9 +598,12 @@
259 SCH_TABLE_CONSTRAINTS,
260 SCH_TABLE_NAMES,
261 SCH_TABLE_PRIVILEGES,
262+ SCH_TABLE_STATS,
263 SCH_TEMPORARY_TABLES,
264+ SCH_THREAD_STATS,
265 SCH_TRIGGERS,
266 SCH_USER_PRIVILEGES,
267+ SCH_USER_STATS,
268 SCH_VARIABLES,
269 SCH_VIEWS
270 };
271@@ -1209,6 +1218,9 @@
d4e9320e
AM
272 bool locked;
273 bool implicit_emptied; /* Can be !=0 only if HEAP */
274 const COND *pushed_cond;
275+ ulonglong rows_read;
276+ ulonglong rows_changed;
277+ ulonglong index_rows_read[MAX_KEY];
278 /**
279 next_insert_id is the next value which should be inserted into the
280 auto_increment column: in a inserting-multi-row statement (like INSERT
b4e1fa2c 281@@ -1260,10 +1272,12 @@
d4e9320e
AM
282 ref_length(sizeof(my_off_t)),
283 ft_handler(0), inited(NONE),
284 locked(FALSE), implicit_emptied(0),
285- pushed_cond(0), next_insert_id(0), insert_id_for_cur_row(0),
286+ pushed_cond(0), rows_read(0), rows_changed(0), next_insert_id(0), insert_id_for_cur_row(0),
b4e1fa2c
AM
287 auto_inc_intervals_count(0),
288 m_psi(NULL)
d4e9320e
AM
289- {}
290+ {
291+ memset(index_rows_read, 0, sizeof(index_rows_read));
292+ }
293 virtual ~handler(void)
294 {
295 DBUG_ASSERT(locked == FALSE);
b4e1fa2c 296@@ -1386,6 +1400,8 @@
d4e9320e
AM
297 {
298 table= table_arg;
299 table_share= share;
b4e1fa2c 300+ rows_read = rows_changed= 0;
d4e9320e
AM
301+ memset(index_rows_read, 0, sizeof(index_rows_read));
302 }
303 virtual double scan_time()
304 { return ulonglong2double(stats.data_file_length) / IO_SIZE + 2; }
b4e1fa2c 305@@ -1753,6 +1769,8 @@
d4e9320e
AM
306 virtual bool is_crashed() const { return 0; }
307 virtual bool auto_repair() const { return 0; }
308
309+ void update_global_table_stats();
310+ void update_global_index_stats();
311
312 #define CHF_CREATE_FLAG 0
313 #define CHF_DELETE_FLAG 1
314diff -ruN a/sql/lex.h b/sql/lex.h
b4e1fa2c
AM
315--- a/sql/lex.h 2010-12-03 20:58:26.000000000 +0300
316+++ b/sql/lex.h 2010-12-30 01:25:40.000000000 +0300
317@@ -111,6 +111,7 @@
d4e9320e 318 { "CIPHER", SYM(CIPHER_SYM)},
b4e1fa2c 319 { "CLASS_ORIGIN", SYM(CLASS_ORIGIN_SYM)},
d4e9320e
AM
320 { "CLIENT", SYM(CLIENT_SYM)},
321+ { "CLIENT_STATISTICS", SYM(CLIENT_STATS_SYM)},
322 { "CLOSE", SYM(CLOSE_SYM)},
323 { "COALESCE", SYM(COALESCE)},
324 { "CODE", SYM(CODE_SYM)},
b4e1fa2c 325@@ -257,6 +258,7 @@
d4e9320e
AM
326 { "IN", SYM(IN_SYM)},
327 { "INDEX", SYM(INDEX_SYM)},
328 { "INDEXES", SYM(INDEXES)},
329+ { "INDEX_STATISTICS", SYM(INDEX_STATS_SYM)},
330 { "INFILE", SYM(INFILE)},
331 { "INITIAL_SIZE", SYM(INITIAL_SIZE_SYM)},
332 { "INNER", SYM(INNER_SYM)},
b4e1fa2c 333@@ -550,12 +552,14 @@
d4e9320e
AM
334 { "TABLES", SYM(TABLES)},
335 { "TABLESPACE", SYM(TABLESPACE)},
336 { "TABLE_CHECKSUM", SYM(TABLE_CHECKSUM_SYM)},
337+ { "TABLE_STATISTICS", SYM(TABLE_STATS_SYM)},
338 { "TEMPORARY", SYM(TEMPORARY)},
339 { "TEMPTABLE", SYM(TEMPTABLE_SYM)},
340 { "TERMINATED", SYM(TERMINATED)},
341 { "TEXT", SYM(TEXT_SYM)},
342 { "THAN", SYM(THAN_SYM)},
343 { "THEN", SYM(THEN_SYM)},
344+ { "THREAD_STATISTICS", SYM(THREAD_STATS_SYM)},
345 { "TIME", SYM(TIME_SYM)},
346 { "TIMESTAMP", SYM(TIMESTAMP)},
347 { "TIMESTAMPADD", SYM(TIMESTAMP_ADD)},
b4e1fa2c 348@@ -591,6 +595,7 @@
d4e9320e
AM
349 { "USE", SYM(USE_SYM)},
350 { "USER", SYM(USER)},
351 { "USER_RESOURCES", SYM(RESOURCES)},
352+ { "USER_STATISTICS", SYM(USER_STATS_SYM)},
353 { "USE_FRM", SYM(USE_FRM)},
354 { "USING", SYM(USING)},
355 { "UTC_DATE", SYM(UTC_DATE_SYM)},
356diff -ruN a/sql/log.cc b/sql/log.cc
b4e1fa2c
AM
357--- a/sql/log.cc 2010-12-03 20:58:26.000000000 +0300
358+++ b/sql/log.cc 2010-12-30 01:55:35.000000000 +0300
d8778560 359@@ -1007,6 +1007,13 @@
d4e9320e
AM
360 mysql_slow_log.reopen_file();
361 }
362
363+void Log_to_file_event_handler::flush_slow_log()
364+{
365+ /* reopen slow log file */
366+ if (opt_slow_log)
367+ mysql_slow_log.reopen_file();
368+}
369+
370 /*
371 Log error with all enabled log event handlers
372
a9ee80b9 373@@ -5042,6 +5049,8 @@
d4e9320e
AM
374 thd->first_successful_insert_id_in_prev_stmt_for_binlog);
375 if (e.write(file))
376 goto err;
377+ if (file == &log_file)
b4e1fa2c 378+ thd->binlog_bytes_written+= e.data_written;
d4e9320e
AM
379 }
380 if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0)
381 {
a9ee80b9 382@@ -5053,12 +5062,16 @@
d4e9320e
AM
383 minimum());
384 if (e.write(file))
385 goto err;
386+ if (file == &log_file)
b4e1fa2c 387+ thd->binlog_bytes_written+= e.data_written;
d4e9320e
AM
388 }
389 if (thd->rand_used)
390 {
391 Rand_log_event e(thd,thd->rand_saved_seed1,thd->rand_saved_seed2);
392 if (e.write(file))
393 goto err;
394+ if (file == &log_file)
b4e1fa2c 395+ thd->binlog_bytes_written+= e.data_written;
d4e9320e
AM
396 }
397 if (thd->user_var_events.elements)
398 {
a9ee80b9 399@@ -5081,6 +5094,8 @@
b4e1fa2c 400 flags);
d4e9320e
AM
401 if (e.write(file))
402 goto err;
403+ if (file == &log_file)
b4e1fa2c 404+ thd->binlog_bytes_written+= e.data_written;
d4e9320e
AM
405 }
406 }
407 }
a9ee80b9 408@@ -5092,6 +5107,8 @@
b4e1fa2c 409 if (event_info->write(file) ||
d4e9320e
AM
410 DBUG_EVALUATE_IF("injecting_fault_writing", 1, 0))
411 goto err;
412+ if (file == &log_file)
b4e1fa2c 413+ thd->binlog_bytes_written+= event_info->data_written;
d4e9320e 414
b4e1fa2c 415 error= 0;
d8778560 416 err:
a9ee80b9 417@@ -5277,7 +5294,8 @@
d4e9320e
AM
418 be reset as a READ_CACHE to be able to read the contents from it.
419 */
420
421-int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log)
b4e1fa2c
AM
422+int MYSQL_BIN_LOG::write_cache(THD *thd, IO_CACHE *cache,
423+ bool lock_log, bool sync_log)
d4e9320e
AM
424 {
425 Mutex_sentry sentry(lock_log ? &LOCK_log : NULL);
426
a9ee80b9 427@@ -5324,6 +5342,7 @@
d4e9320e
AM
428 /* write the first half of the split header */
429 if (my_b_write(&log_file, header, carry))
430 return ER_ERROR_ON_WRITE;
b4e1fa2c 431+ thd->binlog_bytes_written+= carry;
d4e9320e
AM
432
433 /*
434 copy fixed second half of header to cache so the correct
a9ee80b9 435@@ -5392,6 +5411,7 @@
d4e9320e
AM
436 /* Write data to the binary log file */
437 if (my_b_write(&log_file, cache->read_pos, length))
438 return ER_ERROR_ON_WRITE;
b4e1fa2c 439+ thd->binlog_bytes_written+= length;
d4e9320e
AM
440 cache->read_pos=cache->read_end; // Mark buffer used up
441 } while ((length= my_b_fill(cache)));
442
a9ee80b9 443@@ -5506,20 +5526,23 @@
b4e1fa2c 444 Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, FALSE, TRUE, 0);
d4e9320e
AM
445 if (qinfo.write(&log_file))
446 goto err;
b4e1fa2c 447+ thd->binlog_bytes_written+= qinfo.data_written;
d4e9320e
AM
448 DBUG_EXECUTE_IF("crash_before_writing_xid",
449 {
450- if ((write_error= write_cache(cache, false, true)))
451+ if ((write_error= write_cache(thd, cache, false, true)))
452 DBUG_PRINT("info", ("error writing binlog cache: %d",
453 write_error));
454 DBUG_PRINT("info", ("crashing before writing xid"));
7023c87b 455 DBUG_SUICIDE();
d4e9320e
AM
456 });
457
458- if ((write_error= write_cache(cache, false, false)))
459+ if ((write_error= write_cache(thd, cache, false, false)))
460 goto err;
461
462 if (commit_event && commit_event->write(&log_file))
463 goto err;
464+ if (commit_event)
b4e1fa2c 465+ thd->binlog_bytes_written+= commit_event->data_written;
d4e9320e
AM
466
467 if (incident && write_incident(thd, FALSE))
468 goto err;
469diff -ruN a/sql/log.h b/sql/log.h
b4e1fa2c
AM
470--- a/sql/log.h 2010-12-03 20:58:26.000000000 +0300
471+++ b/sql/log.h 2010-12-30 01:56:04.000000000 +0300
472@@ -414,7 +414,8 @@
d4e9320e 473 bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event, bool incident);
d4e9320e 474 bool write_incident(THD *thd, bool lock);
b4e1fa2c 475
d4e9320e 476- int write_cache(IO_CACHE *cache, bool lock_log, bool flush_and_sync);
b4e1fa2c
AM
477+ int write_cache(THD *thd, IO_CACHE *cache,
478+ bool lock_log, bool flush_and_sync);
d8778560 479 void set_write_error(THD *thd, bool is_transactional);
d4e9320e
AM
480 bool check_write_error(THD *thd);
481
b4e1fa2c 482@@ -566,6 +567,7 @@
d4e9320e
AM
483 const char *sql_text, uint sql_text_len,
484 CHARSET_INFO *client_cs);
485 void flush();
486+ void flush_slow_log();
487 void init_pthread_objects();
488 MYSQL_QUERY_LOG *get_mysql_slow_log() { return &mysql_slow_log; }
489 MYSQL_QUERY_LOG *get_mysql_log() { return &mysql_log; }
d4e9320e 490diff -ruN a/sql/mysqld.cc b/sql/mysqld.cc
b4e1fa2c
AM
491--- a/sql/mysqld.cc 2010-12-03 20:58:26.000000000 +0300
492+++ b/sql/mysqld.cc 2010-12-30 02:04:50.000000000 +0300
493@@ -438,6 +438,7 @@
d4e9320e
AM
494 uint opt_debug_sync_timeout= 0;
495 #endif /* defined(ENABLED_DEBUG_SYNC) */
496 my_bool opt_old_style_user_limits= 0, trust_function_creators= 0;
a9ee80b9 497+my_bool opt_userstat= 0, opt_thread_statistics= 0;
b4e1fa2c 498 my_bool opt_optimizer_fix= 0;
d4e9320e
AM
499 /*
500 True if there is at least one per-hour limit for some user, so we should
d8778560 501@@ -489,6 +490,7 @@
d4e9320e 502 ulong binlog_cache_use= 0, binlog_cache_disk_use= 0;
d8778560 503 ulong binlog_stmt_cache_use= 0, binlog_stmt_cache_disk_use= 0;
d4e9320e 504 ulong max_connections, max_connect_errors;
b4e1fa2c
AM
505+ulonglong denied_connections= 0;
506
507 /* flashcache */
508 int cachedev_fd;
d8778560 509@@ -633,7 +635,9 @@
b4e1fa2c
AM
510 LOCK_crypt,
511 LOCK_global_system_variables,
512 LOCK_user_conn, LOCK_slave_list, LOCK_active_mi,
513- LOCK_connection_count, LOCK_error_messages;
514+ LOCK_connection_count, LOCK_error_messages,
515+ LOCK_stats, LOCK_global_user_client_stats,
516+ LOCK_global_table_stats, LOCK_global_index_stats;
d4e9320e
AM
517 /**
518 The below lock protects access to two global server variables:
519 max_prepared_stmt_count and prepared_stmt_count. These variables
d8778560 520@@ -1493,6 +1497,11 @@
b4e1fa2c
AM
521 #ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
522 query_response_time_free();
523 #endif // HAVE_RESPONSE_TIME_DISTRIBUTION
d4e9320e
AM
524+ free_global_user_stats();
525+ free_global_client_stats();
526+ free_global_thread_stats();
527+ free_global_table_stats();
528+ free_global_index_stats();
529 #ifdef HAVE_REPLICATION
530 end_slave_list();
531 #endif
d8778560 532@@ -1596,6 +1605,10 @@
b4e1fa2c
AM
533 mysql_cond_destroy(&COND_thread_cache);
534 mysql_cond_destroy(&COND_flush_thread_cache);
535 mysql_cond_destroy(&COND_manager);
536+ mysql_mutex_destroy(&LOCK_stats);
537+ mysql_mutex_destroy(&LOCK_global_user_client_stats);
538+ mysql_mutex_destroy(&LOCK_global_table_stats);
539+ mysql_mutex_destroy(&LOCK_global_index_stats);
d4e9320e 540 }
d4e9320e 541 #endif /*EMBEDDED_LIBRARY*/
b4e1fa2c 542
d8778560 543@@ -3019,6 +3032,7 @@
d4e9320e
AM
544 {"show_binlog_events", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_BINLOG_EVENTS]), SHOW_LONG_STATUS},
545 {"show_binlogs", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_BINLOGS]), SHOW_LONG_STATUS},
546 {"show_charsets", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CHARSETS]), SHOW_LONG_STATUS},
547+ {"show_client_statistics",(char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CLIENT_STATS]), SHOW_LONG_STATUS},
548 {"show_collations", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_COLLATIONS]), SHOW_LONG_STATUS},
d4e9320e 549 {"show_contributors", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CONTRIBUTORS]), SHOW_LONG_STATUS},
b4e1fa2c 550 {"show_create_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CREATE_DB]), SHOW_LONG_STATUS},
d8778560 551@@ -3039,6 +3053,7 @@
d4e9320e
AM
552 #endif
553 {"show_function_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STATUS_FUNC]), SHOW_LONG_STATUS},
554 {"show_grants", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_GRANTS]), SHOW_LONG_STATUS},
555+ {"show_index_statistics",(char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_INDEX_STATS]), SHOW_LONG_STATUS},
556 {"show_keys", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_KEYS]), SHOW_LONG_STATUS},
557 {"show_master_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_MASTER_STAT]), SHOW_LONG_STATUS},
558 {"show_new_master", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_NEW_MASTER]), SHOW_LONG_STATUS},
d8778560 559@@ -3058,10 +3073,13 @@
b4e1fa2c 560 {"show_slave_status_nolock", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_SLAVE_NOLOCK_STAT]), SHOW_LONG_STATUS},
d4e9320e
AM
561 {"show_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STATUS]), SHOW_LONG_STATUS},
562 {"show_storage_engines", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STORAGE_ENGINES]), SHOW_LONG_STATUS},
563+ {"show_table_statistics",(char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLE_STATS]), SHOW_LONG_STATUS},
564 {"show_table_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLE_STATUS]), SHOW_LONG_STATUS},
565 {"show_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLES]), SHOW_LONG_STATUS},
b4e1fa2c 566 {"show_temporary_tables",(char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TEMPORARY_TABLES]), SHOW_LONG_STATUS},
d4e9320e
AM
567+ {"show_thread_statistics",(char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_THREAD_STATS]), SHOW_LONG_STATUS},
568 {"show_triggers", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TRIGGERS]), SHOW_LONG_STATUS},
569+ {"show_user_statistics", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_USER_STATS]), SHOW_LONG_STATUS},
570 {"show_variables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_VARIABLES]), SHOW_LONG_STATUS},
571 {"show_warnings", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_WARNS]), SHOW_LONG_STATUS},
572 {"slave_start", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_START]), SHOW_LONG_STATUS},
d8778560 573@@ -3582,6 +3600,13 @@
b4e1fa2c
AM
574 mysql_mutex_init(key_LOCK_server_started,
575 &LOCK_server_started, MY_MUTEX_INIT_FAST);
576 mysql_cond_init(key_COND_server_started, &COND_server_started, NULL);
577+ mysql_mutex_init(key_LOCK_stats, &LOCK_stats, MY_MUTEX_INIT_FAST);
578+ mysql_mutex_init(key_LOCK_global_user_client_stats,
579+ &LOCK_global_user_client_stats, MY_MUTEX_INIT_FAST);
580+ mysql_mutex_init(key_LOCK_global_table_stats,
581+ &LOCK_global_table_stats, MY_MUTEX_INIT_FAST);
582+ mysql_mutex_init(key_LOCK_global_index_stats,
583+ &LOCK_global_index_stats, MY_MUTEX_INIT_FAST);
d4e9320e
AM
584 sp_cache_init();
585 #ifdef HAVE_EVENT_SCHEDULER
586 Events::init_mutexes();
d8778560 587@@ -3951,6 +3976,9 @@
b4e1fa2c
AM
588 query_response_time_init();
589 #endif // HAVE_RESPONSE_TIME_DISTRIBUTION
590 /* We have to initialize the storage engines before CSV logging */
d4e9320e
AM
591+ init_global_table_stats();
592+ init_global_index_stats();
593+
d4e9320e
AM
594 if (ha_init())
595 {
b4e1fa2c 596 sql_print_error("Can't init databases");
d8778560 597@@ -4087,6 +4115,9 @@
d4e9320e
AM
598
599 init_max_user_conn();
600 init_update_queries();
601+ init_global_user_stats();
602+ init_global_client_stats();
603+ init_global_thread_stats();
604 DBUG_RETURN(0);
605 }
606
d8778560 607@@ -5118,6 +5149,7 @@
b4e1fa2c
AM
608 {
609 sql_print_warning("%s", ER_DEFAULT(ER_CON_COUNT_ERROR));
610 }
d4e9320e
AM
611+ statistic_increment(denied_connections, &LOCK_status);
612 delete thd;
613 DBUG_VOID_RETURN;
614 }
d8778560 615@@ -7817,6 +7849,8 @@
b4e1fa2c
AM
616 key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi,
617 key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create,
618 key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log,
619+ key_LOCK_stats, key_LOCK_global_user_client_stats,
620+ key_LOCK_global_table_stats, key_LOCK_global_index_stats,
621 key_LOCK_gdl, key_LOCK_global_system_variables,
622 key_LOCK_manager,
623 key_LOCK_prepared_stmt_count,
d8778560 624@@ -7854,6 +7888,13 @@
b4e1fa2c
AM
625 { &key_LOCK_delayed_insert, "LOCK_delayed_insert", PSI_FLAG_GLOBAL},
626 { &key_LOCK_delayed_status, "LOCK_delayed_status", PSI_FLAG_GLOBAL},
627 { &key_LOCK_error_log, "LOCK_error_log", PSI_FLAG_GLOBAL},
628+ { &key_LOCK_stats, "LOCK_stats", PSI_FLAG_GLOBAL},
629+ { &key_LOCK_global_user_client_stats,
630+ "LOCK_global_user_client_stats", PSI_FLAG_GLOBAL},
631+ { &key_LOCK_global_table_stats,
632+ "LOCK_global_table_stats", PSI_FLAG_GLOBAL},
633+ { &key_LOCK_global_index_stats,
634+ "LOCK_global_index_stats", PSI_FLAG_GLOBAL},
635 { &key_LOCK_gdl, "LOCK_gdl", PSI_FLAG_GLOBAL},
636 { &key_LOCK_global_system_variables, "LOCK_global_system_variables", PSI_FLAG_GLOBAL},
637 { &key_LOCK_manager, "LOCK_manager", PSI_FLAG_GLOBAL},
638diff -ruN a/sql/mysqld.h b/sql/mysqld.h
639--- a/sql/mysqld.h 2010-12-03 20:58:26.000000000 +0300
640+++ b/sql/mysqld.h 2010-12-31 06:04:59.000000000 +0300
641@@ -23,6 +23,7 @@
642 #include "my_atomic.h" /* my_atomic_rwlock_t */
643 #include "mysql/psi/mysql_file.h" /* MYSQL_FILE */
644 #include "sql_list.h" /* I_List */
645+#include "hash.h"
646
647 class THD;
648 struct handlerton;
649@@ -114,6 +115,7 @@
650 extern ulonglong slave_type_conversions_options;
651 extern my_bool read_only, opt_readonly;
652 extern my_bool lower_case_file_system;
a9ee80b9 653+extern my_bool opt_userstat, opt_thread_statistics;
b4e1fa2c
AM
654 extern my_bool opt_optimizer_fix;
655 extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs;
656 extern my_bool opt_secure_auth;
d8778560 657@@ -181,6 +183,7 @@
b4e1fa2c
AM
658 extern ulong slave_trans_retries;
659 extern uint slave_net_timeout;
660 extern uint max_user_connections;
661+extern ulonglong denied_connections;
662 extern ulong what_to_log,flush_time;
663 extern ulong max_prepared_stmt_count, prepared_stmt_count;
d8778560
AM
664 extern ulong open_files_limit;
665@@ -207,6 +210,11 @@
b4e1fa2c
AM
666 extern struct system_variables max_system_variables;
667 extern struct system_status_var global_status_var;
668 extern struct rand_struct sql_rand;
669+extern HASH global_user_stats;
670+extern HASH global_client_stats;
671+extern HASH global_thread_stats;
672+extern HASH global_table_stats;
673+extern HASH global_index_stats;
674 extern const char *opt_date_time_formats[];
675 extern handlerton *partition_hton;
676 extern handlerton *myisam_hton;
d8778560 677@@ -244,6 +252,8 @@
b4e1fa2c
AM
678 key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi,
679 key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create,
680 key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log,
681+ key_LOCK_stats, key_LOCK_global_user_client_stats,
682+ key_LOCK_global_table_stats, key_LOCK_global_index_stats,
683 key_LOCK_gdl, key_LOCK_global_system_variables,
684 key_LOCK_logger, key_LOCK_manager,
685 key_LOCK_prepared_stmt_count,
d8778560 686@@ -340,7 +350,9 @@
b4e1fa2c
AM
687 LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
688 LOCK_slave_list, LOCK_active_mi, LOCK_manager,
689 LOCK_global_system_variables, LOCK_user_conn,
690- LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_connection_count;
691+ LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_connection_count,
692+ LOCK_stats, LOCK_global_user_client_stats,
693+ LOCK_global_table_stats, LOCK_global_index_stats;
694 extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_thread_count;
695 #ifdef HAVE_OPENSSL
696 extern mysql_mutex_t LOCK_des_key_file;
d8778560 697@@ -452,6 +464,16 @@
b4e1fa2c
AM
698 return id;
699 }
700
701+void init_global_user_stats(void);
702+void init_global_table_stats(void);
703+void init_global_index_stats(void);
704+void init_global_client_stats(void);
705+void init_global_thread_stats(void);
706+void free_global_user_stats(void);
707+void free_global_table_stats(void);
708+void free_global_index_stats(void);
709+void free_global_client_stats(void);
710+void free_global_thread_stats(void);
711
712 /*
713 TODO: Replace this with an inline function.
d4e9320e 714diff -ruN a/sql/sql_base.cc b/sql/sql_base.cc
b4e1fa2c
AM
715--- a/sql/sql_base.cc 2010-12-03 20:58:26.000000000 +0300
716+++ b/sql/sql_base.cc 2010-12-30 02:33:17.000000000 +0300
717@@ -1524,6 +1524,11 @@
718 table->mdl_ticket= NULL;
d4e9320e 719
b4e1fa2c 720 mysql_mutex_lock(&thd->LOCK_thd_data);
d4e9320e
AM
721+ if(table->file)
722+ {
723+ table->file->update_global_table_stats();
724+ table->file->update_global_index_stats();
725+ }
d4e9320e 726 *table_ptr=table->next;
b4e1fa2c
AM
727 mysql_mutex_unlock(&thd->LOCK_thd_data);
728
729@@ -2149,6 +2154,8 @@
d4e9320e
AM
730 DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'",
731 table->s->db.str, table->s->table_name.str));
732
733+ table->file->update_global_table_stats();
734+ table->file->update_global_index_stats();
735 free_io_cache(table);
736 closefrm(table, 0);
737 if (delete_table)
738diff -ruN a/sql/sql_class.cc b/sql/sql_class.cc
b4e1fa2c
AM
739--- a/sql/sql_class.cc 2010-12-03 20:58:26.000000000 +0300
740+++ b/sql/sql_class.cc 2010-12-30 02:41:40.000000000 +0300
741@@ -601,6 +601,13 @@
d4e9320e
AM
742 mysys_var=0;
743 binlog_evt_union.do_union= FALSE;
744 enable_slow_log= 0;
b4e1fa2c
AM
745+ busy_time= 0;
746+ cpu_time= 0;
747+ bytes_received= 0;
748+ bytes_sent= 0;
749+ binlog_bytes_written= 0;
750+ updated_row_count= 0;
751+ sent_row_count_2= 0;
d4e9320e
AM
752 #ifndef DBUG_OFF
753 dbug_sentry=THD_SENTRY_MAGIC;
754 #endif
b4e1fa2c
AM
755@@ -981,6 +988,7 @@
756 variables.option_bits|= OPTION_BIN_LOG;
757 else
758 variables.option_bits&= ~OPTION_BIN_LOG;
d4e9320e
AM
759+ reset_stats();
760
761 #if defined(ENABLED_DEBUG_SYNC)
762 /* Initialize the Debug Sync Facility. See debug_sync.cc. */
b4e1fa2c 763@@ -988,6 +996,94 @@
d4e9320e
AM
764 #endif /* defined(ENABLED_DEBUG_SYNC) */
765 }
766
767+// Resets stats in a THD.
b4e1fa2c
AM
768+void THD::reset_stats(void)
769+{
770+ current_connect_time= time(NULL);
771+ last_global_update_time= current_connect_time;
d4e9320e
AM
772+ reset_diff_stats();
773+}
774+
775+// Resets the 'diff' stats, which are used to update global stats.
b4e1fa2c
AM
776+void THD::reset_diff_stats(void)
777+{
778+ diff_total_busy_time= 0;
779+ diff_total_cpu_time= 0;
780+ diff_total_bytes_received= 0;
781+ diff_total_bytes_sent= 0;
782+ diff_total_binlog_bytes_written= 0;
783+ diff_total_sent_rows= 0;
784+ diff_total_updated_rows= 0;
785+ diff_total_read_rows= 0;
786+ diff_select_commands= 0;
787+ diff_update_commands= 0;
788+ diff_other_commands= 0;
789+ diff_commit_trans= 0;
790+ diff_rollback_trans= 0;
791+ diff_denied_connections= 0;
792+ diff_lost_connections= 0;
793+ diff_access_denied_errors= 0;
794+ diff_empty_queries= 0;
d4e9320e
AM
795+}
796+
797+// Updates 'diff' stats of a THD.
b4e1fa2c
AM
798+void THD::update_stats(bool ran_command)
799+{
a9ee80b9 800+ if (opt_userstat)
b4e1fa2c
AM
801+ {
802+ diff_total_busy_time+= busy_time;
803+ diff_total_cpu_time+= cpu_time;
804+ diff_total_bytes_received+= bytes_received;
805+ diff_total_bytes_sent+= bytes_sent;
806+ diff_total_binlog_bytes_written+= binlog_bytes_written;
807+ diff_total_sent_rows+= sent_row_count_2;
808+ diff_total_updated_rows+= updated_row_count;
d4e9320e
AM
809+ // diff_total_read_rows is updated in handler.cc.
810+
b4e1fa2c
AM
811+ if (ran_command)
812+ {
d4e9320e
AM
813+ // The replication thread has the COM_CONNECT command.
814+ if ((old_command == COM_QUERY || command == COM_CONNECT) &&
b4e1fa2c
AM
815+ (lex->sql_command >= 0 && lex->sql_command < SQLCOM_END))
816+ {
d4e9320e 817+ // A SQL query.
b4e1fa2c
AM
818+ if (lex->sql_command == SQLCOM_SELECT)
819+ {
d4e9320e
AM
820+ diff_select_commands++;
821+ if (!sent_row_count_2)
822+ diff_empty_queries++;
b4e1fa2c
AM
823+ }
824+ else if (!sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND)
825+ {
d4e9320e
AM
826+ // 'SHOW ' commands become SQLCOM_SELECT.
827+ diff_other_commands++;
828+ // 'SHOW ' commands shouldn't inflate total sent row count.
b4e1fa2c 829+ diff_total_sent_rows-= sent_row_count_2;
d4e9320e
AM
830+ } else if (is_update_query(lex->sql_command)) {
831+ diff_update_commands++;
832+ } else {
833+ diff_other_commands++;
834+ }
835+ }
836+ }
837+ // diff_commit_trans is updated in handler.cc.
838+ // diff_rollback_trans is updated in handler.cc.
839+ // diff_denied_connections is updated in sql_parse.cc.
840+ // diff_lost_connections is updated in sql_parse.cc.
841+ // diff_access_denied_errors is updated in sql_parse.cc.
842+
843+ /* reset counters to zero to avoid double-counting since values
b4e1fa2c
AM
844+ are already store in diff_total_*.
845+ */
d4e9320e 846+ }
b4e1fa2c
AM
847+ busy_time= 0;
848+ cpu_time= 0;
849+ bytes_received= 0;
850+ bytes_sent= 0;
851+ binlog_bytes_written= 0;
852+ updated_row_count= 0;
853+ sent_row_count_2= 0;
d4e9320e
AM
854+}
855
856 /*
857 Init THD for query processing.
d8778560 858@@ -1722,6 +1818,32 @@
d4e9320e
AM
859 }
860 #endif
861
862+char *THD::get_client_host_port(THD *client)
863+{
864+ Security_context *client_sctx= client->security_ctx;
865+ char *client_host= NULL;
866+
867+ if (client->peer_port && (client_sctx->host || client_sctx->ip) &&
868+ security_ctx->host_or_ip[0])
869+ {
870+ if ((client_host= (char *) this->alloc(LIST_PROCESS_HOST_LEN+1)))
871+ my_snprintf((char *) client_host, LIST_PROCESS_HOST_LEN,
872+ "%s:%u", client_sctx->host_or_ip, client->peer_port);
873+ }
874+ else
875+ client_host= this->strdup(client_sctx->host_or_ip[0] ?
876+ client_sctx->host_or_ip :
877+ client_sctx->host ? client_sctx->host : "");
878+
879+ return client_host;
880+}
881+
882+const char *get_client_host(THD *client)
883+{
884+ return client->security_ctx->host_or_ip[0] ?
885+ client->security_ctx->host_or_ip :
886+ client->security_ctx->host ? client->security_ctx->host : "";
887+}
888
889 struct Item_change_record: public ilink
890 {
d8778560 891@@ -1898,6 +2020,7 @@
d4e9320e 892 }
b4e1fa2c 893
d4e9320e
AM
894 thd->sent_row_count++;
895+ thd->sent_row_count_2++;
b4e1fa2c
AM
896
897 if (thd->vio_ok())
898 DBUG_RETURN(protocol->write());
d8778560 899@@ -1990,6 +2113,7 @@
d4e9320e
AM
900 select_export::~select_export()
901 {
902 thd->sent_row_count=row_count;
b4e1fa2c 903+ thd->sent_row_count_2= row_count;
d4e9320e
AM
904 }
905
906
d8778560 907@@ -3013,6 +3137,7 @@
d4e9320e
AM
908 if (likely(thd != 0))
909 { /* current_thd==0 when close_connection() calls net_send_error() */
910 thd->status_var.bytes_sent+= length;
911+ thd->bytes_sent+= length;
912 }
913 }
914
d8778560 915@@ -3020,6 +3145,7 @@
d4e9320e
AM
916 void thd_increment_bytes_received(ulong length)
917 {
918 current_thd->status_var.bytes_received+= length;
919+ current_thd->bytes_received+= length;
920 }
921
922
923diff -ruN a/sql/sql_class.h b/sql/sql_class.h
b4e1fa2c
AM
924--- a/sql/sql_class.h 2010-12-03 20:58:26.000000000 +0300
925+++ b/sql/sql_class.h 2010-12-31 05:15:57.000000000 +0300
a9ee80b9 926@@ -1617,6 +1617,8 @@
d4e9320e
AM
927 */
928 enum enum_server_command command;
b4e1fa2c 929 uint32 server_id;
d4e9320e
AM
930+ // Used to save the command, before it is set to COM_SLEEP.
931+ enum enum_server_command old_command;
d4e9320e
AM
932 uint32 file_id; // for LOAD DATA INFILE
933 /* remote (peer) port */
b4e1fa2c 934 uint16 peer_port;
a9ee80b9 935@@ -2088,6 +2090,8 @@
b4e1fa2c
AM
936 */
937 enum_tx_isolation tx_isolation;
d4e9320e
AM
938 enum_check_fields count_cuted_fields;
939+ ha_rows updated_row_count;
940+ ha_rows sent_row_count_2; /* for userstat */
941
942 DYNAMIC_ARRAY user_var_events; /* For user variables replication */
943 MEM_ROOT *user_var_events_alloc; /* Allocate above array elements here */
a9ee80b9 944@@ -2183,6 +2187,49 @@
d4e9320e
AM
945 */
946 LOG_INFO* current_linfo;
947 NET* slave_net; // network connection from slave -> m.
948+
949+ /*
950+ Used to update global user stats. The global user stats are updated
951+ occasionally with the 'diff' variables. After the update, the 'diff'
952+ variables are reset to 0.
b4e1fa2c 953+ */
d4e9320e
AM
954+ // Time when the current thread connected to MySQL.
955+ time_t current_connect_time;
956+ // Last time when THD stats were updated in global_user_stats.
957+ time_t last_global_update_time;
958+ // Busy (non-idle) time for just one command.
959+ double busy_time;
960+ // Busy time not updated in global_user_stats yet.
961+ double diff_total_busy_time;
962+ // Cpu (non-idle) time for just one thread.
963+ double cpu_time;
964+ // Cpu time not updated in global_user_stats yet.
965+ double diff_total_cpu_time;
966+ /* bytes counting */
967+ ulonglong bytes_received;
968+ ulonglong diff_total_bytes_received;
969+ ulonglong bytes_sent;
970+ ulonglong diff_total_bytes_sent;
971+ ulonglong binlog_bytes_written;
972+ ulonglong diff_total_binlog_bytes_written;
973+
974+ // Number of rows not reflected in global_user_stats yet.
975+ ha_rows diff_total_sent_rows, diff_total_updated_rows, diff_total_read_rows;
976+ // Number of commands not reflected in global_user_stats yet.
977+ ulonglong diff_select_commands, diff_update_commands, diff_other_commands;
978+ // Number of transactions not reflected in global_user_stats yet.
979+ ulonglong diff_commit_trans, diff_rollback_trans;
980+ // Number of connection errors not reflected in global_user_stats yet.
981+ ulonglong diff_denied_connections, diff_lost_connections;
982+ // Number of db access denied, not reflected in global_user_stats yet.
983+ ulonglong diff_access_denied_errors;
984+ // Number of queries that return 0 rows
985+ ulonglong diff_empty_queries;
986+
987+ // Per account query delay in miliseconds. When not 0, sleep this number of
988+ // milliseconds before every SQL command.
989+ ulonglong query_delay_millis;
990+
991 /* Used by the sys_var class to store temporary values */
992 union
993 {
a9ee80b9 994@@ -2263,6 +2310,11 @@
d4e9320e
AM
995 alloc_root.
996 */
997 void init_for_queries();
998+ void reset_stats(void);
999+ void reset_diff_stats(void);
1000+ // ran_command is true when this is called immediately after a
1001+ // command has been run.
1002+ void update_stats(bool ran_command);
1003 void change_user(void);
1004 void cleanup(void);
1005 void cleanup_after_query();
a9ee80b9 1006@@ -2734,6 +2786,15 @@
d4e9320e
AM
1007 }
1008 thd_scheduler scheduler;
1009
b4e1fa2c
AM
1010+ /* Returns string as 'IP:port' for the client-side
1011+ of the connnection represented
1012+ by 'client' as displayed by SHOW PROCESSLIST.
1013+ Allocates memory from the heap of
1014+ this THD and that is not reclaimed
1015+ immediately, so use sparingly. May return NULL.
1016+ */
d4e9320e
AM
1017+ char *get_client_host_port(THD *client);
1018+
1019 public:
1020 inline Internal_error_handler *get_internal_handler()
1021 { return m_internal_handler; }
a9ee80b9 1022@@ -2921,6 +2982,10 @@
d4e9320e
AM
1023 LEX_STRING invoker_host;
1024 };
1025
b4e1fa2c
AM
1026+/* Returns string as 'IP' for the client-side of the connection represented by
1027+ 'client'. Does not allocate memory. May return "".
1028+*/
d4e9320e
AM
1029+const char *get_client_host(THD *client);
1030
b4e1fa2c 1031 /** A short cut for thd->stmt_da->set_ok_status(). */
d4e9320e
AM
1032
1033diff -ruN a/sql/sql_connect.cc b/sql/sql_connect.cc
b4e1fa2c
AM
1034--- a/sql/sql_connect.cc 2010-12-03 20:58:26.000000000 +0300
1035+++ b/sql/sql_connect.cc 2010-12-31 03:53:28.000000000 +0300
1036@@ -55,6 +55,24 @@
1037 #define MIN_HANDSHAKE_SIZE 6
1038 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
d4e9320e
AM
1039
1040+// Increments connection count for user.
1041+static int increment_connection_count(THD* thd, bool use_lock);
1042+
1043+// Uses the THD to update the global stats by user name and client IP
1044+void update_global_user_stats(THD* thd, bool create_user, time_t now);
1045+
1046+HASH global_user_stats;
1047+HASH global_client_stats;
1048+HASH global_thread_stats;
1049+// Protects global_user_stats and global_client_stats
b4e1fa2c 1050+extern mysql_mutex_t LOCK_global_user_client_stats;
d4e9320e
AM
1051+
1052+HASH global_table_stats;
b4e1fa2c 1053+extern mysql_mutex_t LOCK_global_table_stats;
d4e9320e
AM
1054+
1055+HASH global_index_stats;
b4e1fa2c 1056+extern mysql_mutex_t LOCK_global_index_stats;
d4e9320e
AM
1057+
1058 /*
1059 Get structure for logging connection data for the current user
1060 */
b4e1fa2c 1061@@ -112,6 +130,586 @@
d4e9320e
AM
1062
1063 }
1064
1065+extern "C" uchar *get_key_user_stats(USER_STATS *user_stats, size_t *length,
1066+ my_bool not_used __attribute__((unused)))
1067+{
b4e1fa2c
AM
1068+ *length= strlen(user_stats->user);
1069+ return (uchar*) user_stats->user;
d4e9320e
AM
1070+}
1071+
1072+extern "C" uchar *get_key_thread_stats(THREAD_STATS *thread_stats, size_t *length,
1073+ my_bool not_used __attribute__((unused)))
1074+{
b4e1fa2c
AM
1075+ *length= sizeof(my_thread_id);
1076+ return (uchar *) &(thread_stats->id);
d4e9320e
AM
1077+}
1078+
1079+void free_user_stats(USER_STATS* user_stats)
1080+{
b4e1fa2c 1081+ my_free((char *) user_stats);
d4e9320e
AM
1082+}
1083+
1084+void free_thread_stats(THREAD_STATS* thread_stats)
1085+{
b4e1fa2c 1086+ my_free((char *) thread_stats);
d4e9320e
AM
1087+}
1088+
1089+void init_user_stats(USER_STATS *user_stats,
1090+ const char *user,
1091+ const char *priv_user,
1092+ uint total_connections,
1093+ uint concurrent_connections,
1094+ time_t connected_time,
1095+ double busy_time,
1096+ double cpu_time,
1097+ ulonglong bytes_received,
1098+ ulonglong bytes_sent,
1099+ ulonglong binlog_bytes_written,
1100+ ha_rows rows_fetched,
1101+ ha_rows rows_updated,
1102+ ha_rows rows_read,
1103+ ulonglong select_commands,
1104+ ulonglong update_commands,
1105+ ulonglong other_commands,
1106+ ulonglong commit_trans,
1107+ ulonglong rollback_trans,
1108+ ulonglong denied_connections,
1109+ ulonglong lost_connections,
1110+ ulonglong access_denied_errors,
1111+ ulonglong empty_queries)
1112+{
1113+ DBUG_ENTER("init_user_stats");
1114+ DBUG_PRINT("info",
1115+ ("Add user_stats entry for user %s - priv_user %s",
1116+ user, priv_user));
1117+ strncpy(user_stats->user, user, sizeof(user_stats->user));
1118+ strncpy(user_stats->priv_user, priv_user, sizeof(user_stats->priv_user));
1119+
b4e1fa2c
AM
1120+ user_stats->total_connections= total_connections;
1121+ user_stats->concurrent_connections= concurrent_connections;
1122+ user_stats->connected_time= connected_time;
1123+ user_stats->busy_time= busy_time;
1124+ user_stats->cpu_time= cpu_time;
1125+ user_stats->bytes_received= bytes_received;
1126+ user_stats->bytes_sent= bytes_sent;
1127+ user_stats->binlog_bytes_written= binlog_bytes_written;
1128+ user_stats->rows_fetched= rows_fetched;
1129+ user_stats->rows_updated= rows_updated;
1130+ user_stats->rows_read= rows_read;
1131+ user_stats->select_commands= select_commands;
1132+ user_stats->update_commands= update_commands;
1133+ user_stats->other_commands= other_commands;
1134+ user_stats->commit_trans= commit_trans;
1135+ user_stats->rollback_trans= rollback_trans;
1136+ user_stats->denied_connections= denied_connections;
1137+ user_stats->lost_connections= lost_connections;
1138+ user_stats->access_denied_errors= access_denied_errors;
1139+ user_stats->empty_queries= empty_queries;
d4e9320e
AM
1140+ DBUG_VOID_RETURN;
1141+}
1142+
1143+void init_thread_stats(THREAD_STATS *thread_stats,
1144+ my_thread_id id,
1145+ uint total_connections,
1146+ uint concurrent_connections,
1147+ time_t connected_time,
1148+ double busy_time,
1149+ double cpu_time,
1150+ ulonglong bytes_received,
1151+ ulonglong bytes_sent,
1152+ ulonglong binlog_bytes_written,
1153+ ha_rows rows_fetched,
1154+ ha_rows rows_updated,
1155+ ha_rows rows_read,
1156+ ulonglong select_commands,
1157+ ulonglong update_commands,
1158+ ulonglong other_commands,
1159+ ulonglong commit_trans,
1160+ ulonglong rollback_trans,
1161+ ulonglong denied_connections,
1162+ ulonglong lost_connections,
1163+ ulonglong access_denied_errors,
1164+ ulonglong empty_queries)
1165+{
1166+ DBUG_ENTER("init_thread_stats");
1167+ DBUG_PRINT("info",
1168+ ("Add thread_stats entry for thread %lu",
1169+ id));
b4e1fa2c
AM
1170+ thread_stats->id= id;
1171+
1172+ thread_stats->total_connections= total_connections;
1173+ thread_stats->concurrent_connections= concurrent_connections;
1174+ thread_stats->connected_time= connected_time;
1175+ thread_stats->busy_time= busy_time;
1176+ thread_stats->cpu_time= cpu_time;
1177+ thread_stats->bytes_received= bytes_received;
1178+ thread_stats->bytes_sent= bytes_sent;
1179+ thread_stats->binlog_bytes_written= binlog_bytes_written;
1180+ thread_stats->rows_fetched= rows_fetched;
1181+ thread_stats->rows_updated= rows_updated;
1182+ thread_stats->rows_read= rows_read;
1183+ thread_stats->select_commands= select_commands;
1184+ thread_stats->update_commands= update_commands;
1185+ thread_stats->other_commands= other_commands;
1186+ thread_stats->commit_trans= commit_trans;
1187+ thread_stats->rollback_trans= rollback_trans;
1188+ thread_stats->denied_connections= denied_connections;
1189+ thread_stats->lost_connections= lost_connections;
1190+ thread_stats->access_denied_errors= access_denied_errors;
1191+ thread_stats->empty_queries= empty_queries;
d4e9320e
AM
1192+ DBUG_VOID_RETURN;
1193+}
1194+
1195+void add_user_stats(USER_STATS *user_stats,
1196+ uint total_connections,
1197+ uint concurrent_connections,
1198+ time_t connected_time,
1199+ double busy_time,
1200+ double cpu_time,
1201+ ulonglong bytes_received,
1202+ ulonglong bytes_sent,
1203+ ulonglong binlog_bytes_written,
1204+ ha_rows rows_fetched,
1205+ ha_rows rows_updated,
1206+ ha_rows rows_read,
1207+ ulonglong select_commands,
1208+ ulonglong update_commands,
1209+ ulonglong other_commands,
1210+ ulonglong commit_trans,
1211+ ulonglong rollback_trans,
1212+ ulonglong denied_connections,
1213+ ulonglong lost_connections,
1214+ ulonglong access_denied_errors,
1215+ ulonglong empty_queries)
1216+{
b4e1fa2c
AM
1217+ user_stats->total_connections+= total_connections;
1218+ user_stats->concurrent_connections+= concurrent_connections;
1219+ user_stats->connected_time+= connected_time;
1220+ user_stats->busy_time+= busy_time;
1221+ user_stats->cpu_time+= cpu_time;
1222+ user_stats->bytes_received+= bytes_received;
1223+ user_stats->bytes_sent+= bytes_sent;
1224+ user_stats->binlog_bytes_written+= binlog_bytes_written;
1225+ user_stats->rows_fetched+= rows_fetched;
1226+ user_stats->rows_updated+= rows_updated;
1227+ user_stats->rows_read+= rows_read;
1228+ user_stats->select_commands+= select_commands;
1229+ user_stats->update_commands+= update_commands;
1230+ user_stats->other_commands+= other_commands;
1231+ user_stats->commit_trans+= commit_trans;
1232+ user_stats->rollback_trans+= rollback_trans;
1233+ user_stats->denied_connections+= denied_connections;
1234+ user_stats->lost_connections+= lost_connections;
1235+ user_stats->access_denied_errors+= access_denied_errors;
1236+ user_stats->empty_queries+= empty_queries;
d4e9320e
AM
1237+}
1238+
1239+void add_thread_stats(THREAD_STATS *thread_stats,
1240+ uint total_connections,
1241+ uint concurrent_connections,
1242+ time_t connected_time,
1243+ double busy_time,
1244+ double cpu_time,
1245+ ulonglong bytes_received,
1246+ ulonglong bytes_sent,
1247+ ulonglong binlog_bytes_written,
1248+ ha_rows rows_fetched,
1249+ ha_rows rows_updated,
1250+ ha_rows rows_read,
1251+ ulonglong select_commands,
1252+ ulonglong update_commands,
1253+ ulonglong other_commands,
1254+ ulonglong commit_trans,
1255+ ulonglong rollback_trans,
1256+ ulonglong denied_connections,
1257+ ulonglong lost_connections,
1258+ ulonglong access_denied_errors,
1259+ ulonglong empty_queries)
1260+{
b4e1fa2c
AM
1261+ thread_stats->total_connections+= total_connections;
1262+ thread_stats->concurrent_connections+= concurrent_connections;
1263+ thread_stats->connected_time+= connected_time;
1264+ thread_stats->busy_time+= busy_time;
1265+ thread_stats->cpu_time+= cpu_time;
1266+ thread_stats->bytes_received+= bytes_received;
1267+ thread_stats->bytes_sent+= bytes_sent;
1268+ thread_stats->binlog_bytes_written+= binlog_bytes_written;
1269+ thread_stats->rows_fetched+= rows_fetched;
1270+ thread_stats->rows_updated+= rows_updated;
1271+ thread_stats->rows_read+= rows_read;
1272+ thread_stats->select_commands+= select_commands;
1273+ thread_stats->update_commands+= update_commands;
1274+ thread_stats->other_commands+= other_commands;
1275+ thread_stats->commit_trans+= commit_trans;
1276+ thread_stats->rollback_trans+= rollback_trans;
1277+ thread_stats->denied_connections+= denied_connections;
1278+ thread_stats->lost_connections+= lost_connections;
1279+ thread_stats->access_denied_errors+= access_denied_errors;
1280+ thread_stats->empty_queries+= empty_queries;
d4e9320e
AM
1281+}
1282+
1283+void init_global_user_stats(void)
1284+{
b4e1fa2c
AM
1285+ if (my_hash_init(&global_user_stats, system_charset_info, max_connections,
1286+ 0, 0, (my_hash_get_key)get_key_user_stats,
1287+ (my_hash_free_key)free_user_stats, 0)) {
d4e9320e
AM
1288+ sql_print_error("Initializing global_user_stats failed.");
1289+ exit(1);
1290+ }
1291+}
1292+
1293+void init_global_client_stats(void)
1294+{
b4e1fa2c
AM
1295+ if (my_hash_init(&global_client_stats, system_charset_info, max_connections,
1296+ 0, 0, (my_hash_get_key)get_key_user_stats,
1297+ (my_hash_free_key)free_user_stats, 0)) {
d4e9320e
AM
1298+ sql_print_error("Initializing global_client_stats failed.");
1299+ exit(1);
1300+ }
1301+}
1302+
1303+void init_global_thread_stats(void)
1304+{
b4e1fa2c
AM
1305+ if (my_hash_init(&global_thread_stats, &my_charset_bin, max_connections,
1306+ 0, 0, (my_hash_get_key) get_key_thread_stats,
1307+ (my_hash_free_key) free_thread_stats, 0))
1308+ {
d4e9320e
AM
1309+ sql_print_error("Initializing global_client_stats failed.");
1310+ exit(1);
1311+ }
1312+}
1313+
1314+extern "C" uchar *get_key_table_stats(TABLE_STATS *table_stats, size_t *length,
1315+ my_bool not_used __attribute__((unused)))
1316+{
b4e1fa2c
AM
1317+ *length= strlen(table_stats->table);
1318+ return (uchar*) table_stats->table;
d4e9320e
AM
1319+}
1320+
1321+extern "C" void free_table_stats(TABLE_STATS* table_stats)
1322+{
b4e1fa2c 1323+ my_free((char*) table_stats);
d4e9320e
AM
1324+}
1325+
1326+void init_global_table_stats(void)
1327+{
b4e1fa2c
AM
1328+ if (my_hash_init(&global_table_stats, system_charset_info, max_connections,
1329+ 0, 0, (my_hash_get_key)get_key_table_stats,
1330+ (my_hash_free_key)free_table_stats, 0)) {
d4e9320e
AM
1331+ sql_print_error("Initializing global_table_stats failed.");
1332+ exit(1);
1333+ }
1334+}
1335+
1336+extern "C" uchar *get_key_index_stats(INDEX_STATS *index_stats, size_t *length,
1337+ my_bool not_used __attribute__((unused)))
1338+{
b4e1fa2c
AM
1339+ *length= strlen(index_stats->index);
1340+ return (uchar*) index_stats->index;
d4e9320e
AM
1341+}
1342+
1343+extern "C" void free_index_stats(INDEX_STATS* index_stats)
1344+{
b4e1fa2c 1345+ my_free((char*) index_stats);
d4e9320e
AM
1346+}
1347+
1348+void init_global_index_stats(void)
1349+{
b4e1fa2c
AM
1350+ if (my_hash_init(&global_index_stats, system_charset_info, max_connections,
1351+ 0, 0, (my_hash_get_key)get_key_index_stats,
1352+ (my_hash_free_key)free_index_stats, 0)) {
d4e9320e
AM
1353+ sql_print_error("Initializing global_index_stats failed.");
1354+ exit(1);
1355+ }
1356+}
1357+
1358+void free_global_user_stats(void)
1359+{
b4e1fa2c 1360+ my_hash_free(&global_user_stats);
d4e9320e
AM
1361+}
1362+
1363+void free_global_thread_stats(void)
1364+{
b4e1fa2c 1365+ my_hash_free(&global_thread_stats);
d4e9320e
AM
1366+}
1367+
1368+void free_global_table_stats(void)
1369+{
b4e1fa2c 1370+ my_hash_free(&global_table_stats);
d4e9320e
AM
1371+}
1372+
1373+void free_global_index_stats(void)
1374+{
b4e1fa2c 1375+ my_hash_free(&global_index_stats);
d4e9320e
AM
1376+}
1377+
1378+void free_global_client_stats(void)
1379+{
b4e1fa2c 1380+ my_hash_free(&global_client_stats);
d4e9320e
AM
1381+}
1382+
1383+// 'mysql_system_user' is used for when the user is not defined for a THD.
1384+static char mysql_system_user[] = "#mysql_system#";
1385+
1386+// Returns 'user' if it's not NULL. Returns 'mysql_system_user' otherwise.
1387+static char* get_valid_user_string(char* user) {
1388+ return user ? user : mysql_system_user;
1389+}
1390+
1391+// Increments the global stats connection count for an entry from
1392+// global_client_stats or global_user_stats. Returns 0 on success
1393+// and 1 on error.
1394+static int increment_count_by_name(const char *name, const char *role_name,
1395+ HASH *users_or_clients, THD *thd)
1396+{
1397+ USER_STATS* user_stats;
1398+
b4e1fa2c
AM
1399+ if (!(user_stats = (USER_STATS *) my_hash_search(users_or_clients,
1400+ (uchar*) name,
1401+ strlen(name))))
d4e9320e
AM
1402+ {
1403+ // First connection for this user or client
b4e1fa2c 1404+ if (!(user_stats = ((USER_STATS *)
d4e9320e
AM
1405+ my_malloc(sizeof(USER_STATS), MYF(MY_WME | MY_ZEROFILL)))))
1406+ {
1407+ return 1; // Out of memory
1408+ }
1409+
1410+ init_user_stats(user_stats, name, role_name,
1411+ 0, 0, // connections
1412+ 0, 0, 0, // time
1413+ 0, 0, 0, // bytes sent, received and written
1414+ 0, 0, 0, // rows fetched, updated and read
1415+ 0, 0, 0, // select, update and other commands
1416+ 0, 0, // commit and rollback trans
1417+ thd->diff_denied_connections,
1418+ 0, // lost connections
1419+ 0, // access denied errors
1420+ 0); // empty queries
1421+
b4e1fa2c 1422+ if (my_hash_insert(users_or_clients, (uchar *) user_stats))
d4e9320e 1423+ {
b4e1fa2c 1424+ my_free((char *) user_stats);
d4e9320e
AM
1425+ return 1; // Out of memory
1426+ }
1427+ }
1428+ user_stats->total_connections++;
1429+ return 0;
1430+}
1431+
1432+static int increment_count_by_id(my_thread_id id,
1433+ HASH *users_or_clients, THD *thd)
1434+{
1435+ THREAD_STATS* thread_stats;
1436+
b4e1fa2c
AM
1437+ if (!(thread_stats = (THREAD_STATS *) my_hash_search(users_or_clients,
1438+ (uchar*) &id,
1439+ sizeof(my_thread_id))))
d4e9320e
AM
1440+ {
1441+ // First connection for this user or client
b4e1fa2c 1442+ if (!(thread_stats = ((THREAD_STATS *)
d4e9320e
AM
1443+ my_malloc(sizeof(THREAD_STATS), MYF(MY_WME | MY_ZEROFILL)))))
1444+ {
1445+ return 1; // Out of memory
1446+ }
1447+
1448+ init_thread_stats(thread_stats, id,
1449+ 0, 0, // connections
1450+ 0, 0, 0, // time
1451+ 0, 0, 0, // bytes sent, received and written
1452+ 0, 0, 0, // rows fetched, updated and read
1453+ 0, 0, 0, // select, update and other commands
1454+ 0, 0, // commit and rollback trans
1455+ thd->diff_denied_connections,
1456+ 0, // lost connections
1457+ 0, // access denied errors
1458+ 0); // empty queries
1459+
b4e1fa2c 1460+ if (my_hash_insert(users_or_clients, (uchar *) thread_stats))
d4e9320e 1461+ {
b4e1fa2c 1462+ my_free((char *) thread_stats);
d4e9320e
AM
1463+ return 1; // Out of memory
1464+ }
1465+ }
1466+ thread_stats->total_connections++;
1467+ return 0;
1468+}
1469+
b4e1fa2c
AM
1470+/* Increments the global user and client stats connection count. If 'use_lock'
1471+ is true, LOCK_global_user_client_stats will be locked/unlocked. Returns
1472+ 0 on success, 1 on error.
1473+*/
d4e9320e
AM
1474+static int increment_connection_count(THD* thd, bool use_lock)
1475+{
b4e1fa2c
AM
1476+ char* user_string= get_valid_user_string(thd->main_security_ctx.user);
1477+ const char* client_string= get_client_host(thd);
1478+ int return_value= 0;
d4e9320e 1479+
a9ee80b9 1480+ if (!opt_userstat)
d4e9320e
AM
1481+ return return_value;
1482+
b4e1fa2c
AM
1483+ if (use_lock)
1484+ mysql_mutex_lock(&LOCK_global_user_client_stats);
d4e9320e
AM
1485+
1486+ if (increment_count_by_name(user_string, user_string,
1487+ &global_user_stats, thd))
1488+ {
b4e1fa2c 1489+ return_value= 1;
d4e9320e
AM
1490+ goto end;
1491+ }
1492+ if (increment_count_by_name(client_string,
1493+ user_string,
1494+ &global_client_stats, thd))
1495+ {
b4e1fa2c 1496+ return_value= 1;
d4e9320e
AM
1497+ goto end;
1498+ }
b4e1fa2c
AM
1499+ if (opt_thread_statistics)
1500+ {
d4e9320e
AM
1501+ if (increment_count_by_id(thd->thread_id, &global_thread_stats, thd))
1502+ {
b4e1fa2c 1503+ return_value= 1;
d4e9320e
AM
1504+ goto end;
1505+ }
b4e1fa2c 1506+ }
d4e9320e
AM
1507+
1508+end:
b4e1fa2c
AM
1509+ if (use_lock)
1510+ mysql_mutex_unlock(&LOCK_global_user_client_stats);
d4e9320e
AM
1511+ return return_value;
1512+}
1513+
1514+// Used to update the global user and client stats.
1515+static void update_global_user_stats_with_user(THD* thd,
1516+ USER_STATS* user_stats,
1517+ time_t now)
1518+{
b4e1fa2c
AM
1519+ user_stats->connected_time+= now - thd->last_global_update_time;
1520+//thd->last_global_update_time= now;
1521+ user_stats->busy_time+= thd->diff_total_busy_time;
1522+ user_stats->cpu_time+= thd->diff_total_cpu_time;
1523+ user_stats->bytes_received+= thd->diff_total_bytes_received;
1524+ user_stats->bytes_sent+= thd->diff_total_bytes_sent;
1525+ user_stats->binlog_bytes_written+= thd->diff_total_binlog_bytes_written;
1526+ user_stats->rows_fetched+= thd->diff_total_sent_rows;
1527+ user_stats->rows_updated+= thd->diff_total_updated_rows;
1528+ user_stats->rows_read+= thd->diff_total_read_rows;
1529+ user_stats->select_commands+= thd->diff_select_commands;
1530+ user_stats->update_commands+= thd->diff_update_commands;
1531+ user_stats->other_commands+= thd->diff_other_commands;
1532+ user_stats->commit_trans+= thd->diff_commit_trans;
1533+ user_stats->rollback_trans+= thd->diff_rollback_trans;
1534+ user_stats->denied_connections+= thd->diff_denied_connections;
1535+ user_stats->lost_connections+= thd->diff_lost_connections;
1536+ user_stats->access_denied_errors+= thd->diff_access_denied_errors;
1537+ user_stats->empty_queries+= thd->diff_empty_queries;
d4e9320e
AM
1538+}
1539+
1540+static void update_global_thread_stats_with_thread(THD* thd,
1541+ THREAD_STATS* thread_stats,
1542+ time_t now)
1543+{
b4e1fa2c
AM
1544+ thread_stats->connected_time+= now - thd->last_global_update_time;
1545+//thd->last_global_update_time= now;
1546+ thread_stats->busy_time+= thd->diff_total_busy_time;
1547+ thread_stats->cpu_time+= thd->diff_total_cpu_time;
1548+ thread_stats->bytes_received+= thd->diff_total_bytes_received;
1549+ thread_stats->bytes_sent+= thd->diff_total_bytes_sent;
1550+ thread_stats->binlog_bytes_written+= thd->diff_total_binlog_bytes_written;
1551+ thread_stats->rows_fetched+= thd->diff_total_sent_rows;
1552+ thread_stats->rows_updated+= thd->diff_total_updated_rows;
1553+ thread_stats->rows_read+= thd->diff_total_read_rows;
1554+ thread_stats->select_commands+= thd->diff_select_commands;
1555+ thread_stats->update_commands+= thd->diff_update_commands;
1556+ thread_stats->other_commands+= thd->diff_other_commands;
1557+ thread_stats->commit_trans+= thd->diff_commit_trans;
1558+ thread_stats->rollback_trans+= thd->diff_rollback_trans;
1559+ thread_stats->denied_connections+= thd->diff_denied_connections;
1560+ thread_stats->lost_connections+= thd->diff_lost_connections;
1561+ thread_stats->access_denied_errors+= thd->diff_access_denied_errors;
1562+ thread_stats->empty_queries+= thd->diff_empty_queries;
d4e9320e
AM
1563+}
1564+
1565+// Updates the global stats of a user or client
1566+void update_global_user_stats(THD* thd, bool create_user, time_t now)
1567+{
a9ee80b9 1568+ if (opt_userstat)
b4e1fa2c
AM
1569+ {
1570+ char* user_string= get_valid_user_string(thd->main_security_ctx.user);
1571+ const char* client_string= get_client_host(thd);
d4e9320e 1572+
b4e1fa2c
AM
1573+ USER_STATS* user_stats;
1574+ THREAD_STATS* thread_stats;
1575+ mysql_mutex_lock(&LOCK_global_user_client_stats);
d4e9320e 1576+
b4e1fa2c
AM
1577+ // Update by user name
1578+ if ((user_stats = (USER_STATS *) my_hash_search(&global_user_stats,
1579+ (uchar *) user_string,
1580+ strlen(user_string))))
1581+ {
1582+ // Found user.
1583+ update_global_user_stats_with_user(thd, user_stats, now);
1584+ }
1585+ else
1586+ {
1587+ // Create the entry
1588+ if (create_user)
1589+ {
1590+ increment_count_by_name(user_string, user_string,
1591+ &global_user_stats, thd);
1592+ }
d4e9320e 1593+ }
d4e9320e 1594+
b4e1fa2c
AM
1595+ // Update by client IP
1596+ if ((user_stats = (USER_STATS *) my_hash_search(&global_client_stats,
1597+ (uchar *) client_string,
1598+ strlen(client_string))))
1599+ {
1600+ // Found by client IP
1601+ update_global_user_stats_with_user(thd, user_stats, now);
1602+ }
1603+ else
1604+ {
d4e9320e 1605+ // Create the entry
b4e1fa2c
AM
1606+ if (create_user)
1607+ {
1608+ increment_count_by_name(client_string,
1609+ user_string,
1610+ &global_client_stats, thd);
d4e9320e
AM
1611+ }
1612+ }
d4e9320e 1613+
b4e1fa2c
AM
1614+ if (opt_thread_statistics)
1615+ {
1616+ // Update by thread ID
1617+ if ((thread_stats = (THREAD_STATS *) my_hash_search(&global_thread_stats,
1618+ (uchar *) &(thd->thread_id),
1619+ sizeof(my_thread_id))))
1620+ {
1621+ // Found by thread ID
1622+ update_global_thread_stats_with_thread(thd, thread_stats, now);
1623+ }
1624+ else
1625+ {
1626+ // Create the entry
1627+ if (create_user)
1628+ {
1629+ increment_count_by_id(thd->thread_id,
1630+ &global_thread_stats, thd);
1631+ }
1632+ }
1633+ }
d4e9320e 1634+
b4e1fa2c
AM
1635+ thd->last_global_update_time = now;
1636+ thd->reset_diff_stats();
1637+
1638+ mysql_mutex_unlock(&LOCK_global_user_client_stats);
1639+ }
1640+ else
1641+ {
1642+ thd->reset_diff_stats();
d4e9320e
AM
1643+ }
1644+}
1645
1646 /*
1647 check if user has already too many connections
b4e1fa2c 1648@@ -169,6 +767,7 @@
d4e9320e 1649 if (error)
b4e1fa2c 1650 {
d4e9320e
AM
1651 uc->connections--; // no need for decrease_user_connections() here
1652+ statistic_increment(denied_connections, &LOCK_status);
b4e1fa2c
AM
1653 /*
1654 The thread may returned back to the pool and assigned to a user
1655 that doesn't have a limit. Ensure the user is not using resources
1656@@ -565,11 +1164,18 @@
d4e9320e
AM
1657 my_sleep(1000); /* must wait after eof() */
1658 #endif
1659 statistic_increment(aborted_connects,&LOCK_status);
1660+ thd->diff_denied_connections++;
1661 DBUG_RETURN(1);
1662 }
1663 /* Connect completed, set read/write timeouts back to default */
1664 my_net_set_read_timeout(net, thd->variables.net_read_timeout);
1665 my_net_set_write_timeout(net, thd->variables.net_write_timeout);
1666+
1667+ thd->reset_stats();
1668+ // Updates global user connection stats.
b4e1fa2c 1669+ if (increment_connection_count(thd, true))
d4e9320e 1670+ DBUG_RETURN(1);
d4e9320e
AM
1671+
1672 DBUG_RETURN(0);
1673 }
1674
b4e1fa2c 1675@@ -599,6 +1205,7 @@
d4e9320e
AM
1676 if (thd->killed || (net->error && net->vio != 0))
1677 {
1678 statistic_increment(aborted_threads,&LOCK_status);
1679+ thd->diff_lost_connections++;
1680 }
1681
1682 if (net->error && net->vio != 0)
d8778560 1683@@ -729,12 +1336,16 @@
d4e9320e
AM
1684 {
1685 NET *net= &thd->net;
d8778560 1686 bool rc;
d4e9320e
AM
1687+ bool create_user= TRUE;
1688
1689 lex_start(thd);
d8778560
AM
1690 rc= login_connection(thd);
1691 MYSQL_AUDIT_NOTIFY_CONNECTION_CONNECT(thd);
1692 if (rc)
d4e9320e
AM
1693+ {
1694+ create_user= FALSE;
1695 goto end_thread;
1696+ }
1697
d8778560 1698 MYSQL_CONNECTION_START(thd->thread_id, &thd->security_ctx->priv_user[0],
b4e1fa2c 1699 (char *) thd->security_ctx->host_or_ip);
d8778560 1700@@ -761,6 +1372,8 @@
d4e9320e
AM
1701
1702 end_thread:
d8778560 1703 close_connection(thd);
d4e9320e
AM
1704+ thd->update_stats(false);
1705+ update_global_user_stats(thd, create_user, time(NULL));
b4e1fa2c
AM
1706 if (MYSQL_CALLBACK_ELSE(thread_scheduler, end_thread, (thd, 1), 0))
1707 return; // Probably no-threads
d4e9320e
AM
1708
1709diff -ruN a/sql/sql_delete.cc b/sql/sql_delete.cc
b4e1fa2c
AM
1710--- a/sql/sql_delete.cc 2010-12-03 20:58:26.000000000 +0300
1711+++ b/sql/sql_delete.cc 2010-12-31 03:58:22.000000000 +0300
1712@@ -411,6 +411,7 @@
1713 my_ok(thd, deleted);
d4e9320e
AM
1714 DBUG_PRINT("info",("%ld records deleted",(long) deleted));
1715 }
b4e1fa2c 1716+ thd->updated_row_count+= deleted;
d4e9320e
AM
1717 DBUG_RETURN(error >= 0 || thd->is_error());
1718 }
1719
b4e1fa2c
AM
1720@@ -1005,6 +1006,7 @@
1721 {
1722 ::my_ok(thd, deleted);
d4e9320e 1723 }
b4e1fa2c 1724+ thd->updated_row_count+= deleted;
d4e9320e
AM
1725 return 0;
1726 }
1727
1728diff -ruN a/sql/sql_insert.cc b/sql/sql_insert.cc
b4e1fa2c
AM
1729--- a/sql/sql_insert.cc 2010-12-03 20:58:26.000000000 +0300
1730+++ b/sql/sql_insert.cc 2010-12-31 04:12:35.000000000 +0300
d8778560 1731@@ -1069,13 +1069,14 @@
b4e1fa2c
AM
1732
1733 if (error)
1734 goto abort;
1735+ ha_rows row_count;
1736 if (values_list.elements == 1 && (!(thd->variables.option_bits & OPTION_WARNINGS) ||
1737 !thd->cuted_fields))
1738 {
1739- my_ok(thd, info.copied + info.deleted +
1740+ row_count= info.copied + info.deleted +
1741 ((thd->client_capabilities & CLIENT_FOUND_ROWS) ?
1742- info.touched : info.updated),
1743- id);
1744+ info.touched : info.updated);
1745+ my_ok(thd, row_count, id);
d4e9320e 1746 }
b4e1fa2c
AM
1747 else
1748 {
d8778560 1749@@ -1091,8 +1092,10 @@
b4e1fa2c
AM
1750 sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
1751 (ulong) (info.deleted + updated),
1752 (ulong) thd->warning_info->statement_warn_count());
1753- ::my_ok(thd, info.copied + info.deleted + updated, id, buff);
1754+ row_count= info.copied + info.deleted + updated;
1755+ ::my_ok(thd, row_count, id, buff);
1756 }
1757+ thd->updated_row_count+= row_count;
d4e9320e
AM
1758 thd->abort_on_warning= 0;
1759 DBUG_RETURN(FALSE);
1760
d8778560 1761@@ -3539,6 +3542,7 @@
d4e9320e
AM
1762 thd->first_successful_insert_id_in_prev_stmt :
1763 (info.copied ? autoinc_value_of_last_inserted_row : 0));
b4e1fa2c
AM
1764 ::my_ok(thd, row_count, id, buff);
1765+ thd->updated_row_count+= row_count;
d4e9320e
AM
1766 DBUG_RETURN(0);
1767 }
1768
1769diff -ruN a/sql/sql_lex.h b/sql/sql_lex.h
b4e1fa2c
AM
1770--- a/sql/sql_lex.h 2010-12-03 20:58:26.000000000 +0300
1771+++ b/sql/sql_lex.h 2010-12-31 05:07:18.000000000 +0300
1772@@ -196,6 +196,9 @@
d4e9320e
AM
1773 When a command is added here, be sure it's also added in mysqld.cc
1774 in "struct show_var_st status_vars[]= {" ...
1775 */
1776+ // TODO(mcallaghan): update status_vars in mysqld to export these
1777+ SQLCOM_SHOW_USER_STATS, SQLCOM_SHOW_TABLE_STATS, SQLCOM_SHOW_INDEX_STATS,
1778+ SQLCOM_SHOW_CLIENT_STATS, SQLCOM_SHOW_THREAD_STATS,
1779 /* This should be the last !!! */
1780 SQLCOM_END
1781 };
1782diff -ruN a/sql/sql_parse.cc b/sql/sql_parse.cc
b4e1fa2c
AM
1783--- a/sql/sql_parse.cc 2010-12-03 20:58:26.000000000 +0300
1784+++ b/sql/sql_parse.cc 2010-12-31 04:57:45.000000000 +0300
1785@@ -116,6 +116,9 @@
d4e9320e 1786 static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables);
b4e1fa2c 1787 static void sql_kill(THD *thd, ulong id, bool only_kill_query);
d4e9320e
AM
1788
1789+// Uses the THD to update the global stats by user name and client IP
1790+void update_global_user_stats(THD* thd, bool create_user, time_t now);
1791+
1792 const char *any_db="*any*"; // Special symbol for check_access
1793
1794 const LEX_STRING command_name[]={
b4e1fa2c 1795@@ -701,6 +704,12 @@
d4e9320e
AM
1796 */
1797 thd->clear_error(); // Clear error message
b4e1fa2c
AM
1798 thd->stmt_da->reset_diagnostics_area();
1799+ thd->updated_row_count= 0;
1800+ thd->busy_time= 0;
1801+ thd->cpu_time= 0;
1802+ thd->bytes_received= 0;
1803+ thd->bytes_sent= 0;
1804+ thd->binlog_bytes_written= 0;
d4e9320e
AM
1805
1806 net_new_transaction(net);
1807
b4e1fa2c
AM
1808@@ -886,6 +895,10 @@
1809 (char *) thd->security_ctx->host_or_ip);
1810
d4e9320e 1811 thd->command=command;
b4e1fa2c
AM
1812+ /* To increment the corrent command counter for user stats, 'command' must
1813+ be saved because it is set to COM_SLEEP at the end of this function.
1814+ */
1815+ thd->old_command= command;
d4e9320e
AM
1816 /*
1817 Commands which always take a long time are logged into
1818 the slow log only if opt_log_slow_admin_statements is set.
d8778560 1819@@ -1626,6 +1639,13 @@
d4e9320e
AM
1820 thd->profiling.discard_current_query();
1821 #endif
1822 break;
1823+ case SCH_USER_STATS:
1824+ case SCH_CLIENT_STATS:
1825+ case SCH_THREAD_STATS:
1826+ if (check_global_access(thd, SUPER_ACL | PROCESS_ACL))
1827+ DBUG_RETURN(1);
1828+ case SCH_TABLE_STATS:
1829+ case SCH_INDEX_STATS:
1830 case SCH_OPEN_TABLES:
1831 case SCH_VARIABLES:
1832 case SCH_STATUS:
d8778560 1833@@ -1783,6 +1803,7 @@
d4e9320e
AM
1834 thd->security_ctx->priv_host)) &&
1835 check_global_access(thd, SUPER_ACL))
1836 {
1837+ thd->diff_access_denied_errors++;
1838 my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
1839 DBUG_RETURN(TRUE);
1840 }
d8778560 1841@@ -4725,6 +4746,7 @@
b4e1fa2c
AM
1842 case ACL_INTERNAL_ACCESS_DENIED:
1843 if (! no_errors)
1844 {
1845+ thd->diff_access_denied_errors++;
1846 my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
1847 sctx->priv_user, sctx->priv_host, db);
1848 }
d8778560 1849@@ -4775,6 +4797,7 @@
d4e9320e
AM
1850 DBUG_PRINT("error",("No possible access"));
1851 if (!no_errors)
b4e1fa2c 1852 {
d4e9320e 1853+ thd->diff_access_denied_errors++;
b4e1fa2c
AM
1854 if (thd->password == 2)
1855 my_error(ER_ACCESS_DENIED_NO_PASSWORD_ERROR, MYF(0),
1856 sctx->priv_user,
d8778560 1857@@ -4891,6 +4914,7 @@
d4e9320e
AM
1858
1859 if (!thd->col_access && check_grant_db(thd, dst_db_name))
1860 {
1861+ thd->diff_access_denied_errors++;
1862 my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
1863 thd->security_ctx->priv_user,
1864 thd->security_ctx->priv_host,
d8778560 1865@@ -5161,6 +5185,7 @@
d4e9320e
AM
1866 if ((thd->security_ctx->master_access & want_access))
1867 return 0;
1868 get_privilege_desc(command, sizeof(command), want_access);
1869+ thd->diff_access_denied_errors++;
1870 my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command);
1871 return 1;
1872 #else
d8778560 1873@@ -5542,6 +5567,32 @@
d4e9320e
AM
1874 lex_start(thd);
1875 mysql_reset_thd_for_next_command(thd);
1876
b4e1fa2c
AM
1877+ int start_time_error= 0;
1878+ int end_time_error= 0;
d4e9320e 1879+ struct timeval start_time, end_time;
b4e1fa2c
AM
1880+ double start_usecs= 0;
1881+ double end_usecs= 0;
d4e9320e 1882+ /* cpu time */
b4e1fa2c 1883+ int cputime_error= 0;
d4e9320e 1884+ struct timespec tp;
b4e1fa2c
AM
1885+ double start_cpu_nsecs= 0;
1886+ double end_cpu_nsecs= 0;
d4e9320e 1887+
a9ee80b9 1888+ if (opt_userstat)
b4e1fa2c 1889+ {
d4e9320e
AM
1890+#ifdef HAVE_CLOCK_GETTIME
1891+ /* get start cputime */
1892+ if (!(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp)))
1893+ start_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec;
d4e9320e
AM
1894+#endif
1895+
1896+ // Gets the start time, in order to measure how long this command takes.
b4e1fa2c
AM
1897+ if (!(start_time_error = gettimeofday(&start_time, NULL)))
1898+ {
d4e9320e
AM
1899+ start_usecs = start_time.tv_sec * 1000000.0 + start_time.tv_usec;
1900+ }
1901+ }
1902+
1903 if (query_cache_send_result_to_client(thd, rawbuf, length) <= 0)
1904 {
1905 LEX *lex= thd->lex;
d8778560 1906@@ -5610,6 +5661,52 @@
b4e1fa2c 1907 DBUG_ASSERT(thd->change_list.is_empty());
d4e9320e
AM
1908 }
1909
a9ee80b9 1910+ if (opt_userstat)
b4e1fa2c 1911+ {
d4e9320e 1912+ // Gets the end time.
b4e1fa2c
AM
1913+ if (!(end_time_error= gettimeofday(&end_time, NULL)))
1914+ {
1915+ end_usecs= end_time.tv_sec * 1000000.0 + end_time.tv_usec;
d4e9320e
AM
1916+ }
1917+
1918+ // Calculates the difference between the end and start times.
b4e1fa2c
AM
1919+ if (start_usecs && end_usecs >= start_usecs && !start_time_error && !end_time_error)
1920+ {
1921+ thd->busy_time= (end_usecs - start_usecs) / 1000000;
d4e9320e 1922+ // In case there are bad values, 2629743 is the #seconds in a month.
b4e1fa2c
AM
1923+ if (thd->busy_time > 2629743)
1924+ {
1925+ thd->busy_time= 0;
d4e9320e 1926+ }
b4e1fa2c
AM
1927+ }
1928+ else
1929+ {
d4e9320e 1930+ // end time went back in time, or gettimeofday() failed.
b4e1fa2c 1931+ thd->busy_time= 0;
d4e9320e
AM
1932+ }
1933+
1934+#ifdef HAVE_CLOCK_GETTIME
1935+ /* get end cputime */
1936+ if (!cputime_error &&
1937+ !(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp)))
1938+ end_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec;
1939+#endif
b4e1fa2c
AM
1940+ if (start_cpu_nsecs && !cputime_error)
1941+ {
d4e9320e
AM
1942+ thd->cpu_time = (end_cpu_nsecs - start_cpu_nsecs) / 1000000000;
1943+ // In case there are bad values, 2629743 is the #seconds in a month.
b4e1fa2c
AM
1944+ if (thd->cpu_time > 2629743)
1945+ {
d4e9320e
AM
1946+ thd->cpu_time = 0;
1947+ }
b4e1fa2c
AM
1948+ }
1949+ else
d4e9320e
AM
1950+ thd->cpu_time = 0;
1951+ }
1952+ // Updates THD stats and the global user stats.
1953+ thd->update_stats(true);
1954+ update_global_user_stats(thd, true, time(NULL));
1955+
1956 DBUG_VOID_RETURN;
1957 }
1958
d4e9320e 1959diff -ruN a/sql/sql_prepare.cc b/sql/sql_prepare.cc
b4e1fa2c
AM
1960--- a/sql/sql_prepare.cc 2010-12-03 20:58:26.000000000 +0300
1961+++ b/sql/sql_prepare.cc 2010-12-31 04:25:04.000000000 +0300
1962@@ -114,6 +114,9 @@
d4e9320e 1963 #endif
b4e1fa2c 1964 #include "lock.h" // MYSQL_OPEN_FORCE_SHARED_MDL
d4e9320e
AM
1965
1966+// Uses the THD to update the global stats by user name and client IP
1967+void update_global_user_stats(THD* thd, bool create_user, time_t now);
1968+
1969 /**
1970 A result class used to send cursor rows using the binary protocol.
1971 */
b4e1fa2c 1972@@ -2173,8 +2176,34 @@
d4e9320e
AM
1973 /* First of all clear possible warnings from the previous command */
1974 mysql_reset_thd_for_next_command(thd);
1975
b4e1fa2c
AM
1976+ int start_time_error= 0;
1977+ int end_time_error= 0;
d4e9320e 1978+ struct timeval start_time, end_time;
b4e1fa2c
AM
1979+ double start_usecs= 0;
1980+ double end_usecs= 0;
d4e9320e 1981+ /* cpu time */
b4e1fa2c 1982+ int cputime_error= 0;
d4e9320e 1983+ struct timespec tp;
b4e1fa2c
AM
1984+ double start_cpu_nsecs= 0;
1985+ double end_cpu_nsecs= 0;
d4e9320e 1986+
a9ee80b9 1987+ if (opt_userstat)
b4e1fa2c 1988+ {
d4e9320e
AM
1989+#ifdef HAVE_CLOCK_GETTIME
1990+ /* get start cputime */
b4e1fa2c
AM
1991+ if (!(cputime_error= clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp)))
1992+ start_cpu_nsecs= tp.tv_sec * 1000000000.0 + tp.tv_nsec;
d4e9320e
AM
1993+#endif
1994+
1995+ // Gets the start time, in order to measure how long this command takes.
b4e1fa2c
AM
1996+ if (!(start_time_error= gettimeofday(&start_time, NULL)))
1997+ {
1998+ start_usecs= start_time.tv_sec * 1000000.0 + start_time.tv_usec;
d4e9320e
AM
1999+ }
2000+ }
2001+
2002 if (! (stmt= new Prepared_statement(thd)))
2003- DBUG_VOID_RETURN; /* out of memory: error is set in Sql_alloc */
2004+ goto end; /* out of memory: error is set in Sql_alloc */
2005
2006 if (thd->stmt_map.insert(thd, stmt))
2007 {
b4e1fa2c 2008@@ -2182,7 +2211,7 @@
d4e9320e
AM
2009 The error is set in the insert. The statement itself
2010 will be also deleted there (this is how the hash works).
2011 */
2012- DBUG_VOID_RETURN;
2013+ goto end;
2014 }
2015
b4e1fa2c
AM
2016 thd->protocol= &thd->protocol_binary;
2017@@ -2196,6 +2225,53 @@
d4e9320e
AM
2018 thd->protocol= save_protocol;
2019
2020 /* check_prepared_statemnt sends the metadata packet in case of success */
2021+end:
a9ee80b9 2022+ if (opt_userstat)
b4e1fa2c 2023+ {
d4e9320e 2024+ // Gets the end time.
b4e1fa2c
AM
2025+ if (!(end_time_error= gettimeofday(&end_time, NULL)))
2026+ {
2027+ end_usecs= end_time.tv_sec * 1000000.0 + end_time.tv_usec;
d4e9320e
AM
2028+ }
2029+
2030+ // Calculates the difference between the end and start times.
b4e1fa2c
AM
2031+ if (start_usecs && end_usecs >= start_usecs && !start_time_error && !end_time_error)
2032+ {
2033+ thd->busy_time= (end_usecs - start_usecs) / 1000000;
d4e9320e 2034+ // In case there are bad values, 2629743 is the #seconds in a month.
b4e1fa2c
AM
2035+ if (thd->busy_time > 2629743)
2036+ {
2037+ thd->busy_time= 0;
d4e9320e 2038+ }
b4e1fa2c
AM
2039+ }
2040+ else
2041+ {
d4e9320e 2042+ // end time went back in time, or gettimeofday() failed.
b4e1fa2c 2043+ thd->busy_time= 0;
d4e9320e
AM
2044+ }
2045+
2046+#ifdef HAVE_CLOCK_GETTIME
2047+ /* get end cputime */
2048+ if (!cputime_error &&
b4e1fa2c
AM
2049+ !(cputime_error= clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp)))
2050+ end_cpu_nsecs= tp.tv_sec*1000000000.0+tp.tv_nsec;
d4e9320e 2051+#endif
b4e1fa2c
AM
2052+ if (start_cpu_nsecs && !cputime_error)
2053+ {
2054+ thd->cpu_time= (end_cpu_nsecs - start_cpu_nsecs) / 1000000000;
d4e9320e 2055+ // In case there are bad values, 2629743 is the #seconds in a month.
b4e1fa2c
AM
2056+ if (thd->cpu_time > 2629743)
2057+ {
2058+ thd->cpu_time= 0;
d4e9320e 2059+ }
b4e1fa2c
AM
2060+ }
2061+ else
d4e9320e
AM
2062+ thd->cpu_time = 0;
2063+ }
2064+ // Updates THD stats and the global user stats.
2065+ thd->update_stats(true);
2066+ update_global_user_stats(thd, true, time(NULL));
2067+
2068 DBUG_VOID_RETURN;
2069 }
2070
d8778560 2071@@ -2540,12 +2616,38 @@
d4e9320e
AM
2072 /* First of all clear possible warnings from the previous command */
2073 mysql_reset_thd_for_next_command(thd);
2074
b4e1fa2c
AM
2075+ int start_time_error= 0;
2076+ int end_time_error= 0;
d4e9320e 2077+ struct timeval start_time, end_time;
b4e1fa2c
AM
2078+ double start_usecs= 0;
2079+ double end_usecs= 0;
d4e9320e 2080+ /* cpu time */
b4e1fa2c 2081+ int cputime_error= 0;
d4e9320e 2082+ struct timespec tp;
b4e1fa2c
AM
2083+ double start_cpu_nsecs= 0;
2084+ double end_cpu_nsecs= 0;
d4e9320e 2085+
a9ee80b9 2086+ if (opt_userstat)
b4e1fa2c 2087+ {
d4e9320e
AM
2088+#ifdef HAVE_CLOCK_GETTIME
2089+ /* get start cputime */
2090+ if (!(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp)))
2091+ start_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec;
2092+#endif
2093+
2094+ // Gets the start time, in order to measure how long this command takes.
b4e1fa2c
AM
2095+ if (!(start_time_error = gettimeofday(&start_time, NULL)))
2096+ {
d4e9320e
AM
2097+ start_usecs = start_time.tv_sec * 1000000.0 + start_time.tv_usec;
2098+ }
2099+ }
2100+
2101 if (!(stmt= find_prepared_statement(thd, stmt_id)))
2102 {
2103 char llbuf[22];
2104 my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf),
2105 llstr(stmt_id, llbuf), "mysqld_stmt_execute");
2106- DBUG_VOID_RETURN;
2107+ goto end;
2108 }
2109
b4e1fa2c 2110 #if defined(ENABLED_PROFILING)
d8778560 2111@@ -2563,6 +2665,53 @@
d4e9320e
AM
2112 /* Close connection socket; for use with client testing (Bug#43560). */
2113 DBUG_EXECUTE_IF("close_conn_after_stmt_execute", vio_close(thd->net.vio););
2114
2115+end:
a9ee80b9 2116+ if (opt_userstat)
b4e1fa2c 2117+ {
d4e9320e 2118+ // Gets the end time.
b4e1fa2c
AM
2119+ if (!(end_time_error= gettimeofday(&end_time, NULL)))
2120+ {
2121+ end_usecs= end_time.tv_sec * 1000000.0 + end_time.tv_usec;
d4e9320e
AM
2122+ }
2123+
2124+ // Calculates the difference between the end and start times.
b4e1fa2c
AM
2125+ if (start_usecs && end_usecs >= start_usecs && !start_time_error && !end_time_error)
2126+ {
2127+ thd->busy_time= (end_usecs - start_usecs) / 1000000;
d4e9320e 2128+ // In case there are bad values, 2629743 is the #seconds in a month.
b4e1fa2c
AM
2129+ if (thd->busy_time > 2629743)
2130+ {
2131+ thd->busy_time= 0;
d4e9320e 2132+ }
b4e1fa2c
AM
2133+ }
2134+ else
2135+ {
d4e9320e 2136+ // end time went back in time, or gettimeofday() failed.
b4e1fa2c 2137+ thd->busy_time= 0;
d4e9320e
AM
2138+ }
2139+
2140+#ifdef HAVE_CLOCK_GETTIME
2141+ /* get end cputime */
2142+ if (!cputime_error &&
b4e1fa2c
AM
2143+ !(cputime_error= clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp)))
2144+ end_cpu_nsecs= tp.tv_sec*1000000000.0+tp.tv_nsec;
d4e9320e 2145+#endif
b4e1fa2c
AM
2146+ if (start_cpu_nsecs && !cputime_error)
2147+ {
2148+ thd->cpu_time= (end_cpu_nsecs - start_cpu_nsecs) / 1000000000;
d4e9320e 2149+ // In case there are bad values, 2629743 is the #seconds in a month.
b4e1fa2c
AM
2150+ if (thd->cpu_time > 2629743)
2151+ {
2152+ thd->cpu_time= 0;
d4e9320e 2153+ }
b4e1fa2c
AM
2154+ }
2155+ else
d4e9320e
AM
2156+ thd->cpu_time = 0;
2157+ }
2158+ // Updates THD stats and the global user stats.
2159+ thd->update_stats(true);
2160+ update_global_user_stats(thd, true, time(NULL));
2161+
2162 DBUG_VOID_RETURN;
d4e9320e 2163 }
b4e1fa2c 2164
d8778560 2165@@ -2635,20 +2784,47 @@
d4e9320e
AM
2166
2167 /* First of all clear possible warnings from the previous command */
2168 mysql_reset_thd_for_next_command(thd);
2169+
b4e1fa2c
AM
2170+ int start_time_error= 0;
2171+ int end_time_error= 0;
d4e9320e 2172+ struct timeval start_time, end_time;
b4e1fa2c
AM
2173+ double start_usecs= 0;
2174+ double end_usecs= 0;
d4e9320e 2175+ /* cpu time */
b4e1fa2c 2176+ int cputime_error= 0;
d4e9320e 2177+ struct timespec tp;
b4e1fa2c
AM
2178+ double start_cpu_nsecs= 0;
2179+ double end_cpu_nsecs= 0;
d4e9320e 2180+
a9ee80b9 2181+ if (opt_userstat)
b4e1fa2c 2182+ {
d4e9320e
AM
2183+#ifdef HAVE_CLOCK_GETTIME
2184+ /* get start cputime */
b4e1fa2c
AM
2185+ if (!(cputime_error= clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp)))
2186+ start_cpu_nsecs= tp.tv_sec*1000000000.0+tp.tv_nsec;
d4e9320e
AM
2187+#endif
2188+
2189+ // Gets the start time, in order to measure how long this command takes.
b4e1fa2c
AM
2190+ if (!(start_time_error= gettimeofday(&start_time, NULL)))
2191+ {
2192+ start_usecs= start_time.tv_sec * 1000000.0 + start_time.tv_usec;
d4e9320e
AM
2193+ }
2194+ }
2195+
2196 status_var_increment(thd->status_var.com_stmt_fetch);
2197 if (!(stmt= find_prepared_statement(thd, stmt_id)))
2198 {
2199 char llbuf[22];
2200 my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf),
2201 llstr(stmt_id, llbuf), "mysqld_stmt_fetch");
2202- DBUG_VOID_RETURN;
2203+ goto end;
2204 }
2205
2206 cursor= stmt->cursor;
2207 if (!cursor)
2208 {
2209 my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0), stmt_id);
2210- DBUG_VOID_RETURN;
2211+ goto end;
2212 }
2213
2214 thd->stmt_arena= stmt;
d8778560 2215@@ -2665,6 +2841,52 @@
d4e9320e
AM
2216 thd->restore_backup_statement(stmt, &stmt_backup);
2217 thd->stmt_arena= thd;
2218
2219+end:
a9ee80b9 2220+ if (opt_userstat)
b4e1fa2c 2221+ {
d4e9320e 2222+ // Gets the end time.
b4e1fa2c
AM
2223+ if (!(end_time_error = gettimeofday(&end_time, NULL)))
2224+ {
d4e9320e
AM
2225+ end_usecs = end_time.tv_sec * 1000000.0 + end_time.tv_usec;
2226+ }
2227+
2228+ // Calculates the difference between the end and start times.
b4e1fa2c
AM
2229+ if (start_usecs && end_usecs >= start_usecs && !start_time_error && !end_time_error)
2230+ {
2231+ thd->busy_time= (end_usecs - start_usecs) / 1000000;
d4e9320e 2232+ // In case there are bad values, 2629743 is the #seconds in a month.
b4e1fa2c
AM
2233+ if (thd->busy_time > 2629743)
2234+ {
2235+ thd->busy_time= 0;
d4e9320e 2236+ }
b4e1fa2c
AM
2237+ }
2238+ else
2239+ {
d4e9320e 2240+ // end time went back in time, or gettimeofday() failed.
b4e1fa2c 2241+ thd->busy_time= 0;
d4e9320e
AM
2242+ }
2243+
2244+#ifdef HAVE_CLOCK_GETTIME
2245+ /* get end cputime */
2246+ if (!cputime_error &&
b4e1fa2c
AM
2247+ !(cputime_error= clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp)))
2248+ end_cpu_nsecs= tp.tv_sec*1000000000.0+tp.tv_nsec;
d4e9320e 2249+#endif
b4e1fa2c
AM
2250+ if (start_cpu_nsecs && !cputime_error)
2251+ {
2252+ thd->cpu_time= (end_cpu_nsecs - start_cpu_nsecs) / 1000000000;
d4e9320e 2253+ // In case there are bad values, 2629743 is the #seconds in a month.
b4e1fa2c
AM
2254+ if (thd->cpu_time > 2629743)
2255+ {
2256+ thd->cpu_time= 0;
d4e9320e
AM
2257+ }
2258+ } else
b4e1fa2c 2259+ thd->cpu_time= 0;
d4e9320e
AM
2260+ }
2261+ // Updates THD stats and the global user stats.
2262+ thd->update_stats(true);
2263+ update_global_user_stats(thd, true, time(NULL));
2264+
2265 DBUG_VOID_RETURN;
2266 }
2267
d8778560 2268@@ -2695,13 +2917,39 @@
d4e9320e
AM
2269 /* First of all clear possible warnings from the previous command */
2270 mysql_reset_thd_for_next_command(thd);
2271
b4e1fa2c
AM
2272+ int start_time_error= 0;
2273+ int end_time_error= 0;
d4e9320e 2274+ struct timeval start_time, end_time;
b4e1fa2c
AM
2275+ double start_usecs= 0;
2276+ double end_usecs= 0;
d4e9320e 2277+ /* cpu time */
b4e1fa2c 2278+ int cputime_error= 0;
d4e9320e 2279+ struct timespec tp;
b4e1fa2c
AM
2280+ double start_cpu_nsecs= 0;
2281+ double end_cpu_nsecs= 0;
d4e9320e 2282+
a9ee80b9 2283+ if (opt_userstat)
b4e1fa2c 2284+ {
d4e9320e
AM
2285+#ifdef HAVE_CLOCK_GETTIME
2286+ /* get start cputime */
b4e1fa2c
AM
2287+ if (!(cputime_error= clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp)))
2288+ start_cpu_nsecs= tp.tv_sec * 1000000000.0+tp.tv_nsec;
d4e9320e
AM
2289+#endif
2290+
2291+ // Gets the start time, in order to measure how long this command takes.
b4e1fa2c
AM
2292+ if (!(start_time_error= gettimeofday(&start_time, NULL)))
2293+ {
2294+ start_usecs= start_time.tv_sec * 1000000.0 + start_time.tv_usec;
d4e9320e
AM
2295+ }
2296+ }
2297+
2298 status_var_increment(thd->status_var.com_stmt_reset);
2299 if (!(stmt= find_prepared_statement(thd, stmt_id)))
2300 {
2301 char llbuf[22];
2302 my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf),
2303 llstr(stmt_id, llbuf), "mysqld_stmt_reset");
2304- DBUG_VOID_RETURN;
2305+ goto end;
2306 }
2307
2308 stmt->close_cursor();
d8778560 2309@@ -2718,6 +2966,53 @@
d4e9320e
AM
2310
2311 my_ok(thd);
2312
2313+end:
a9ee80b9 2314+ if (opt_userstat)
b4e1fa2c 2315+ {
d4e9320e 2316+ // Gets the end time.
b4e1fa2c
AM
2317+ if (!(end_time_error = gettimeofday(&end_time, NULL)))
2318+ {
d4e9320e
AM
2319+ end_usecs = end_time.tv_sec * 1000000.0 + end_time.tv_usec;
2320+ }
2321+
2322+ // Calculates the difference between the end and start times.
b4e1fa2c
AM
2323+ if (start_usecs && end_usecs >= start_usecs && !start_time_error && !end_time_error)
2324+ {
2325+ thd->busy_time= (end_usecs - start_usecs) / 1000000;
d4e9320e 2326+ // In case there are bad values, 2629743 is the #seconds in a month.
b4e1fa2c
AM
2327+ if (thd->busy_time > 2629743)
2328+ {
2329+ thd->busy_time= 0;
d4e9320e 2330+ }
b4e1fa2c
AM
2331+ }
2332+ else
2333+ {
d4e9320e 2334+ // end time went back in time, or gettimeofday() failed.
b4e1fa2c 2335+ thd->busy_time= 0;
d4e9320e
AM
2336+ }
2337+
2338+#ifdef HAVE_CLOCK_GETTIME
2339+ /* get end cputime */
2340+ if (!cputime_error &&
2341+ !(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp)))
2342+ end_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec;
2343+#endif
b4e1fa2c
AM
2344+ if (start_cpu_nsecs && !cputime_error)
2345+ {
d4e9320e
AM
2346+ thd->cpu_time = (end_cpu_nsecs - start_cpu_nsecs) / 1000000000;
2347+ // In case there are bad values, 2629743 is the #seconds in a month.
b4e1fa2c
AM
2348+ if (thd->cpu_time > 2629743)
2349+ {
2350+ thd->cpu_time= 0;
d4e9320e 2351+ }
b4e1fa2c
AM
2352+ }
2353+ else
2354+ thd->cpu_time= 0;
d4e9320e
AM
2355+ }
2356+ // Updates THD stats and the global user stats.
2357+ thd->update_stats(true);
2358+ update_global_user_stats(thd, true, time(NULL));
2359+
2360 DBUG_VOID_RETURN;
2361 }
2362
b4e1fa2c
AM
2363diff -ruN a/sql/sql_reload.cc b/sql/sql_reload.cc
2364--- a/sql/sql_reload.cc 2010-12-03 20:58:26.000000000 +0300
2365+++ b/sql/sql_reload.cc 2010-12-31 05:00:59.000000000 +0300
d8778560 2366@@ -280,14 +280,48 @@
b4e1fa2c
AM
2367 mysql_mutex_unlock(&LOCK_active_mi);
2368 }
2369 #endif
2370- if (options & REFRESH_USER_RESOURCES)
2371- reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
2372 #ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
2373 if (options & REFRESH_QUERY_RESPONSE_TIME)
2374 {
2375 query_response_time_flush();
2376 }
2377 #endif // HAVE_RESPONSE_TIME_DISTRIBUTION
2378+ if (options & REFRESH_USER_RESOURCES)
2379+ reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
2380+ if (options & REFRESH_TABLE_STATS)
2381+ {
2382+ mysql_mutex_lock(&LOCK_global_table_stats);
2383+ free_global_table_stats();
2384+ init_global_table_stats();
2385+ mysql_mutex_unlock(&LOCK_global_table_stats);
2386+ }
2387+ if (options & REFRESH_INDEX_STATS)
2388+ {
2389+ mysql_mutex_lock(&LOCK_global_index_stats);
2390+ free_global_index_stats();
2391+ init_global_index_stats();
2392+ mysql_mutex_unlock(&LOCK_global_index_stats);
2393+ }
2394+ if (options & (REFRESH_USER_STATS | REFRESH_CLIENT_STATS | REFRESH_THREAD_STATS))
2395+ {
2396+ mysql_mutex_lock(&LOCK_global_user_client_stats);
2397+ if (options & REFRESH_USER_STATS)
2398+ {
2399+ free_global_user_stats();
2400+ init_global_user_stats();
2401+ }
2402+ if (options & REFRESH_CLIENT_STATS)
2403+ {
2404+ free_global_client_stats();
2405+ init_global_client_stats();
2406+ }
2407+ if (options & REFRESH_THREAD_STATS)
2408+ {
2409+ free_global_thread_stats();
2410+ init_global_thread_stats();
2411+ }
2412+ mysql_mutex_unlock(&LOCK_global_user_client_stats);
2413+ }
d8778560
AM
2414 if (*write_to_binlog != -1)
2415 *write_to_binlog= tmp_write_to_binlog;
b4e1fa2c 2416 /*
d4e9320e 2417diff -ruN a/sql/sql_show.cc b/sql/sql_show.cc
b4e1fa2c
AM
2418--- a/sql/sql_show.cc 2010-12-03 20:58:26.000000000 +0300
2419+++ b/sql/sql_show.cc 2010-12-31 04:39:23.000000000 +0300
2420@@ -114,6 +114,43 @@
d4e9320e
AM
2421
2422 static COND * make_cond_for_info_schema(COND *cond, TABLE_LIST *table);
2423
2424+/*
b4e1fa2c
AM
2425+ * Solaris 10 does not have strsep().
2426+ *
d4e9320e
AM
2427+ * based on getToken from http://www.winehq.org/pipermail/wine-patches/2001-November/001322.html
2428+ *
b4e1fa2c 2429+*/
d4e9320e
AM
2430+
2431+#ifndef HAVE_STRSEP
2432+static char* strsep(char** str, const char* delims)
2433+{
2434+ char *token;
2435+
b4e1fa2c
AM
2436+ if (*str == NULL)
2437+ {
d4e9320e
AM
2438+ /* No more tokens */
2439+ return NULL;
2440+ }
2441+
b4e1fa2c
AM
2442+ token= *str;
2443+ while (**str != '\0')
2444+ {
2445+ if (strchr(delims, **str) != NULL)
2446+ {
2447+ **str= '\0';
d4e9320e
AM
2448+ (*str)++;
2449+ return token;
2450+ }
2451+ (*str)++;
2452+ }
2453+
2454+ /* There is not another token */
b4e1fa2c 2455+ *str= NULL;
d4e9320e
AM
2456+
2457+ return token;
2458+}
2459+#endif
2460+
2461 /***************************************************************************
2462 ** List all table types supported
2463 ***************************************************************************/
b4e1fa2c 2464@@ -799,6 +836,7 @@
d4e9320e
AM
2465 sctx->master_access);
2466 if (!(db_access & DB_ACLS) && check_grant_db(thd,dbname))
2467 {
2468+ thd->diff_access_denied_errors++;
2469 my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
2470 sctx->priv_user, sctx->host_or_ip, dbname);
2471 general_log_print(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
b4e1fa2c 2472@@ -2351,6 +2389,284 @@
d4e9320e
AM
2473 DBUG_RETURN(res);
2474 }
2475
2476+/*
2477+ Write result to network for SHOW USER_STATISTICS
2478+
2479+ SYNOPSIS
2480+ send_user_stats
2481+ all_user_stats - values to return
2482+ table - I_S table
2483+
2484+ RETURN
2485+ 0 - OK
2486+ 1 - error
b4e1fa2c 2487+*/
d4e9320e
AM
2488+int send_user_stats(THD* thd, HASH *all_user_stats, TABLE *table)
2489+{
2490+ DBUG_ENTER("send_user_stats");
b4e1fa2c
AM
2491+ for (uint i = 0; i < all_user_stats->records; ++i)
2492+ {
d4e9320e 2493+ restore_record(table, s->default_values);
b4e1fa2c 2494+ USER_STATS *user_stats = (USER_STATS *) my_hash_element(all_user_stats, i);
d4e9320e
AM
2495+ table->field[0]->store(user_stats->user, strlen(user_stats->user), system_charset_info);
2496+ table->field[1]->store((longlong)user_stats->total_connections);
2497+ table->field[2]->store((longlong)user_stats->concurrent_connections);
2498+ table->field[3]->store((longlong)user_stats->connected_time);
2499+ table->field[4]->store((longlong)user_stats->busy_time);
2500+ table->field[5]->store((longlong)user_stats->cpu_time);
2501+ table->field[6]->store((longlong)user_stats->bytes_received);
2502+ table->field[7]->store((longlong)user_stats->bytes_sent);
2503+ table->field[8]->store((longlong)user_stats->binlog_bytes_written);
2504+ table->field[9]->store((longlong)user_stats->rows_fetched);
2505+ table->field[10]->store((longlong)user_stats->rows_updated);
2506+ table->field[11]->store((longlong)user_stats->rows_read);
2507+ table->field[12]->store((longlong)user_stats->select_commands);
2508+ table->field[13]->store((longlong)user_stats->update_commands);
2509+ table->field[14]->store((longlong)user_stats->other_commands);
2510+ table->field[15]->store((longlong)user_stats->commit_trans);
2511+ table->field[16]->store((longlong)user_stats->rollback_trans);
2512+ table->field[17]->store((longlong)user_stats->denied_connections);
2513+ table->field[18]->store((longlong)user_stats->lost_connections);
2514+ table->field[19]->store((longlong)user_stats->access_denied_errors);
2515+ table->field[20]->store((longlong)user_stats->empty_queries);
2516+ if (schema_table_store_record(thd, table))
2517+ {
2518+ DBUG_PRINT("error", ("store record error"));
2519+ DBUG_RETURN(1);
2520+ }
2521+ }
2522+ DBUG_RETURN(0);
2523+}
2524+
2525+int send_thread_stats(THD* thd, HASH *all_thread_stats, TABLE *table)
2526+{
2527+ DBUG_ENTER("send_thread_stats");
b4e1fa2c
AM
2528+ for (uint i = 0; i < all_thread_stats->records; ++i)
2529+ {
d4e9320e 2530+ restore_record(table, s->default_values);
b4e1fa2c 2531+ THREAD_STATS *user_stats = (THREAD_STATS *) my_hash_element(all_thread_stats, i);
d4e9320e
AM
2532+ table->field[0]->store((longlong)user_stats->id);
2533+ table->field[1]->store((longlong)user_stats->total_connections);
2534+ table->field[2]->store((longlong)user_stats->concurrent_connections);
2535+ table->field[3]->store((longlong)user_stats->connected_time);
2536+ table->field[4]->store((longlong)user_stats->busy_time);
2537+ table->field[5]->store((longlong)user_stats->cpu_time);
2538+ table->field[6]->store((longlong)user_stats->bytes_received);
2539+ table->field[7]->store((longlong)user_stats->bytes_sent);
2540+ table->field[8]->store((longlong)user_stats->binlog_bytes_written);
2541+ table->field[9]->store((longlong)user_stats->rows_fetched);
2542+ table->field[10]->store((longlong)user_stats->rows_updated);
2543+ table->field[11]->store((longlong)user_stats->rows_read);
2544+ table->field[12]->store((longlong)user_stats->select_commands);
2545+ table->field[13]->store((longlong)user_stats->update_commands);
2546+ table->field[14]->store((longlong)user_stats->other_commands);
2547+ table->field[15]->store((longlong)user_stats->commit_trans);
2548+ table->field[16]->store((longlong)user_stats->rollback_trans);
2549+ table->field[17]->store((longlong)user_stats->denied_connections);
2550+ table->field[18]->store((longlong)user_stats->lost_connections);
2551+ table->field[19]->store((longlong)user_stats->access_denied_errors);
2552+ table->field[20]->store((longlong)user_stats->empty_queries);
2553+ if (schema_table_store_record(thd, table))
2554+ {
2555+ DBUG_PRINT("error", ("store record error"));
2556+ DBUG_RETURN(1);
2557+ }
2558+ }
2559+ DBUG_RETURN(0);
2560+}
2561+
2562+/*
2563+ Process SHOW USER_STATISTICS
2564+
2565+ SYNOPSIS
2566+ mysqld_show_user_stats
2567+ thd - current thread
2568+ wild - limit results to the entry for this user
2569+ with_roles - when true, display role for mapped users
2570+
2571+ RETURN
2572+ 0 - OK
2573+ 1 - error
b4e1fa2c 2574+*/
d4e9320e
AM
2575+
2576+
2577+int fill_schema_user_stats(THD* thd, TABLE_LIST* tables, COND* cond)
2578+{
2579+ TABLE *table= tables->table;
2580+ DBUG_ENTER("fill_schema_user_stats");
2581+
2582+ if (check_global_access(thd, SUPER_ACL | PROCESS_ACL))
2583+ DBUG_RETURN(1);
2584+
2585+ // Iterates through all the global stats and sends them to the client.
2586+ // Pattern matching on the client IP is supported.
2587+
b4e1fa2c 2588+ mysql_mutex_lock(&LOCK_global_user_client_stats);
d4e9320e 2589+ int result= send_user_stats(thd, &global_user_stats, table);
b4e1fa2c 2590+ mysql_mutex_unlock(&LOCK_global_user_client_stats);
d4e9320e
AM
2591+ if (result)
2592+ goto err;
2593+
2594+ DBUG_PRINT("exit", ("fill_schema_user_stats result is 0"));
2595+ DBUG_RETURN(0);
2596+
2597+ err:
2598+ DBUG_PRINT("exit", ("fill_schema_user_stats result is 1"));
2599+ DBUG_RETURN(1);
2600+}
2601+
2602+/*
2603+ Process SHOW CLIENT_STATISTICS
2604+
2605+ SYNOPSIS
2606+ mysqld_show_client_stats
2607+ thd - current thread
2608+ wild - limit results to the entry for this client
2609+
2610+ RETURN
2611+ 0 - OK
2612+ 1 - error
b4e1fa2c 2613+*/
d4e9320e
AM
2614+
2615+
2616+int fill_schema_client_stats(THD* thd, TABLE_LIST* tables, COND* cond)
2617+{
2618+ TABLE *table= tables->table;
2619+ DBUG_ENTER("fill_schema_client_stats");
2620+
2621+ if (check_global_access(thd, SUPER_ACL | PROCESS_ACL))
2622+ DBUG_RETURN(1);
2623+
2624+ // Iterates through all the global stats and sends them to the client.
2625+ // Pattern matching on the client IP is supported.
2626+
b4e1fa2c 2627+ mysql_mutex_lock(&LOCK_global_user_client_stats);
d4e9320e 2628+ int result= send_user_stats(thd, &global_client_stats, table);
b4e1fa2c 2629+ mysql_mutex_unlock(&LOCK_global_user_client_stats);
d4e9320e
AM
2630+ if (result)
2631+ goto err;
2632+
2633+ DBUG_PRINT("exit", ("mysqld_show_client_stats result is 0"));
2634+ DBUG_RETURN(0);
2635+
2636+ err:
2637+ DBUG_PRINT("exit", ("mysqld_show_client_stats result is 1"));
2638+ DBUG_RETURN(1);
2639+}
2640+
2641+int fill_schema_thread_stats(THD* thd, TABLE_LIST* tables, COND* cond)
2642+{
2643+ TABLE *table= tables->table;
2644+ DBUG_ENTER("fill_schema_thread_stats");
2645+
2646+ if (check_global_access(thd, SUPER_ACL | PROCESS_ACL))
2647+ DBUG_RETURN(1);
2648+
2649+ // Iterates through all the global stats and sends them to the client.
2650+ // Pattern matching on the client IP is supported.
2651+
b4e1fa2c 2652+ mysql_mutex_lock(&LOCK_global_user_client_stats);
d4e9320e 2653+ int result= send_thread_stats(thd, &global_thread_stats, table);
b4e1fa2c 2654+ mysql_mutex_unlock(&LOCK_global_user_client_stats);
d4e9320e
AM
2655+ if (result)
2656+ goto err;
2657+
2658+ DBUG_PRINT("exit", ("mysqld_show_thread_stats result is 0"));
2659+ DBUG_RETURN(0);
2660+
2661+ err:
2662+ DBUG_PRINT("exit", ("mysqld_show_thread_stats result is 1"));
2663+ DBUG_RETURN(1);
2664+}
2665+
2666+// Sends the global table stats back to the client.
2667+int fill_schema_table_stats(THD* thd, TABLE_LIST* tables, COND* cond)
2668+{
2669+ TABLE *table= tables->table;
2670+ DBUG_ENTER("fill_schema_table_stats");
2671+ char *table_full_name, *table_schema;
2672+
b4e1fa2c
AM
2673+ mysql_mutex_lock(&LOCK_global_table_stats);
2674+ for (uint i = 0; i < global_table_stats.records; ++i)
2675+ {
d4e9320e 2676+ restore_record(table, s->default_values);
b4e1fa2c
AM
2677+ TABLE_STATS *table_stats =
2678+ (TABLE_STATS *) my_hash_element(&global_table_stats, i);
d4e9320e
AM
2679+
2680+ table_full_name= thd->strdup(table_stats->table);
2681+ table_schema= strsep(&table_full_name, ".");
2682+
2683+ TABLE_LIST tmp_table;
b4e1fa2c 2684+ bzero((char *) &tmp_table,sizeof(tmp_table));
d4e9320e
AM
2685+ tmp_table.table_name= table_full_name;
2686+ tmp_table.db= table_schema;
2687+ tmp_table.grant.privilege= 0;
b4e1fa2c 2688+ if (check_access(thd, SELECT_ACL, tmp_table.db,
d4e9320e 2689+ &tmp_table.grant.privilege, 0, 0,
b4e1fa2c 2690+ is_infoschema_db(table_schema)) ||
d4e9320e
AM
2691+ check_grant(thd, SELECT_ACL, &tmp_table, 1, UINT_MAX, 1))
2692+ continue;
2693+
2694+ table->field[0]->store(table_schema, strlen(table_schema), system_charset_info);
2695+ table->field[1]->store(table_full_name, strlen(table_full_name), system_charset_info);
2696+ table->field[2]->store((longlong)table_stats->rows_read, TRUE);
2697+ table->field[3]->store((longlong)table_stats->rows_changed, TRUE);
2698+ table->field[4]->store((longlong)table_stats->rows_changed_x_indexes, TRUE);
2699+
2700+ if (schema_table_store_record(thd, table))
2701+ {
b4e1fa2c 2702+ mysql_mutex_unlock(&LOCK_global_table_stats);
d4e9320e
AM
2703+ DBUG_RETURN(1);
2704+ }
2705+ }
b4e1fa2c 2706+ mysql_mutex_unlock(&LOCK_global_table_stats);
d4e9320e
AM
2707+ DBUG_RETURN(0);
2708+}
2709+
2710+// Sends the global index stats back to the client.
2711+int fill_schema_index_stats(THD* thd, TABLE_LIST* tables, COND* cond)
2712+{
2713+ TABLE *table= tables->table;
2714+ DBUG_ENTER("fill_schema_index_stats");
2715+ char *index_full_name, *table_schema, *table_name;
2716+
b4e1fa2c
AM
2717+ mysql_mutex_lock(&LOCK_global_index_stats);
2718+ for (uint i = 0; i < global_index_stats.records; ++i)
2719+ {
d4e9320e
AM
2720+ restore_record(table, s->default_values);
2721+ INDEX_STATS *index_stats =
b4e1fa2c 2722+ (INDEX_STATS *) my_hash_element(&global_index_stats, i);
d4e9320e
AM
2723+
2724+ index_full_name= thd->strdup(index_stats->index);
2725+ table_schema= strsep(&index_full_name, ".");
2726+ table_name= strsep(&index_full_name, ".");
2727+
2728+ TABLE_LIST tmp_table;
b4e1fa2c 2729+ bzero((char *) &tmp_table,sizeof(tmp_table));
d4e9320e
AM
2730+ tmp_table.table_name= table_name;
2731+ tmp_table.db= table_schema;
2732+ tmp_table.grant.privilege= 0;
b4e1fa2c 2733+ if (check_access(thd, SELECT_ACL, tmp_table.db,
d4e9320e 2734+ &tmp_table.grant.privilege, 0, 0,
b4e1fa2c 2735+ is_infoschema_db(table_schema)) ||
d4e9320e
AM
2736+ check_grant(thd, SELECT_ACL, &tmp_table, 1, UINT_MAX, 1))
2737+ continue;
2738+
2739+ table->field[0]->store(table_schema, strlen(table_schema), system_charset_info);
2740+ table->field[1]->store(table_name, strlen(table_name), system_charset_info);
2741+ table->field[2]->store(index_full_name, strlen(index_full_name), system_charset_info);
2742+ table->field[3]->store((longlong)index_stats->rows_read, TRUE);
2743+
2744+ if (schema_table_store_record(thd, table))
b4e1fa2c
AM
2745+ {
2746+ mysql_mutex_unlock(&LOCK_global_index_stats);
d4e9320e
AM
2747+ DBUG_RETURN(1);
2748+ }
2749+ }
b4e1fa2c 2750+ mysql_mutex_unlock(&LOCK_global_index_stats);
d4e9320e
AM
2751+ DBUG_RETURN(0);
2752+}
b4e1fa2c 2753+
d4e9320e
AM
2754
2755 /* collect status for all running threads */
2756
d8778560 2757@@ -7512,6 +7828,104 @@
d4e9320e
AM
2758 };
2759
2760
2761+ST_FIELD_INFO user_stats_fields_info[]=
2762+{
2763+ {"USER", USERNAME_LENGTH, MYSQL_TYPE_STRING, 0, 0, "User", SKIP_OPEN_TABLE},
2764+ {"TOTAL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Total_connections", SKIP_OPEN_TABLE},
2765+ {"CONCURRENT_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Concurrent_connections", SKIP_OPEN_TABLE},
2766+ {"CONNECTED_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Connected_time", SKIP_OPEN_TABLE},
2767+ {"BUSY_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Busy_time", SKIP_OPEN_TABLE},
2768+ {"CPU_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Cpu_time", SKIP_OPEN_TABLE},
2769+ {"BYTES_RECEIVED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Bytes_received", SKIP_OPEN_TABLE},
2770+ {"BYTES_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Bytes_sent", SKIP_OPEN_TABLE},
2771+ {"BINLOG_BYTES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Binlog_bytes_written", SKIP_OPEN_TABLE},
2772+ {"ROWS_FETCHED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_fetched", SKIP_OPEN_TABLE},
2773+ {"ROWS_UPDATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_updated", SKIP_OPEN_TABLE},
2774+ {"TABLE_ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Table_rows_read", SKIP_OPEN_TABLE},
2775+ {"SELECT_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Select_commands", SKIP_OPEN_TABLE},
2776+ {"UPDATE_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Update_commands", SKIP_OPEN_TABLE},
2777+ {"OTHER_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Other_commands", SKIP_OPEN_TABLE},
2778+ {"COMMIT_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Commit_transactions", SKIP_OPEN_TABLE},
2779+ {"ROLLBACK_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rollback_transactions", SKIP_OPEN_TABLE},
2780+ {"DENIED_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Denied_connections", SKIP_OPEN_TABLE},
2781+ {"LOST_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Lost_connections", SKIP_OPEN_TABLE},
2782+ {"ACCESS_DENIED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Access_denied", SKIP_OPEN_TABLE},
2783+ {"EMPTY_QUERIES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Empty_queries", SKIP_OPEN_TABLE},
2784+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
2785+};
2786+
2787+ST_FIELD_INFO client_stats_fields_info[]=
2788+{
2789+ {"CLIENT", LIST_PROCESS_HOST_LEN, MYSQL_TYPE_STRING, 0, 0, "Client", SKIP_OPEN_TABLE},
2790+ {"TOTAL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Total_connections", SKIP_OPEN_TABLE},
2791+ {"CONCURRENT_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Concurrent_connections", SKIP_OPEN_TABLE},
2792+ {"CONNECTED_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Connected_time", SKIP_OPEN_TABLE},
2793+ {"BUSY_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Busy_time", SKIP_OPEN_TABLE},
2794+ {"CPU_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Cpu_time", SKIP_OPEN_TABLE},
2795+ {"BYTES_RECEIVED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Bytes_received", SKIP_OPEN_TABLE},
2796+ {"BYTES_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Bytes_sent", SKIP_OPEN_TABLE},
2797+ {"BINLOG_BYTES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Binlog_bytes_written", SKIP_OPEN_TABLE},
2798+ {"ROWS_FETCHED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_fetched", SKIP_OPEN_TABLE},
2799+ {"ROWS_UPDATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_updated", SKIP_OPEN_TABLE},
2800+ {"TABLE_ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Table_rows_read", SKIP_OPEN_TABLE},
2801+ {"SELECT_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Select_commands", SKIP_OPEN_TABLE},
2802+ {"UPDATE_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Update_commands", SKIP_OPEN_TABLE},
2803+ {"OTHER_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Other_commands", SKIP_OPEN_TABLE},
2804+ {"COMMIT_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Commit_transactions", SKIP_OPEN_TABLE},
2805+ {"ROLLBACK_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rollback_transactions", SKIP_OPEN_TABLE},
2806+ {"DENIED_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Denied_connections", SKIP_OPEN_TABLE},
2807+ {"LOST_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Lost_connections", SKIP_OPEN_TABLE},
2808+ {"ACCESS_DENIED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Access_denied", SKIP_OPEN_TABLE},
2809+ {"EMPTY_QUERIES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Empty_queries", SKIP_OPEN_TABLE},
2810+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
2811+};
2812+
2813+ST_FIELD_INFO thread_stats_fields_info[]=
2814+{
2815+ {"THREAD_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Thread_id", SKIP_OPEN_TABLE},
2816+ {"TOTAL_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Total_connections", SKIP_OPEN_TABLE},
2817+ {"CONCURRENT_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Concurrent_connections", SKIP_OPEN_TABLE},
2818+ {"CONNECTED_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Connected_time", SKIP_OPEN_TABLE},
2819+ {"BUSY_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Busy_time", SKIP_OPEN_TABLE},
2820+ {"CPU_TIME", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Cpu_time", SKIP_OPEN_TABLE},
2821+ {"BYTES_RECEIVED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Bytes_received", SKIP_OPEN_TABLE},
2822+ {"BYTES_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Bytes_sent", SKIP_OPEN_TABLE},
2823+ {"BINLOG_BYTES_WRITTEN", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Binlog_bytes_written", SKIP_OPEN_TABLE},
2824+ {"ROWS_FETCHED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_fetched", SKIP_OPEN_TABLE},
2825+ {"ROWS_UPDATED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_updated", SKIP_OPEN_TABLE},
2826+ {"TABLE_ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Table_rows_read", SKIP_OPEN_TABLE},
2827+ {"SELECT_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Select_commands", SKIP_OPEN_TABLE},
2828+ {"UPDATE_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Update_commands", SKIP_OPEN_TABLE},
2829+ {"OTHER_COMMANDS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Other_commands", SKIP_OPEN_TABLE},
2830+ {"COMMIT_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Commit_transactions", SKIP_OPEN_TABLE},
2831+ {"ROLLBACK_TRANSACTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rollback_transactions", SKIP_OPEN_TABLE},
2832+ {"DENIED_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Denied_connections", SKIP_OPEN_TABLE},
2833+ {"LOST_CONNECTIONS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Lost_connections", SKIP_OPEN_TABLE},
2834+ {"ACCESS_DENIED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Access_denied", SKIP_OPEN_TABLE},
2835+ {"EMPTY_QUERIES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Empty_queries", SKIP_OPEN_TABLE},
2836+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
2837+};
2838+
2839+ST_FIELD_INFO table_stats_fields_info[]=
2840+{
2841+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_schema", SKIP_OPEN_TABLE},
2842+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_name", SKIP_OPEN_TABLE},
2843+ {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_read", SKIP_OPEN_TABLE},
2844+ {"ROWS_CHANGED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_changed", SKIP_OPEN_TABLE},
2845+ {"ROWS_CHANGED_X_INDEXES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_changed_x_#indexes", SKIP_OPEN_TABLE},
2846+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
2847+};
2848+
2849+ST_FIELD_INFO index_stats_fields_info[]=
2850+{
2851+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_schema", SKIP_OPEN_TABLE},
2852+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_name", SKIP_OPEN_TABLE},
2853+ {"INDEX_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Index_name", SKIP_OPEN_TABLE},
2854+ {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Rows_read", SKIP_OPEN_TABLE},
2855+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
2856+};
2857+
2858+
2859 ST_FIELD_INFO processlist_fields_info[]=
2860 {
2861 {"ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Id", SKIP_OPEN_TABLE},
d8778560 2862@@ -7701,6 +8115,8 @@
d4e9320e
AM
2863 {
2864 {"CHARACTER_SETS", charsets_fields_info, create_schema_table,
2865 fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0, 0},
b4e1fa2c 2866+ {"CLIENT_STATISTICS", client_stats_fields_info, create_schema_table,
d4e9320e
AM
2867+ fill_schema_client_stats, make_old_format, 0, -1, -1, 0, 0},
2868 {"COLLATIONS", collation_fields_info, create_schema_table,
2869 fill_schema_collation, make_old_format, 0, -1, -1, 0, 0},
2870 {"COLLATION_CHARACTER_SET_APPLICABILITY", coll_charset_app_fields_info,
d8778560 2871@@ -7710,6 +8126,8 @@
d4e9320e
AM
2872 OPTIMIZE_I_S_TABLE|OPEN_VIEW_FULL},
2873 {"COLUMN_PRIVILEGES", column_privileges_fields_info, create_schema_table,
2874 fill_schema_column_privileges, 0, 0, -1, -1, 0, 0},
2875+ {"INDEX_STATISTICS", index_stats_fields_info, create_schema_table,
2876+ fill_schema_index_stats, make_old_format, 0, -1, -1, 0, 0},
2877 {"ENGINES", engines_fields_info, create_schema_table,
2878 fill_schema_engines, make_old_format, 0, -1, -1, 0, 0},
2879 #ifdef HAVE_EVENT_SCHEDULER
d8778560 2880@@ -7782,14 +8200,20 @@
d4e9320e
AM
2881 get_all_tables, make_table_names_old_format, 0, 1, 2, 1, 0},
2882 {"TABLE_PRIVILEGES", table_privileges_fields_info, create_schema_table,
2883 fill_schema_table_privileges, 0, 0, -1, -1, 0, 0},
2884+ {"TABLE_STATISTICS", table_stats_fields_info, create_schema_table,
2885+ fill_schema_table_stats, make_old_format, 0, -1, -1, 0, 0},
b4e1fa2c
AM
2886 {"TEMPORARY_TABLES", temporary_table_fields_info, create_schema_table,
2887 fill_temporary_tables, make_temporary_tables_old_format, 0, 2, 3, 0,
2888 OPEN_TABLE_ONLY|OPTIMIZE_I_S_TABLE},
d4e9320e
AM
2889+ {"THREAD_STATISTICS", thread_stats_fields_info, create_schema_table,
2890+ fill_schema_thread_stats, make_old_format, 0, -1, -1, 0, 0},
2891 {"TRIGGERS", triggers_fields_info, create_schema_table,
2892 get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0,
b4e1fa2c 2893 OPEN_TRIGGER_ONLY|OPTIMIZE_I_S_TABLE},
d4e9320e
AM
2894 {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table,
2895 fill_schema_user_privileges, 0, 0, -1, -1, 0, 0},
b4e1fa2c 2896+ {"USER_STATISTICS", user_stats_fields_info, create_schema_table,
d4e9320e
AM
2897+ fill_schema_user_stats, make_old_format, 0, -1, -1, 0, 0},
2898 {"VARIABLES", variables_fields_info, create_schema_table, fill_variables,
2899 make_old_format, 0, 0, -1, 1, 0},
2900 {"VIEWS", view_fields_info, create_schema_table,
2901diff -ruN a/sql/sql_update.cc b/sql/sql_update.cc
b4e1fa2c
AM
2902--- a/sql/sql_update.cc 2010-12-03 20:58:26.000000000 +0300
2903+++ b/sql/sql_update.cc 2010-12-31 04:08:17.000000000 +0300
d8778560 2904@@ -900,8 +900,10 @@
b4e1fa2c
AM
2905 my_snprintf(buff, sizeof(buff), ER(ER_UPDATE_INFO), (ulong) found,
2906 (ulong) updated,
2907 (ulong) thd->warning_info->statement_warn_count());
2908- my_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
2909- id, buff);
2910+ ha_rows row_count=
2911+ (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
2912+ my_ok(thd, row_count, id, buff);
2913+ thd->updated_row_count += row_count;
d4e9320e
AM
2914 DBUG_PRINT("info",("%ld records updated", (long) updated));
2915 }
2916 thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */
d8778560 2917@@ -2146,7 +2148,9 @@
b4e1fa2c
AM
2918 thd->first_successful_insert_id_in_prev_stmt : 0;
2919 my_snprintf(buff, sizeof(buff), ER(ER_UPDATE_INFO),
2920 (ulong) found, (ulong) updated, (ulong) thd->cuted_fields);
2921- ::my_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
2922- id, buff);
2923+ ha_rows row_count=
2924+ (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
2925+ ::my_ok(thd, row_count, id, buff);
2926+ thd->updated_row_count+= row_count;
d4e9320e
AM
2927 DBUG_RETURN(FALSE);
2928 }
2929diff -ruN a/sql/sql_yacc.yy b/sql/sql_yacc.yy
b4e1fa2c
AM
2930--- a/sql/sql_yacc.yy 2010-12-03 20:58:26.000000000 +0300
2931+++ b/sql/sql_yacc.yy 2010-12-31 05:06:16.000000000 +0300
2932@@ -864,6 +864,7 @@
d4e9320e 2933 %token CIPHER_SYM
b4e1fa2c 2934 %token CLASS_ORIGIN_SYM /* SQL-2003-N */
d4e9320e
AM
2935 %token CLIENT_SYM
2936+%token CLIENT_STATS_SYM
2937 %token CLOSE_SYM /* SQL-2003-R */
2938 %token COALESCE /* SQL-2003-N */
2939 %token CODE_SYM
b4e1fa2c 2940@@ -1017,6 +1018,7 @@
d4e9320e
AM
2941 %token IMPORT
2942 %token INDEXES
2943 %token INDEX_SYM
2944+%token INDEX_STATS_SYM
2945 %token INFILE
2946 %token INITIAL_SIZE_SYM
2947 %token INNER_SYM /* SQL-2003-R */
b4e1fa2c 2948@@ -1315,6 +1317,7 @@
d4e9320e
AM
2949 %token TABLESPACE
2950 %token TABLE_REF_PRIORITY
2951 %token TABLE_SYM /* SQL-2003-R */
2952+%token TABLE_STATS_SYM
2953 %token TABLE_CHECKSUM_SYM
b4e1fa2c 2954 %token TABLE_NAME_SYM /* SQL-2003-N */
d4e9320e 2955 %token TEMPORARY /* SQL-2003-N */
b4e1fa2c 2956@@ -1324,6 +1327,7 @@
d4e9320e
AM
2957 %token TEXT_SYM
2958 %token THAN_SYM
2959 %token THEN_SYM /* SQL-2003-R */
2960+%token THREAD_STATS_SYM
2961 %token TIMESTAMP /* SQL-2003-R */
2962 %token TIMESTAMP_ADD
2963 %token TIMESTAMP_DIFF
b4e1fa2c 2964@@ -1361,6 +1365,7 @@
d4e9320e
AM
2965 %token UPGRADE_SYM
2966 %token USAGE /* SQL-2003-N */
2967 %token USER /* SQL-2003-R */
2968+%token USER_STATS_SYM
2969 %token USE_FRM
2970 %token USE_SYM
2971 %token USING /* SQL-2003-R */
b4e1fa2c
AM
2972@@ -11109,6 +11114,41 @@
2973 MYSQL_YYABORT;
2974 #endif // HAVE_RESPONSE_TIME_DISTRIBUTION
2975 }
2976+ | CLIENT_STATS_SYM wild_and_where
d4e9320e
AM
2977+ {
2978+ LEX *lex= Lex;
b4e1fa2c 2979+ Lex->sql_command= SQLCOM_SELECT;
d4e9320e
AM
2980+ if (prepare_schema_table(YYTHD, lex, 0, SCH_CLIENT_STATS))
2981+ MYSQL_YYABORT;
2982+ }
b4e1fa2c 2983+ | USER_STATS_SYM wild_and_where
d4e9320e
AM
2984+ {
2985+ LEX *lex= Lex;
b4e1fa2c 2986+ lex->sql_command= SQLCOM_SELECT;
d4e9320e
AM
2987+ if (prepare_schema_table(YYTHD, lex, 0, SCH_USER_STATS))
2988+ MYSQL_YYABORT;
2989+ }
2990+ | THREAD_STATS_SYM wild_and_where
2991+ {
2992+ LEX *lex= Lex;
b4e1fa2c 2993+ Lex->sql_command= SQLCOM_SELECT;
d4e9320e
AM
2994+ if (prepare_schema_table(YYTHD, lex, 0, SCH_THREAD_STATS))
2995+ MYSQL_YYABORT;
2996+ }
2997+ | TABLE_STATS_SYM wild_and_where
2998+ {
2999+ LEX *lex= Lex;
3000+ lex->sql_command= SQLCOM_SELECT;
3001+ if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_STATS))
3002+ MYSQL_YYABORT;
3003+ }
3004+ | INDEX_STATS_SYM wild_and_where
3005+ {
3006+ LEX *lex= Lex;
3007+ lex->sql_command= SQLCOM_SELECT;
3008+ if (prepare_schema_table(YYTHD, lex, 0, SCH_INDEX_STATS))
3009+ MYSQL_YYABORT;
3010+ }
b4e1fa2c 3011 | CREATE PROCEDURE_SYM sp_name
d4e9320e
AM
3012 {
3013 LEX *lex= Lex;
b4e1fa2c
AM
3014@@ -11351,6 +11391,16 @@
3015 Lex->type|= REFRESH_QUERY_RESPONSE_TIME;
3016 #endif // HAVE_RESPONSE_TIME_DISTRIBUTION
3017 }
d4e9320e
AM
3018+ | CLIENT_STATS_SYM
3019+ { Lex->type|= REFRESH_CLIENT_STATS; }
3020+ | USER_STATS_SYM
3021+ { Lex->type|= REFRESH_USER_STATS; }
3022+ | THREAD_STATS_SYM
3023+ { Lex->type|= REFRESH_THREAD_STATS; }
3024+ | TABLE_STATS_SYM
3025+ { Lex->type|= REFRESH_TABLE_STATS; }
3026+ | INDEX_STATS_SYM
3027+ { Lex->type|= REFRESH_INDEX_STATS; }
3028 | MASTER_SYM
3029 { Lex->type|= REFRESH_MASTER; }
3030 | DES_KEY_FILE
b4e1fa2c 3031@@ -12473,6 +12523,7 @@
d4e9320e
AM
3032 | CHAIN_SYM {}
3033 | CHANGED {}
3034 | CIPHER_SYM {}
3035+ | CLIENT_STATS_SYM {}
3036 | CLIENT_SYM {}
b4e1fa2c 3037 | CLASS_ORIGIN_SYM {}
d4e9320e 3038 | COALESCE {}
b4e1fa2c 3039@@ -12541,6 +12592,7 @@
d4e9320e
AM
3040 | HOSTS_SYM {}
3041 | HOUR_SYM {}
3042 | IDENTIFIED_SYM {}
3043+ | INDEX_STATS_SYM {}
b4e1fa2c 3044 | IGNORE_SERVER_IDS_SYM {}
d4e9320e
AM
3045 | INVOKER_SYM {}
3046 | IMPORT {}
b4e1fa2c 3047@@ -12692,6 +12744,7 @@
d4e9320e
AM
3048 | SUSPEND_SYM {}
3049 | SWAPS_SYM {}
3050 | SWITCHES_SYM {}
3051+ | TABLE_STATS_SYM {}
b4e1fa2c 3052 | TABLE_NAME_SYM {}
d4e9320e
AM
3053 | TABLES {}
3054 | TABLE_CHECKSUM_SYM {}
b4e1fa2c 3055@@ -12717,6 +12770,7 @@
d4e9320e
AM
3056 | UNKNOWN_SYM {}
3057 | UNTIL_SYM {}
3058 | USER {}
3059+ | USER_STATS_SYM {}
3060 | USE_FRM {}
3061 | VARIABLES {}
3062 | VIEW_SYM {}
3063diff -ruN a/sql/structs.h b/sql/structs.h
b4e1fa2c
AM
3064--- a/sql/structs.h 2010-12-03 20:58:26.000000000 +0300
3065+++ b/sql/structs.h 2010-12-31 05:12:04.000000000 +0300
3066@@ -25,6 +25,7 @@
3067 #include "my_time.h" /* enum_mysql_timestamp_type */
3068 #include "thr_lock.h" /* thr_lock_type */
3069 #include "my_base.h" /* ha_rows, ha_key_alg */
3070+#include "mysql_com.h"
3071
3072 struct TABLE;
3073 class Field;
3074@@ -218,6 +219,171 @@
d4e9320e
AM
3075 USER_RESOURCES user_resources;
3076 } USER_CONN;
3077
3078+typedef struct st_user_stats {
3079+ char user[max(USERNAME_LENGTH, LIST_PROCESS_HOST_LEN) + 1];
3080+ // Account name the user is mapped to when this is a user from mapped_user.
3081+ // Otherwise, the same value as user.
3082+ char priv_user[max(USERNAME_LENGTH, LIST_PROCESS_HOST_LEN) + 1];
3083+ uint total_connections;
3084+ uint concurrent_connections;
3085+ time_t connected_time; // in seconds
3086+ double busy_time; // in seconds
3087+ double cpu_time; // in seconds
3088+ ulonglong bytes_received;
3089+ ulonglong bytes_sent;
3090+ ulonglong binlog_bytes_written;
3091+ ha_rows rows_fetched, rows_updated, rows_read;
3092+ ulonglong select_commands, update_commands, other_commands;
3093+ ulonglong commit_trans, rollback_trans;
3094+ ulonglong denied_connections, lost_connections;
3095+ ulonglong access_denied_errors;
3096+ ulonglong empty_queries;
3097+} USER_STATS;
3098+
b4e1fa2c 3099+/* Lookup function for my_hash tables with USER_STATS entries */
d4e9320e
AM
3100+extern "C" uchar *get_key_user_stats(USER_STATS *user_stats, size_t *length,
3101+ my_bool not_used __attribute__((unused)));
3102+
b4e1fa2c 3103+/* Free all memory for a my_hash table with USER_STATS entries */
d4e9320e
AM
3104+extern void free_user_stats(USER_STATS* user_stats);
3105+
3106+/* Intialize an instance of USER_STATS */
3107+extern void
3108+init_user_stats(USER_STATS *user_stats,
3109+ const char *user,
3110+ const char *priv_user,
3111+ uint total_connections,
3112+ uint concurrent_connections,
3113+ time_t connected_time,
3114+ double busy_time,
3115+ double cpu_time,
3116+ ulonglong bytes_received,
3117+ ulonglong bytes_sent,
3118+ ulonglong binlog_bytes_written,
3119+ ha_rows rows_fetched,
3120+ ha_rows rows_updated,
3121+ ha_rows rows_read,
3122+ ulonglong select_commands,
3123+ ulonglong update_commands,
3124+ ulonglong other_commands,
3125+ ulonglong commit_trans,
3126+ ulonglong rollback_trans,
3127+ ulonglong denied_connections,
3128+ ulonglong lost_connections,
3129+ ulonglong access_denied_errors,
3130+ ulonglong empty_queries);
3131+
3132+/* Increment values of an instance of USER_STATS */
3133+extern void
3134+add_user_stats(USER_STATS *user_stats,
3135+ uint total_connections,
3136+ uint concurrent_connections,
3137+ time_t connected_time,
3138+ double busy_time,
3139+ double cpu_time,
3140+ ulonglong bytes_received,
3141+ ulonglong bytes_sent,
3142+ ulonglong binlog_bytes_written,
3143+ ha_rows rows_fetched,
3144+ ha_rows rows_updated,
3145+ ha_rows rows_read,
3146+ ulonglong select_commands,
3147+ ulonglong update_commands,
3148+ ulonglong other_commands,
3149+ ulonglong commit_trans,
3150+ ulonglong rollback_trans,
3151+ ulonglong denied_connections,
3152+ ulonglong lost_connections,
3153+ ulonglong access_denied_errors,
3154+ ulonglong empty_queries);
3155+
3156+typedef struct st_thread_stats {
3157+ my_thread_id id;
3158+ uint total_connections;
3159+ uint concurrent_connections;
3160+ time_t connected_time; // in seconds
3161+ double busy_time; // in seconds
3162+ double cpu_time; // in seconds
3163+ ulonglong bytes_received;
3164+ ulonglong bytes_sent;
3165+ ulonglong binlog_bytes_written;
3166+ ha_rows rows_fetched, rows_updated, rows_read;
3167+ ulonglong select_commands, update_commands, other_commands;
3168+ ulonglong commit_trans, rollback_trans;
3169+ ulonglong denied_connections, lost_connections;
3170+ ulonglong access_denied_errors;
3171+ ulonglong empty_queries;
3172+} THREAD_STATS;
3173+
b4e1fa2c 3174+/* Lookup function for my_hash tables with THREAD_STATS entries */
d4e9320e
AM
3175+extern "C" uchar *get_key_thread_stats(THREAD_STATS *thread_stats, size_t *length,
3176+ my_bool not_used __attribute__((unused)));
3177+
b4e1fa2c 3178+/* Free all memory for a my_hash table with THREAD_STATS entries */
d4e9320e
AM
3179+extern void free_thread_stats(THREAD_STATS* thread_stats);
3180+
3181+/* Intialize an instance of THREAD_STATS */
3182+extern void
3183+init_thread_stats(THREAD_STATS *thread_stats,
3184+ my_thread_id id,
3185+ uint total_connections,
3186+ uint concurrent_connections,
3187+ time_t connected_time,
3188+ double busy_time,
3189+ double cpu_time,
3190+ ulonglong bytes_received,
3191+ ulonglong bytes_sent,
3192+ ulonglong binlog_bytes_written,
3193+ ha_rows rows_fetched,
3194+ ha_rows rows_updated,
3195+ ha_rows rows_read,
3196+ ulonglong select_commands,
3197+ ulonglong update_commands,
3198+ ulonglong other_commands,
3199+ ulonglong commit_trans,
3200+ ulonglong rollback_trans,
3201+ ulonglong denied_connections,
3202+ ulonglong lost_connections,
3203+ ulonglong access_denied_errors,
3204+ ulonglong empty_queries);
3205+
3206+/* Increment values of an instance of THREAD_STATS */
3207+extern void
3208+add_thread_stats(THREAD_STATS *thread_stats,
3209+ uint total_connections,
3210+ uint concurrent_connections,
3211+ time_t connected_time,
3212+ double busy_time,
3213+ double cpu_time,
3214+ ulonglong bytes_received,
3215+ ulonglong bytes_sent,
3216+ ulonglong binlog_bytes_written,
3217+ ha_rows rows_fetched,
3218+ ha_rows rows_updated,
3219+ ha_rows rows_read,
3220+ ulonglong select_commands,
3221+ ulonglong update_commands,
3222+ ulonglong other_commands,
3223+ ulonglong commit_trans,
3224+ ulonglong rollback_trans,
3225+ ulonglong denied_connections,
3226+ ulonglong lost_connections,
3227+ ulonglong access_denied_errors,
3228+ ulonglong empty_queries);
3229+
3230+typedef struct st_table_stats {
3231+ char table[NAME_LEN * 2 + 2]; // [db] + '.' + [table] + '\0'
3232+ ulonglong rows_read, rows_changed;
3233+ ulonglong rows_changed_x_indexes;
3234+ /* Stores enum db_type, but forward declarations cannot be done */
3235+ int engine_type;
3236+} TABLE_STATS;
3237+
3238+typedef struct st_index_stats {
3239+ char index[NAME_LEN * 3 + 3]; // [db] + '.' + [table] + '.' + [index] + '\0'
3240+ ulonglong rows_read;
3241+} INDEX_STATS;
3242+
3243 /* Bits in form->update */
3244 #define REG_MAKE_DUPP 1 /* Make a copy of record when read */
3245 #define REG_NEW_RECORD 2 /* Write a new record if not found */
b4e1fa2c
AM
3246diff -ruN a/sql/sys_vars.cc b/sql/sys_vars.cc
3247--- a/sql/sys_vars.cc 2010-12-03 20:58:26.000000000 +0300
3248+++ b/sql/sys_vars.cc 2010-12-30 02:22:25.000000000 +0300
d8778560 3249@@ -1563,6 +1563,17 @@
b4e1fa2c
AM
3250 NO_MUTEX_GUARD, NOT_IN_BINLOG,
3251 ON_CHECK(check_read_only), ON_UPDATE(fix_read_only));
3252
a9ee80b9
ER
3253+static Sys_var_mybool Sys_userstat(
3254+ "userstat",
b4e1fa2c
AM
3255+ "Control USER_STATISTICS, CLIENT_STATISTICS, THREAD_STATISTICS, "
3256+ "INDEX_STATISTICS and TABLE_STATISTICS running",
a9ee80b9 3257+ GLOBAL_VAR(opt_userstat), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
b4e1fa2c
AM
3258+
3259+static Sys_var_mybool Sys_thread_statistics(
3260+ "thread_statistics",
a9ee80b9 3261+ "Control TABLE_STATISTICS running, when userstat is enabled",
b4e1fa2c
AM
3262+ GLOBAL_VAR(opt_thread_statistics), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
3263+
3264 // Small lower limit to be able to test MRR
3265 static Sys_var_ulong Sys_read_rnd_buff_size(
3266 "read_rnd_buffer_size",
d4e9320e 3267diff -ruN a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc
b4e1fa2c
AM
3268--- a/storage/myisam/ha_myisam.cc 2010-12-03 20:58:26.000000000 +0300
3269+++ b/storage/myisam/ha_myisam.cc 2010-12-31 05:58:01.000000000 +0300
d8778560 3270@@ -768,6 +768,7 @@
d4e9320e
AM
3271
3272 int ha_myisam::write_row(uchar *buf)
3273 {
3274+ int error;
3275 ha_statistic_increment(&SSV::ha_write_count);
3276
3277 /* If we have a timestamp column, update it to the current time */
d8778560 3278@@ -780,11 +781,13 @@
d4e9320e
AM
3279 */
3280 if (table->next_number_field && buf == table->record[0])
3281 {
3282- int error;
3283 if ((error= update_auto_increment()))
3284 return error;
3285 }
3286- return mi_write(file,buf);
3287+ error=mi_write(file,buf);
b4e1fa2c
AM
3288+ if (!error)
3289+ rows_changed++;
d4e9320e
AM
3290+ return error;
3291 }
3292
3293 int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
d8778560 3294@@ -1535,16 +1538,24 @@
d4e9320e
AM
3295
3296 int ha_myisam::update_row(const uchar *old_data, uchar *new_data)
3297 {
3298+ int error;
3299 ha_statistic_increment(&SSV::ha_update_count);
3300 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
3301 table->timestamp_field->set_time();
3302- return mi_update(file,old_data,new_data);
3303+ error=mi_update(file,old_data,new_data);
b4e1fa2c
AM
3304+ if (!error)
3305+ rows_changed++;
d4e9320e
AM
3306+ return error;
3307 }
3308
3309 int ha_myisam::delete_row(const uchar *buf)
3310 {
3311+ int error;
3312 ha_statistic_increment(&SSV::ha_delete_count);
3313- return mi_delete(file,buf);
3314+ error=mi_delete(file,buf);
b4e1fa2c
AM
3315+ if (!error)
3316+ rows_changed++;
d4e9320e
AM
3317+ return error;
3318 }
3319
3320 int ha_myisam::index_read_map(uchar *buf, const uchar *key,
d8778560 3321@@ -1556,6 +1567,14 @@
d4e9320e
AM
3322 ha_statistic_increment(&SSV::ha_read_key_count);
3323 int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag);
3324 table->status=error ? STATUS_NOT_FOUND: 0;
b4e1fa2c
AM
3325+ if (!error)
3326+ {
d4e9320e
AM
3327+ rows_read++;
3328+
3329+ int inx = (active_index == MAX_KEY) ? file->lastinx : active_index;
3330+ if (inx >= 0 && inx < MAX_KEY)
3331+ index_rows_read[inx]++;
3332+ }
b4e1fa2c 3333 MYSQL_INDEX_READ_ROW_DONE(error);
d4e9320e
AM
3334 return error;
3335 }
d8778560 3336@@ -1568,6 +1587,14 @@
d4e9320e
AM
3337 ha_statistic_increment(&SSV::ha_read_key_count);
3338 int error=mi_rkey(file, buf, index, key, keypart_map, find_flag);
3339 table->status=error ? STATUS_NOT_FOUND: 0;
b4e1fa2c
AM
3340+ if (!error)
3341+ {
d4e9320e
AM
3342+ rows_read++;
3343+
3344+ int inx = index;
3345+ if (inx >= 0 && inx < MAX_KEY)
3346+ index_rows_read[inx]++;
3347+ }
b4e1fa2c 3348 MYSQL_INDEX_READ_ROW_DONE(error);
d4e9320e
AM
3349 return error;
3350 }
d8778560 3351@@ -1582,6 +1609,14 @@
d4e9320e
AM
3352 int error=mi_rkey(file, buf, active_index, key, keypart_map,
3353 HA_READ_PREFIX_LAST);
3354 table->status=error ? STATUS_NOT_FOUND: 0;
b4e1fa2c
AM
3355+ if (!error)
3356+ {
d4e9320e
AM
3357+ rows_read++;
3358+
3359+ int inx = (active_index == MAX_KEY) ? file->lastinx : active_index;
3360+ if (inx >= 0 && inx < MAX_KEY)
3361+ index_rows_read[inx]++;
3362+ }
b4e1fa2c 3363 MYSQL_INDEX_READ_ROW_DONE(error);
d4e9320e
AM
3364 DBUG_RETURN(error);
3365 }
d8778560 3366@@ -1593,6 +1628,13 @@
d4e9320e
AM
3367 ha_statistic_increment(&SSV::ha_read_next_count);
3368 int error=mi_rnext(file,buf,active_index);
3369 table->status=error ? STATUS_NOT_FOUND: 0;
3370+ if (!error) {
3371+ rows_read++;
3372+
3373+ int inx = (active_index == MAX_KEY) ? file->lastinx : active_index;
3374+ if (inx >= 0 && inx < MAX_KEY)
3375+ index_rows_read[inx]++;
3376+ }
b4e1fa2c 3377 MYSQL_INDEX_READ_ROW_DONE(error);
d4e9320e
AM
3378 return error;
3379 }
d8778560 3380@@ -1604,6 +1646,13 @@
d4e9320e
AM
3381 ha_statistic_increment(&SSV::ha_read_prev_count);
3382 int error=mi_rprev(file,buf, active_index);
3383 table->status=error ? STATUS_NOT_FOUND: 0;
3384+ if (!error) {
3385+ rows_read++;
3386+
3387+ int inx = (active_index == MAX_KEY) ? file->lastinx : active_index;
3388+ if (inx >= 0 && inx < MAX_KEY)
3389+ index_rows_read[inx]++;
3390+ }
b4e1fa2c 3391 MYSQL_INDEX_READ_ROW_DONE(error);
d4e9320e
AM
3392 return error;
3393 }
d8778560 3394@@ -1615,6 +1664,14 @@
d4e9320e
AM
3395 ha_statistic_increment(&SSV::ha_read_first_count);
3396 int error=mi_rfirst(file, buf, active_index);
3397 table->status=error ? STATUS_NOT_FOUND: 0;
b4e1fa2c
AM
3398+ if (!error)
3399+ {
d4e9320e
AM
3400+ rows_read++;
3401+
3402+ int inx = (active_index == MAX_KEY) ? file->lastinx : active_index;
3403+ if (inx >= 0 && inx < MAX_KEY)
3404+ index_rows_read[inx]++;
3405+ }
b4e1fa2c 3406 MYSQL_INDEX_READ_ROW_DONE(error);
d4e9320e
AM
3407 return error;
3408 }
d8778560 3409@@ -1626,6 +1683,14 @@
d4e9320e
AM
3410 ha_statistic_increment(&SSV::ha_read_last_count);
3411 int error=mi_rlast(file, buf, active_index);
3412 table->status=error ? STATUS_NOT_FOUND: 0;
b4e1fa2c
AM
3413+ if (!error)
3414+ {
d4e9320e
AM
3415+ rows_read++;
3416+
3417+ int inx = (active_index == MAX_KEY) ? file->lastinx : active_index;
3418+ if (inx >= 0 && inx < MAX_KEY)
3419+ index_rows_read[inx]++;
3420+ }
b4e1fa2c 3421 MYSQL_INDEX_READ_ROW_DONE(error);
d4e9320e
AM
3422 return error;
3423 }
d8778560 3424@@ -1643,6 +1708,14 @@
d4e9320e
AM
3425 error= mi_rnext_same(file,buf);
3426 } while (error == HA_ERR_RECORD_DELETED);
3427 table->status=error ? STATUS_NOT_FOUND: 0;
b4e1fa2c
AM
3428+ if (!error)
3429+ {
d4e9320e
AM
3430+ rows_read++;
3431+
3432+ int inx = (active_index == MAX_KEY) ? file->lastinx : active_index;
3433+ if (inx >= 0 && inx < MAX_KEY)
3434+ index_rows_read[inx]++;
3435+ }
b4e1fa2c 3436 MYSQL_INDEX_READ_ROW_DONE(error);
d4e9320e
AM
3437 return error;
3438 }
d8778560 3439@@ -1662,6 +1735,8 @@
d4e9320e
AM
3440 ha_statistic_increment(&SSV::ha_read_rnd_next_count);
3441 int error=mi_scan(file, buf);
3442 table->status=error ? STATUS_NOT_FOUND: 0;
b4e1fa2c
AM
3443+ if (!error)
3444+ rows_read++;
3445 MYSQL_READ_ROW_DONE(error);
d4e9320e
AM
3446 return error;
3447 }
d8778560 3448@@ -1678,6 +1753,8 @@
d4e9320e
AM
3449 ha_statistic_increment(&SSV::ha_read_rnd_count);
3450 int error=mi_rrnd(file, buf, my_get_ptr(pos,ref_length));
3451 table->status=error ? STATUS_NOT_FOUND: 0;
b4e1fa2c
AM
3452+ if (!error)
3453+ rows_read++;
3454 MYSQL_READ_ROW_DONE(error);
d4e9320e
AM
3455 return error;
3456 }
This page took 2.420719 seconds and 4 git commands to generate.