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