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