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