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