summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <cmiller@zippy.cornsilk.net>2007-01-03 17:15:10 -0500
committerunknown <cmiller@zippy.cornsilk.net>2007-01-03 17:15:10 -0500
commit66dfd85cf4d55e6d87e8bb81b8fc8450eb9b3f67 (patch)
tree3ccc1d229c4d2704fc85d800e206032a74a7a2e0
parent96fa010c66bffd1f904d5d71bd2d0a0087ad287b (diff)
downloadmariadb-git-66dfd85cf4d55e6d87e8bb81b8fc8450eb9b3f67.tar.gz
Bug#24795: Add SHOW PROFILE
Patch contributed by Jeremy Cole. CLA received Oct 2006 by Kaj Arnö Add rudimentary query profiling support. libmysqld/Makefile.am: Add profile file to source list. sql/Makefile.am: Add profiling files to source and header lists. sql/ha_archive.cc: Macro-ized other discovered instances of setting proc_info. sql/ha_myisam.cc: Macroize setting thread-state info sql/item_func.cc: Macro-ized other discovered instances of setting proc_info. sql/lex.h: Add lexer info for profiling. sql/lock.cc: Macroize setting thread-state info sql/log_event.cc: Macro-ized other discovered instances of setting proc_info. sql/mysql_priv.h: Set constants for profiling. sql/repl_failsafe.cc: Macro-ized other discovered instances of setting proc_info. sql/slave.cc: Macro-ized other discovered instances of setting proc_info. sql/sp_head.cc: Macro-ized other discovered instances of setting proc_info. sql/sql_base.cc: Macroize setting thread-state info --- Macro-ized other discovered instances of setting proc_info. sql/sql_cache.cc: Macroize setting thread-state info sql/sql_class.cc: Integrate profiling. sql/sql_class.h: Instantiate profiling object. sql/sql_delete.cc: Macroize setting thread-state info sql/sql_insert.cc: Macroize setting thread-state info --- Macro-ized other discovered instances of setting proc_info. sql/sql_lex.cc: Initialize profiling. sql/sql_lex.h: Define lex tokens and allocate space for profiling options. sql/sql_parse.cc: Integrate profiling. --- Macro-ized other discovered instances of setting proc_info. sql/sql_repl.cc: Macro-ized other discovered instances of setting proc_info. sql/sql_select.cc: Macroize setting thread-state info. Clean up some lines. sql/sql_show.cc: Macro-ized other discovered instances of setting proc_info. --- Revert bad use of macro. sql/sql_table.cc: Macroize setting thread-state info sql/sql_update.cc: Macroize setting thread-state info sql/sql_view.cc: Macro-ized other discovered instances of setting proc_info. sql/sql_yacc.yy: Add parser info for profiling. --- Fix new YACC shift/reduce conflict. (Now at 249.) mysql-test/r/profile.result: Test profiling code. --- A not-very-useful result. mysql-test/t/profile.test: Test profiling code. --- Test syntax, but not values of profiles code. sql/sql_profile.cc: Add profiling code. --- Add wishlist comment. sql/sql_profile.h: Add profiling code. --- Changed the value of the macro so that it's syntactically equivalent to a single statement.
-rw-r--r--BitKeeper/etc/collapsed3
-rw-r--r--libmysqld/Makefile.am1
-rw-r--r--mysql-test/r/profile.result30
-rw-r--r--mysql-test/t/profile.test39
-rw-r--r--sql/Makefile.am2
-rw-r--r--sql/ha_archive.cc4
-rw-r--r--sql/ha_myisam.cc24
-rw-r--r--sql/item_func.cc8
-rw-r--r--sql/lex.h13
-rw-r--r--sql/lock.cc8
-rw-r--r--sql/log_event.cc8
-rw-r--r--sql/mysql_priv.h4
-rw-r--r--sql/repl_failsafe.cc6
-rw-r--r--sql/slave.cc6
-rw-r--r--sql/sp_head.cc4
-rw-r--r--sql/sql_base.cc24
-rw-r--r--sql/sql_cache.cc12
-rw-r--r--sql/sql_class.cc2
-rw-r--r--sql/sql_class.h3
-rw-r--r--sql/sql_delete.cc12
-rw-r--r--sql/sql_insert.cc38
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_lex.h3
-rw-r--r--sql/sql_parse.cc40
-rw-r--r--sql/sql_profile.cc441
-rw-r--r--sql/sql_profile.h187
-rw-r--r--sql/sql_repl.cc2
-rw-r--r--sql/sql_select.cc73
-rw-r--r--sql/sql_show.cc2
-rw-r--r--sql/sql_table.cc20
-rw-r--r--sql/sql_update.cc14
-rw-r--r--sql/sql_view.cc2
-rw-r--r--sql/sql_yacc.yy74
33 files changed, 976 insertions, 134 deletions
diff --git a/BitKeeper/etc/collapsed b/BitKeeper/etc/collapsed
index 10bc7a2182a..63e4bff0331 100644
--- a/BitKeeper/etc/collapsed
+++ b/BitKeeper/etc/collapsed
@@ -19,3 +19,6 @@
4538a7b0EbDHHkWPbIwxO6ZIDdg6Dg
454a7ef8gdvE_ddMlJyghvOAkKPNOQ
454f8960jsVT_kMKJtZ9OCgXoba0xQ
+459c03b9N_mqF2XJKK6DwSrIt7e6_g
+459c1965_BQMBzBO8S_gVqjTHYQrmw
+459c2098XoAUsUn8N07IVRDD6CTM-A
diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am
index cdd71724166..2b54bf6a386 100644
--- a/libmysqld/Makefile.am
+++ b/libmysqld/Makefile.am
@@ -53,6 +53,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
protocol.cc net_serv.cc opt_range.cc \
opt_sum.cc procedure.cc records.cc sql_acl.cc \
sql_load.cc discover.cc sql_locale.cc \
+ sql_profile.cc \
sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \
sql_crypt.cc sql_db.cc sql_delete.cc sql_error.cc sql_insert.cc \
sql_lex.cc sql_list.cc sql_manager.cc sql_map.cc sql_parse.cc \
diff --git a/mysql-test/r/profile.result b/mysql-test/r/profile.result
new file mode 100644
index 00000000000..8a4db348445
--- /dev/null
+++ b/mysql-test/r/profile.result
@@ -0,0 +1,30 @@
+create table t1 (
+a int,
+b int
+);
+insert into t1 values (1,1), (2,null), (3, 4);
+insert into t1 values (5,1), (6,null), (7, 4);
+insert into t1 values (1,1), (2,null), (3, 4);
+insert into t1 values (5,1), (6,null), (7, 4);
+insert into t1 values (5,1), (6,null), (7, 4);
+select sum(a) from t1;
+select sum(a) from t1 group by b;
+select sum(a) + sum(b) from t1 group by b;
+select max(x) from (select sum(a) as x from t1 group by b) as teeone;
+show profiles;
+show profile for query 8;
+show profile cpu, block io for query 8;
+show profile cpu for query 8;
+show profile cpu for query 9 limit 2 offset 2;
+show profile cpu for query 10 limit 0;
+show profile cpu for query 65534;
+show profile memory;
+show profile block io;
+show profile context switches;
+show profile page faults;
+show profile ipc;
+show profile swaps limit 1 offset 2;
+show profile source;
+show profile all for query 0 limit 0;
+drop table t1;
+End of 5.0 tests
diff --git a/mysql-test/t/profile.test b/mysql-test/t/profile.test
new file mode 100644
index 00000000000..4cf2a3aa92f
--- /dev/null
+++ b/mysql-test/t/profile.test
@@ -0,0 +1,39 @@
+
+create table t1 (
+ a int,
+ b int
+);
+--disable_result_log
+insert into t1 values (1,1), (2,null), (3, 4);
+insert into t1 values (5,1), (6,null), (7, 4);
+insert into t1 values (1,1), (2,null), (3, 4);
+insert into t1 values (5,1), (6,null), (7, 4);
+insert into t1 values (5,1), (6,null), (7, 4);
+select sum(a) from t1;
+select sum(a) from t1 group by b;
+select sum(a) + sum(b) from t1 group by b;
+select max(x) from (select sum(a) as x from t1 group by b) as teeone;
+
+# Merely verify that commands work. Checking values is impossible, right?
+show profiles;
+show profile for query 8;
+show profile cpu, block io for query 8;
+show profile cpu for query 8;
+show profile cpu for query 9 limit 2 offset 2;
+show profile cpu for query 10 limit 0;
+show profile cpu for query 65534;
+show profile memory;
+show profile block io;
+show profile context switches;
+show profile page faults;
+show profile ipc;
+show profile swaps limit 1 offset 2;
+show profile source;
+show profile all for query 0 limit 0;
+--enable_result_log
+
+drop table t1;
+
+
+##
+--echo End of 5.0 tests
diff --git a/sql/Makefile.am b/sql/Makefile.am
index cbb87f16d80..597ab49a135 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -52,6 +52,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
procedure.h sql_class.h sql_lex.h sql_list.h \
sql_manager.h sql_map.h sql_string.h unireg.h \
sql_error.h field.h handler.h mysqld_suffix.h \
+ sql_profile.h \
ha_myisammrg.h\
ha_heap.h ha_myisam.h ha_berkeley.h ha_innodb.h \
ha_ndbcluster.h opt_range.h protocol.h \
@@ -80,6 +81,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
set_var.cc sql_parse.cc sql_yacc.yy \
sql_base.cc table.cc sql_select.cc sql_insert.cc \
sql_prepare.cc sql_error.cc sql_locale.cc \
+ sql_profile.cc \
sql_update.cc sql_delete.cc uniques.cc sql_do.cc \
procedure.cc item_uniq.cc sql_test.cc \
log.cc log_event.cc init.cc derror.cc sql_acl.cc \
diff --git a/sql/ha_archive.cc b/sql/ha_archive.cc
index e3f979952e0..da879915d72 100644
--- a/sql/ha_archive.cc
+++ b/sql/ha_archive.cc
@@ -1206,7 +1206,7 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt)
ha_rows count= share->rows_recorded;
DBUG_ENTER("ha_archive::check");
- thd->proc_info= "Checking table";
+ THD_PROC_INFO(thd, "Checking table");
/* Flush any waiting data */
gzflush(share->archive_write, Z_SYNC_FLUSH);
@@ -1230,7 +1230,7 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt)
my_free((char*)buf, MYF(0));
- thd->proc_info= old_proc_info;
+ THD_PROC_INFO(thd, old_proc_info);
if ((rc && rc != HA_ERR_END_OF_FILE) || count)
{
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 19ec1b29da3..a09682cc0ab 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -340,7 +340,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
MYISAM_SHARE* share = file->s;
const char *old_proc_info=thd->proc_info;
- thd->proc_info="Checking table";
+ THD_PROC_INFO(thd, "Checking table");
myisamchk_init(&param);
param.thd = thd;
param.op_name = "check";
@@ -414,7 +414,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
}
- thd->proc_info=old_proc_info;
+ THD_PROC_INFO(thd, old_proc_info);
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
}
@@ -680,22 +680,22 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
char buf[40];
/* TODO: respect myisam_repair_threads variable */
my_snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map));
- thd->proc_info=buf;
+ THD_PROC_INFO(thd, buf);
error = mi_repair_parallel(&param, file, fixed_name,
param.testflag & T_QUICK);
- thd->proc_info="Repair done"; // to reset proc_info, as
+ THD_PROC_INFO(thd, "Repair done"); // to reset proc_info, as
// it was pointing to local buffer
}
else
{
- thd->proc_info="Repair by sorting";
+ THD_PROC_INFO(thd, "Repair by sorting");
error = mi_repair_by_sort(&param, file, fixed_name,
param.testflag & T_QUICK);
}
}
else
{
- thd->proc_info="Repair with keycache";
+ THD_PROC_INFO(thd, "Repair with keycache");
param.testflag &= ~T_REP_BY_SORT;
error= mi_repair(&param, file, fixed_name,
param.testflag & T_QUICK);
@@ -709,7 +709,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
(share->state.changed & STATE_NOT_SORTED_PAGES))
{
optimize_done=1;
- thd->proc_info="Sorting index";
+ THD_PROC_INFO(thd, "Sorting index");
error=mi_sort_index(&param,file,fixed_name);
}
if (!statistics_done && (local_testflag & T_STATISTICS))
@@ -717,14 +717,14 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
if (share->state.changed & STATE_NOT_ANALYZED)
{
optimize_done=1;
- thd->proc_info="Analyzing";
+ THD_PROC_INFO(thd, "Analyzing");
error = chk_key(&param, file);
}
else
local_testflag&= ~T_STATISTICS; // Don't update statistics
}
}
- thd->proc_info="Saving state";
+ THD_PROC_INFO(thd, "Saving state");
if (!error)
{
if ((share->state.changed & STATE_CHANGED) || mi_is_crashed(file))
@@ -762,7 +762,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
update_state_info(&param, file, 0);
}
- thd->proc_info=old_proc_info;
+ THD_PROC_INFO(thd, old_proc_info);
if (!thd->locked_tables)
mi_lock_database(file,F_UNLCK);
DBUG_RETURN(error ? HA_ADMIN_FAILED :
@@ -987,7 +987,7 @@ int ha_myisam::enable_indexes(uint mode)
THD *thd=current_thd;
MI_CHECK param;
const char *save_proc_info=thd->proc_info;
- thd->proc_info="Creating index";
+ THD_PROC_INFO(thd, "Creating index");
myisamchk_init(&param);
param.op_name= "recreating_index";
param.testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK |
@@ -1012,7 +1012,7 @@ int ha_myisam::enable_indexes(uint mode)
thd->clear_error();
}
info(HA_STATUS_CONST);
- thd->proc_info=save_proc_info;
+ THD_PROC_INFO(thd, save_proc_info);
}
else
{
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 659a214e9c2..ddd2f28c5a5 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -3193,7 +3193,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout)
Structure is now initialized. Try to get the lock.
Set up control struct to allow others to abort locks
*/
- thd->proc_info="User lock";
+ THD_PROC_INFO(thd, "User lock");
thd->mysys_var->current_mutex= &LOCK_user_locks;
thd->mysys_var->current_cond= &ull->cond;
@@ -3218,7 +3218,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout)
}
pthread_mutex_unlock(&LOCK_user_locks);
pthread_mutex_lock(&thd->mysys_var->mutex);
- thd->proc_info=0;
+ THD_PROC_INFO(thd, 0);
thd->mysys_var->current_mutex= 0;
thd->mysys_var->current_cond= 0;
pthread_mutex_unlock(&thd->mysys_var->mutex);
@@ -3299,7 +3299,7 @@ longlong Item_func_get_lock::val_int()
Structure is now initialized. Try to get the lock.
Set up control struct to allow others to abort locks.
*/
- thd->proc_info="User lock";
+ THD_PROC_INFO(thd, "User lock");
thd->mysys_var->current_mutex= &LOCK_user_locks;
thd->mysys_var->current_cond= &ull->cond;
@@ -3337,7 +3337,7 @@ longlong Item_func_get_lock::val_int()
pthread_mutex_unlock(&LOCK_user_locks);
pthread_mutex_lock(&thd->mysys_var->mutex);
- thd->proc_info=0;
+ THD_PROC_INFO(thd, 0);
thd->mysys_var->current_mutex= 0;
thd->mysys_var->current_cond= 0;
pthread_mutex_unlock(&thd->mysys_var->mutex);
diff --git a/sql/lex.h b/sql/lex.h
index 68f34d8de93..11791457b8d 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -88,6 +88,7 @@ static SYMBOL symbols[] = {
{ "BINLOG", SYM(BINLOG_SYM)},
{ "BIT", SYM(BIT_SYM)},
{ "BLOB", SYM(BLOB_SYM)},
+ { "BLOCK", SYM(BLOCK_SYM)},
{ "BOOL", SYM(BOOL_SYM)},
{ "BOOLEAN", SYM(BOOLEAN_SYM)},
{ "BOTH", SYM(BOTH)},
@@ -126,8 +127,10 @@ static SYMBOL symbols[] = {
{ "CONSISTENT", SYM(CONSISTENT_SYM)},
{ "CONSTRAINT", SYM(CONSTRAINT)},
{ "CONTAINS", SYM(CONTAINS_SYM)},
+ { "CONTEXT", SYM(CONTEXT_SYM)},
{ "CONTINUE", SYM(CONTINUE_SYM)},
{ "CONVERT", SYM(CONVERT_SYM)},
+ { "CPU", SYM(CPU_SYM)},
{ "CREATE", SYM(CREATE)},
{ "CROSS", SYM(CROSS)},
{ "CUBE", SYM(CUBE_SYM)},
@@ -193,6 +196,7 @@ static SYMBOL symbols[] = {
{ "EXTENDED", SYM(EXTENDED_SYM)},
{ "FALSE", SYM(FALSE_SYM)},
{ "FAST", SYM(FAST_SYM)},
+ { "FAULTS", SYM(FAULTS_SYM)},
{ "FETCH", SYM(FETCH_SYM)},
{ "FIELDS", SYM(COLUMNS)},
{ "FILE", SYM(FILE_SYM)},
@@ -252,7 +256,9 @@ static SYMBOL symbols[] = {
{ "INTEGER", SYM(INT_SYM)},
{ "INTERVAL", SYM(INTERVAL_SYM)},
{ "INTO", SYM(INTO)},
+ { "IO", SYM(IO_SYM)},
{ "IO_THREAD", SYM(RELAY_THREAD)},
+ { "IPC", SYM(IPC_SYM)},
{ "IS", SYM(IS)},
{ "ISOLATION", SYM(ISOLATION)},
{ "ISSUER", SYM(ISSUER_SYM)},
@@ -310,6 +316,7 @@ static SYMBOL symbols[] = {
{ "MEDIUMBLOB", SYM(MEDIUMBLOB)},
{ "MEDIUMINT", SYM(MEDIUMINT)},
{ "MEDIUMTEXT", SYM(MEDIUMTEXT)},
+ { "MEMORY", SYM(MEMORY_SYM)},
{ "MERGE", SYM(MERGE_SYM)},
{ "MICROSECOND", SYM(MICROSECOND_SYM)},
{ "MIDDLEINT", SYM(MEDIUMINT)}, /* For powerbuilder */
@@ -357,6 +364,7 @@ static SYMBOL symbols[] = {
{ "OUT", SYM(OUT_SYM)},
{ "OUTER", SYM(OUTER)},
{ "OUTFILE", SYM(OUTFILE)},
+ { "PAGE", SYM(PAGE_SYM)},
{ "PACK_KEYS", SYM(PACK_KEYS_SYM)},
{ "PARTIAL", SYM(PARTIAL)},
{ "PASSWORD", SYM(PASSWORD)},
@@ -371,6 +379,8 @@ static SYMBOL symbols[] = {
{ "PROCEDURE", SYM(PROCEDURE)},
{ "PROCESS" , SYM(PROCESS)},
{ "PROCESSLIST", SYM(PROCESSLIST_SYM)},
+ { "PROFILE", SYM(PROFILE_SYM)},
+ { "PROFILES", SYM(PROFILES_SYM)},
{ "PURGE", SYM(PURGE)},
{ "QUARTER", SYM(QUARTER_SYM)},
{ "QUERY", SYM(QUERY_SYM)},
@@ -438,6 +448,7 @@ static SYMBOL symbols[] = {
{ "SOME", SYM(ANY_SYM)},
{ "SONAME", SYM(UDF_SONAME_SYM)},
{ "SOUNDS", SYM(SOUNDS_SYM)},
+ { "SOURCE", SYM(SOURCE_SYM)},
{ "SPATIAL", SYM(SPATIAL_SYM)},
{ "SPECIFIC", SYM(SPECIFIC_SYM)},
{ "SQL", SYM(SQL_SYM)},
@@ -472,6 +483,8 @@ static SYMBOL symbols[] = {
{ "SUBJECT", SYM(SUBJECT_SYM)},
{ "SUPER", SYM(SUPER_SYM)},
{ "SUSPEND", SYM(SUSPEND_SYM)},
+ { "SWAPS", SYM(SWAPS_SYM)},
+ { "SWITCHES", SYM(SWITCHES_SYM)},
{ "TABLE", SYM(TABLE_SYM)},
{ "TABLES", SYM(TABLES)},
{ "TABLESPACE", SYM(TABLESPACE)},
diff --git a/sql/lock.cc b/sql/lock.cc
index 90ddcc957a2..71c0b753b2a 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -151,7 +151,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
}
}
- thd->proc_info="System lock";
+ THD_PROC_INFO(thd, "System lock");
if (lock_external(thd, tables, count))
{
/* Clear the lock type of all lock data to avoid reusage. */
@@ -160,7 +160,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
sql_lock=0;
break;
}
- thd->proc_info="Table lock";
+ THD_PROC_INFO(thd, "Table lock");
thd->locked=1;
/* Copy the lock data array. thr_multi_lock() reorders its contens. */
memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
@@ -194,7 +194,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
thd->locked=0;
break;
}
- thd->proc_info=0;
+ THD_PROC_INFO(thd, 0);
/* some table was altered or deleted. reopen tables marked deleted */
mysql_unlock_tables(thd,sql_lock);
@@ -209,7 +209,7 @@ retry:
if (wait_for_tables(thd))
break; // Couldn't open tables
}
- thd->proc_info=0;
+ THD_PROC_INFO(thd, 0);
if (thd->killed)
{
thd->send_kill_message();
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 0d7ef7e8f2a..e6f4665d49b 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -4266,7 +4266,7 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
bzero((char*)&file, sizeof(file));
fname_buf= strmov(proc_info, "Making temp file ");
ext= slave_load_file_stem(fname_buf, file_id, server_id, ".info");
- thd->proc_info= proc_info;
+ THD_PROC_INFO(thd, proc_info);
my_delete(fname_buf, MYF(0)); // old copy may exist already
if ((fd= my_create(fname_buf, CREATE_MODE,
O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
@@ -4320,7 +4320,7 @@ err:
end_io_cache(&file);
if (fd >= 0)
my_close(fd, MYF(0));
- thd->proc_info= 0;
+ THD_PROC_INFO(thd, 0);
return error ? 1 : Log_event::exec_event(rli);
}
#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
@@ -4440,7 +4440,7 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
fname= strmov(proc_info, "Making temp file ");
slave_load_file_stem(fname, file_id, server_id, ".data");
- thd->proc_info= proc_info;
+ THD_PROC_INFO(thd, proc_info);
if (get_create_or_append())
{
my_delete(fname, MYF(0)); // old copy may exist already
@@ -4474,7 +4474,7 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
err:
if (fd >= 0)
my_close(fd, MYF(0));
- thd->proc_info= 0;
+ THD_PROC_INFO(thd, 0);
DBUG_RETURN(error ? error : Log_event::exec_event(rli));
}
#endif
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index c5ec6f02cdd..06762516f76 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -174,6 +174,8 @@ MY_LOCALE *my_locale_by_name(const char *name);
#define BDB_LOG_ALLOC_BLOCK_SIZE 1024
#define WARN_ALLOC_BLOCK_SIZE 2048
#define WARN_ALLOC_PREALLOC_SIZE 1024
+#define PROFILE_ALLOC_BLOCK_SIZE 2048
+#define PROFILE_ALLOC_PREALLOC_SIZE 1024
/*
The following parameters is to decide when to use an extra cache to
@@ -542,6 +544,8 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
#include "field.h" /* Field definitions */
#include "protocol.h"
#include "sql_udf.h"
+#include "sql_profile.h"
+
class user_var_entry;
class Security_context;
enum enum_var_type
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 21e46e71825..e085ebc77b2 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -92,7 +92,7 @@ static int init_failsafe_rpl_thread(THD* thd)
if (thd->variables.max_join_size == HA_POS_ERROR)
thd->options|= OPTION_BIG_SELECTS;
- thd->proc_info="Thread initialized";
+ THD_PROC_INFO(thd, "Thread initialized");
thd->version=refresh_version;
thd->set_time();
DBUG_RETURN(0);
@@ -598,7 +598,7 @@ pthread_handler_t handle_failsafe_rpl(void *arg)
{
bool break_req_chain = 0;
pthread_cond_wait(&COND_rpl_status, &LOCK_rpl_status);
- thd->proc_info="Processing request";
+ THD_PROC_INFO(thd, "Processing request");
while (!break_req_chain)
{
switch (rpl_status) {
@@ -942,7 +942,7 @@ bool load_master_data(THD* thd)
goto err;
}
}
- thd->proc_info="purging old relay logs";
+ THD_PROC_INFO(thd, "purging old relay logs");
if (purge_relay_logs(&active_mi->rli,thd,
0 /* not only reset, but also reinit */,
&errmsg))
diff --git a/sql/slave.cc b/sql/slave.cc
index d0396444ace..eaa53a15ac3 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -2925,9 +2925,9 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
#endif
if (thd_type == SLAVE_THD_SQL)
- thd->proc_info= "Waiting for the next event in relay log";
+ THD_PROC_INFO(thd, "Waiting for the next event in relay log");
else
- thd->proc_info= "Waiting for master update";
+ THD_PROC_INFO(thd, "Waiting for master update");
thd->version=refresh_version;
thd->set_time();
DBUG_RETURN(0);
@@ -3546,7 +3546,7 @@ dump");
}
mi->slave_running= MYSQL_SLAVE_RUN_NOT_CONNECT;
- thd->proc_info= "Waiting to reconnect after a failed binlog dump request";
+ THD_PROC_INFO(thd, "Waiting to reconnect after a failed binlog dump request");
#ifdef SIGNAL_WITH_VIO_CLOSE
thd->clear_active_vio();
#endif
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 152bc87aead..badd8c3f9cf 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -2372,9 +2372,9 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
m_lex->unit.cleanup();
- thd->proc_info="closing tables";
+ THD_PROC_INFO(thd, "closing tables");
close_thread_tables(thd);
- thd->proc_info= 0;
+ THD_PROC_INFO(thd, 0);
if (m_lex->query_tables_own_last)
{
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 90043e45052..54af1064088 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -309,7 +309,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
*/
thd->mysys_var->current_mutex= &LOCK_open;
thd->mysys_var->current_cond= &COND_refresh;
- thd->proc_info="Flushing tables";
+ THD_PROC_INFO(thd, "Flushing tables");
close_old_data_files(thd,thd->open_tables,1,1);
mysql_ha_flush(thd, tables, MYSQL_HA_REOPEN_ON_USAGE | MYSQL_HA_FLUSH_ALL,
@@ -351,7 +351,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
pthread_mutex_lock(&thd->mysys_var->mutex);
thd->mysys_var->current_mutex= 0;
thd->mysys_var->current_cond= 0;
- thd->proc_info=0;
+ THD_PROC_INFO(thd, 0);
pthread_mutex_unlock(&thd->mysys_var->mutex);
}
DBUG_RETURN(result);
@@ -1065,7 +1065,7 @@ void wait_for_refresh(THD *thd)
thd->mysys_var->current_mutex= &LOCK_open;
thd->mysys_var->current_cond= &COND_refresh;
proc_info=thd->proc_info;
- thd->proc_info="Waiting for table";
+ THD_PROC_INFO(thd, "Waiting for table");
if (!thd->killed)
(void) pthread_cond_wait(&COND_refresh,&LOCK_open);
@@ -1073,7 +1073,7 @@ void wait_for_refresh(THD *thd)
pthread_mutex_lock(&thd->mysys_var->mutex);
thd->mysys_var->current_mutex= 0;
thd->mysys_var->current_cond= 0;
- thd->proc_info= proc_info;
+ THD_PROC_INFO(thd, proc_info);
pthread_mutex_unlock(&thd->mysys_var->mutex);
DBUG_VOID_RETURN;
}
@@ -1778,7 +1778,7 @@ bool wait_for_tables(THD *thd)
bool result;
DBUG_ENTER("wait_for_tables");
- thd->proc_info="Waiting for tables";
+ THD_PROC_INFO(thd, "Waiting for tables");
pthread_mutex_lock(&LOCK_open);
while (!thd->killed)
{
@@ -1794,12 +1794,12 @@ bool wait_for_tables(THD *thd)
else
{
/* Now we can open all tables without any interference */
- thd->proc_info="Reopen tables";
+ THD_PROC_INFO(thd, "Reopen tables");
thd->version= refresh_version;
result=reopen_tables(thd,0,0);
}
pthread_mutex_unlock(&LOCK_open);
- thd->proc_info=0;
+ THD_PROC_INFO(thd, 0);
DBUG_RETURN(result);
}
@@ -2098,7 +2098,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
restart:
*counter= 0;
query_tables_last_own= 0;
- thd->proc_info="Opening tables";
+ THD_PROC_INFO(thd, "Opening tables");
/*
If we are not already executing prelocked statement and don't have
@@ -2278,7 +2278,7 @@ process_view_routines:
}
err:
- thd->proc_info=0;
+ THD_PROC_INFO(thd, 0);
free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block
if (query_tables_last_own)
@@ -2352,7 +2352,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
bool refresh;
DBUG_ENTER("open_ltable");
- thd->proc_info="Opening table";
+ THD_PROC_INFO(thd, "Opening table");
thd->current_tablenr= 0;
/* open_ltable can be used only for BASIC TABLEs */
table_list->required_type= FRMTYPE_TABLE;
@@ -2386,7 +2386,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
table= 0;
}
}
- thd->proc_info=0;
+ THD_PROC_INFO(thd, 0);
DBUG_RETURN(table);
}
@@ -5387,7 +5387,7 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
List_iterator<Item_func_match> li(*(select_lex->ftfunc_list));
Item_func_match *ifm;
DBUG_PRINT("info",("Performing FULLTEXT search"));
- thd->proc_info="FULLTEXT initialization";
+ THD_PROC_INFO(thd, "FULLTEXT initialization");
while ((ifm=li++))
ifm->init_search(no_order);
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 2c77e0ef230..3f9a41fecd9 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -670,6 +670,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
void query_cache_abort(NET *net)
{
DBUG_ENTER("query_cache_abort");
+ THD *thd= current_thd;
/* See the comment on double-check locking usage above. */
if (net->query_cache_query == 0)
@@ -688,6 +689,7 @@ void query_cache_abort(NET *net)
net->query_cache_query);
if (query_block) // Test if changed by other thread
{
+ THD_PROC_INFO(thd, "storing result in query cache");
DUMP(&query_cache);
BLOCK_LOCK_WR(query_block);
// The following call will remove the lock on query_block
@@ -725,6 +727,7 @@ void query_cache_end_of_result(THD *thd)
query_block= ((Query_cache_block*) thd->net.query_cache_query);
if (query_block)
{
+ THD_PROC_INFO(thd, "storing result in query cache");
DUMP(&query_cache);
BLOCK_LOCK_WR(query_block);
Query_cache_query *header= query_block->query();
@@ -1089,6 +1092,8 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
DBUG_PRINT("qcache", ("No active database"));
}
+ THD_PROC_INFO(thd, "checking query cache for query");
+
// fill all gaps between fields with 0 to get repeatable key
bzero(&flags, QUERY_CACHE_FLAGS_SIZE);
flags.client_long_flag= test(thd->client_capabilities & CLIENT_LONG_FLAG);
@@ -1163,6 +1168,7 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
}
// Check access;
+ THD_PROC_INFO(thd, "checking privileges on cached query");
block_table= query_block->table(0);
block_table_end= block_table+query_block->n_tables;
for (; block_table != block_table_end; block_table++)
@@ -1255,6 +1261,7 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
Send cached result to client
*/
#ifndef EMBEDDED_LIBRARY
+ THD_PROC_INFO(thd, "sending cached result to client");
do
{
DBUG_PRINT("qcache", ("Results (len: %lu used: %lu headers: %lu)",
@@ -1332,9 +1339,11 @@ void Query_cache::invalidate(THD *thd, TABLE_LIST *tables_used,
void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used)
{
+ THD *thd= current_thd;
DBUG_ENTER("Query_cache::invalidate (changed table list)");
if (tables_used)
{
+ THD_PROC_INFO(thd, "invalidating query cache entries (table list)");
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0 && !flush_in_progress)
{
@@ -1365,9 +1374,11 @@ void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used)
*/
void Query_cache::invalidate_locked_for_write(TABLE_LIST *tables_used)
{
+ THD *thd= current_thd;
DBUG_ENTER("Query_cache::invalidate_locked_for_write");
if (tables_used)
{
+ THD_PROC_INFO(thd, "invalidating query cache entries (table)");
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0 && !flush_in_progress)
{
@@ -1417,6 +1428,7 @@ void Query_cache::invalidate(THD *thd, const char *key, uint32 key_length,
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0 && !flush_in_progress)
{
+ THD_PROC_INFO(thd, "invalidating query cache entries (key)");
using_transactions= using_transactions &&
(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
if (using_transactions) // used for innodb => has_transactions() is TRUE
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index d2f1e9ed0d9..3745f537612 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -248,6 +248,7 @@ THD::THD()
init();
/* Initialize sub structures */
init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
+ profiling.set_thd(this);
user_connect=(USER_CONN *)0;
hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(hash_get_key) get_var_key,
@@ -330,6 +331,7 @@ void THD::init_for_queries()
variables.trans_alloc_block_size,
variables.trans_prealloc_size);
#endif
+ profiling.reset();
transaction.xid_state.xid.null();
transaction.xid_state.in_thd=1;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 9ad67524998..cbccaf884b0 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1309,6 +1309,9 @@ public:
List <MYSQL_ERROR> warn_list;
uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
uint total_warn_count;
+
+ PROFILING profiling;
+
/*
Id of current query. Statement can be reused to execute several queries
query_id is global in context of the whole MySQL server.
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index b665113dd18..ecb0f498812 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -55,7 +55,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
table->file->print_error(error, MYF(0));
DBUG_RETURN(error);
}
- thd->proc_info="init";
+ THD_PROC_INFO(thd, "init");
table->map=1;
if (mysql_prepare_delete(thd, table_list, &conds))
@@ -206,7 +206,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
deleted=0L;
init_ftfuncs(thd, select_lex, 1);
- thd->proc_info="updating";
+ THD_PROC_INFO(thd, "updating");
if (table->triggers)
table->triggers->mark_fields_used(thd, TRG_EVENT_DELETE);
@@ -262,7 +262,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
}
if (thd->killed && !error)
error= 1; // Aborted
- thd->proc_info="end";
+ THD_PROC_INFO(thd, "end");
end_read_record(&info);
free_io_cache(table); // Will not do any harm
if (options & OPTION_QUICK)
@@ -486,7 +486,7 @@ multi_delete::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
DBUG_ENTER("multi_delete::prepare");
unit= u;
do_delete= 1;
- thd->proc_info="deleting from main table";
+ THD_PROC_INFO(thd, "deleting from main table");
DBUG_RETURN(0);
}
@@ -750,7 +750,7 @@ int multi_delete::do_deletes()
bool multi_delete::send_eof()
{
- thd->proc_info="deleting from reference tables";
+ THD_PROC_INFO(thd, "deleting from reference tables");
/* Does deletes for the last n - 1 tables, returns 0 if ok */
int local_error= do_deletes(); // returns 0 if success
@@ -759,7 +759,7 @@ bool multi_delete::send_eof()
local_error= local_error || error;
/* reset used flags */
- thd->proc_info="end";
+ THD_PROC_INFO(thd, "end");
/*
We must invalidate the query cache before binlog writing and
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 2ce83caa369..48bb8305e02 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -398,7 +398,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (res || thd->is_fatal_error)
DBUG_RETURN(TRUE);
- thd->proc_info="init";
+ THD_PROC_INFO(thd, "init");
thd->used_tables=0;
values= its++;
@@ -471,7 +471,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
error=0;
id=0;
- thd->proc_info="update";
+ THD_PROC_INFO(thd, "update");
if (duplic != DUP_ERROR || ignore)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
if (duplic == DUP_REPLACE)
@@ -677,7 +677,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->lock=0;
}
}
- thd->proc_info="end";
+ THD_PROC_INFO(thd, "end");
table->next_number_field=0;
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
thd->next_insert_id=0; // Reset this if wrongly used
@@ -1408,7 +1408,7 @@ I_List<delayed_insert> delayed_threads;
delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list)
{
- thd->proc_info="waiting for delay_list";
+ THD_PROC_INFO(thd, "waiting for delay_list");
pthread_mutex_lock(&LOCK_delayed_insert); // Protect master list
I_List_iterator<delayed_insert> it(delayed_threads);
delayed_insert *tmp;
@@ -1445,7 +1445,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
*/
if (delayed_insert_threads >= thd->variables.max_insert_delayed_threads)
DBUG_RETURN(0);
- thd->proc_info="Creating delayed handler";
+ THD_PROC_INFO(thd, "Creating delayed handler");
pthread_mutex_lock(&LOCK_delayed_create);
/*
The first search above was done without LOCK_delayed_create.
@@ -1487,13 +1487,13 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
}
/* Wait until table is open */
- thd->proc_info="waiting for handler open";
+ THD_PROC_INFO(thd, "waiting for handler open");
while (!tmp->thd.killed && !tmp->table && !thd->killed)
{
pthread_cond_wait(&tmp->cond_client,&tmp->mutex);
}
pthread_mutex_unlock(&tmp->mutex);
- thd->proc_info="got old table";
+ THD_PROC_INFO(thd, "got old table");
if (tmp->thd.killed)
{
if (tmp->thd.is_fatal_error)
@@ -1553,13 +1553,13 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
tables_in_use++;
if (!thd.lock) // Table is not locked
{
- client_thd->proc_info="waiting for handler lock";
+ THD_PROC_INFO(client_thd, "waiting for handler lock");
pthread_cond_signal(&cond); // Tell handler to lock table
while (!dead && !thd.lock && ! client_thd->killed)
{
pthread_cond_wait(&cond_client,&mutex);
}
- client_thd->proc_info="got handler lock";
+ THD_PROC_INFO(client_thd, "got handler lock");
if (client_thd->killed)
goto error;
if (dead)
@@ -1577,7 +1577,7 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
bytes. Since the table copy is used for creating one record only,
the other record buffers and alignment are unnecessary.
*/
- client_thd->proc_info="allocating local table";
+ THD_PROC_INFO(client_thd, "allocating local table");
copy= (TABLE*) client_thd->alloc(sizeof(*copy)+
(table->s->fields+1)*sizeof(Field**)+
table->s->reclength);
@@ -1657,11 +1657,11 @@ static int write_delayed(THD *thd,TABLE *table,enum_duplicates duplic, bool igno
delayed_insert *di=thd->di;
DBUG_ENTER("write_delayed");
- thd->proc_info="waiting for handler insert";
+ THD_PROC_INFO(thd, "waiting for handler insert");
pthread_mutex_lock(&di->mutex);
while (di->stacked_inserts >= delayed_queue_size && !thd->killed)
pthread_cond_wait(&di->cond_client,&di->mutex);
- thd->proc_info="storing row into queue";
+ THD_PROC_INFO(thd, "storing row into queue");
if (thd->killed || !(row= new delayed_row(duplic, ignore, log_on)))
goto err;
@@ -1873,7 +1873,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
/* Information for pthread_kill */
di->thd.mysys_var->current_mutex= &di->mutex;
di->thd.mysys_var->current_cond= &di->cond;
- di->thd.proc_info="Waiting for INSERT";
+ THD_PROC_INFO(&(di->thd), "Waiting for INSERT");
DBUG_PRINT("info",("Waiting for someone to insert rows"));
while (!thd->killed)
@@ -1908,7 +1908,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
pthread_mutex_unlock(&di->thd.mysys_var->mutex);
pthread_mutex_lock(&di->mutex);
}
- di->thd.proc_info=0;
+ THD_PROC_INFO(&(di->thd), 0);
if (di->tables_in_use && ! thd->lock)
{
@@ -2027,7 +2027,7 @@ bool delayed_insert::handle_inserts(void)
table->next_number_field=table->found_next_number_field;
- thd.proc_info="upgrading lock";
+ THD_PROC_INFO(&thd, "upgrading lock");
if (thr_upgrade_write_delay_lock(*thd.lock->locks))
{
/* This can only happen if thread is killed by shutdown */
@@ -2035,7 +2035,7 @@ bool delayed_insert::handle_inserts(void)
goto err;
}
- thd.proc_info="insert";
+ THD_PROC_INFO(&thd, "insert");
max_rows= delayed_insert_limit;
if (thd.killed || table->s->version != refresh_version)
{
@@ -2153,7 +2153,7 @@ bool delayed_insert::handle_inserts(void)
{
if (tables_in_use)
pthread_cond_broadcast(&cond_client); // If waiting clients
- thd.proc_info="reschedule";
+ THD_PROC_INFO(&thd, "reschedule");
pthread_mutex_unlock(&mutex);
if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
{
@@ -2172,14 +2172,14 @@ bool delayed_insert::handle_inserts(void)
if (!using_bin_log)
table->file->extra(HA_EXTRA_WRITE_CACHE);
pthread_mutex_lock(&mutex);
- thd.proc_info="insert";
+ THD_PROC_INFO(&thd, "insert");
}
if (tables_in_use)
pthread_cond_broadcast(&cond_client); // If waiting clients
}
}
- thd.proc_info=0;
+ THD_PROC_INFO(&thd, 0);
table->next_number_field=0;
pthread_mutex_unlock(&mutex);
if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 3de842c8551..7e775cfffdd 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -174,6 +174,7 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->proc_list.first= 0;
lex->escape_used= FALSE;
lex->reset_query_tables_list(FALSE);
+ lex->profile_options= PROFILE_NONE;
lex->nest_level=0 ;
lex->allow_sum_func= 0;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index be12467d097..a918188a4bc 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -95,6 +95,7 @@ enum enum_sql_command {
SQLCOM_XA_START, SQLCOM_XA_END, SQLCOM_XA_PREPARE,
SQLCOM_XA_COMMIT, SQLCOM_XA_ROLLBACK, SQLCOM_XA_RECOVER,
SQLCOM_SHOW_PROC_CODE, SQLCOM_SHOW_FUNC_CODE,
+ SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES,
/* This should be the last !!! */
SQLCOM_END
@@ -940,6 +941,8 @@ typedef struct st_lex : public Query_tables_list
enum enum_var_type option_type;
enum enum_view_create_mode create_view_mode;
enum enum_drop_mode drop_mode;
+ uint profile_options;
+ uint profile_query_id;
uint uint_geom_type;
uint grant, grant_tot_col, which_columns;
uint fk_delete_opt, fk_update_opt, fk_match_option;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index fec7e5ab20d..4124db36b7f 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1059,7 +1059,7 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var,
Vio* save_vio;
ulong save_client_capabilities;
- thd->proc_info= "Execution of init_command";
+ THD_PROC_INFO(thd, "Execution of init_command");
/*
We need to lock init_command_var because
during execution of init_command_var query
@@ -1159,7 +1159,7 @@ pthread_handler_t handle_one_connection(void *arg)
net->compress=1; // Use compression
thd->version= refresh_version;
- thd->proc_info= 0;
+ THD_PROC_INFO(thd, 0);
thd->command= COM_SLEEP;
thd->set_time();
thd->init_for_queries();
@@ -1176,7 +1176,7 @@ pthread_handler_t handle_one_connection(void *arg)
sctx->host_or_ip, "init_connect command failed");
sql_print_warning("%s", net->last_error);
}
- thd->proc_info=0;
+ THD_PROC_INFO(thd, 0);
thd->set_time();
thd->init_for_queries();
}
@@ -1259,7 +1259,7 @@ pthread_handler_t handle_bootstrap(void *arg)
if (thd->variables.max_join_size == HA_POS_ERROR)
thd->options |= OPTION_BIG_SELECTS;
- thd->proc_info=0;
+ THD_PROC_INFO(thd, 0);
thd->version=refresh_version;
thd->security_ctx->priv_user=
thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
@@ -2106,7 +2106,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (thd->lock || thd->open_tables || thd->derived_tables ||
thd->prelocked_mode)
{
- thd->proc_info="closing tables";
+ THD_PROC_INFO(thd, "closing tables");
close_thread_tables(thd); /* Free tables */
}
/*
@@ -2129,9 +2129,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
log_slow_statement(thd);
- thd->proc_info="cleaning up";
+ THD_PROC_INFO(thd, "cleaning up");
VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
- thd->proc_info=0;
+ THD_PROC_INFO(thd, 0);
thd->command=COM_SLEEP;
thd->query=0;
thd->query_length=0;
@@ -2164,8 +2164,6 @@ void log_slow_statement(THD *thd)
*/
if (thd->enable_slow_log && !thd->user_time)
{
- thd->proc_info="logging slow query";
-
if ((ulong) (thd->start_time - thd->time_after_lock) >
thd->variables.long_query_time ||
(thd->server_status &
@@ -2174,6 +2172,7 @@ void log_slow_statement(THD *thd)
/* == SQLCOM_END unless this is a SHOW command */
thd->lex->orig_sql_command == SQLCOM_END)
{
+ THD_PROC_INFO(thd, "logging slow query");
thd->status_var.long_query_count++;
mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
}
@@ -2697,6 +2696,20 @@ mysql_execute_command(THD *thd)
(1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
break;
}
+ case SQLCOM_SHOW_PROFILES:
+ {
+ thd->profiling.store();
+ thd->profiling.discard();
+ res= thd->profiling.show_profiles();
+ break;
+ }
+ case SQLCOM_SHOW_PROFILE:
+ {
+ thd->profiling.store();
+ thd->profiling.discard(); // will get re-enabled by reset()
+ res= thd->profiling.show_last(lex->profile_options);
+ break;
+ }
case SQLCOM_SHOW_NEW_MASTER:
{
if (check_global_access(thd, REPL_SLAVE_ACL))
@@ -3544,7 +3557,7 @@ end_with_restore_list:
if (add_item_to_list(thd, new Item_null()))
goto error;
- thd->proc_info="init";
+ THD_PROC_INFO(thd, "init");
if ((res= open_and_lock_tables(thd, all_tables)))
break;
@@ -4972,7 +4985,7 @@ end_with_restore_list:
send_ok(thd);
break;
}
- thd->proc_info="query end";
+ THD_PROC_INFO(thd, "query end");
/* Two binlog-related cleanups: */
/*
@@ -5143,6 +5156,8 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
else
save_priv= &dummy;
+ THD_PROC_INFO(thd, "checking permissions");
+
if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
{
DBUG_PRINT("error",("No database"));
@@ -5630,6 +5645,7 @@ void mysql_reset_thd_for_next_command(THD *thd)
thd->total_warn_count=0; // Warnings for this query
thd->rand_used= 0;
thd->sent_row_count= thd->examined_row_count= 0;
+ thd->profiling.reset();
}
DBUG_VOID_RETURN;
}
@@ -5853,7 +5869,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
query_cache_abort(&thd->net);
lex->unit.cleanup();
}
- thd->proc_info="freeing items";
+ THD_PROC_INFO(thd, "freeing items");
thd->end_statement();
thd->cleanup_after_query();
DBUG_ASSERT(thd->change_list.is_empty());
diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc
new file mode 100644
index 00000000000..98a5f8d7576
--- /dev/null
+++ b/sql/sql_profile.cc
@@ -0,0 +1,441 @@
+/* Copyright (C) 2005 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "mysql_priv.h"
+#include "sp_rcontext.h"
+
+#define RUSAGE_USEC(tv) ((tv).tv_sec*1000000 + (tv).tv_usec)
+#define RUSAGE_DIFF_USEC(tv1, tv2) (RUSAGE_USEC((tv1))-RUSAGE_USEC((tv2)))
+
+PROFILE_ENTRY::PROFILE_ENTRY()
+ :status(NULL), time(0), function(NULL), file(NULL), line(0)
+{
+ collect();
+}
+
+PROFILE_ENTRY::PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg)
+ :profile(profile_arg), function(NULL), file(NULL), line(0)
+{
+ collect();
+ if (status_arg)
+ set_status(status_arg);
+}
+
+PROFILE_ENTRY::PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg,
+ const char *function_arg,
+ const char *file_arg, unsigned int line_arg)
+ :profile(profile_arg)
+{
+ collect();
+ if (status_arg)
+ set_status(status_arg);
+ if (function_arg)
+ function= strdup_root(&profile->profiling->root, function_arg);
+ if (file_arg)
+ file= strdup_root(&profile->profiling->root, file_arg);
+ line= line_arg;
+}
+
+PROFILE_ENTRY::~PROFILE_ENTRY()
+{
+ if (status)
+ free(status);
+ if (function)
+ free(function);
+ if (file)
+ free(file);
+}
+
+void PROFILE_ENTRY::set_status(const char *status_arg)
+{
+ status= strdup_root(&profile->profiling->root, status_arg);
+}
+
+void PROFILE_ENTRY::collect()
+{
+ time= my_getsystime();
+ getrusage(RUSAGE_SELF, &rusage);
+}
+
+PROFILE::PROFILE(PROFILING *profiling_arg)
+ :profiling(profiling_arg)
+{
+ profile_end= &profile_start;
+}
+
+PROFILE::~PROFILE()
+{
+ entries.empty();
+}
+
+void PROFILE::status(const char *status_arg,
+ const char *function_arg=NULL,
+ const char *file_arg=NULL, unsigned int line_arg=0)
+{
+ PROFILE_ENTRY *prof= NULL;
+ MEM_ROOT *old_root= NULL;
+ THD *thd= profiling->thd;
+
+ DBUG_ENTER("PROFILE::status");
+
+ /* Blank status. Just return, and thd->proc_info will be set blank later. */
+ if (unlikely(!status_arg))
+ DBUG_VOID_RETURN;
+
+ /* If thd->proc_info is currently set to status_arg, don't profile twice. */
+ if (unlikely(thd->proc_info && !(strcmp(thd->proc_info, status_arg))))
+ DBUG_VOID_RETURN;
+
+ /* Is this the same query as our profile currently contains? */
+ if (unlikely(thd->query_id != query_id && !thd->spcont))
+ reset();
+
+ /*
+ In order to keep the profile information between queries (i.e. from
+ SELECT to the following SHOW PROFILE command) the following code is
+ necessary to keep the profile from getting freed automatically when
+ mysqld cleans up after the query. This code is shamelessly stolen
+ from SHOW WARNINGS.
+
+ The thd->mem_root structure is freed after each query is completed,
+ so temporarily override it.
+ */
+ old_root= thd->mem_root;
+ thd->mem_root= &profiling->root;
+ if (function_arg && file_arg) {
+ if ((profile_end= prof= new PROFILE_ENTRY(this, status_arg, function_arg, file_arg, line_arg)))
+ entries.push_back(prof);
+ } else {
+ if ((profile_end= prof= new PROFILE_ENTRY(this, status_arg)))
+ entries.push_back(prof);
+ }
+ thd->mem_root= old_root;
+
+ DBUG_VOID_RETURN;
+}
+
+void PROFILE::reset()
+{
+ DBUG_ENTER("PROFILE::reset");
+ if (profiling->thd->query_id != query_id)
+ {
+ query_id= profiling->thd->query_id;
+ profile_start.collect();
+ entries.empty();
+ }
+ DBUG_VOID_RETURN;
+}
+
+bool PROFILE::show(uint options)
+{
+ PROFILE_ENTRY *prof;
+ THD *thd= profiling->thd;
+ PROFILE_ENTRY *ps= &profile_start;
+ List<Item> field_list;
+ DBUG_ENTER("PROFILE::show");
+
+ field_list.push_back(new Item_empty_string("Status", MYSQL_ERRMSG_SIZE));
+ field_list.push_back(new Item_return_int("Time_elapsed", 20,
+ MYSQL_TYPE_LONGLONG));
+
+ if (options & PROFILE_CPU)
+ {
+ field_list.push_back(new Item_return_int("CPU_user", 20,
+ MYSQL_TYPE_LONGLONG));
+ field_list.push_back(new Item_return_int("CPU_system", 20,
+ MYSQL_TYPE_LONGLONG));
+ }
+
+ if (options & PROFILE_MEMORY)
+ {
+ }
+
+ if (options & PROFILE_CONTEXT)
+ {
+ field_list.push_back(new Item_return_int("Context_voluntary", 10,
+ MYSQL_TYPE_LONG));
+ field_list.push_back(new Item_return_int("Context_involuntary", 10,
+ MYSQL_TYPE_LONG));
+ }
+
+ if (options & PROFILE_BLOCK_IO)
+ {
+ field_list.push_back(new Item_return_int("Block_ops_in", 10,
+ MYSQL_TYPE_LONG));
+ field_list.push_back(new Item_return_int("Block_ops_out", 10,
+ MYSQL_TYPE_LONG));
+ }
+
+ if (options & PROFILE_IPC)
+ {
+ field_list.push_back(new Item_return_int("Messages_sent", 10,
+ MYSQL_TYPE_LONG));
+ field_list.push_back(new Item_return_int("Messages_received", 10,
+ MYSQL_TYPE_LONG));
+ }
+
+ if (options & PROFILE_PAGE_FAULTS)
+ {
+ field_list.push_back(new Item_return_int("Page_faults_major", 10,
+ MYSQL_TYPE_LONG));
+ field_list.push_back(new Item_return_int("Page_faults_minor", 10,
+ MYSQL_TYPE_LONG));
+ }
+
+ if (options & PROFILE_SWAPS)
+ {
+ field_list.push_back(new Item_return_int("Swaps", 10, MYSQL_TYPE_LONG));
+ }
+
+ if(options & PROFILE_SOURCE)
+ {
+ field_list.push_back(new Item_empty_string("Source_function",
+ MYSQL_ERRMSG_SIZE));
+ field_list.push_back(new Item_empty_string("Source_file",
+ MYSQL_ERRMSG_SIZE));
+ field_list.push_back(new Item_return_int("Source_line", 10,
+ MYSQL_TYPE_LONG));
+ }
+
+ if (thd->protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
+
+ SELECT_LEX *sel= &thd->lex->select_lex;
+ SELECT_LEX_UNIT *unit= &thd->lex->unit;
+ ha_rows idx= 0;
+ Protocol *protocol=thd->protocol;
+
+ unit->set_limit(sel);
+
+ List_iterator<PROFILE_ENTRY> it(entries);
+ ulonglong last_time= ps->time;
+ while ((prof= it++))
+ {
+ if (++idx <= unit->offset_limit_cnt)
+ continue;
+ if (idx > unit->select_limit_cnt)
+ break;
+
+ protocol->prepare_for_resend();
+ protocol->store(prof->status, strlen(prof->status), system_charset_info);
+ protocol->store((ulonglong)(prof->time - ps->time)/10);
+
+ if (options & PROFILE_CPU)
+ {
+ protocol->store((ulonglong)RUSAGE_DIFF_USEC(prof->rusage.ru_utime,
+ ps->rusage.ru_utime));
+ protocol->store((ulonglong)RUSAGE_DIFF_USEC(prof->rusage.ru_stime,
+ ps->rusage.ru_stime));
+ }
+
+ if (options & PROFILE_CONTEXT)
+ {
+ protocol->store((uint32)(prof->rusage.ru_nvcsw - ps->rusage.ru_nvcsw));
+ protocol->store((uint32)(prof->rusage.ru_nivcsw - ps->rusage.ru_nivcsw));
+ }
+
+ if (options & PROFILE_BLOCK_IO)
+ {
+ protocol->store((uint32)(prof->rusage.ru_inblock-ps->rusage.ru_inblock));
+ protocol->store((uint32)(prof->rusage.ru_oublock-ps->rusage.ru_oublock));
+ }
+
+ if (options & PROFILE_IPC)
+ {
+ protocol->store((uint32)(prof->rusage.ru_msgsnd - ps->rusage.ru_msgsnd));
+ protocol->store((uint32)(prof->rusage.ru_msgrcv - ps->rusage.ru_msgrcv));
+ }
+
+ if (options & PROFILE_PAGE_FAULTS)
+ {
+ protocol->store((uint32)(prof->rusage.ru_majflt - ps->rusage.ru_majflt));
+ protocol->store((uint32)(prof->rusage.ru_minflt - ps->rusage.ru_minflt));
+ }
+
+ if (options & PROFILE_SWAPS)
+ {
+ protocol->store((uint32)(prof->rusage.ru_nswap - ps->rusage.ru_nswap));
+ }
+
+ if (options & PROFILE_SOURCE)
+ {
+ if(prof->function && prof->file)
+ {
+ protocol->store(prof->function, strlen(prof->function), system_charset_info);
+ protocol->store(prof->file, strlen(prof->file), system_charset_info);
+ protocol->store(prof->line);
+ } else {
+ protocol->store("(unknown)", 10, system_charset_info);
+ protocol->store("(unknown)", 10, system_charset_info);
+ protocol->store((uint32) 0);
+ }
+ }
+
+ if (protocol->write())
+ DBUG_RETURN(TRUE);
+ last_time= prof->time;
+ }
+ send_eof(thd);
+ DBUG_RETURN(FALSE);
+}
+
+/* XXX: enabled should be set to the current global profiling setting */
+PROFILING::PROFILING()
+ :enabled(1), keeping(1), current(NULL), last(NULL)
+{
+ init_sql_alloc(&root,
+ PROFILE_ALLOC_BLOCK_SIZE,
+ PROFILE_ALLOC_PREALLOC_SIZE);
+}
+
+PROFILING::~PROFILING()
+{
+ free_root(&root, MYF(0));
+}
+
+void PROFILING::status(const char *status_arg,
+ const char *function_arg,
+ const char *file_arg, unsigned int line_arg)
+{
+ DBUG_ENTER("PROFILING::status");
+
+ if(!current)
+ reset();
+
+ if(unlikely(enabled))
+ current->status(status_arg, function_arg, file_arg, line_arg);
+
+ thd->proc_info= status_arg;
+
+ DBUG_VOID_RETURN;
+}
+
+void PROFILING::store()
+{
+ MEM_ROOT *old_root;
+ DBUG_ENTER("PROFILING::store");
+
+ if (last && current && (last->query_id == current->query_id))
+ DBUG_VOID_RETURN;
+
+ if (history.elements > 10) /* XXX: global/session var */
+ {
+ PROFILE *tmp= history.pop();
+ delete tmp;
+ }
+
+ old_root= thd->mem_root;
+ thd->mem_root= &root;
+
+ if (current)
+ {
+ if (keeping && (!current->entries.is_empty())) {
+ last= current;
+ history.push_back(current);
+ current= NULL;
+ } else {
+ delete current;
+ }
+ }
+
+ current= new PROFILE(this);
+ thd->mem_root= old_root;
+
+ DBUG_VOID_RETURN;
+}
+
+void PROFILING::reset()
+{
+ DBUG_ENTER("PROFILING::reset");
+
+ store();
+
+ current->reset();
+ /*free_root(&root, MYF(0));*/
+ keep();
+
+ DBUG_VOID_RETURN;
+}
+
+bool PROFILING::show_profiles()
+{
+ PROFILE *prof;
+ List<Item> field_list;
+ DBUG_ENTER("PROFILING::list_all");
+
+ field_list.push_back(new Item_return_int("Query_ID", 10,
+ MYSQL_TYPE_LONG));
+ field_list.push_back(new Item_return_int("Time", 20,
+ MYSQL_TYPE_LONGLONG));
+ /* TODO: Add another field that lists the query. */
+
+ if (thd->protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
+
+ SELECT_LEX *sel= &thd->lex->select_lex;
+ SELECT_LEX_UNIT *unit= &thd->lex->unit;
+ ha_rows idx= 0;
+ Protocol *protocol=thd->protocol;
+
+ unit->set_limit(sel);
+
+ List_iterator<PROFILE> it(history);
+ while ((prof= it++))
+ {
+ PROFILE_ENTRY *ps= &prof->profile_start;
+ PROFILE_ENTRY *pe= prof->profile_end;
+
+ if (++idx <= unit->offset_limit_cnt)
+ continue;
+ if (idx > unit->select_limit_cnt)
+ break;
+
+ protocol->prepare_for_resend();
+ protocol->store((uint32)(prof->query_id));
+ protocol->store((ulonglong)((pe->time - ps->time)/10));
+
+ if (protocol->write())
+ DBUG_RETURN(TRUE);
+ }
+ send_eof(thd);
+ DBUG_RETURN(FALSE);
+}
+
+bool PROFILING::show(uint options, uint query_id)
+{
+ DBUG_ENTER("PROFILING::show");
+ PROFILE *prof;
+
+ List_iterator<PROFILE> it(history);
+ while ((prof= it++))
+ {
+ if(prof->query_id == query_id)
+ prof->show(options);
+ }
+
+ DBUG_RETURN(TRUE);
+}
+
+bool PROFILING::show_last(uint options)
+{
+ DBUG_ENTER("PROFILING::show_last");
+ if (!history.is_empty()) {
+ DBUG_RETURN(last->show(options));
+ }
+ DBUG_RETURN(TRUE);
+}
diff --git a/sql/sql_profile.h b/sql/sql_profile.h
new file mode 100644
index 00000000000..698a80f07e4
--- /dev/null
+++ b/sql/sql_profile.h
@@ -0,0 +1,187 @@
+/* Copyright (C) 2005 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef SQL_PROFILE_H
+#define SQL_PROFILE_H
+
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#if 1
+#define THD_PROC_INFO(thd, msg) do { if(unlikely((thd)->profiling.enabled)) { (thd)->profiling.status((msg), __FUNCTION__, __FILE__, __LINE__); } else { (thd)->proc_info= (msg); } } while (0)
+#else
+#define THD_PROC_INFO(thd, msg) do { (thd)->proc_info= (msg); } while (0)
+#endif
+
+#if 0
+
+ struct rusage {
+ struct timeval ru_utime; /* user time used */
+ struct timeval ru_stime; /* system time used */
+ long ru_maxrss; /* integral max resident set size */
+ long ru_ixrss; /* integral shared text memory size */
+ long ru_idrss; /* integral unshared data size */
+ long ru_isrss; /* integral unshared stack size */
+ long ru_minflt; /* page reclaims */
+ long ru_majflt; /* page faults */
+ long ru_nswap; /* swaps */
+ long ru_inblock; /* block input operations */
+ long ru_oublock; /* block output operations */
+ long ru_msgsnd; /* messages sent */
+ long ru_msgrcv; /* messages received */
+ long ru_nsignals; /* signals received */
+ long ru_nvcsw; /* voluntary context switches */
+ long ru_nivcsw; /* involuntary context switches */
+ };
+
+#endif
+
+#define PROFILE_NONE 0
+#define PROFILE_CPU 1
+#define PROFILE_MEMORY 2
+#define PROFILE_BLOCK_IO 4
+#define PROFILE_CONTEXT 8
+#define PROFILE_PAGE_FAULTS 16
+#define PROFILE_IPC 32
+#define PROFILE_SWAPS 64
+#define PROFILE_SOURCE 16384
+#define PROFILE_ALL 32767
+
+class PROFILE_ENTRY;
+class PROFILE;
+class PROFILING;
+
+/*
+ A single entry in a single profile.
+*/
+
+class PROFILE_ENTRY: public Sql_alloc
+{
+public:
+ PROFILE *profile;
+ char *status;
+ ulonglong time;
+ struct rusage rusage;
+
+ char *function;
+ char *file;
+ unsigned int line;
+
+ PROFILE_ENTRY();
+ PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg);
+ PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg,
+ const char *function_arg,
+ const char *file_arg, unsigned int line_arg);
+ ~PROFILE_ENTRY();
+
+ void set_status(const char *status_arg);
+ void collect();
+};
+
+/*
+ The full profile for a single query. Includes multiple PROFILE_ENTRY
+ objects.
+*/
+
+class PROFILE: public Sql_alloc
+{
+public:
+ PROFILING *profiling;
+ query_id_t query_id;
+ PROFILE_ENTRY profile_start;
+ PROFILE_ENTRY *profile_end;
+ List<PROFILE_ENTRY> entries;
+
+ PROFILE(PROFILING *profiling_arg);
+ ~PROFILE();
+
+ /* Add a profile status change to the current profile. */
+ void status(const char *status_arg,
+ const char *function_arg,
+ const char *file_arg, unsigned int line_arg);
+
+ /* Reset the contents of this profile entry. */
+ void reset();
+
+ /* Show this profile. This is called by PROFILING. */
+ bool show(uint options);
+};
+
+/*
+ Profiling state for a single THD. Contains multiple PROFILE objects.
+*/
+
+class PROFILING: public Sql_alloc
+{
+public:
+ MEM_ROOT root;
+ THD *thd;
+ bool enabled;
+ bool keeping;
+
+ PROFILE *current;
+ PROFILE *last;
+ List<PROFILE> history;
+
+ PROFILING();
+ ~PROFILING();
+
+ inline void set_thd(THD *thd_arg) { thd= thd_arg; };
+
+ /*
+ Should we try to collect profiling information at all?
+
+ If we disable profiling, we cannot later decide to turn it back
+ on for the same query.
+ */
+ inline void enable() { enabled= 1; };
+ inline void disable() { enabled= 0; };
+
+ /*
+ Do we intend to keep the currently collected profile?
+
+ We don't keep profiles for some commands, such as SHOW PROFILE,
+ SHOW PROFILES, and some SQLCOM commands which aren't useful to
+ profile. The keep() and discard() functions can be called many
+ times, only the final setting when the query finishes is used
+ to decide whether to discard the profile.
+
+ The default is to keep the profile for all queries.
+ */
+ inline void keep() { keeping= 1; };
+ inline void discard() { keeping= 0; };
+
+ void status(const char *status_arg,
+ const char *function_arg,
+ const char *file_arg, unsigned int line_arg);
+
+ /* Stash this profile in the profile history. */
+ void store();
+
+ /* Reset the current profile and state of profiling for the next query. */
+ void reset();
+
+ /* SHOW PROFILES */
+ bool show_profiles();
+
+ /* SHOW PROFILE FOR QUERY query_id */
+ bool show(uint options, uint query_id);
+
+ /* SHOW PROFILE */
+ bool show_last(uint options);
+};
+
+#endif /* SQL_PROFILE_H */
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 8da8bbe25ca..5da31ed479a 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1197,7 +1197,7 @@ bool change_master(THD* thd, MASTER_INFO* mi)
if (need_relay_log_purge)
{
relay_log_purge= 1;
- thd->proc_info="Purging old relay logs";
+ THD_PROC_INFO(thd, "Purging old relay logs");
if (purge_relay_logs(&mi->rli, thd,
0 /* not only reset, but also reinit */,
&errmsg))
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 3d2f46a9982..cb8f39084df 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -599,6 +599,7 @@ JOIN::optimize()
if (thd->lex->orig_sql_command != SQLCOM_SHOW_STATUS)
thd->status_var.last_query_cost= 0.0;
+ THD_PROC_INFO(thd, "optimizing");
row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR :
unit->select_limit_cnt);
/* select_limit is used to decide if we are likely to scan the whole table */
@@ -702,14 +703,14 @@ JOIN::optimize()
thd->fatal_error();
error= res;
DBUG_PRINT("error",("Error from opt_sum_query"));
- DBUG_RETURN(1);
+ DBUG_RETURN(1);
}
if (res < 0)
{
DBUG_PRINT("info",("No matching min/max row"));
- zero_result_cause= "No matching min/max row";
- error=0;
- DBUG_RETURN(0);
+ zero_result_cause= "No matching min/max row";
+ error=0;
+ DBUG_RETURN(0);
}
DBUG_PRINT("info",("Select tables optimized away"));
zero_result_cause= "Select tables optimized away";
@@ -745,7 +746,7 @@ JOIN::optimize()
sort_by_table= get_sort_by_table(order, group_list, select_lex->leaf_tables);
/* Calculate how to do the join */
- thd->proc_info= "statistics";
+ THD_PROC_INFO(thd, "statistics");
if (make_join_statistics(this, select_lex->leaf_tables, conds, &keyuse) ||
thd->is_fatal_error)
{
@@ -755,7 +756,7 @@ JOIN::optimize()
/* Remove distinct if only const tables */
select_distinct= select_distinct && (const_tables != tables);
- thd->proc_info= "preparing";
+ THD_PROC_INFO(thd, "preparing");
if (result->initialize_tables(this))
{
DBUG_PRINT("error",("Error: initialize_tables() failed"));
@@ -1102,8 +1103,9 @@ JOIN::optimize()
join_tab[const_tables].type != JT_REF_OR_NULL &&
(order && simple_order || group_list && simple_group))
{
- if (add_ref_to_table_cond(thd,&join_tab[const_tables]))
+ if (add_ref_to_table_cond(thd,&join_tab[const_tables])) {
DBUG_RETURN(1);
+ }
}
if (!(select_options & SELECT_BIG_RESULT) &&
@@ -1161,7 +1163,7 @@ JOIN::optimize()
if (need_tmp)
{
DBUG_PRINT("info",("Creating tmp table"));
- thd->proc_info="Creating tmp table";
+ THD_PROC_INFO(thd, "creating temporary table");
init_items_ref_array();
@@ -1190,7 +1192,9 @@ JOIN::optimize()
select_options,
tmp_rows_limit,
(char *) "")))
+ {
DBUG_RETURN(1);
+ }
/*
We don't have to store rows in temp table that doesn't match HAVING if:
@@ -1210,28 +1214,35 @@ JOIN::optimize()
if (group_list && simple_group)
{
DBUG_PRINT("info",("Sorting for group"));
- thd->proc_info="Sorting for group";
+ THD_PROC_INFO(thd, "sorting for group");
if (create_sort_index(thd, this, group_list,
HA_POS_ERROR, HA_POS_ERROR) ||
alloc_group_fields(this, group_list) ||
make_sum_func_list(all_fields, fields_list, 1) ||
setup_sum_funcs(thd, sum_funcs))
- DBUG_RETURN(1);
+ {
+ DBUG_RETURN(1);
+ }
group_list=0;
}
else
{
if (make_sum_func_list(all_fields, fields_list, 0) ||
setup_sum_funcs(thd, sum_funcs))
- DBUG_RETURN(1);
+ {
+ DBUG_RETURN(1);
+ }
+
if (!group_list && ! exec_tmp_table1->distinct && order && simple_order)
{
- DBUG_PRINT("info",("Sorting for order"));
- thd->proc_info="Sorting for order";
- if (create_sort_index(thd, this, order,
+ DBUG_PRINT("info",("Sorting for order"));
+ THD_PROC_INFO(thd, "Sorting for order");
+ if (create_sort_index(thd, this, order,
HA_POS_ERROR, HA_POS_ERROR))
- DBUG_RETURN(1);
- order=0;
+ {
+ DBUG_RETURN(1);
+ }
+ order=0;
}
}
@@ -1354,6 +1365,7 @@ JOIN::exec()
int tmp_error;
DBUG_ENTER("JOIN::exec");
+ THD_PROC_INFO(thd, "executing");
error= 0;
if (procedure)
{
@@ -1493,7 +1505,7 @@ JOIN::exec()
curr_tmp_table= exec_tmp_table1;
/* Copy data to the temporary table */
- thd->proc_info= "Copying to tmp table";
+ THD_PROC_INFO(thd, "Copying to tmp table");
DBUG_PRINT("info", ("%s", thd->proc_info));
if ((tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table, 0)))
{
@@ -1616,7 +1628,7 @@ JOIN::exec()
}
if (curr_join->group_list)
{
- thd->proc_info= "Creating sort index";
+ THD_PROC_INFO(thd, "Creating sort index");
if (curr_join->join_tab == join_tab && save_join_tab())
{
DBUG_VOID_RETURN;
@@ -1630,7 +1642,7 @@ JOIN::exec()
sortorder= curr_join->sortorder;
}
- thd->proc_info="Copying to group table";
+ THD_PROC_INFO(thd, "Copying to group table");
DBUG_PRINT("info", ("%s", thd->proc_info));
tmp_error= -1;
if (curr_join != this)
@@ -1686,7 +1698,7 @@ JOIN::exec()
curr_join->join_free(); /* Free quick selects */
if (curr_join->select_distinct && ! curr_join->group_list)
{
- thd->proc_info="Removing duplicates";
+ THD_PROC_INFO(thd, "Removing duplicates");
if (curr_join->tmp_having)
curr_join->tmp_having->update_used_tables();
if (remove_duplicates(curr_join, curr_tmp_table,
@@ -1747,7 +1759,7 @@ JOIN::exec()
if (curr_join->group_list || curr_join->order)
{
DBUG_PRINT("info",("Sorting for send_fields"));
- thd->proc_info="Sorting result";
+ THD_PROC_INFO(thd, "Sorting result");
/* If we have already done the group, add HAVING to sorted table */
if (curr_join->tmp_having && ! curr_join->group_list &&
! curr_join->sort_and_group)
@@ -1871,7 +1883,7 @@ JOIN::exec()
}
else
{
- thd->proc_info="Sending data";
+ THD_PROC_INFO(thd, "Sending data");
DBUG_PRINT("info", ("%s", thd->proc_info));
result->send_fields((procedure ? curr_join->procedure_fields_list :
*curr_fields_list),
@@ -2019,7 +2031,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
{
if (!(join= new JOIN(thd, fields, select_options, result)))
DBUG_RETURN(TRUE);
- thd->proc_info="init";
+ THD_PROC_INFO(thd, "init");
thd->used_tables=0; // Updated by setup_fields
if (err= join->prepare(rref_pointer_array, tables, wild_num,
conds, og_num, order, group, having, proc_param,
@@ -2064,8 +2076,9 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
err:
if (free_join)
{
- thd->proc_info="end";
+ THD_PROC_INFO(thd, "cleaning up");
err|= select_lex->cleanup();
+ THD_PROC_INFO(thd, "end");
DBUG_RETURN(err || thd->net.report_error);
}
DBUG_RETURN(join->error);
@@ -9745,7 +9758,7 @@ free_tmp_table(THD *thd, TABLE *entry)
DBUG_PRINT("enter",("table: %s",entry->alias));
save_proc_info=thd->proc_info;
- thd->proc_info="removing tmp table";
+ THD_PROC_INFO(thd, "removing tmp table");
if (entry->file)
{
@@ -9773,7 +9786,7 @@ free_tmp_table(THD *thd, TABLE *entry)
bitmap_clear_bit(&temp_pool, entry->temp_pool_slot);
free_root(&own_root, MYF(0)); /* the table is allocated in its own root */
- thd->proc_info=save_proc_info;
+ THD_PROC_INFO(thd, save_proc_info);
DBUG_VOID_RETURN;
}
@@ -9803,7 +9816,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
DBUG_RETURN(1); // End of memory
save_proc_info=thd->proc_info;
- thd->proc_info="converting HEAP to MyISAM";
+ THD_PROC_INFO(thd, "converting HEAP to MyISAM");
if (create_myisam_tmp_table(&new_table,param,
thd->lex->select_lex.options | thd->options))
@@ -9856,8 +9869,8 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
table->s= &table->share_not_to_be_used;
table->file->change_table_ptr(table);
if (save_proc_info)
- thd->proc_info= (!strcmp(save_proc_info,"Copying to tmp table") ?
- "Copying to tmp table on disk" : save_proc_info);
+ THD_PROC_INFO(thd, (!strcmp(save_proc_info,"Copying to tmp table") ?
+ "Copying to tmp table on disk" : save_proc_info));
DBUG_RETURN(0);
err:
@@ -9869,7 +9882,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
new_table.file->delete_table(new_table.s->table_name);
delete new_table.file;
err2:
- thd->proc_info=save_proc_info;
+ THD_PROC_INFO(thd, save_proc_info);
DBUG_RETURN(1);
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index ee310ea6fe4..f4e67fc24f4 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1350,7 +1350,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
#if !defined(DONT_USE_THR_ALARM) && ! defined(SCO)
if (pthread_kill(tmp->real_id,0))
- tmp->proc_info="*** DEAD ***"; // This shouldn't happen
+ THD_PROC_INFO(tmp, "*** DEAD ***"); // This shouldn't happen
#endif
#ifdef EXTRA_DEBUG
thd_info->start_time= tmp->time_after_lock;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index c14529f6eb1..0e2fd67965f 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1728,7 +1728,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
}
}
- thd->proc_info="creating table";
+ THD_PROC_INFO(thd, "creating table");
create_info->table_existed= 0; // Mark that table is created
if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)
@@ -1759,7 +1759,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
end:
VOID(pthread_mutex_unlock(&LOCK_open));
- thd->proc_info="After create";
+ THD_PROC_INFO(thd, "After create");
DBUG_RETURN(error);
warn:
@@ -2878,7 +2878,7 @@ mysql_discard_or_import_tablespace(THD *thd,
ALTER TABLE
*/
- thd->proc_info="discard_or_import_tablespace";
+ THD_PROC_INFO(thd, "discard_or_import_tablespace");
discard= test(tablespace_op == DISCARD_TABLESPACE);
@@ -2895,7 +2895,7 @@ mysql_discard_or_import_tablespace(THD *thd,
error=table->file->discard_or_import_tablespace(discard);
- thd->proc_info="end";
+ THD_PROC_INFO(thd, "end");
if (error)
goto err;
@@ -2958,7 +2958,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
frm_type_enum frm_type;
DBUG_ENTER("mysql_alter_table");
- thd->proc_info="init";
+ THD_PROC_INFO(thd, "init");
table_name=table_list->table_name;
alias= (lower_case_table_names == 2) ? table_list->alias : table_name;
@@ -3093,7 +3093,7 @@ view_err:
DBUG_RETURN(TRUE);
}
- thd->proc_info="setup";
+ THD_PROC_INFO(thd, "setup");
if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) &&
!table->s->tmp_table) // no need to touch frm
{
@@ -3101,7 +3101,7 @@ view_err:
VOID(pthread_mutex_lock(&LOCK_open));
if (new_name != table_name || new_db != db)
{
- thd->proc_info="rename";
+ THD_PROC_INFO(thd, "rename");
/* Then do a 'simple' rename of the table */
error=0;
if (!access(new_name_buff,F_OK))
@@ -3573,7 +3573,7 @@ view_err:
/* We don't want update TIMESTAMP fields during ALTER TABLE. */
thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
thd->cuted_fields=0L;
- thd->proc_info="copy to tmp table";
+ THD_PROC_INFO(thd, "copy to tmp table");
next_insert_id=thd->next_insert_id; // Remember for logging
copied=deleted=0;
if (new_table && !new_table->s->is_view)
@@ -3645,7 +3645,7 @@ view_err:
from the cache, free all locks, close the old table and remove it.
*/
- thd->proc_info="rename result table";
+ THD_PROC_INFO(thd, "rename result table");
my_snprintf(old_name, sizeof(old_name), "%s2-%lx-%lx", tmp_file_prefix,
current_pid, thd->thread_id);
if (lower_case_table_names)
@@ -3756,7 +3756,7 @@ view_err:
broadcast_refresh();
goto err;
}
- thd->proc_info="end";
+ THD_PROC_INFO(thd, "end");
if (mysql_bin_log.is_open())
{
thd->clear_error();
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 3b6aa5f1aa2..6d3e29516ba 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -167,7 +167,7 @@ int mysql_update(THD *thd,
mysql_handle_derived(thd->lex, &mysql_derived_filling)))
DBUG_RETURN(1);
- thd->proc_info="init";
+ THD_PROC_INFO(thd, "init");
table= table_list->table;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
@@ -359,7 +359,7 @@ int mysql_update(THD *thd,
else
init_read_record_idx(&info, thd, table, 1, used_index);
- thd->proc_info="Searching rows for update";
+ THD_PROC_INFO(thd, "Searching rows for update");
uint tmp_limit= limit;
while (!(error=info.read_record(&info)) && !thd->killed)
@@ -424,7 +424,7 @@ int mysql_update(THD *thd,
updated= found= 0;
thd->count_cuted_fields= CHECK_FIELD_WARN; /* calc cuted fields */
thd->cuted_fields=0L;
- thd->proc_info="Updating";
+ THD_PROC_INFO(thd, "Updating");
query_id=thd->query_id;
transactional_table= table->file->has_transactions();
@@ -512,7 +512,7 @@ int mysql_update(THD *thd,
end_read_record(&info);
free_io_cache(table); // If ORDER BY
delete select;
- thd->proc_info="end";
+ THD_PROC_INFO(thd, "end");
VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY));
/*
@@ -960,7 +960,7 @@ int multi_update::prepare(List<Item> &not_used_values,
thd->count_cuted_fields= CHECK_FIELD_WARN;
thd->cuted_fields=0L;
- thd->proc_info="updating main table";
+ THD_PROC_INFO(thd, "updating main table");
tables_to_update= get_table_map(fields);
@@ -1512,11 +1512,11 @@ err2:
bool multi_update::send_eof()
{
char buff[STRING_BUFFER_USUAL_SIZE];
- thd->proc_info="updating reference tables";
+ THD_PROC_INFO(thd, "updating reference tables");
/* Does updates for the last n - 1 tables, returns 0 if ok */
int local_error = (table_count) ? do_updates(0) : 0;
- thd->proc_info= "end";
+ THD_PROC_INFO(thd, "end");
/* We must invalidate the query cache before binlog writing and
ha_autocommit_... */
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 53844eb0fd2..15c58bd0673 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -589,7 +589,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
DBUG_RETURN(0);
err:
- thd->proc_info= "end";
+ THD_PROC_INFO(thd, "end");
lex->link_first_table_back(view, link_to_local);
unit->cleanup();
DBUG_RETURN(res || thd->net.report_error);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index a362d1ce4ea..9c60630fd50 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -181,6 +181,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token BIT_SYM
%token BIT_XOR
%token BLOB_SYM
+%token BLOCK_SYM
%token BOOLEAN_SYM
%token BOOL_SYM
%token BOTH
@@ -221,10 +222,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token CONSISTENT_SYM
%token CONSTRAINT
%token CONTAINS_SYM
+%token CONTEXT_SYM
%token CONTINUE_SYM
%token CONVERT_SYM
%token CONVERT_TZ_SYM
%token COUNT_SYM
+%token CPU_SYM
%token CREATE
%token CROSS
%token CUBE_SYM
@@ -298,6 +301,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token EXTRACT_SYM
%token FALSE_SYM
%token FAST_SYM
+%token FAULTS_SYM
%token FETCH_SYM
%token FIELD_FUNC
%token FILE_SYM
@@ -367,6 +371,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token INT_SYM
%token INVOKER_SYM
%token IN_SYM
+%token IO_SYM
+%token IPC_SYM
%token IS
%token ISOLATION
%token ISSUER_SYM
@@ -435,6 +441,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token MEDIUMINT
%token MEDIUMTEXT
%token MEDIUM_SYM
+%token MEMORY_SYM
%token MERGE_SYM
%token MICROSECOND_SYM
%token MIGRATE_SYM
@@ -493,6 +500,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token OUTFILE
%token OUT_SYM
%token PACK_KEYS_SYM
+%token PAGE_SYM
%token PARTIAL
%token PASSWORD
%token PARAM_MARKER
@@ -510,6 +518,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token PROCEDURE
%token PROCESS
%token PROCESSLIST_SYM
+%token PROFILE_SYM
+%token PROFILES_SYM
%token PURGE
%token QUARTER_SYM
%token QUERY_SYM
@@ -580,6 +590,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token SMALLINT
%token SNAPSHOT_SYM
%token SOUNDS_SYM
+%token SOURCE_SYM
%token SPATIAL_SYM
%token SPECIFIC_SYM
%token SQLEXCEPTION_SYM
@@ -610,6 +621,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token SUM_SYM
%token SUPER_SYM
%token SUSPEND_SYM
+%token SWAPS_SYM
+%token SWITCHES_SYM
%token SYSDATE
%token TABLES
%token TABLESPACE
@@ -735,7 +748,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
union_opt select_derived_init option_type2
%type <ulong_num>
- ulong_num raid_types merge_insert_types
+ ulong_num raid_types merge_insert_types opt_profile_query_arg
%type <ulonglong_number>
ulonglong_num
@@ -6472,6 +6485,48 @@ opt_table_sym:
/* empty */
| TABLE_SYM;
+opt_profile_defs:
+ /* empty */
+ | profile_defs
+
+profile_defs:
+ profile_def
+ | profile_defs ',' profile_def
+
+profile_def:
+ CPU_SYM
+ { Lex->profile_options|= PROFILE_CPU; }
+ | MEMORY_SYM
+ { Lex->profile_options|= PROFILE_MEMORY; }
+ | BLOCK_SYM IO_SYM
+ { Lex->profile_options|= PROFILE_BLOCK_IO; }
+ | CONTEXT_SYM SWITCHES_SYM
+ { Lex->profile_options|= PROFILE_CONTEXT; }
+ | PAGE_SYM FAULTS_SYM
+ { Lex->profile_options|= PROFILE_PAGE_FAULTS; }
+ | IPC_SYM
+ { Lex->profile_options|= PROFILE_IPC; }
+ | SWAPS_SYM
+ { Lex->profile_options|= PROFILE_SWAPS; }
+ | SOURCE_SYM
+ { Lex->profile_options|= PROFILE_SOURCE; }
+ | ALL
+ { Lex->profile_options|= PROFILE_ALL; }
+ ;
+
+opt_profile_query_arg:
+ /* empty */
+ { $$= 0; }
+ | QUERY_SYM NUM
+ { $$= atoi($2.str); }
+ ;
+
+opt_profile_args:
+ /* empty */
+ | FOR_SYM opt_profile_query_arg
+ { Lex->profile_query_id = $2; }
+ ;
+
/* Show things */
show: SHOW
@@ -6607,6 +6662,10 @@ show_param:
{ Lex->sql_command = SQLCOM_SHOW_WARNS;}
| ERRORS opt_limit_clause_init
{ Lex->sql_command = SQLCOM_SHOW_ERRORS;}
+ | PROFILES_SYM
+ { Lex->sql_command = SQLCOM_SHOW_PROFILES; }
+ | PROFILE_SYM opt_profile_defs opt_profile_args opt_limit_clause_init
+ { Lex->sql_command = SQLCOM_SHOW_PROFILE; }
| opt_var_type STATUS_SYM wild_and_where
{
LEX *lex= Lex;
@@ -7698,6 +7757,7 @@ keyword_sp:
| BERKELEY_DB_SYM {}
| BINLOG_SYM {}
| BIT_SYM {}
+ | BLOCK_SYM {}
| BOOL_SYM {}
| BOOLEAN_SYM {}
| BTREE_SYM {}
@@ -7714,6 +7774,8 @@ keyword_sp:
| COMPRESSED_SYM {}
| CONCURRENT {}
| CONSISTENT_SYM {}
+ | CONTEXT_SYM {}
+ | CPU_SYM {}
| CUBE_SYM {}
| DATA_SYM {}
| DATETIME {}
@@ -7736,6 +7798,7 @@ keyword_sp:
| EXPANSION_SYM {}
| EXTENDED_SYM {}
| FAST_SYM {}
+ | FAULTS_SYM {}
| FOUND_SYM {}
| DISABLE_SYM {}
| ENABLE_SYM {}
@@ -7760,6 +7823,8 @@ keyword_sp:
| ISSUER_SYM {}
| INNOBASE_SYM {}
| INSERT_METHOD {}
+ | IO_SYM {}
+ | IPC_SYM {}
| RELAY_THREAD {}
| LAST_SYM {}
| LEAVES {}
@@ -7789,6 +7854,7 @@ keyword_sp:
| MAX_UPDATES_PER_HOUR {}
| MAX_USER_CONNECTIONS_SYM {}
| MEDIUM_SYM {}
+ | MEMORY_SYM {}
| MERGE_SYM {}
| MICROSECOND_SYM {}
| MIGRATE_SYM {}
@@ -7815,6 +7881,7 @@ keyword_sp:
| ONE_SHOT_SYM {}
| ONE_SYM {}
| PACK_KEYS_SYM {}
+ | PAGE_SYM {}
| PARTIAL {}
| PASSWORD {}
| PHASE_SYM {}
@@ -7824,6 +7891,8 @@ keyword_sp:
| PRIVILEGES {}
| PROCESS {}
| PROCESSLIST_SYM {}
+ | PROFILE_SYM {}
+ | PROFILES_SYM {}
| QUARTER_SYM {}
| QUERY_SYM {}
| QUICK {}
@@ -7857,6 +7926,7 @@ keyword_sp:
| SHUTDOWN {}
| SNAPSHOT_SYM {}
| SOUNDS_SYM {}
+ | SOURCE_SYM {}
| SQL_CACHE_SYM {}
| SQL_BUFFER_RESULT {}
| SQL_NO_CACHE_SYM {}
@@ -7868,6 +7938,8 @@ keyword_sp:
| SUBJECT_SYM {}
| SUPER_SYM {}
| SUSPEND_SYM {}
+ | SWAPS_SYM {}
+ | SWITCHES_SYM {}
| TABLES {}
| TABLESPACE {}
| TEMPORARY {}