From 66dfd85cf4d55e6d87e8bb81b8fc8450eb9b3f67 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 3 Jan 2007 17:15:10 -0500 Subject: [PATCH 01/33] Bug#24795: Add SHOW PROFILE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- BitKeeper/etc/collapsed | 3 + libmysqld/Makefile.am | 1 + mysql-test/r/profile.result | 30 +++ mysql-test/t/profile.test | 39 ++++ sql/Makefile.am | 2 + sql/ha_archive.cc | 4 +- sql/ha_myisam.cc | 24 +- sql/item_func.cc | 8 +- sql/lex.h | 13 ++ sql/lock.cc | 8 +- sql/log_event.cc | 8 +- sql/mysql_priv.h | 4 + sql/repl_failsafe.cc | 6 +- sql/slave.cc | 6 +- sql/sp_head.cc | 4 +- sql/sql_base.cc | 24 +- sql/sql_cache.cc | 12 + sql/sql_class.cc | 2 + sql/sql_class.h | 3 + sql/sql_delete.cc | 12 +- sql/sql_insert.cc | 38 ++-- sql/sql_lex.cc | 1 + sql/sql_lex.h | 3 + sql/sql_parse.cc | 40 +++- sql/sql_profile.cc | 441 ++++++++++++++++++++++++++++++++++++ sql/sql_profile.h | 187 +++++++++++++++ sql/sql_repl.cc | 2 +- sql/sql_select.cc | 73 +++--- sql/sql_show.cc | 2 +- sql/sql_table.cc | 20 +- sql/sql_update.cc | 14 +- sql/sql_view.cc | 2 +- sql/sql_yacc.yy | 74 +++++- 33 files changed, 976 insertions(+), 134 deletions(-) create mode 100644 mysql-test/r/profile.result create mode 100644 mysql-test/t/profile.test create mode 100644 sql/sql_profile.cc create mode 100644 sql/sql_profile.h 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(¶m); 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 ¶m, 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(¶m, 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(¶m, 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(¶m, file, fixed_name, param.testflag & T_QUICK); @@ -709,7 +709,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, 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(¶m,file,fixed_name); } if (!statistics_done && (local_testflag & T_STATISTICS)) @@ -717,14 +717,14 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) if (share->state.changed & STATE_NOT_ANALYZED) { optimize_done=1; - thd->proc_info="Analyzing"; + THD_PROC_INFO(thd, "Analyzing"); error = chk_key(¶m, 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 ¶m, bool optimize) file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; update_state_info(¶m, 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(¶m); 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 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 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 &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_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 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 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 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 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 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 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 +#include + +#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 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 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 *) 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 ¬_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 raid_types merge_insert_types + ulong_num raid_types merge_insert_types opt_profile_query_arg %type 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 {} From 03490a842ee9d272f40df8ba447f5aae462bb010 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 8 Jan 2007 15:57:03 -0500 Subject: [PATCH 02/33] Community version numbering. --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 49e295eeebb..2a3e5988385 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.34) +AM_INIT_AUTOMAKE(mysql, 5.0.33) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 From 4369b5f36e2f91ab7a4d641ec8e8554f0db4a363 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 9 Jan 2007 13:02:15 +0100 Subject: [PATCH 03/33] configure.in: raise version to 5.0.33 configure.in: raise version to 5.0.33 --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index f6a6eedac70..f72476cd4cf 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.32) +AM_INIT_AUTOMAKE(mysql, 5.0.33) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 @@ -19,7 +19,7 @@ SHARED_LIB_VERSION=$SHARED_LIB_MAJOR_VERSION:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=32 +NDB_VERSION_BUILD=33 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From 8326c2c25dd9038781951b00ed6e6e04e612e8ff Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 9 Jan 2007 14:42:56 +0100 Subject: [PATCH 04/33] raise version number after cloning 5.0.33 --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index f72476cd4cf..fddf2dc8192 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.33) +AM_INIT_AUTOMAKE(mysql, 5.0.35) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 @@ -19,7 +19,7 @@ SHARED_LIB_VERSION=$SHARED_LIB_MAJOR_VERSION:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=33 +NDB_VERSION_BUILD=35 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From 351b966462232060eb27288275508453406b6401 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 18 Jan 2007 09:50:16 -0500 Subject: [PATCH 05/33] Bug#24822: Patch: uptime_since_flush_status Provide the number of seconds since flush as a new status variable named "Uptime_since_flush_status". --- Override the post-flush value, as a second could pass between the two statements. mysql-test/r/information_schema.result: Test new status variable. --- Override the post-flush value, as a second could pass between the two statements. mysql-test/t/information_schema.test: Test new status variable. --- Override the post-flush value, as a second could pass between the two statements. sql/mysql_priv.h: Add variable to hold previous flush time. sql/mysqld.cc: Add variable to hold previous flush time. Insert name for referring to it, and initialize the value. sql/sql_show.cc: Yield value of elapsed time since flush when asked. sql/structs.h: Add new show-flush-time to SHOW types enumeration. --- BitKeeper/etc/collapsed | 2 ++ mysql-test/r/information_schema.result | 7 +++++++ mysql-test/t/information_schema.test | 13 ++++++++++--- sql/mysql_priv.h | 2 +- sql/mysqld.cc | 6 ++++-- sql/sql_show.cc | 4 ++++ sql/structs.h | 1 + 7 files changed, 29 insertions(+), 6 deletions(-) diff --git a/BitKeeper/etc/collapsed b/BitKeeper/etc/collapsed index e754ac133ea..43292906ddd 100644 --- a/BitKeeper/etc/collapsed +++ b/BitKeeper/etc/collapsed @@ -32,3 +32,5 @@ 459c03b9N_mqF2XJKK6DwSrIt7e6_g 459c1965_BQMBzBO8S_gVqjTHYQrmw 459c2098XoAUsUn8N07IVRDD6CTM-A +459ea845XenN-uWqEM5LFvUT60tW_A +45af88c9RIIJWPfBxs3o7zekI-ELPQ diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 21d7bfb1b21..d4fd536003a 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1269,3 +1269,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 0 const row not found 2 DERIVED tables ALL NULL NULL NULL NULL 2 drop view v1; +show global status like "Uptime_%"; +Variable_name Value +Uptime_since_flush_status # +flush status; +show global status like "Uptime_%"; +Variable_name Value +Uptime_since_flush_status # diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 623ccee49e4..a4cf3b497be 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -971,9 +971,6 @@ SELECT COLUMN_NAME, MD5(COLUMN_DEFAULT), LENGTH(COLUMN_DEFAULT), COLUMN_DEFAULT= DROP TABLE bug23037; DROP FUNCTION get_value; - - - # # Bug#22413: EXPLAIN SELECT FROM view with ORDER BY yield server crash # @@ -987,4 +984,14 @@ explain select * from v1; explain select * from (select table_name from information_schema.tables) as a; drop view v1; +# +# Bug#24822: Patch: uptime_since_flush_status +# +--replace_column 2 # +show global status like "Uptime_%"; +flush status; +--replace_column 2 # +show global status like "Uptime_%"; # Almost certainly zero + + # End of 5.0 tests. diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b28e885e2a5..e8fd84beaf9 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1190,7 +1190,7 @@ void my_dbopt_free(void); External variables */ -extern time_t start_time; +extern time_t start_time, flush_status_time; extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH], mysql_real_data_home[], *opt_mysql_tmpdir, mysql_charsets_dir[], def_ft_boolean_syntax[sizeof(ft_boolean_syntax)]; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 95de1f91ecf..4a07cd0be0d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -428,7 +428,7 @@ ulong expire_logs_days = 0; ulong rpl_recovery_rank=0; double log_10[32]; /* 10 potences */ -time_t start_time; +time_t start_time, flush_status_time; char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], system_time_zone[30]; char *default_tz_name; @@ -2589,7 +2589,7 @@ static int init_common_variables(const char *conf_file_name, int argc, tzset(); // Set tzname max_system_variables.pseudo_thread_id= (ulong)~0; - start_time=time((time_t*) 0); + start_time= flush_status_time= time((time_t*) 0); if (init_thread_environment()) return 1; mysql_init_variables(); @@ -6264,6 +6264,7 @@ struct show_var_st status_vars[]= { {"Threads_created", (char*) &thread_created, SHOW_LONG_CONST}, {"Threads_running", (char*) &thread_running, SHOW_INT_CONST}, {"Uptime", (char*) 0, SHOW_STARTTIME}, + {"Uptime_since_flush_status",(char*) 0, SHOW_FLUSHTIME}, {NullS, NullS, SHOW_LONG} }; @@ -7534,6 +7535,7 @@ void refresh_status(THD *thd) /* Reset the counters of all key caches (default and named). */ process_key_caches(reset_key_cache_counters); + flush_status_time= time((time_t*) 0); pthread_mutex_unlock(&LOCK_status); /* diff --git a/sql/sql_show.cc b/sql/sql_show.cc index ac3acd5c986..0a39640aa4f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1492,6 +1492,10 @@ static bool show_status_array(THD *thd, const char *wild, nr= (long) (thd->query_start() - start_time); end= int10_to_str(nr, buff, 10); break; + case SHOW_FLUSHTIME: + nr= (long) (thd->query_start() - flush_status_time); + end= int10_to_str(nr, buff, 10); + break; case SHOW_QUESTION: end= int10_to_str((long) thd->query_id, buff, 10); break; diff --git a/sql/structs.h b/sql/structs.h index 2dcafdef615..4bb4d625cb4 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -174,6 +174,7 @@ enum SHOW_TYPE SHOW_BOOL, SHOW_MY_BOOL, SHOW_OPENTABLES, SHOW_STARTTIME, SHOW_QUESTION, SHOW_LONG_CONST, SHOW_INT_CONST, SHOW_HAVE, SHOW_SYS, SHOW_HA_ROWS, SHOW_VARS, + SHOW_FLUSHTIME, #ifdef HAVE_OPENSSL SHOW_SSL_CTX_SESS_ACCEPT, SHOW_SSL_CTX_SESS_ACCEPT_GOOD, SHOW_SSL_GET_VERSION, SHOW_SSL_CTX_GET_SESSION_CACHE_MODE, From 607c224969df2aa13f6b236440e02713a18e6c34 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 22 Feb 2007 10:03:08 -0500 Subject: [PATCH 06/33] Prevent bugs by making DBUG_* expressions syntactically equivalent to a single statement. --- Bug#24795: SHOW PROFILE Profiling is only partially functional on some architectures. Where there is no getrusage() system call, presently Null values are returned where it would be required. Notably, Windows needs some love applied to make it as useful. Syntax this adds: SHOW PROFILES SHOW PROFILE [types] [FOR QUERY n] [OFFSET n] [LIMIT n] where "n" is an integer and "types" is zero or many (comma-separated) of "CPU" "MEMORY" (not presently supported) "BLOCK IO" "CONTEXT SWITCHES" "PAGE FAULTS" "IPC" "SWAPS" "SOURCE" "ALL" It also adds a session variable (boolean) "profiling", set to "no" by default, and (integer) profiling_history_size, set to 15 by default. This patch abstracts setting THDs' "proc_info" behind a macro that can be used as a hook into the profiling code when profiling support is compiled in. All future code in this line should use that mechanism for setting thd->proc_info. --- Tests are now set to omit the statistics. --- Adds an Information_schema table, "profiling" for access to "show profile" data. --- Merge zippy.cornsilk.net:/home/cmiller/work/mysql/mysql-5.0-community-3--bug24795 into zippy.cornsilk.net:/home/cmiller/work/mysql/mysql-5.0-community --- Fix merge problems. --- Fixed one bug in the query_source being NULL. Updated test results. --- Include more thorough profiling tests. Improve support for prepared statements. Use session-specific query IDs, starting at zero. --- Selecting from I_S.profiling is no longer quashed in profiling, as requested by Giuseppe. Limit the size of captured query text. No longer log queries that are zero length. BitKeeper/deleted/.del-profile.result: Rename: mysql-test/r/profile.result -> BitKeeper/deleted/.del-profile.result BitKeeper/deleted/.del-profile.test: Rename: mysql-test/t/profile.test -> BitKeeper/deleted/.del-profile.test BitKeeper/deleted/.del-sql_profile.cc: Rename: sql/sql_profile.cc -> BitKeeper/deleted/.del-sql_profile.cc BitKeeper/deleted/.del-sql_profile.h: Rename: sql/sql_profile.h -> BitKeeper/deleted/.del-sql_profile.h configure.in: Add a configure-time option to enable/disable query profiling. The default is enabled. include/my_dbug.h: DBUG_* statements should be syntactically equivalent to a single statement. myisam/mi_open.c: DBUG_* statements should be syntactically equivalent to a single statement. mysql-test/r/information_schema.result: Updated (re-recorded) tests that I missed somehow. I verified these for correctness. mysql-test/r/information_schema_db.result: Updated test results I missed. mysql-test/r/mysqlshow.result: Fix merge problems. ndb/src/ndbapi/DictCache.cpp: DBUG_* statements should be syntactically equivalent to a single statement. sql/ha_archive.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/ha_berkeley.cc: Include patch backported to 5.0-global. THD::options is a ulonglong, not ulong. sql/ha_myisam.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/ha_myisammrg.cc: DBUG_* statements should be syntactically equivalent to a single statement. sql/ha_ndbcluster.cc: DBUG_* statements should be syntactically equivalent to a single statement. sql/item_cmpfunc.cc: DBUG_* statements should be syntactically equivalent to a single statement. sql/item_func.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/lock.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/log_event.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/mysql_priv.h: Use 64-bit constants for the 64-bit bit field. Add a new option bit for whether profiling is active or not. sql/mysqld.cc: Add semicolon to DBUG statement. Add a new system variable and set it. --- Set the minimum, which is zero and not 50. sql/repl_failsafe.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/set_var.cc: Make a new system global variable and session variable, to determine behavior of profiling. --- Include patch backported to 5.0-global. THD::options is a ulonglong, not ulong. sql/set_var.h: The THD::options bit field is ulonglong, not ulong. sql/slave.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. --- Include patch backported to 5.0-global. THD::options is a ulonglong, not ulong. sql/sp_head.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/sql_base.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. --- Include patch backported to 5.0-global. THD::options is a ulonglong, not ulong. sql/sql_cache.cc: DBUG_* statements should be syntactically equivalent to a single statement. --- Fix merge problems. sql/sql_class.cc: Insert a pointer to the current thread in the profiling code. --- Manual merge, undoing first patch. --- Fix merge problems. sql/sql_class.h: Create a new system variable, profiling_history_size, and add a member to THD to hold profiling information about this thread's execution. --- Manual merge, undoing first patch. sql/sql_delete.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. --- Include patch backported to 5.0-global. THD::options is a ulonglong, not ulong. sql/sql_insert.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. --- Fix merge problems. sql/sql_lex.cc: Initialize profiling options to empty. --- Manual merge, undoing first patch. sql/sql_lex.h: Add info to the lexer object so that we can hold data that comes from parsing statements. Reuse memory addresses of uints that can't occur in the same state- ment. This is dangerous because it involves knowledge of what symbols are never used together, which is information stored obliquely in another file. --- Manual merge, undoing first patch. sql/sql_parse.cc: Add hooks to the parser to jump to profiling code. If profiling is not present, then return an error message upon being used. --- Manual merge, undoing first patch. --- Fix merge problems. --- Include patch backported to 5.0-global. THD::options is a ulonglong, not ulong. sql/sql_prepare.cc: From prepared statement execution, set the query source in the profiler, as we can't get it from thd . --- Make it less expensive to limit the size of the queries. sql/sql_repl.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/sql_select.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. --- Fix merge problems. sql/sql_show.cc: Abstract setting thread-info into a function or macro. Also, remove "static" qualification on schema_table_store_record() so that external functions may use it. --- Manual merge, undoing first patch. sql/sql_table.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/sql_update.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/sql_view.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/sql_yacc.yy: Add new lexer symbols and insert new grammatical rules necessary to retreive profiling information. --- Manual merge, undoing first patch. --- Fix merge problems. sql/table.h: Add enum item for query profiling. BitKeeper/deleted/.del-profiling-master.opt: New BitKeeper file ``mysql-test/t/profiling-master.opt'' mysql-test/r/profiling.result: New BitKeeper file ``mysql-test/r/profiling.result'' --- Include more verbose that describes the queries so far. Include Giuseppe's tests. --- Selecting from I_S.profiling is no longer quashed in profiling, as requested by Giuseppe. mysql-test/t/profiling.test: New BitKeeper file ``mysql-test/t/profiling.test'' --- Include more verbose that describes the queries so far. Include Giuseppe's tests. --- Selecting from I_S.profiling is no longer quashed in profiling, as requested by Giuseppe. sql/sql_profile.cc: New BitKeeper file ``sql/sql_profile.cc'' --- If query_source is NULL, as can sometimes happen, then don't try to copy that memory. --- Make each new session use its own numbering of query_ids, and not show the global-pool numbers to the user. Provide a way for prepared statements to set the query_source. --- Selecting from I_S.profiling is no longer quashed in profiling, as requested by Giuseppe. Limit the size of captured query text. No longer log queries that are zero length. sql/sql_profile.h: New BitKeeper file ``sql/sql_profile.h'' --- Make each new session use its own numbering of query_ids, and not show the global-pool numbers to the user. Provide a way for prepared statements to set the query_source. --- Make it less expensive to limit the size of the queries. --- BitKeeper/etc/collapsed | 9 + configure.in | 14 + include/my_dbug.h | 12 +- myisam/mi_open.c | 2 +- mysql-test/r/information_schema.result | 11 +- mysql-test/r/information_schema_db.result | 1 + mysql-test/r/mysqlshow.result | 2 + mysql-test/r/profile.result | 30 - mysql-test/r/profiling.result | 365 +++++++++++++ mysql-test/t/profile.test | 39 -- mysql-test/t/profiling.test | 195 +++++++ ndb/src/ndbapi/DictCache.cpp | 2 +- sql/ha_archive.cc | 4 +- sql/ha_berkeley.cc | 4 +- sql/ha_myisam.cc | 24 +- sql/ha_myisammrg.cc | 2 +- sql/ha_ndbcluster.cc | 4 +- sql/item_cmpfunc.cc | 2 +- sql/item_func.cc | 8 +- sql/lock.cc | 8 +- sql/log_event.cc | 8 +- sql/mysql_priv.h | 73 +-- sql/mysqld.cc | 9 +- sql/repl_failsafe.cc | 10 +- sql/set_var.cc | 18 +- sql/set_var.h | 4 +- sql/slave.cc | 40 +- sql/sp_head.cc | 4 +- sql/sql_base.cc | 30 +- sql/sql_cache.cc | 22 +- sql/sql_class.cc | 3 +- sql/sql_class.h | 7 +- sql/sql_delete.cc | 14 +- sql/sql_insert.cc | 38 +- sql/sql_lex.cc | 3 +- sql/sql_lex.h | 9 +- sql/sql_parse.cc | 71 ++- sql/sql_prepare.cc | 1 + sql/sql_profile.cc | 638 +++++++++++++++++----- sql/sql_profile.h | 246 +++++---- sql/sql_repl.cc | 18 +- sql/sql_select.cc | 47 +- sql/sql_show.cc | 8 +- sql/sql_table.cc | 20 +- sql/sql_update.cc | 14 +- sql/sql_view.cc | 2 +- sql/sql_yacc.yy | 80 +-- sql/table.h | 1 + 48 files changed, 1602 insertions(+), 574 deletions(-) delete mode 100644 mysql-test/r/profile.result create mode 100644 mysql-test/r/profiling.result delete mode 100644 mysql-test/t/profile.test create mode 100644 mysql-test/t/profiling.test diff --git a/BitKeeper/etc/collapsed b/BitKeeper/etc/collapsed index 43292906ddd..c79a4cf25cc 100644 --- a/BitKeeper/etc/collapsed +++ b/BitKeeper/etc/collapsed @@ -34,3 +34,12 @@ 459c2098XoAUsUn8N07IVRDD6CTM-A 459ea845XenN-uWqEM5LFvUT60tW_A 45af88c9RIIJWPfBxs3o7zekI-ELPQ +45c38d90tNwOTSaYKHXd3ccLtnytlQ +45c390d6BbWrwyEi5T5VsWKYxl06Rg +45c39d31g0iik6UE_oTK5N55ry-ycA +45da6370nnZlAAIieMCrXkxF9toOyQ +45da6551zUuplwxuqcT2fhRgceC0CQ +45db0d4bkGtxBk21sZFJgbCV1FcNRg +45db468b-DKE8kUTV42eYMYmk8_g9g +45dd21d1rVPnDfvZTNVHLalcjnbsZw +45ddaf15_Ld7IAEpUUP3FJjJ-oSEFg diff --git a/configure.in b/configure.in index b86353d6b79..3e0e6c9762b 100644 --- a/configure.in +++ b/configure.in @@ -667,6 +667,20 @@ else AC_MSG_RESULT([no]) fi +# Add query profiler +AC_ARG_ENABLE(profiling, + [ --disable-profiling Build a version without query profiling code ], + [ ENABLED_PROFILING=$enableval ], + [ ENABLED_PROFILING=yes ]) + +if test "$ENABLED_PROFILING" = "yes" +then + AC_DEFINE([ENABLED_PROFILING], [1], + [If SHOW PROFILE should be enabled]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi # Use this to set the place used for unix socket used to local communication. AC_ARG_WITH(unix-socket-path, diff --git a/include/my_dbug.h b/include/my_dbug.h index a3591f0151a..ba5bddad1bc 100644 --- a/include/my_dbug.h +++ b/include/my_dbug.h @@ -50,12 +50,12 @@ extern void _db_unlock_file(void); &_db_framep_) #define DBUG_LEAVE \ (_db_return_ (__LINE__, &_db_func_, &_db_file_, &_db_level_)) -#define DBUG_RETURN(a1) {DBUG_LEAVE; return(a1);} -#define DBUG_VOID_RETURN {DBUG_LEAVE; return;} +#define DBUG_RETURN(a1) do {DBUG_LEAVE; return(a1);} while(0) +#define DBUG_VOID_RETURN do {DBUG_LEAVE; return;} while(0) #define DBUG_EXECUTE(keyword,a1) \ - {if (_db_on_) {if (_db_keyword_ (keyword)) { a1 }}} + do {if (_db_on_) {if (_db_keyword_ (keyword)) { a1 }}} while(0) #define DBUG_PRINT(keyword,arglist) \ - {if (_db_on_) {_db_pargs_(__LINE__,keyword); _db_doprnt_ arglist;}} + do {if (_db_on_) {_db_pargs_(__LINE__,keyword); _db_doprnt_ arglist;}} while(0) #define DBUG_PUSH(a1) _db_push_ (a1) #define DBUG_POP() _db_pop_ () #define DBUG_PROCESS(a1) (_db_process_ = a1) @@ -63,7 +63,7 @@ extern void _db_unlock_file(void); #define DBUG_SETJMP(a1) (_db_setjmp_ (), setjmp (a1)) #define DBUG_LONGJMP(a1,a2) (_db_longjmp_ (), longjmp (a1, a2)) #define DBUG_DUMP(keyword,a1,a2)\ - {if (_db_on_) {_db_dump_(__LINE__,keyword,a1,a2);}} + do {if (_db_on_) {_db_dump_(__LINE__,keyword,a1,a2);}} while(0) #define DBUG_IN_USE (_db_fp_ && _db_fp_ != stderr) #define DEBUGGER_OFF _no_db_=1;_db_on_=0; #define DEBUGGER_ON _no_db_=0 @@ -73,7 +73,7 @@ extern void _db_unlock_file(void); #define DBUG_OUTPUT(A) { _db_output_(A); } #define DBUG_ASSERT(A) assert(A) #define DBUG_EXECUTE_IF(keyword,a1) \ - {if (_db_on_) {if (_db_strict_keyword_ (keyword)) { a1 }}} + do {if (_db_on_) {if (_db_strict_keyword_ (keyword)) { a1 }}} while(0) #else /* No debugger */ #define DBUG_ENTER(a1) diff --git a/myisam/mi_open.c b/myisam/mi_open.c index 20a50fff9d7..b911826a976 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -196,7 +196,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) if (len != MI_BASE_INFO_SIZE) { DBUG_PRINT("warning",("saved_base_info_length: %d base_info_length: %d", - len,MI_BASE_INFO_SIZE)) + len,MI_BASE_INFO_SIZE)); } disk_pos= (char*) my_n_base_info_read((uchar*) disk_cache + base_pos, &share->base); diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index d4fd536003a..742d35d4ce7 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -42,6 +42,7 @@ COLLATION_CHARACTER_SET_APPLICABILITY COLUMNS COLUMN_PRIVILEGES KEY_COLUMN_USAGE +PROFILING ROUTINES SCHEMATA SCHEMA_PRIVILEGES @@ -730,7 +731,7 @@ CREATE TABLE t_crashme ( f1 BIGINT); CREATE VIEW a1 (t_CRASHME) AS SELECT f1 FROM t_crashme GROUP BY f1; CREATE VIEW a2 AS SELECT t_CRASHME FROM a1; count(*) -101 +102 drop view a2, a1; drop table t_crashme; select table_schema,table_name, column_name from @@ -801,7 +802,7 @@ delete from mysql.db where user='mysqltest_4'; flush privileges; SELECT table_schema, count(*) FROM information_schema.TABLES GROUP BY TABLE_SCHEMA; table_schema count(*) -information_schema 16 +information_schema 17 mysql 17 create table t1 (i int, j int); create trigger trg1 before insert on t1 for each row @@ -1094,8 +1095,8 @@ table_schema='information_schema' and (column_type = 'varchar(7)' or column_type = 'varchar(20)') group by column_type order by num; column_type group_concat(table_schema, '.', table_name) num -varchar(20) information_schema.COLUMNS 1 -varchar(7) information_schema.ROUTINES,information_schema.VIEWS 2 +varchar(20) information_schema.COLUMNS,information_schema.PROFILING 2 +varchar(7) information_schema.PROFILING,information_schema.PROFILING,information_schema.PROFILING,information_schema.ROUTINES,information_schema.VIEWS 5 create table t1(f1 char(1) not null, f2 char(9) not null) default character set utf8; select CHARACTER_MAXIMUM_LENGTH, CHARACTER_OCTET_LENGTH from @@ -1192,6 +1193,7 @@ COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME COLUMNS TABLE_SCHEMA COLUMN_PRIVILEGES TABLE_SCHEMA KEY_COLUMN_USAGE CONSTRAINT_SCHEMA +PROFILING Query_id ROUTINES ROUTINE_SCHEMA SCHEMATA SCHEMA_NAME SCHEMA_PRIVILEGES TABLE_SCHEMA @@ -1223,6 +1225,7 @@ COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME COLUMNS TABLE_SCHEMA COLUMN_PRIVILEGES TABLE_SCHEMA KEY_COLUMN_USAGE CONSTRAINT_SCHEMA +PROFILING Query_id ROUTINES ROUTINE_SCHEMA SCHEMATA SCHEMA_NAME SCHEMA_PRIVILEGES TABLE_SCHEMA diff --git a/mysql-test/r/information_schema_db.result b/mysql-test/r/information_schema_db.result index 40773a7afc1..dcd48d3aa46 100644 --- a/mysql-test/r/information_schema_db.result +++ b/mysql-test/r/information_schema_db.result @@ -11,6 +11,7 @@ COLLATION_CHARACTER_SET_APPLICABILITY COLUMNS COLUMN_PRIVILEGES KEY_COLUMN_USAGE +PROFILING ROUTINES SCHEMATA SCHEMA_PRIVILEGES diff --git a/mysql-test/r/mysqlshow.result b/mysql-test/r/mysqlshow.result index 2bf8a58de4e..31b4940ec53 100644 --- a/mysql-test/r/mysqlshow.result +++ b/mysql-test/r/mysqlshow.result @@ -85,6 +85,7 @@ Database: information_schema | COLUMNS | | COLUMN_PRIVILEGES | | KEY_COLUMN_USAGE | +| PROFILING | | ROUTINES | | SCHEMATA | | SCHEMA_PRIVILEGES | @@ -106,6 +107,7 @@ Database: INFORMATION_SCHEMA | COLUMNS | | COLUMN_PRIVILEGES | | KEY_COLUMN_USAGE | +| PROFILING | | ROUTINES | | SCHEMATA | | SCHEMA_PRIVILEGES | diff --git a/mysql-test/r/profile.result b/mysql-test/r/profile.result deleted file mode 100644 index 8a4db348445..00000000000 --- a/mysql-test/r/profile.result +++ /dev/null @@ -1,30 +0,0 @@ -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/r/profiling.result b/mysql-test/r/profiling.result new file mode 100644 index 00000000000..f8aa060eee4 --- /dev/null +++ b/mysql-test/r/profiling.result @@ -0,0 +1,365 @@ +show session variables like 'profil%'; +Variable_name Value +profiling OFF +profiling_history_size 15 +select @@profiling; +@@profiling +0 +set global profiling = ON; +ERROR HY000: Variable 'profiling' is a SESSION variable and can't be used with SET GLOBAL +set global profiling_history_size=100; +show global variables like 'profil%'; +Variable_name Value +profiling OFF +profiling_history_size 100 +set session profiling = ON; +set session profiling_history_size=30; +show session variables like 'profil%'; +Variable_name Value +profiling ON +profiling_history_size 30 +select @@profiling; +@@profiling +1 +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); +select max(x) from (select sum(a) as x from t1 group by b) as teeone; +max(x) +20 +insert into t1 select * from t1; +select count(*) from t1; +count(*) +24 +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +select count(*) from t1; +count(*) +192 +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +select count(*) from t1; +count(*) +1536 +select sum(a) from t1; +sum(a) +6144 +select sum(a) from t1 group by b; +sum(a) +2048 +1536 +2560 +select sum(a) + sum(b) from t1 group by b; +sum(a) + sum(b) +NULL +2048 +4608 +select max(x) from (select sum(a) as x from t1 group by b) as teeone; +max(x) +2560 +select '012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890' as big_string; +big_string +012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890 +show profiles; +Query_ID Duration Query +0 # set session profiling = ON +1 # set session profiling_history_size=30 +2 # show session variables like 'profil%' +3 # select @@profiling +4 # create table t1 ( +a int, +b int +) +5 # insert into t1 values (1,1), (2,null), (3, 4) +6 # insert into t1 values (5,1), (6,null), (7, 4) +7 # insert into t1 values (1,1), (2,null), (3, 4) +8 # insert into t1 values (5,1), (6,null), (7, 4) +9 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +10 # insert into t1 select * from t1 +11 # select count(*) from t1 +12 # insert into t1 select * from t1 +13 # insert into t1 select * from t1 +14 # insert into t1 select * from t1 +15 # select count(*) from t1 +16 # insert into t1 select * from t1 +17 # insert into t1 select * from t1 +18 # insert into t1 select * from t1 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +show profile for query 15; +show profile cpu for query 15; +show profile cpu, block io for query 15; +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; +show profile all for query 15; +select * from information_schema.profiling; +select query_id, state, duration from information_schema.profiling; +select query_id, sum(duration) from information_schema.profiling group by query_id; +select query_id, count(*) from information_schema.profiling group by query_id; +select sum(duration) from information_schema.profiling; +select query_id, count(*), sum(duration) from information_schema.profiling group by query_id; +select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling; +drop table if exists t1, t2, t3; +Warnings: +Note 1051 Unknown table 't2' +Note 1051 Unknown table 't3' +create table t1 (id int ); +create table t2 (id int not null); +create table t3 (id int not null primary key); +insert into t1 values (1), (2), (3); +insert into t2 values (1), (2), (3); +insert into t3 values (1), (2), (3); +show profiles; +Query_ID Duration Query +10 # insert into t1 select * from t1 +11 # select count(*) from t1 +12 # insert into t1 select * from t1 +13 # insert into t1 select * from t1 +14 # insert into t1 select * from t1 +15 # select count(*) from t1 +16 # insert into t1 select * from t1 +17 # insert into t1 select * from t1 +18 # insert into t1 select * from t1 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +25 # select * from information_schema.profiling +26 # select query_id, state, duration from information_schema.profiling +27 # select query_id, sum(duration) from information_schema.profiling group by query_id +28 # select query_id, count(*) from information_schema.profiling group by query_id +29 # select sum(duration) from information_schema.profiling +30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +32 # drop table if exists t1, t2, t3 +33 # SHOW WARNINGS +34 # create table t1 (id int ) +35 # create table t2 (id int not null) +36 # create table t3 (id int not null primary key) +37 # insert into t1 values (1), (2), (3) +38 # insert into t2 values (1), (2), (3) +39 # insert into t3 values (1), (2), (3) +select * from t1; +id +1 +2 +3 +show profiles; +Query_ID Duration Query +11 # select count(*) from t1 +12 # insert into t1 select * from t1 +13 # insert into t1 select * from t1 +14 # insert into t1 select * from t1 +15 # select count(*) from t1 +16 # insert into t1 select * from t1 +17 # insert into t1 select * from t1 +18 # insert into t1 select * from t1 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +25 # select * from information_schema.profiling +26 # select query_id, state, duration from information_schema.profiling +27 # select query_id, sum(duration) from information_schema.profiling group by query_id +28 # select query_id, count(*) from information_schema.profiling group by query_id +29 # select sum(duration) from information_schema.profiling +30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +32 # drop table if exists t1, t2, t3 +33 # SHOW WARNINGS +34 # create table t1 (id int ) +35 # create table t2 (id int not null) +36 # create table t3 (id int not null primary key) +37 # insert into t1 values (1), (2), (3) +38 # insert into t2 values (1), (2), (3) +39 # insert into t3 values (1), (2), (3) +40 # select * from t1 +This ^^ should end in "select * from t1;\" +delete from t1; +insert into t1 values (1), (2), (3); +insert into t1 values (1), (2), (3); +select * from t1; +id +1 +2 +3 +1 +2 +3 +show profiles; +Query_ID Duration Query +15 # select count(*) from t1 +16 # insert into t1 select * from t1 +17 # insert into t1 select * from t1 +18 # insert into t1 select * from t1 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +25 # select * from information_schema.profiling +26 # select query_id, state, duration from information_schema.profiling +27 # select query_id, sum(duration) from information_schema.profiling group by query_id +28 # select query_id, count(*) from information_schema.profiling group by query_id +29 # select sum(duration) from information_schema.profiling +30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +32 # drop table if exists t1, t2, t3 +33 # SHOW WARNINGS +34 # create table t1 (id int ) +35 # create table t2 (id int not null) +36 # create table t3 (id int not null primary key) +37 # insert into t1 values (1), (2), (3) +38 # insert into t2 values (1), (2), (3) +39 # insert into t3 values (1), (2), (3) +40 # select * from t1 +41 # delete from t1 +42 # insert into t1 values (1), (2), (3) +43 # insert into t1 values (1), (2), (3) +44 # select * from t1 +set session profiling = OFF; +select sum(id) from t1; +sum(id) +12 +show profiles; +Query_ID Duration Query +16 # insert into t1 select * from t1 +17 # insert into t1 select * from t1 +18 # insert into t1 select * from t1 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +25 # select * from information_schema.profiling +26 # select query_id, state, duration from information_schema.profiling +27 # select query_id, sum(duration) from information_schema.profiling group by query_id +28 # select query_id, count(*) from information_schema.profiling group by query_id +29 # select sum(duration) from information_schema.profiling +30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +32 # drop table if exists t1, t2, t3 +33 # SHOW WARNINGS +34 # create table t1 (id int ) +35 # create table t2 (id int not null) +36 # create table t3 (id int not null primary key) +37 # insert into t1 values (1), (2), (3) +38 # insert into t2 values (1), (2), (3) +39 # insert into t3 values (1), (2), (3) +40 # select * from t1 +41 # delete from t1 +42 # insert into t1 values (1), (2), (3) +43 # insert into t1 values (1), (2), (3) +44 # select * from t1 +45 # set session profiling = OFF +set session profiling = ON; +select @@profiling; +@@profiling +1 +create function f1() returns varchar(50) return 'hello'; +select @@profiling; +@@profiling +1 +select * from t1 where id <> f1(); +id +1 +2 +3 +1 +2 +3 +select @@profiling; +@@profiling +1 +set session profiling = ON; +drop table if exists t2; +create table t2 (id int not null); +create trigger t2_bi before insert on t2 for each row set @x=0; +select @@profiling; +@@profiling +1 +insert into t2 values (1), (2), (3); +select @@profiling; +@@profiling +1 +set session profiling = ON; +drop table if exists t1, t2; +create table t1 (id int not null primary key); +create table t2 (id int not null primary key, id1 int not null); +select @@profiling; +@@profiling +1 +alter table t2 add foreign key (id1) references t1 (id) on delete cascade; +select @@profiling; +@@profiling +1 +lock table t1 write; +select @@profiling; +@@profiling +1 +unlock table; +select @@profiling; +@@profiling +1 +set autocommit=0; +select @@profiling, @@autocommit; +@@profiling @@autocommit +1 0 +begin; +select @@profiling; +@@profiling +1 +insert into t1 values (1); +insert into t2 values (1,1); +testing referential integrity cascade +delete from t1 where id = 1; +select @@profiling; +@@profiling +1 +testing rollback +rollback; +select @@profiling; +@@profiling +1 +testing commit +begin; +select @@profiling; +@@profiling +1 +commit; +select @@profiling; +@@profiling +1 +drop table if exists t1, t2, t3; +drop view if exists v1; +Warnings: +Note 1051 Unknown table 'test.v1' +drop function if exists f1; +set session profiling = OFF; +End of 5.0 tests diff --git a/mysql-test/t/profile.test b/mysql-test/t/profile.test deleted file mode 100644 index 4cf2a3aa92f..00000000000 --- a/mysql-test/t/profile.test +++ /dev/null @@ -1,39 +0,0 @@ - -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/mysql-test/t/profiling.test b/mysql-test/t/profiling.test new file mode 100644 index 00000000000..ebde8eeffd8 --- /dev/null +++ b/mysql-test/t/profiling.test @@ -0,0 +1,195 @@ +# default is OFF +show session variables like 'profil%'; +select @@profiling; + +# setting global variable is an error +--error ER_LOCAL_VARIABLE +set global profiling = ON; + +# But size is okay +set global profiling_history_size=100; +show global variables like 'profil%'; + +# turn on for testing +set session profiling = ON; +set session profiling_history_size=30; # small enough to overflow + +# verify it is active +show session variables like 'profil%'; +select @@profiling; + +# Profiling is a descriptive look into the way the server operated +# in retrospect. Chad doesn't think it's wise to include the result +# log, as this creates a proscriptive specification about how the +# server should work in the future -- or it forces everyone who +# changes the server significantly to record the test results again, +# and that violates the spirit of our tests. Please don't include +# execution-specific data here, as in all of the "show profile" and +# information_schema.profiling results. + +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); +select max(x) from (select sum(a) as x from t1 group by b) as teeone; +insert into t1 select * from t1; +select count(*) from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +select count(*) from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +select count(*) from t1; +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; +select '012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890' as big_string; + +--enable_result_log +--replace_column 2 # +show profiles; + +--disable_result_log +###--replace_column 2 # 3 # 4 # +show profile for query 15; +###--replace_column 2 # 3 # 4 # +show profile cpu for query 15; +###--replace_column 2 # 3 # 4 # 5 # 6 # +show profile cpu, block io for query 15; +###--replace_column 2 # 3 # 4 # +show profile cpu for query 9 limit 2 offset 2; +show profile cpu for query 10 limit 0; +--error 0,ER_WRONG_ARGUMENTS +show profile cpu for query 65534; +###--replace_column 2 # +show profile memory; +###--replace_column 2 # 3 # 4 # +show profile block io; +###--replace_column 2 # 3 # 4 # +show profile context switches; +###--replace_column 2 # 3 # 4 # +show profile page faults; +###--replace_column 2 # 3 # 4 # +show profile ipc; +###--replace_column 2 # +show profile swaps limit 1 offset 2; +###--replace_column 2 # 5 # +show profile source; +show profile all for query 0 limit 0; +###--replace_column 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 11 # 12 # 13 # 16 # +show profile all for query 15; +###--replace_column 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 11 # 12 # 13 # 16 # + +select * from information_schema.profiling; +select query_id, state, duration from information_schema.profiling; +select query_id, sum(duration) from information_schema.profiling group by query_id; +select query_id, count(*) from information_schema.profiling group by query_id; +select sum(duration) from information_schema.profiling; + +# Broken down into number of stages and duration of each query. +select query_id, count(*), sum(duration) from information_schema.profiling group by query_id; +select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling; + + +--enable_result_log +drop table if exists t1, t2, t3; +create table t1 (id int ); +create table t2 (id int not null); +create table t3 (id int not null primary key); +insert into t1 values (1), (2), (3); +insert into t2 values (1), (2), (3); +insert into t3 values (1), (2), (3); + +--replace_column 2 # +show profiles; + +select * from t1; +--replace_column 2 # +show profiles; +--echo This ^^ should end in \"select * from t1;\" + +delete from t1; +insert into t1 values (1), (2), (3); +insert into t1 values (1), (2), (3); + +select * from t1; +--replace_column 2 # +show profiles; + +# Turning profiling off does freeze it +set session profiling = OFF; +select sum(id) from t1; +--replace_column 2 # +show profiles; + +## Verify that the various juggling of THD contexts doesn't affect profiling. + +## Functions +set session profiling = ON; +select @@profiling; +create function f1() returns varchar(50) return 'hello'; +select @@profiling; +select * from t1 where id <> f1(); +select @@profiling; + +## Triggers +set session profiling = ON; +drop table if exists t2; +create table t2 (id int not null); +create trigger t2_bi before insert on t2 for each row set @x=0; +select @@profiling; +insert into t2 values (1), (2), (3); +select @@profiling; + +## ALTER TABLE +set session profiling = ON; +drop table if exists t1, t2; +create table t1 (id int not null primary key); +create table t2 (id int not null primary key, id1 int not null); +select @@profiling; +alter table t2 add foreign key (id1) references t1 (id) on delete cascade; +select @@profiling; + +## Table LOCKing +lock table t1 write; +select @@profiling; +unlock table; +select @@profiling; + +## Transactions +set autocommit=0; +select @@profiling, @@autocommit; +begin; +select @@profiling; +insert into t1 values (1); +insert into t2 values (1,1); +--echo testing referential integrity cascade +delete from t1 where id = 1; +select @@profiling; +--echo testing rollback +--disable_warnings +rollback; +--enable_warnings +select @@profiling; +--echo testing commit +begin; +select @@profiling; +commit; +select @@profiling; + +drop table if exists t1, t2, t3; +drop view if exists v1; +drop function if exists f1; + +## last thing in the file +set session profiling = OFF; + +## +--echo End of 5.0 tests diff --git a/ndb/src/ndbapi/DictCache.cpp b/ndb/src/ndbapi/DictCache.cpp index 82e8d82bc24..226243ba7a0 100644 --- a/ndb/src/ndbapi/DictCache.cpp +++ b/ndb/src/ndbapi/DictCache.cpp @@ -284,7 +284,7 @@ GlobalDictCache::drop(NdbTableImpl * tab) ver.m_refCount--; ver.m_status = DROPPED; if(ver.m_refCount == 0){ - DBUG_PRINT("info", ("refCount is zero, deleting m_impl")) + DBUG_PRINT("info", ("refCount is zero, deleting m_impl")); delete ver.m_impl; vers->erase(i); } diff --git a/sql/ha_archive.cc b/sql/ha_archive.cc index 6a4d372c43a..70d16f65699 100644 --- a/sql/ha_archive.cc +++ b/sql/ha_archive.cc @@ -1205,7 +1205,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(thd, "Checking table"); + thd_proc_info(thd, "Checking table"); /* Flush any waiting data */ gzflush(share->archive_write, Z_SYNC_FLUSH); @@ -1229,7 +1229,7 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt) my_free((char*)buf, MYF(0)); - THD_PROC_INFO(thd, old_proc_info); + thd_proc_info(thd, old_proc_info); if ((rc && rc != HA_ERR_END_OF_FILE) || count) { diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index d63935f1a9c..e8cff05dac9 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -1855,8 +1855,8 @@ int ha_berkeley::external_lock(THD *thd, int lock_type) OPTION_TABLE_LOCK)) && !trx->all) { /* We have to start a master transaction */ - DBUG_PRINT("trans",("starting transaction all: options: 0x%lx", - (ulong) thd->options)); + DBUG_PRINT("trans",("starting transaction all: options: 0x%llx", + thd->options)); if ((error=txn_begin(db_env, 0, &trx->all, 0))) { trx->bdb_lock_count--; // We didn't get the lock diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 7bb597ccf4f..4d562f5347c 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -339,7 +339,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(thd, "Checking table"); + thd_proc_info(thd, "Checking table"); myisamchk_init(¶m); param.thd = thd; param.op_name = "check"; @@ -413,7 +413,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt) file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; } - THD_PROC_INFO(thd, old_proc_info); + thd_proc_info(thd, old_proc_info); return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK; } @@ -679,22 +679,22 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, 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(thd, buf); + thd_proc_info(thd, buf); error = mi_repair_parallel(¶m, file, fixed_name, param.testflag & T_QUICK); - THD_PROC_INFO(thd, "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(thd, "Repair by sorting"); + thd_proc_info(thd, "Repair by sorting"); error = mi_repair_by_sort(¶m, file, fixed_name, param.testflag & T_QUICK); } } else { - THD_PROC_INFO(thd, "Repair with keycache"); + thd_proc_info(thd, "Repair with keycache"); param.testflag &= ~T_REP_BY_SORT; error= mi_repair(¶m, file, fixed_name, param.testflag & T_QUICK); @@ -708,7 +708,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) (share->state.changed & STATE_NOT_SORTED_PAGES)) { optimize_done=1; - THD_PROC_INFO(thd, "Sorting index"); + thd_proc_info(thd, "Sorting index"); error=mi_sort_index(¶m,file,fixed_name); } if (!statistics_done && (local_testflag & T_STATISTICS)) @@ -716,14 +716,14 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) if (share->state.changed & STATE_NOT_ANALYZED) { optimize_done=1; - THD_PROC_INFO(thd, "Analyzing"); + thd_proc_info(thd, "Analyzing"); error = chk_key(¶m, file); } else local_testflag&= ~T_STATISTICS; // Don't update statistics } } - THD_PROC_INFO(thd, "Saving state"); + thd_proc_info(thd, "Saving state"); if (!error) { if ((share->state.changed & STATE_CHANGED) || mi_is_crashed(file)) @@ -761,7 +761,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; update_state_info(¶m, file, 0); } - THD_PROC_INFO(thd, 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 : @@ -986,7 +986,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(thd, "Creating index"); + thd_proc_info(thd, "Creating index"); myisamchk_init(¶m); param.op_name= "recreating_index"; param.testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK | @@ -1011,7 +1011,7 @@ int ha_myisam::enable_indexes(uint mode) thd->clear_error(); } info(HA_STATUS_CONST); - THD_PROC_INFO(thd, save_proc_info); + thd_proc_info(thd, save_proc_info); } else { diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 09445f775de..c943627a9b5 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -96,7 +96,7 @@ int ha_myisammrg::open(const char *name, int mode, uint test_if_locked) DBUG_PRINT("info", ("ha_myisammrg::open exit %d", my_errno)); return (my_errno ? my_errno : -1); } - DBUG_PRINT("info", ("ha_myisammrg::open myrg_extrafunc...")) + DBUG_PRINT("info", ("ha_myisammrg::open myrg_extrafunc...")); myrg_extrafunc(file, query_cache_invalidate_by_MyISAM_filename_ref); if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED || test_if_locked == HA_OPEN_ABORT_IF_LOCKED)) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 0f580c833a9..37203076bb6 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -5821,14 +5821,14 @@ ha_ndbcluster::register_query_cache_table(THD *thd, if (!is_autocommit) { - DBUG_PRINT("exit", ("Can't register table during transaction")) + DBUG_PRINT("exit", ("Can't register table during transaction")); DBUG_RETURN(FALSE); } if (ndb_get_commitcount(thd, m_dbname, m_tabname, &commit_count)) { *engine_data= 0; - DBUG_PRINT("exit", ("Error, could not get commitcount")) + DBUG_PRINT("exit", ("Error, could not get commitcount")); DBUG_RETURN(FALSE); } *engine_data= commit_count; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 936ae04e93d..4492d629f8a 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -3006,7 +3006,7 @@ longlong Item_is_not_null_test::val_int() } if (args[0]->is_null()) { - DBUG_PRINT("info", ("null")) + DBUG_PRINT("info", ("null")); owner->was_null|= 1; DBUG_RETURN(0); } diff --git a/sql/item_func.cc b/sql/item_func.cc index 0b1d959b6a4..fa6f92ef9f6 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3204,7 +3204,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(thd, "User lock"); + thd_proc_info(thd, "User lock"); thd->mysys_var->current_mutex= &LOCK_user_locks; thd->mysys_var->current_cond= &ull->cond; @@ -3229,7 +3229,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(thd, 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); @@ -3310,7 +3310,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(thd, "User lock"); + thd_proc_info(thd, "User lock"); thd->mysys_var->current_mutex= &LOCK_user_locks; thd->mysys_var->current_cond= &ull->cond; @@ -3348,7 +3348,7 @@ longlong Item_func_get_lock::val_int() pthread_mutex_unlock(&LOCK_user_locks); pthread_mutex_lock(&thd->mysys_var->mutex); - THD_PROC_INFO(thd, 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/lock.cc b/sql/lock.cc index daf07e16dc5..8c9de2cd317 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -150,7 +150,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, } } - THD_PROC_INFO(thd, "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. */ @@ -159,7 +159,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, sql_lock=0; break; } - THD_PROC_INFO(thd, "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, @@ -193,7 +193,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, thd->locked=0; break; } - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); /* some table was altered or deleted. reopen tables marked deleted */ mysql_unlock_tables(thd,sql_lock); @@ -208,7 +208,7 @@ retry: if (wait_for_tables(thd)) break; // Couldn't open tables } - THD_PROC_INFO(thd, 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 d493cdfbae9..e0711d687e8 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4265,7 +4265,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(thd, 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, @@ -4319,7 +4319,7 @@ err: end_io_cache(&file); if (fd >= 0) my_close(fd, MYF(0)); - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); return error ? 1 : Log_event::exec_event(rli); } #endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ @@ -4439,7 +4439,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(thd, proc_info); + thd_proc_info(thd, proc_info); if (get_create_or_append()) { my_delete(fname, MYF(0)); // old copy may exist already @@ -4473,7 +4473,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(thd, 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 458d5faa857..bd69a137a2d 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -20,6 +20,9 @@ except the part which must be in the server and in the client. */ +#ifndef MYSQL_PRIV_H_INCLUDED +#define MYSQL_PRIV_H_INCLUDED + #ifndef MYSQL_CLIENT #include @@ -298,55 +301,57 @@ MY_LOCALE *my_locale_by_name(const char *name); TODO: separate three contexts above, move them to separate bitfields. */ -#define SELECT_DISTINCT (1L << 0) // SELECT, user -#define SELECT_STRAIGHT_JOIN (1L << 1) // SELECT, user -#define SELECT_DESCRIBE (1L << 2) // SELECT, user -#define SELECT_SMALL_RESULT (1L << 3) // SELECT, user -#define SELECT_BIG_RESULT (1L << 4) // SELECT, user -#define OPTION_FOUND_ROWS (1L << 5) // SELECT, user -#define OPTION_TO_QUERY_CACHE (1L << 6) // SELECT, user -#define SELECT_NO_JOIN_CACHE (1L << 7) // intern -#define OPTION_BIG_TABLES (1L << 8) // THD, user -#define OPTION_BIG_SELECTS (1L << 9) // THD, user -#define OPTION_LOG_OFF (1L << 10) // THD, user -#define OPTION_UPDATE_LOG (1L << 11) // THD, user, unused -#define TMP_TABLE_ALL_COLUMNS (1L << 12) // SELECT, intern -#define OPTION_WARNINGS (1L << 13) // THD, user -#define OPTION_AUTO_IS_NULL (1L << 14) // THD, user, binlog -#define OPTION_FOUND_COMMENT (1L << 15) // SELECT, intern, parser -#define OPTION_SAFE_UPDATES (1L << 16) // THD, user -#define OPTION_BUFFER_RESULT (1L << 17) // SELECT, user -#define OPTION_BIN_LOG (1L << 18) // THD, user -#define OPTION_NOT_AUTOCOMMIT (1L << 19) // THD, user -#define OPTION_BEGIN (1L << 20) // THD, intern -#define OPTION_TABLE_LOCK (1L << 21) // THD, intern -#define OPTION_QUICK (1L << 22) // SELECT (for DELETE) -#define OPTION_QUOTE_SHOW_CREATE (1L << 23) // THD, user +#define SELECT_DISTINCT (ULL(1) << 0) // SELECT, user +#define SELECT_STRAIGHT_JOIN (ULL(1) << 1) // SELECT, user +#define SELECT_DESCRIBE (ULL(1) << 2) // SELECT, user +#define SELECT_SMALL_RESULT (ULL(1) << 3) // SELECT, user +#define SELECT_BIG_RESULT (ULL(1) << 4) // SELECT, user +#define OPTION_FOUND_ROWS (ULL(1) << 5) // SELECT, user +#define OPTION_TO_QUERY_CACHE (ULL(1) << 6) // SELECT, user +#define SELECT_NO_JOIN_CACHE (ULL(1) << 7) // intern +#define OPTION_BIG_TABLES (ULL(1) << 8) // THD, user +#define OPTION_BIG_SELECTS (ULL(1) << 9) // THD, user +#define OPTION_LOG_OFF (ULL(1) << 10) // THD, user +#define OPTION_UPDATE_LOG (ULL(1) << 11) // THD, user, unused +#define TMP_TABLE_ALL_COLUMNS (ULL(1) << 12) // SELECT, intern +#define OPTION_WARNINGS (ULL(1) << 13) // THD, user +#define OPTION_AUTO_IS_NULL (ULL(1) << 14) // THD, user, binlog +#define OPTION_FOUND_COMMENT (ULL(1) << 15) // SELECT, intern, parser +#define OPTION_SAFE_UPDATES (ULL(1) << 16) // THD, user +#define OPTION_BUFFER_RESULT (ULL(1) << 17) // SELECT, user +#define OPTION_BIN_LOG (ULL(1) << 18) // THD, user +#define OPTION_NOT_AUTOCOMMIT (ULL(1) << 19) // THD, user +#define OPTION_BEGIN (ULL(1) << 20) // THD, intern +#define OPTION_TABLE_LOCK (ULL(1) << 21) // THD, intern +#define OPTION_QUICK (ULL(1) << 22) // SELECT (for DELETE) +#define OPTION_QUOTE_SHOW_CREATE (ULL(1) << 23) // THD, user /* Thr following is used to detect a conflict with DISTINCT in the user query has requested */ -#define SELECT_ALL (1L << 24) // SELECT, user, parser +#define SELECT_ALL (ULL(1) << 24) // SELECT, user, parser /* Set if we are updating a non-transaction safe table */ -#define OPTION_STATUS_NO_TRANS_UPDATE (1L << 25) // THD, intern +#define OPTION_STATUS_NO_TRANS_UPDATE (ULL(1) << 25) // THD, intern /* The following can be set when importing tables in a 'wrong order' to suppress foreign key checks */ -#define OPTION_NO_FOREIGN_KEY_CHECKS (1L << 26) // THD, user, binlog +#define OPTION_NO_FOREIGN_KEY_CHECKS (ULL(1) << 26) // THD, user, binlog /* The following speeds up inserts to InnoDB tables by suppressing unique key checks in some cases */ -#define OPTION_RELAXED_UNIQUE_CHECKS (1L << 27) // THD, user, binlog -#define SELECT_NO_UNLOCK (1L << 28) // SELECT, intern -#define OPTION_SCHEMA_TABLE (1L << 29) // SELECT, intern +#define OPTION_RELAXED_UNIQUE_CHECKS (ULL(1) << 27) // THD, user, binlog +#define SELECT_NO_UNLOCK (ULL(1) << 28) // SELECT, intern +#define OPTION_SCHEMA_TABLE (ULL(1) << 29) // SELECT, intern /* Flag set if setup_tables already done */ -#define OPTION_SETUP_TABLES_DONE (1L << 30) // intern +#define OPTION_SETUP_TABLES_DONE (ULL(1) << 30) // intern /* If not set then the thread will ignore all warnings with level notes. */ -#define OPTION_SQL_NOTES (1UL << 31) // THD, user +#define OPTION_SQL_NOTES (ULL(1) << 31) // THD, user /* Force the used temporary table to be a MyISAM table (because we will use fulltext functions when reading from it. */ -#define TMP_TABLE_FORCE_MYISAM (LL(1) << 32) +#define TMP_TABLE_FORCE_MYISAM (ULL(1) << 32) +#define OPTION_PROFILING (ULL(1) << 33) + /* Maximum length of time zone name that we support @@ -1686,3 +1691,5 @@ inline void kill_delayed_threads(void) {} #endif #endif /* MYSQL_CLIENT */ + +#endif diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 29590cdd6a0..a2afc3449cd 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1657,7 +1657,7 @@ void end_thread(THD *thd, bool put_in_cache) ! abort_loop && !kill_cached_threads) { /* Don't kill the thread, just put it in cache for reuse */ - DBUG_PRINT("info", ("Adding thread to cache")) + DBUG_PRINT("info", ("Adding thread to cache")); cached_thread_count++; while (!abort_loop && ! wake_thread && ! kill_cached_threads) (void) pthread_cond_wait(&COND_thread_cache, &LOCK_thread_count); @@ -4696,6 +4696,7 @@ enum options_mysqld OPT_TABLE_LOCK_WAIT_TIMEOUT, OPT_PORT_OPEN_TIMEOUT, OPT_MERGE, + OPT_PROFILING, OPT_INNODB_ROLLBACK_ON_TIMEOUT }; @@ -5257,6 +5258,12 @@ Disable with --skip-ndbcluster (will save memory).", "Maximum time in seconds to wait for the port to become free. " "(Default: no wait)", (gptr*) &mysqld_port_timeout, (gptr*) &mysqld_port_timeout, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef ENABLED_PROFILING + {"profiling_history_size", OPT_PROFILING, "Limit of query profiling memory", + (gptr*) &global_system_variables.profiling_history_size, + (gptr*) &max_system_variables.profiling_history_size, + 0, GET_UINT, REQUIRED_ARG, 15, 0, 100, 0, 0, 0}, +#endif {"relay-log", OPT_RELAY_LOG, "The location and name to use for relay logs.", (gptr*) &opt_relay_logname, (gptr*) &opt_relay_logname, 0, diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 88b45caf354..3d8a4ebd547 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -91,7 +91,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(thd, "Thread initialized"); + thd_proc_info(thd, "Thread initialized"); thd->version=refresh_version; thd->set_time(); DBUG_RETURN(0); @@ -597,7 +597,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(thd, "Processing request"); + thd_proc_info(thd, "Processing request"); while (!break_req_chain) { switch (rpl_status) { @@ -941,7 +941,7 @@ bool load_master_data(THD* thd) goto err; } } - THD_PROC_INFO(thd, "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)) @@ -968,7 +968,7 @@ bool load_master_data(THD* thd) flush_relay_log_info(&active_mi->rli); pthread_cond_broadcast(&active_mi->rli.data_cond); pthread_mutex_unlock(&active_mi->rli.data_lock); - thd->proc_info = "starting slave"; + thd_proc_info(thd, "starting slave"); if (restart_thread_mask) { error=start_slave_threads(0 /* mutex not needed */, @@ -980,7 +980,7 @@ bool load_master_data(THD* thd) err: unlock_slave_threads(active_mi); pthread_mutex_unlock(&LOCK_active_mi); - thd->proc_info = 0; + thd_proc_info(thd, 0); mysql_close(&mysql); // safe to call since we always do mysql_init() if (!error) diff --git a/sql/set_var.cc b/sql/set_var.cc index b4fd6b90d18..c02561261c0 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -545,6 +545,12 @@ static sys_var_thd_bit sys_unique_checks("unique_checks", 0, set_option_bit, OPTION_RELAXED_UNIQUE_CHECKS, 1); +#ifdef ENABLED_PROFILING +static sys_var_thd_bit sys_profiling("profiling", NULL, set_option_bit, + ulonglong(OPTION_PROFILING)); +sys_var_thd_ulong sys_profiling_history_size("profiling_history_size", + &SV::profiling_history_size); +#endif /* Local state variables */ @@ -696,6 +702,10 @@ sys_var *sys_variables[]= &sys_optimizer_prune_level, &sys_optimizer_search_depth, &sys_preload_buff_size, +#ifdef ENABLED_PROFILING + &sys_profiling, + &sys_profiling_history_size, +#endif &sys_pseudo_thread_id, &sys_query_alloc_block_size, &sys_query_cache_size, @@ -1003,6 +1013,10 @@ struct show_var_st init_vars[]= { {"pid_file", (char*) pidfile_name, SHOW_CHAR}, {"port", (char*) &mysqld_port, SHOW_INT}, {sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS}, +#ifdef ENABLED_PROFILING + {sys_profiling.name, (char*) &sys_profiling, SHOW_SYS}, + {sys_profiling_history_size.name, (char*) &sys_profiling_history_size, SHOW_SYS}, +#endif {"protocol_version", (char*) &protocol_version, SHOW_INT}, {sys_query_alloc_block_size.name, (char*) &sys_query_alloc_block_size, SHOW_SYS}, @@ -2842,14 +2856,14 @@ static bool set_option_autocommit(THD *thd, set_var *var) if ((org_options & OPTION_NOT_AUTOCOMMIT)) { /* We changed to auto_commit mode */ - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); thd->server_status|= SERVER_STATUS_AUTOCOMMIT; if (ha_commit(thd)) return 1; } else { - thd->options&= ~(ulong) (OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(OPTION_STATUS_NO_TRANS_UPDATE); thd->server_status&= ~SERVER_STATUS_AUTOCOMMIT; } } diff --git a/sql/set_var.h b/sql/set_var.h index 3304f552a97..d55ca4d289f 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -457,11 +457,11 @@ class sys_var_thd_bit :public sys_var_thd sys_check_func check_func; sys_update_func update_func; public: - ulong bit_flag; + ulonglong bit_flag; bool reverse; sys_var_thd_bit(const char *name_arg, sys_check_func c_func, sys_update_func u_func, - ulong bit, bool reverse_arg=0) + ulonglong bit, bool reverse_arg=0) :sys_var_thd(name_arg), check_func(c_func), update_func(u_func), bit_flag(bit), reverse(reverse_arg) {} diff --git a/sql/slave.cc b/sql/slave.cc index 94e4fb7b6bd..83bd6b7bd2d 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1557,8 +1557,8 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, /* Create the table. We do not want to log the "create table" statement */ save_options = thd->options; - thd->options &= ~(ulong) (OPTION_BIN_LOG); - thd->proc_info = "Creating table from master dump"; + thd->options &= ~ (OPTION_BIN_LOG); + thd_proc_info(thd, "Creating table from master dump"); // save old db in case we are creating in a different database save_db = thd->db; save_db_length= thd->db_length; @@ -1572,7 +1572,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, if (thd->query_error) goto err; // mysql_parse took care of the error send - thd->proc_info = "Opening master dump table"; + thd_proc_info(thd, "Opening master dump table"); tables.lock_type = TL_WRITE; if (!open_ltable(thd, &tables, TL_WRITE)) { @@ -1581,7 +1581,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, } file = tables.table->file; - thd->proc_info = "Reading master dump table data"; + thd_proc_info(thd, "Reading master dump table data"); /* Copy the data file */ if (file->net_read_dump(net)) { @@ -1593,7 +1593,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, check_opt.init(); check_opt.flags|= T_VERY_SILENT | T_CALC_CHECKSUM | T_QUICK; - thd->proc_info = "Rebuilding the index on master dump table"; + thd_proc_info(thd, "Rebuilding the index on master dump table"); /* We do not want repair() to spam us with messages just send them to the error log, and report the failure in case of @@ -2924,9 +2924,9 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) #endif if (thd_type == SLAVE_THD_SQL) - THD_PROC_INFO(thd, "Waiting for the next event in relay log"); + thd_proc_info(thd, "Waiting for the next event in relay log"); else - THD_PROC_INFO(thd, "Waiting for master update"); + thd_proc_info(thd, "Waiting for master update"); thd->version=refresh_version; thd->set_time(); DBUG_RETURN(0); @@ -3486,7 +3486,7 @@ slave_begin: goto err; } - thd->proc_info = "Connecting to master"; + thd_proc_info(thd, "Connecting to master"); // we can get killed during safe_connect if (!safe_connect(thd, mysql, mi)) { @@ -3513,7 +3513,7 @@ connected: // TODO: the assignment below should be under mutex (5.0) mi->slave_running= MYSQL_SLAVE_RUN_CONNECT; thd->slave_net = &mysql->net; - thd->proc_info = "Checking master version"; + thd_proc_info(thd, "Checking master version"); if (get_master_version_and_clock(mysql, mi)) goto err; @@ -3524,7 +3524,7 @@ connected: If fails, this is not fatal - we just print the error message and go on with life. */ - thd->proc_info = "Registering slave on master"; + thd_proc_info(thd, "Registering slave on master"); if (register_slave_on_master(mysql) || update_slave_list(mysql, mi)) goto err; } @@ -3533,7 +3533,7 @@ connected: while (!io_slave_killed(thd,mi)) { bool suppress_warnings= 0; - thd->proc_info = "Requesting binlog dump"; + thd_proc_info(thd, "Requesting binlog dump"); if (request_dump(mysql, mi, &suppress_warnings)) { sql_print_error("Failed on request_dump()"); @@ -3545,7 +3545,7 @@ dump"); } mi->slave_running= MYSQL_SLAVE_RUN_NOT_CONNECT; - THD_PROC_INFO(thd, "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 @@ -3569,7 +3569,7 @@ dump"); goto err; } - thd->proc_info = "Reconnecting after a failed binlog dump request"; + thd_proc_info(thd, "Reconnecting after a failed binlog dump request"); if (!suppress_warnings) sql_print_error("Slave I/O thread: failed dump request, \ reconnecting to try again, log '%s' at postion %s", IO_RPL_LOG_NAME, @@ -3594,7 +3594,7 @@ after reconnect"); important thing is to not confuse users by saying "reading" whereas we're in fact receiving nothing. */ - thd->proc_info = "Waiting for master to send event"; + thd_proc_info(thd, "Waiting for master to send event"); ulong event_len = read_event(mysql, mi, &suppress_warnings); if (io_slave_killed(thd,mi)) { @@ -3622,7 +3622,7 @@ max_allowed_packet", goto err; } mi->slave_running= MYSQL_SLAVE_RUN_NOT_CONNECT; - thd->proc_info = "Waiting to reconnect after a failed master event read"; + thd_proc_info(thd, "Waiting to reconnect after a failed master event read"); #ifdef SIGNAL_WITH_VIO_CLOSE thd->clear_active_vio(); #endif @@ -3641,7 +3641,7 @@ max_allowed_packet", reconnect after a failed read"); goto err; } - thd->proc_info = "Reconnecting after a failed master event read"; + thd_proc_info(thd, "Reconnecting after a failed master event read"); if (!suppress_warnings) sql_print_information("Slave I/O thread: Failed reading log event, \ reconnecting to retry, log '%s' position %s", IO_RPL_LOG_NAME, @@ -3658,7 +3658,7 @@ reconnect done to recover from failed read"); } // if (event_len == packet_error) retry_count=0; // ok event, reset retry counter - thd->proc_info = "Queueing master event to the relay log"; + thd_proc_info(thd, "Queueing master event to the relay log"); if (queue_event(mi,(const char*)mysql->net.read_pos + 1, event_len)) { @@ -3740,7 +3740,7 @@ err: mi->mysql=0; } write_ignored_events_info_to_relay_log(thd, mi); - thd->proc_info = "Waiting for slave mutex on exit"; + thd_proc_info(thd, "Waiting for slave mutex on exit"); pthread_mutex_lock(&mi->run_lock); /* Forget the relay log's format */ @@ -3912,7 +3912,7 @@ Slave SQL thread aborted. Can't execute init_slave query"); while (!sql_slave_killed(thd,rli)) { - thd->proc_info = "Reading event from the relay log"; + thd_proc_info(thd, "Reading event from the relay log"); DBUG_ASSERT(rli->sql_thd == thd); THD_CHECK_SENTRY(thd); if (exec_relay_log_event(thd,rli)) @@ -3944,7 +3944,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ thd->query= 0; thd->query_length= 0; VOID(pthread_mutex_unlock(&LOCK_thread_count)); - thd->proc_info = "Waiting for slave mutex on exit"; + thd_proc_info(thd, "Waiting for slave mutex on exit"); pthread_mutex_lock(&rli->run_lock); /* We need data_lock, at least to wake up any waiting master_pos_wait() */ pthread_mutex_lock(&rli->data_lock); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index c6e49fae801..c0d24a5afdc 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2387,9 +2387,9 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, m_lex->unit.cleanup(); - THD_PROC_INFO(thd, "closing tables"); + thd_proc_info(thd, "closing tables"); close_thread_tables(thd); - THD_PROC_INFO(thd, 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 636006ea7c2..11cc1584780 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -306,7 +306,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(thd, "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, @@ -348,7 +348,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(thd, 0); + thd_proc_info(thd, 0); pthread_mutex_unlock(&thd->mysys_var->mutex); } DBUG_RETURN(result); @@ -549,7 +549,7 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) good idea to turn off OPTION_TABLE_LOCK flag. */ DBUG_ASSERT(thd->lex->requires_prelocking()); - thd->options&= ~(ulong) (OPTION_TABLE_LOCK); + thd->options&= ~(OPTION_TABLE_LOCK); } DBUG_VOID_RETURN; @@ -1070,7 +1070,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(thd, "Waiting for table"); + thd_proc_info(thd, "Waiting for table"); if (!thd->killed) (void) pthread_cond_wait(&COND_refresh,&LOCK_open); @@ -1078,7 +1078,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(thd, proc_info); + thd_proc_info(thd, proc_info); pthread_mutex_unlock(&thd->mysys_var->mutex); DBUG_VOID_RETURN; } @@ -1783,7 +1783,7 @@ bool wait_for_tables(THD *thd) bool result; DBUG_ENTER("wait_for_tables"); - THD_PROC_INFO(thd, "Waiting for tables"); + thd_proc_info(thd, "Waiting for tables"); pthread_mutex_lock(&LOCK_open); while (!thd->killed) { @@ -1799,12 +1799,12 @@ bool wait_for_tables(THD *thd) else { /* Now we can open all tables without any interference */ - THD_PROC_INFO(thd, "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(thd, 0); + thd_proc_info(thd, 0); DBUG_RETURN(result); } @@ -2103,7 +2103,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) restart: *counter= 0; query_tables_last_own= 0; - THD_PROC_INFO(thd, "Opening tables"); + thd_proc_info(thd, "Opening tables"); /* If we are not already executing prelocked statement and don't have @@ -2283,7 +2283,7 @@ process_view_routines: } err: - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block if (query_tables_last_own) @@ -2357,7 +2357,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type) bool refresh; DBUG_ENTER("open_ltable"); - THD_PROC_INFO(thd, "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; @@ -2391,7 +2391,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type) table= 0; } } - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); DBUG_RETURN(table); } @@ -2611,7 +2611,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) { if (thd->lex->requires_prelocking()) { - thd->options&= ~(ulong) (OPTION_TABLE_LOCK); + thd->options&= ~(OPTION_TABLE_LOCK); thd->in_lock_tables=0; } DBUG_RETURN(-1); @@ -2644,7 +2644,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) ha_rollback_stmt(thd); mysql_unlock_tables(thd, thd->locked_tables); thd->locked_tables= 0; - thd->options&= ~(ulong) (OPTION_TABLE_LOCK); + thd->options&= ~(OPTION_TABLE_LOCK); DBUG_RETURN(-1); } } @@ -5436,7 +5436,7 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order) List_iterator li(*(select_lex->ftfunc_list)); Item_func_match *ifm; DBUG_PRINT("info",("Performing FULLTEXT search")); - THD_PROC_INFO(thd, "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 7340da5ce93..cb65eb562a2 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -315,13 +315,13 @@ TODO list: #define MUTEX_UNLOCK(M) {DBUG_PRINT("lock", ("mutex unlock 0x%lx",\ (ulong)(M))); pthread_mutex_unlock(M);} #define RW_WLOCK(M) {DBUG_PRINT("lock", ("rwlock wlock 0x%lx",(ulong)(M))); \ - if (!rw_wrlock(M)) DBUG_PRINT("lock", ("rwlock wlock ok")) \ + if (!rw_wrlock(M)) DBUG_PRINT("lock", ("rwlock wlock ok")); \ else DBUG_PRINT("lock", ("rwlock wlock FAILED %d", errno)); } #define RW_RLOCK(M) {DBUG_PRINT("lock", ("rwlock rlock 0x%lx", (ulong)(M))); \ - if (!rw_rdlock(M)) DBUG_PRINT("lock", ("rwlock rlock ok")) \ + if (!rw_rdlock(M)) DBUG_PRINT("lock", ("rwlock rlock ok")); \ else DBUG_PRINT("lock", ("rwlock wlock FAILED %d", errno)); } #define RW_UNLOCK(M) {DBUG_PRINT("lock", ("rwlock unlock 0x%lx",(ulong)(M))); \ - if (!rw_unlock(M)) DBUG_PRINT("lock", ("rwlock unlock ok")) \ + if (!rw_unlock(M)) DBUG_PRINT("lock", ("rwlock unlock ok")); \ else DBUG_PRINT("lock", ("rwlock unlock FAILED %d", errno)); } #define STRUCT_LOCK(M) {DBUG_PRINT("lock", ("%d struct lock...",__LINE__)); \ pthread_mutex_lock(M);DBUG_PRINT("lock", ("struct lock OK"));} @@ -688,7 +688,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"); + 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 @@ -726,7 +726,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"); + thd_proc_info(thd, "storing result in query cache"); DUMP(&query_cache); BLOCK_LOCK_WR(query_block); Query_cache_query *header= query_block->query(); @@ -1091,7 +1091,7 @@ 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"); + 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); @@ -1167,7 +1167,7 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu", } // Check access; - THD_PROC_INFO(thd, "checking privileges on cached query"); + 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++) @@ -1260,7 +1260,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"); + thd_proc_info(thd, "sending cached result to client"); do { DBUG_PRINT("qcache", ("Results (len: %lu used: %lu headers: %lu)", @@ -1342,7 +1342,7 @@ void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used) DBUG_ENTER("Query_cache::invalidate (changed table list)"); if (tables_used) { - THD_PROC_INFO(thd, "invalidating query cache entries (table list)"); + thd_proc_info(thd, "invalidating query cache entries (table list)"); STRUCT_LOCK(&structure_guard_mutex); if (query_cache_size > 0 && !flush_in_progress) { @@ -1377,7 +1377,7 @@ void Query_cache::invalidate_locked_for_write(TABLE_LIST *tables_used) DBUG_ENTER("Query_cache::invalidate_locked_for_write"); if (tables_used) { - THD_PROC_INFO(thd, "invalidating query cache entries (table)"); + thd_proc_info(thd, "invalidating query cache entries (table)"); STRUCT_LOCK(&structure_guard_mutex); if (query_cache_size > 0 && !flush_in_progress) { @@ -1427,7 +1427,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)"); + 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 fc9ec55f54a..4878acabbb2 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -247,7 +247,9 @@ THD::THD() init(); /* Initialize sub structures */ init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE); +#ifdef ENABLED_PROFILING profiling.set_thd(this); +#endif 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,7 +332,6 @@ 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 582d6afe51c..3795627fd58 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -521,6 +521,7 @@ struct system_variables ulong optimizer_prune_level; ulong optimizer_search_depth; ulong preload_buff_size; + ulong profiling_history_size; ulong query_cache_type; ulong read_buff_size; ulong read_rnd_buff_size; @@ -1154,6 +1155,9 @@ public: Points to info-string that we show in SHOW PROCESSLIST You are supposed to update thd->proc_info only if you have coded a time-consuming piece that MySQL can get stuck in for a long time. + + Set it using the thd_proc_info(THD *thread, const char *message) + macro/function. */ const char *proc_info; @@ -1308,8 +1312,9 @@ public: List warn_list; uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END]; uint total_warn_count; - +#ifdef ENABLED_PROFILING PROFILING profiling; +#endif /* Id of current query. Statement can be reused to execute several queries diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index d02bc89068e..ac290a50b9b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -54,7 +54,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(thd, "init"); + thd_proc_info(thd, "init"); table->map=1; if (mysql_prepare_delete(thd, table_list, &conds)) @@ -205,7 +205,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, deleted=0L; init_ftfuncs(thd, select_lex, 1); - THD_PROC_INFO(thd, "updating"); + thd_proc_info(thd, "updating"); if (table->triggers) table->triggers->mark_fields_used(thd, TRG_EVENT_DELETE); @@ -261,7 +261,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, } if (thd->killed && !error) error= 1; // Aborted - THD_PROC_INFO(thd, "end"); + thd_proc_info(thd, "end"); end_read_record(&info); free_io_cache(table); // Will not do any harm if (options & OPTION_QUICK) @@ -485,7 +485,7 @@ multi_delete::prepare(List &values, SELECT_LEX_UNIT *u) DBUG_ENTER("multi_delete::prepare"); unit= u; do_delete= 1; - THD_PROC_INFO(thd, "deleting from main table"); + thd_proc_info(thd, "deleting from main table"); DBUG_RETURN(0); } @@ -749,7 +749,7 @@ int multi_delete::do_deletes() bool multi_delete::send_eof() { - THD_PROC_INFO(thd, "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 @@ -758,7 +758,7 @@ bool multi_delete::send_eof() local_error= local_error || error; /* reset used flags */ - THD_PROC_INFO(thd, "end"); + thd_proc_info(thd, "end"); /* We must invalidate the query cache before binlog writing and @@ -903,7 +903,7 @@ end: /* Probably InnoDB table */ ulonglong save_options= thd->options; table_list->lock_type= TL_WRITE; - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT); + thd->options&= ~(OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT); ha_enable_transaction(thd, FALSE); mysql_init_select(thd->lex); error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0, diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index c2e30c47cfb..b384098bc00 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -397,7 +397,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, if (res || thd->is_fatal_error) DBUG_RETURN(TRUE); - THD_PROC_INFO(thd, "init"); + thd_proc_info(thd, "init"); thd->used_tables=0; values= its++; @@ -470,7 +470,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, error=0; id=0; - THD_PROC_INFO(thd, "update"); + thd_proc_info(thd, "update"); if (duplic != DUP_ERROR || ignore) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); if (duplic == DUP_REPLACE) @@ -676,7 +676,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, thd->lock=0; } } - THD_PROC_INFO(thd, "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 @@ -1407,7 +1407,7 @@ I_List delayed_threads; delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list) { - THD_PROC_INFO(thd, "waiting for delay_list"); + thd_proc_info(thd, "waiting for delay_list"); pthread_mutex_lock(&LOCK_delayed_insert); // Protect master list I_List_iterator it(delayed_threads); delayed_insert *tmp; @@ -1444,7 +1444,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(thd, "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. @@ -1486,13 +1486,13 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) } /* Wait until table is open */ - THD_PROC_INFO(thd, "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(thd, "got old table"); + thd_proc_info(thd, "got old table"); if (tmp->thd.killed) { if (tmp->thd.is_fatal_error) @@ -1552,13 +1552,13 @@ TABLE *delayed_insert::get_local_table(THD* client_thd) tables_in_use++; if (!thd.lock) // Table is not locked { - THD_PROC_INFO(client_thd, "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); } - THD_PROC_INFO(client_thd, "got handler lock"); + thd_proc_info(client_thd, "got handler lock"); if (client_thd->killed) goto error; if (dead) @@ -1576,7 +1576,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. */ - THD_PROC_INFO(client_thd, "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); @@ -1656,11 +1656,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(thd, "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(thd, "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; @@ -1869,7 +1869,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; - THD_PROC_INFO(&(di->thd), "Waiting for INSERT"); + thd_proc_info(&(di->thd), "Waiting for INSERT"); DBUG_PRINT("info",("Waiting for someone to insert rows")); while (!thd->killed) @@ -1904,7 +1904,7 @@ pthread_handler_t handle_delayed_insert(void *arg) pthread_mutex_unlock(&di->thd.mysys_var->mutex); pthread_mutex_lock(&di->mutex); } - THD_PROC_INFO(&(di->thd), 0); + thd_proc_info(&(di->thd), 0); if (di->tables_in_use && ! thd->lock) { @@ -2023,7 +2023,7 @@ bool delayed_insert::handle_inserts(void) table->next_number_field=table->found_next_number_field; - THD_PROC_INFO(&thd, "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 */ @@ -2031,7 +2031,7 @@ bool delayed_insert::handle_inserts(void) goto err; } - THD_PROC_INFO(&thd, "insert"); + thd_proc_info(&thd, "insert"); max_rows= delayed_insert_limit; if (thd.killed || table->s->version != refresh_version) { @@ -2149,7 +2149,7 @@ bool delayed_insert::handle_inserts(void) { if (tables_in_use) pthread_cond_broadcast(&cond_client); // If waiting clients - THD_PROC_INFO(&thd, "reschedule"); + thd_proc_info(&thd, "reschedule"); pthread_mutex_unlock(&mutex); if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) { @@ -2168,14 +2168,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(&thd, "insert"); + thd_proc_info(&thd, "insert"); } if (tables_in_use) pthread_cond_broadcast(&cond_client); // If waiting clients } } - THD_PROC_INFO(&thd, 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 da562babea1..47fe2e8ac0e 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -173,8 +173,9 @@ void lex_start(THD *thd, uchar *buf,uint length) lex->proc_list.first= 0; lex->escape_used= FALSE; lex->reset_query_tables_list(FALSE); +#ifdef ENABLED_PROFILING lex->profile_options= PROFILE_NONE; - +#endif lex->nest_level=0 ; lex->allow_sum_func= 0; lex->in_sum_func= NULL; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 96ce02f7409..22f9d6026f9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -95,8 +95,12 @@ enum enum_sql_command { 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 !!! */ + /* + When a command is added here, be sure it's also added in mysqld.cc + in "struct show_var_st status_vars[]= {" ... + */ + /* This should be the last !!! */ SQLCOM_END }; @@ -939,8 +943,9 @@ 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 profile_options; 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 779db99a4ff..449d57c2b2d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -140,14 +140,14 @@ static bool end_active_trans(THD *thd) if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN | OPTION_TABLE_LOCK)) { - DBUG_PRINT("info",("options: 0x%lx", (ulong) thd->options)); + DBUG_PRINT("info",("options: 0x%llx", thd->options)); /* Safety if one did "drop table" on locked tables */ if (!thd->locked_tables) thd->options&= ~OPTION_TABLE_LOCK; thd->server_status&= ~SERVER_STATUS_IN_TRANS; if (ha_commit(thd)) error=1; - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); } DBUG_RETURN(error); } @@ -171,7 +171,7 @@ static bool begin_trans(THD *thd) else { LEX *lex= thd->lex; - thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) | + thd->options= ((thd->options & ~(OPTION_STATUS_NO_TRANS_UPDATE)) | OPTION_BEGIN); thd->server_status|= SERVER_STATUS_IN_TRANS; if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT) @@ -1058,7 +1058,7 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var, Vio* save_vio; ulong save_client_capabilities; - THD_PROC_INFO(thd, "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 @@ -1158,7 +1158,7 @@ pthread_handler_t handle_one_connection(void *arg) net->compress=1; // Use compression thd->version= refresh_version; - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); thd->command= COM_SLEEP; thd->set_time(); thd->init_for_queries(); @@ -1175,7 +1175,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(thd, 0); + thd_proc_info(thd, 0); thd->set_time(); thd->init_for_queries(); } @@ -1258,7 +1258,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(thd, 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)); @@ -1447,7 +1447,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) */ thd->server_status&= ~SERVER_STATUS_IN_TRANS; res= ha_commit(thd); - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); break; case COMMIT_RELEASE: do_release= 1; /* fall through */ @@ -1464,7 +1464,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) thd->server_status&= ~SERVER_STATUS_IN_TRANS; if (ha_rollback(thd)) res= -1; - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); if (!res && (completion == ROLLBACK_AND_CHAIN)) res= begin_trans(thd); break; @@ -2105,7 +2105,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(thd, "closing tables"); + thd_proc_info(thd, "closing tables"); close_thread_tables(thd); /* Free tables */ } /* @@ -2128,9 +2128,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, log_slow_statement(thd); - THD_PROC_INFO(thd, "cleaning up"); + thd_proc_info(thd, "cleaning up"); VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); thd->command=COM_SLEEP; thd->query=0; thd->query_length=0; @@ -2163,6 +2163,8 @@ void log_slow_statement(THD *thd) */ if (thd->enable_slow_log && !thd->user_time) { + thd_proc_info(thd, "logging slow query"); + if ((ulong) (thd->start_time - thd->time_after_lock) > thd->variables.long_query_time || (thd->server_status & @@ -2171,7 +2173,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_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); } @@ -2698,16 +2700,33 @@ mysql_execute_command(THD *thd) } case SQLCOM_SHOW_PROFILES: { +#ifdef ENABLED_PROFILING thd->profiling.store(); thd->profiling.discard(); res= thd->profiling.show_profiles(); + if (res) + goto error; +#else + my_error(ER_FEATURE_DISABLED, MYF(0), "query profiling", "enable-profiling"); + goto error; +#endif break; } case SQLCOM_SHOW_PROFILE: { +#ifdef ENABLED_PROFILING thd->profiling.store(); thd->profiling.discard(); // will get re-enabled by reset() - res= thd->profiling.show_last(lex->profile_options); + if (lex->profile_query_id != 0) + res= thd->profiling.show(lex->profile_options, lex->profile_query_id); + else + res= thd->profiling.show_last(lex->profile_options); + if (res) + goto error; +#else + my_error(ER_FEATURE_DISABLED, MYF(0), "query profiling", "enable-profiling"); + goto error; +#endif break; } case SQLCOM_SHOW_NEW_MASTER: @@ -3557,7 +3576,7 @@ end_with_restore_list: if (add_item_to_list(thd, new Item_null())) goto error; - THD_PROC_INFO(thd, "init"); + thd_proc_info(thd, "init"); if ((res= open_and_lock_tables(thd, all_tables))) break; @@ -3721,7 +3740,7 @@ end_with_restore_list: if (thd->options & OPTION_TABLE_LOCK) { end_active_trans(thd); - thd->options&= ~(ulong) (OPTION_TABLE_LOCK); + thd->options&= ~(OPTION_TABLE_LOCK); } if (thd->global_read_lock) unlock_global_read_lock(thd); @@ -3747,7 +3766,7 @@ end_with_restore_list: send_ok(thd); } else - thd->options&= ~(ulong) (OPTION_TABLE_LOCK); + thd->options&= ~(OPTION_TABLE_LOCK); thd->in_lock_tables=0; break; case SQLCOM_CREATE_DB: @@ -4847,7 +4866,7 @@ create_sp_error: thd->transaction.xid_state.xa_state=XA_ACTIVE; thd->transaction.xid_state.xid.set(thd->lex->xid); xid_cache_insert(&thd->transaction.xid_state); - thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) | + thd->options= ((thd->options & ~(OPTION_STATUS_NO_TRANS_UPDATE)) | OPTION_BEGIN); thd->server_status|= SERVER_STATUS_IN_TRANS; send_ok(thd); @@ -4941,7 +4960,7 @@ create_sp_error: xa_state_names[thd->transaction.xid_state.xa_state]); break; } - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); thd->server_status&= ~SERVER_STATUS_IN_TRANS; xid_cache_delete(&thd->transaction.xid_state); thd->transaction.xid_state.xa_state=XA_NOTR; @@ -4971,7 +4990,7 @@ create_sp_error: my_error(ER_XAER_RMERR, MYF(0)); else send_ok(thd); - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); thd->server_status&= ~SERVER_STATUS_IN_TRANS; xid_cache_delete(&thd->transaction.xid_state); thd->transaction.xid_state.xa_state=XA_NOTR; @@ -4986,7 +5005,7 @@ create_sp_error: send_ok(thd); break; } - THD_PROC_INFO(thd, "query end"); + thd_proc_info(thd, "query end"); /* Two binlog-related cleanups: */ /* @@ -5157,8 +5176,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, else save_priv= &dummy; - THD_PROC_INFO(thd, "checking permissions"); - + thd_proc_info(thd, "checking permissions"); if ((!db || !db[0]) && !thd->db && !dont_check_global_grants) { DBUG_PRINT("error",("No database")); @@ -5605,6 +5623,9 @@ mysql_init_query(THD *thd, uchar *buf, uint length) DBUG_ENTER("mysql_init_query"); lex_start(thd, buf, length); mysql_reset_thd_for_next_command(thd); +#ifdef ENABLED_PROFILING + thd->profiling.reset(); +#endif DBUG_VOID_RETURN; } @@ -5646,7 +5667,9 @@ 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; +#ifdef ENABLED_PROFILING thd->profiling.reset(); +#endif } DBUG_VOID_RETURN; } @@ -5870,7 +5893,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length) query_cache_abort(&thd->net); lex->unit.cleanup(); } - THD_PROC_INFO(thd, "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_prepare.cc b/sql/sql_prepare.cc index 152cc3aa385..83ddb9c9212 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2222,6 +2222,7 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute"))) DBUG_VOID_RETURN; + thd->profiling.set_query_source(stmt->query, stmt->query_length); DBUG_PRINT("exec_query", ("%s", stmt->query)); DBUG_PRINT("info",("stmt: %p", stmt)); diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 98a5f8d7576..e9b6ef0b522 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -14,149 +14,282 @@ 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) +#include "mysql_priv.h" +#include "my_sys.h" + +#define TIME_FLOAT_DIGITS 7 +#define MAX_QUERY_LENGTH 300 + +bool schema_table_store_record(THD *thd, TABLE *table); + +/* Reserved for systems that can't record the function name in source. */ +const char *_db_func_= ""; + +/** + Connects Information_Schema and Profiling. +*/ +int fill_query_profile_statistics_info(THD *thd, struct st_table_list *tables, + Item *cond) +{ +#ifdef ENABLED_PROFILING + return(thd->profiling.fill_statistics_info(thd, tables, cond)); +#else + return(1); +#endif +} + +ST_FIELD_INFO query_profile_statistics_info[]= +{ + /* name, length, type, value, maybe_null, old_name */ + {"Query_id", 20, MYSQL_TYPE_LONG, 0, false, NULL}, + {"Seq", 20, MYSQL_TYPE_LONG, 0, false, NULL}, + {"State", 30, MYSQL_TYPE_STRING, 0, false, NULL}, + {"Duration", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, false, NULL}, + {"CPU_user", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, + {"CPU_system", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, + {"Context_voluntary", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Context_involuntary", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Block_ops_in", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Block_ops_out", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Messages_sent", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Messages_received", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Page_faults_major", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Page_faults_minor", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Swaps", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Source_function", 30, MYSQL_TYPE_STRING, 0, true, NULL}, + {"Source_file", 20, MYSQL_TYPE_STRING, 0, true, NULL}, + {"Source_line", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL} +}; + +#ifdef ENABLED_PROFILING + +#define RUSAGE_USEC(tv) ((tv).tv_sec*1000*1000 + (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) + :profile(NULL), status(NULL), function(NULL), file(NULL), line(0), + time_usecs(0.0), allocated_status_memory(NULL) { collect(); } -PROFILE_ENTRY::PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg) - :profile(profile_arg), function(NULL), file(NULL), line(0) +PROFILE_ENTRY::PROFILE_ENTRY(QUERY_PROFILE *profile_arg, const char *status_arg) + :profile(profile_arg) { collect(); - if (status_arg) - set_status(status_arg); + set_status(status_arg, NULL, NULL, 0); } -PROFILE_ENTRY::PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg, +PROFILE_ENTRY::PROFILE_ENTRY(QUERY_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; + set_status(status_arg, function_arg, file_arg, line_arg); } PROFILE_ENTRY::~PROFILE_ENTRY() { - if (status) - free(status); - if (function) - free(function); - if (file) - free(file); + if (allocated_status_memory != NULL) + my_free(allocated_status_memory, MYF(0)); + status= function= file= NULL; } -void PROFILE_ENTRY::set_status(const char *status_arg) +void PROFILE_ENTRY::set_status(const char *status_arg, const char *function_arg, const char *file_arg, unsigned int line_arg) { - status= strdup_root(&profile->profiling->root, status_arg); + size_t sizes[3]; /* 3 == status+function+file */ + char *cursor; + + /* + Compute all the space we'll need to allocate one block for everything + we'll need, instead of N mallocs. + */ + if (status_arg != NULL) + sizes[0]= strlen(status_arg) + 1; + else + sizes[0]= 0; + + if (function_arg != NULL) + sizes[1]= strlen(function_arg) + 1; + else + sizes[1]= 0; + + if (file_arg != NULL) + sizes[2]= strlen(file_arg) + 1; + else + sizes[2]= 0; + + allocated_status_memory= (char *) my_malloc(sizes[0] + sizes[1] + sizes[2], MYF(0)); + DBUG_ASSERT(allocated_status_memory != NULL); + + cursor= allocated_status_memory; + + if (status_arg != NULL) + { + strcpy(cursor, status_arg); + status= cursor; + cursor+= sizes[0]; + } + else + status= NULL; + + if (function_arg != NULL) + { + strcpy(cursor, function_arg); + function= cursor; + cursor+= sizes[1]; + } + else + function= NULL; + + if (file_arg != NULL) + { + strcpy(cursor, file_arg); + file= cursor; + cursor+= sizes[2]; + } + else + file= NULL; + + line= line_arg; } void PROFILE_ENTRY::collect() { - time= my_getsystime(); + time_usecs= (double) my_getsystime() / 10.0; /* 1 sec was 1e7, now is 1e6 */ +#ifdef HAVE_GETRUSAGE getrusage(RUSAGE_SELF, &rusage); +#endif } -PROFILE::PROFILE(PROFILING *profiling_arg) - :profiling(profiling_arg) +QUERY_PROFILE::QUERY_PROFILE(PROFILING *profiling_arg, char *query_source_arg, + uint query_length_arg) + :profiling(profiling_arg), server_query_id(-1), profiling_query_id(-1), + query_source(NULL) { profile_end= &profile_start; + set_query_source(query_source_arg, query_length_arg); } -PROFILE::~PROFILE() +void QUERY_PROFILE::set_query_source(char *query_source_arg, + uint query_length_arg) { + /* Truncate to avoid DoS attacks. */ + uint length= min(MAX_QUERY_LENGTH, query_length_arg); + /* TODO?: Provide a way to include the full text, as in SHOW PROCESSLIST. */ + + if (query_source_arg != NULL) + query_source= my_strdup_with_length(query_source_arg, length, MYF(0)); +} + +QUERY_PROFILE::~QUERY_PROFILE() +{ + PROFILE_ENTRY *entry; + List_iterator it(entries); + while ((entry= it++) != NULL) + delete entry; entries.empty(); + + if (query_source != NULL) + my_free(query_source, MYF(0)); } -void PROFILE::status(const char *status_arg, - const char *function_arg=NULL, - const char *file_arg=NULL, unsigned int line_arg=0) +void QUERY_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"); + PROFILE_ENTRY *prof; + MEM_ROOT *saved_mem_root; + DBUG_ENTER("QUERY_PROFILE::status"); /* Blank status. Just return, and thd->proc_info will be set blank later. */ - if (unlikely(!status_arg)) + if (unlikely(status_arg == NULL)) 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)))) + if (likely((thd->proc_info != NULL) && + ((thd->proc_info == status_arg) || + (strcmp(thd->proc_info, status_arg) == 0)))) + { DBUG_VOID_RETURN; + } /* Is this the same query as our profile currently contains? */ - if (unlikely(thd->query_id != query_id && !thd->spcont)) + if (unlikely((thd->query_id != server_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. + mysqld cleans up after the query. + + The "entries" list allocates is memory from the current thd's mem_root. + We substitute our mem_root temporarily so that we intercept those + allocations into our own mem_root. 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))) + saved_mem_root= thd->mem_root; + thd->mem_root= &profiling->mem_root; + //thd->mem_root= NULL; + + 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 { + } + else + { if ((profile_end= prof= new PROFILE_ENTRY(this, status_arg))) entries.push_back(prof); } - thd->mem_root= old_root; + + /* Restore mem_root */ + thd->mem_root= saved_mem_root; DBUG_VOID_RETURN; } -void PROFILE::reset() +void QUERY_PROFILE::reset() { - DBUG_ENTER("PROFILE::reset"); - if (profiling->thd->query_id != query_id) + DBUG_ENTER("QUERY_PROFILE::reset"); + if (likely(profiling->thd->query_id != server_query_id)) { - query_id= profiling->thd->query_id; + server_query_id= profiling->thd->query_id; /* despite name, is global */ profile_start.collect(); + + PROFILE_ENTRY *entry; + List_iterator it(entries); + while ((entry= it++) != NULL) + delete entry; entries.empty(); } DBUG_VOID_RETURN; } -bool PROFILE::show(uint options) +bool QUERY_PROFILE::show(uint options) { - PROFILE_ENTRY *prof; THD *thd= profiling->thd; - PROFILE_ENTRY *ps= &profile_start; List field_list; - DBUG_ENTER("PROFILE::show"); + DBUG_ENTER("QUERY_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)); + field_list.push_back(new Item_return_int("Duration", TIME_FLOAT_DIGITS, + MYSQL_TYPE_DOUBLE)); 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)); + field_list.push_back(new Item_return_int("CPU_user", TIME_FLOAT_DIGITS, + MYSQL_TYPE_DOUBLE)); + field_list.push_back(new Item_return_int("CPU_system", TIME_FLOAT_DIGITS, + MYSQL_TYPE_DOUBLE)); } if (options & PROFILE_MEMORY) @@ -200,7 +333,7 @@ bool PROFILE::show(uint options) field_list.push_back(new Item_return_int("Swaps", 10, MYSQL_TYPE_LONG)); } - if(options & PROFILE_SOURCE) + if (options & PROFILE_SOURCE) { field_list.push_back(new Item_empty_string("Source_function", MYSQL_ERRMSG_SIZE)); @@ -214,146 +347,231 @@ bool PROFILE::show(uint options) Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); + Protocol *protocol= thd->protocol; 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); + double last_time= profile_start.time_usecs; +#ifdef HAVE_GETRUSAGE + struct rusage *last_rusage= &(profile_start.rusage); +#endif List_iterator it(entries); - ulonglong last_time= ps->time; - while ((prof= it++)) + PROFILE_ENTRY *entry; + while ((entry= it++) != NULL) { +#ifdef HAVE_GETRUSAGE + struct rusage *rusage= &(entry->rusage); +#endif + String elapsed; + 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); + protocol->store(entry->status, strlen(entry->status), system_charset_info); + protocol->store((double)(entry->time_usecs - last_time)/(1000.0*1000), + (uint32) TIME_FLOAT_DIGITS-1, &elapsed); + //protocol->store((double)(entry->time - last_time)/(1000*1000*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)); +#ifdef HAVE_GETRUSAGE + String cpu_utime, cpu_stime; + protocol->store((double)(RUSAGE_DIFF_USEC(rusage->ru_utime, + last_rusage->ru_utime))/(1000.0*1000), + (uint32) TIME_FLOAT_DIGITS-1, &cpu_utime); + protocol->store((double)(RUSAGE_DIFF_USEC(rusage->ru_stime, + last_rusage->ru_stime))/(1000.0*1000), + (uint32) TIME_FLOAT_DIGITS-1, &cpu_stime); +#else + protocol->store_null(); + protocol->store_null(); +#endif } 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)); +#ifdef HAVE_GETRUSAGE + protocol->store((uint32)(rusage->ru_nvcsw - last_rusage->ru_nvcsw)); + protocol->store((uint32)(rusage->ru_nivcsw - last_rusage->ru_nivcsw)); +#else + protocol->store_null(); + protocol->store_null(); +#endif } 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)); +#ifdef HAVE_GETRUSAGE + protocol->store((uint32)(rusage->ru_inblock - last_rusage->ru_inblock)); + protocol->store((uint32)(rusage->ru_oublock - last_rusage->ru_oublock)); +#else + protocol->store_null(); + protocol->store_null(); +#endif } 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)); +#ifdef HAVE_GETRUSAGE + protocol->store((uint32)(rusage->ru_msgsnd - last_rusage->ru_msgsnd)); + protocol->store((uint32)(rusage->ru_msgrcv - last_rusage->ru_msgrcv)); +#else + protocol->store_null(); + protocol->store_null(); +#endif } 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)); +#ifdef HAVE_GETRUSAGE + protocol->store((uint32)(rusage->ru_majflt - last_rusage->ru_majflt)); + protocol->store((uint32)(rusage->ru_minflt - last_rusage->ru_minflt)); +#else + protocol->store_null(); + protocol->store_null(); +#endif } if (options & PROFILE_SWAPS) { - protocol->store((uint32)(prof->rusage.ru_nswap - ps->rusage.ru_nswap)); +#ifdef HAVE_GETRUSAGE + protocol->store((uint32)(rusage->ru_nswap - last_rusage->ru_nswap)); +#else + protocol->store_null(); +#endif } if (options & PROFILE_SOURCE) { - if(prof->function && prof->file) + if ((entry->function != NULL) && (entry->file != NULL)) { - protocol->store(prof->function, strlen(prof->function), system_charset_info); - protocol->store(prof->file, strlen(prof->file), system_charset_info); - protocol->store(prof->line); + protocol->store(entry->function, strlen(entry->function), + system_charset_info); + protocol->store(entry->file, strlen(entry->file), system_charset_info); + protocol->store(entry->line); } else { - protocol->store("(unknown)", 10, system_charset_info); - protocol->store("(unknown)", 10, system_charset_info); - protocol->store((uint32) 0); + protocol->store_null(); + protocol->store_null(); + protocol->store_null(); } } if (protocol->write()) DBUG_RETURN(TRUE); - last_time= prof->time; + + last_time= entry->time_usecs; +#ifdef HAVE_GETRUSAGE + last_rusage= &(entry->rusage); +#endif + } 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) + :profile_id_counter(0), keeping(1), current(NULL), last(NULL) { - init_sql_alloc(&root, + init_sql_alloc(&mem_root, PROFILE_ALLOC_BLOCK_SIZE, PROFILE_ALLOC_PREALLOC_SIZE); } PROFILING::~PROFILING() { - free_root(&root, MYF(0)); + QUERY_PROFILE *prof; + + List_iterator it(history); + while ((prof= it++) != NULL) + delete prof; + history.empty(); + + if (current != NULL) + delete current; + + free_root(&mem_root, MYF(0)); } -void PROFILING::status(const char *status_arg, - const char *function_arg, - const char *file_arg, unsigned int line_arg) +void PROFILING::status_change(const char *status_arg, + const char *function_arg, + const char *file_arg, unsigned int line_arg) { - DBUG_ENTER("PROFILING::status"); + DBUG_ENTER("PROFILING::status_change"); - if(!current) - reset(); + if (unlikely((thd->options & OPTION_PROFILING) != 0)) + { + if (unlikely(current == NULL)) + reset(); + + DBUG_ASSERT(current != NULL); - 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; + MEM_ROOT *saved_mem_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 */ + /* Already stored */ + if (unlikely((last != NULL) && + (current != NULL) && + (last->server_query_id == current->server_query_id))) { - PROFILE *tmp= history.pop(); + DBUG_VOID_RETURN; + } + + while (history.elements > thd->variables.profiling_history_size) + { + QUERY_PROFILE *tmp= history.pop(); delete tmp; } - old_root= thd->mem_root; - thd->mem_root= &root; + /* + Switch out memory roots so that we're sure that we keep what we need + + The "history" list implementation allocates its memory in the current + thd's mem_root. We substitute our mem_root temporarily so that we + intercept those allocations into our own mem_root. + */ + + saved_mem_root= thd->mem_root; + thd->mem_root= &mem_root; - if (current) + if (current != NULL) { - if (keeping && (!current->entries.is_empty())) { - last= current; + if (keeping && + (current->query_source != NULL) && + (current->query_source[0] != '\0') && + (!current->entries.is_empty())) + { + current->profiling_query_id= next_profile_id(); /* assign an id */ + + last= current; /* never contains something that is not in the history. */ history.push_back(current); current= NULL; - } else { + } + else + { delete current; + current= NULL; } } - current= new PROFILE(this); - thd->mem_root= old_root; + DBUG_ASSERT(current == NULL); + current= new QUERY_PROFILE(this, thd->query, thd->query_length); + + /* Restore memory root */ + thd->mem_root= saved_mem_root; DBUG_VOID_RETURN; } @@ -364,8 +582,8 @@ void PROFILING::reset() store(); - current->reset(); - /*free_root(&root, MYF(0));*/ + if (current != NULL) + current->reset(); keep(); DBUG_VOID_RETURN; @@ -373,15 +591,15 @@ void PROFILING::reset() bool PROFILING::show_profiles() { - PROFILE *prof; + DBUG_ENTER("PROFILING::show_profiles"); + QUERY_PROFILE *prof; List 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. */ + field_list.push_back(new Item_return_int("Duration", TIME_FLOAT_DIGITS-1, + MYSQL_TYPE_DOUBLE)); + field_list.push_back(new Item_empty_string("Query", 40)); if (thd->protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) @@ -390,13 +608,15 @@ bool PROFILING::show_profiles() SELECT_LEX *sel= &thd->lex->select_lex; SELECT_LEX_UNIT *unit= &thd->lex->unit; ha_rows idx= 0; - Protocol *protocol=thd->protocol; + Protocol *protocol= thd->protocol; unit->set_limit(sel); - List_iterator it(history); - while ((prof= it++)) + List_iterator it(history); + while ((prof= it++) != NULL) { + String elapsed; + PROFILE_ENTRY *ps= &prof->profile_start; PROFILE_ENTRY *pe= prof->profile_end; @@ -406,8 +626,14 @@ bool PROFILING::show_profiles() break; protocol->prepare_for_resend(); - protocol->store((uint32)(prof->query_id)); - protocol->store((ulonglong)((pe->time - ps->time)/10)); + protocol->store((uint32)(prof->profiling_query_id)); + protocol->store((double)(pe->time_usecs - ps->time_usecs)/(1000.0*1000), + (uint32) TIME_FLOAT_DIGITS-1, &elapsed); + if (prof->query_source != NULL) + protocol->store(prof->query_source, strlen(prof->query_source), + system_charset_info); + else + protocol->store_null(); if (protocol->write()) DBUG_RETURN(TRUE); @@ -416,18 +642,37 @@ bool PROFILING::show_profiles() DBUG_RETURN(FALSE); } -bool PROFILING::show(uint options, uint query_id) +/* + This is an awful hack to let prepared statements tell us the query + that they're executing. +*/ +void PROFILING::set_query_source(char *query_source_arg, uint query_length_arg) +{ + DBUG_ENTER("PROFILING::set_query_source"); + + /* We can't get this query source through normal means. */ + DBUG_ASSERT((thd->query == NULL) || (thd->query_length == 0)); + + if (current != NULL) + current->set_query_source(query_source_arg, query_length_arg); + else + DBUG_PRINT("info", ("no current profile to send query source to")); + DBUG_VOID_RETURN; +} + +bool PROFILING::show(uint options, uint profiling_query_id) { DBUG_ENTER("PROFILING::show"); - PROFILE *prof; + QUERY_PROFILE *prof; - List_iterator it(history); - while ((prof= it++)) + List_iterator it(history); + while ((prof= it++) != NULL) { - if(prof->query_id == query_id) - prof->show(options); + if(prof->profiling_query_id == profiling_query_id) + DBUG_RETURN(prof->show(options)); } + my_error(ER_WRONG_ARGUMENTS, MYF(0), "SHOW PROFILE"); DBUG_RETURN(TRUE); } @@ -439,3 +684,130 @@ bool PROFILING::show_last(uint options) } DBUG_RETURN(TRUE); } + + +/** + Fill the information schema table, "query_profile", as defined in show.cc . +*/ +int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item *cond) +{ + DBUG_ENTER("PROFILING::fill_statistics_info"); + TABLE *table= tables->table; + ulonglong row_number= 0; + + List_iterator query_it(history); + QUERY_PROFILE *query; + /* Go through each query in this thread's stored history... */ + while ((query= query_it++) != NULL) + { + PROFILE_ENTRY *ps= &(query->profile_start); + double last_time= ps->time_usecs; +#ifdef HAVE_GETRUSAGE + struct rusage *last_rusage= &(ps->rusage); +#endif + + /* + Because we put all profiling info into a table that may be reordered, let + us also include a numbering of each state per query. The query_id and + the "seq" together are unique. + */ + ulonglong seq; + + List_iterator step_it(query->entries); + PROFILE_ENTRY *entry; + /* ...and for each query, go through all its state-change steps. */ + for (seq= 0, entry= step_it++; + entry != NULL; +#ifdef HAVE_GETRUSAGE + last_rusage= &(entry->rusage), +#endif + seq++, last_time= entry->time_usecs, entry= step_it++, row_number++) + { + /* Set default values for this row. */ + restore_record(table, s->default_values); + + /* + The order of these fields is set by the query_profile_statistics_info + array. + */ + table->field[0]->store((ulonglong) query->profiling_query_id); + table->field[1]->store((ulonglong) seq); /* the step in the sequence */ + table->field[2]->store(entry->status, strlen(entry->status), + system_charset_info); + table->field[3]->store((double)(entry->time_usecs - last_time)/(1000*1000)); + +#ifdef HAVE_GETRUSAGE + table->field[4]->store((double)RUSAGE_DIFF_USEC(entry->rusage.ru_utime, + last_rusage->ru_utime)/(1000.0*1000)); + table->field[4]->null_ptr= NULL; + table->field[5]->store((double)RUSAGE_DIFF_USEC(entry->rusage.ru_stime, + last_rusage->ru_stime)/(1000.0*1000)); + + table->field[5]->null_ptr= NULL; +#else + /* TODO: Add CPU-usage info for non-BSD systems */ +#endif + +#ifdef HAVE_GETRUSAGE + table->field[6]->store((uint32)(entry->rusage.ru_nvcsw - last_rusage->ru_nvcsw)); + table->field[6]->null_ptr= NULL; + table->field[7]->store((uint32)(entry->rusage.ru_nivcsw - last_rusage->ru_nivcsw)); + table->field[7]->null_ptr= NULL; +#else + /* TODO: Add context switch info for non-BSD systems */ +#endif + +#ifdef HAVE_GETRUSAGE + table->field[8]->store((uint32)(entry->rusage.ru_inblock - last_rusage->ru_inblock)); + table->field[8]->null_ptr= NULL; + table->field[9]->store((uint32)(entry->rusage.ru_oublock - last_rusage->ru_oublock)); + table->field[9]->null_ptr= NULL; +#else + /* TODO: Add block IO info for non-BSD systems */ +#endif + +#ifdef HAVE_GETRUSAGE + table->field[10]->store((uint32)(entry->rusage.ru_msgsnd - last_rusage->ru_msgsnd), true); + table->field[10]->null_ptr= NULL; + table->field[11]->store((uint32)(entry->rusage.ru_msgrcv - last_rusage->ru_msgrcv), true); + table->field[11]->null_ptr= NULL; +#else + /* TODO: Add message info for non-BSD systems */ +#endif + +#ifdef HAVE_GETRUSAGE + table->field[12]->store((uint32)(entry->rusage.ru_majflt - last_rusage->ru_majflt), true); + table->field[12]->null_ptr= NULL; + table->field[13]->store((uint32)(entry->rusage.ru_minflt - last_rusage->ru_minflt), true); + table->field[13]->null_ptr= NULL; +#else + /* TODO: Add page fault info for non-BSD systems */ +#endif + +#ifdef HAVE_GETRUSAGE + table->field[14]->store((uint32)(entry->rusage.ru_nswap - last_rusage->ru_nswap), true); + table->field[14]->null_ptr= NULL; +#else + /* TODO: Add swap info for non-BSD systems */ +#endif + + if ((entry->function != NULL) && (entry->file != NULL)) + { + table->field[15]->store(entry->function, strlen(entry->function), + system_charset_info); + table->field[15]->null_ptr= NULL; + table->field[16]->store(entry->file, strlen(entry->file), system_charset_info); + table->field[16]->null_ptr= NULL; + table->field[17]->store(entry->line, true); + table->field[17]->null_ptr= NULL; + } + + if (schema_table_store_record(thd, table)) + DBUG_RETURN(1); + + } + } + + DBUG_RETURN(0); +} +#endif /* ENABLED_PROFILING */ diff --git a/sql/sql_profile.h b/sql/sql_profile.h index 698a80f07e4..006760cab79 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2005 MySQL AB +/* Copyright (C) 2007 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 @@ -14,99 +14,135 @@ 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 +#ifndef _SQL_PROFILE_H +#define _SQL_PROFILE_H -#include -#include - -#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) +#if __STDC_VERSION__ < 199901L +# if __GNUC__ >= 2 +# define __func__ __FUNCTION__ +# else +# define __func__ _db_func_ +extern const char *_db_func_; +# endif +#elif defined(_MSC_VER) +# if _MSC_VER < 1300 +# define __func__ _db_func_ +extern const char *_db_func_; +# else +# define __func__ __FUNCTION__ +# endif +#elif defined(__BORLANDC__) +# define __func__ __FUNC__ #else -#define THD_PROC_INFO(thd, msg) do { (thd)->proc_info= (msg); } while (0) +# define __func__ _db_func_ +extern const char *_db_func_; #endif -#if 0 +extern ST_FIELD_INFO query_profile_statistics_info[]; +int fill_query_profile_statistics_info(THD *thd, struct st_table_list *tables, Item *cond); - 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 +#define PROFILE_CPU (1<<0) +#define PROFILE_MEMORY (1<<1) +#define PROFILE_BLOCK_IO (1<<2) +#define PROFILE_CONTEXT (1<<3) +#define PROFILE_PAGE_FAULTS (1<<4) +#define PROFILE_IPC (1<<5) +#define PROFILE_SWAPS (1<<6) +#define PROFILE_SOURCE (1<<16) +#define PROFILE_ALL (~0) + + +#ifndef ENABLED_PROFILING + +# define thd_proc_info(thd, msg) do { (thd)->proc_info= (msg); } while (0) + +#else + +# define thd_proc_info(thd, msg) \ + do { \ + if (unlikely(((thd)->options & OPTION_PROFILING) != 0)) \ + { \ + (thd)->profiling.status_change((msg), __func__, __FILE__, __LINE__); \ + } \ + else \ + { \ + (thd)->proc_info= (msg); \ + } \ + } while (0) + +#include "mysql_priv.h" + +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif + class PROFILE_ENTRY; -class PROFILE; +class QUERY_PROFILE; class PROFILING; -/* + +/** A single entry in a single profile. */ - -class PROFILE_ENTRY: public Sql_alloc +class PROFILE_ENTRY { -public: - PROFILE *profile; - char *status; - ulonglong time; +private: + friend class QUERY_PROFILE; + friend class PROFILING; + + QUERY_PROFILE *profile; + char *status; +#ifdef HAVE_GETRUSAGE struct rusage rusage; +#endif char *function; char *file; unsigned int line; + + double time_usecs; + char *allocated_status_memory; + + void set_status(const char *status_arg, const char *function_arg, + const char *file_arg, unsigned int line_arg); + void clean_up(); PROFILE_ENTRY(); - PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg); - PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg, + PROFILE_ENTRY(QUERY_PROFILE *profile_arg, const char *status_arg); + PROFILE_ENTRY(QUERY_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 + +/** + The full profile for a single query, and includes multiple PROFILE_ENTRY objects. */ - -class PROFILE: public Sql_alloc +class QUERY_PROFILE { -public: +private: + friend class PROFILING; + PROFILING *profiling; - query_id_t query_id; + + query_id_t server_query_id; /* Global id. */ + query_id_t profiling_query_id; /* Session-specific id. */ + char *query_source; PROFILE_ENTRY profile_start; PROFILE_ENTRY *profile_end; List entries; - PROFILE(PROFILING *profiling_arg); - ~PROFILE(); + + QUERY_PROFILE(PROFILING *profiling_arg, char *query_source_arg, uint query_length_arg); + ~QUERY_PROFILE(); + + void set_query_source(char *query_source_arg, uint query_length_arg); /* Add a profile status change to the current profile. */ void status(const char *status_arg, @@ -120,68 +156,86 @@ public: bool show(uint options); }; -/* - Profiling state for a single THD. Contains multiple PROFILE objects. -*/ -class PROFILING: public Sql_alloc +/** + Profiling state for a single THD; contains multiple QUERY_PROFILE objects. +*/ +class PROFILING { -public: - MEM_ROOT root; +private: + friend class PROFILE_ENTRY; + friend class QUERY_PROFILE; + + /* + Not the system query_id, but a counter unique to profiling. + */ + query_id_t profile_id_counter; + MEM_ROOT mem_root; THD *thd; - bool enabled; bool keeping; - PROFILE *current; - PROFILE *last; - List history; + QUERY_PROFILE *current; + QUERY_PROFILE *last; + List history; + + query_id_t next_profile_id() { return(profile_id_counter++); } +public: PROFILING(); ~PROFILING(); + void set_query_source(char *query_source_arg, uint query_length_arg); - inline void set_thd(THD *thd_arg) { thd= thd_arg; }; + /** Reset the current profile and state of profiling for the next query. */ + void reset(); - /* - 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. + 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; }; + inline void keep() { keeping= true; }; - void status(const char *status_arg, - const char *function_arg, - const char *file_arg, unsigned int line_arg); + /** + Do we intend to keep the currently collected profile? + @see keep() + */ + inline void discard() { keeping= false; }; - /* Stash this profile in the profile history. */ + /** + Stash this profile in the profile history and remove the oldest + profile if the history queue is full, as defined by the + profiling_history_size system variable. + */ void store(); - - /* Reset the current profile and state of profiling for the next query. */ - void reset(); + + /** + Called with every update of the status via thd_proc_info() , and is + therefore the main hook into the profiling code. + */ + void status_change(const char *status_arg, + const char *function_arg, + const char *file_arg, unsigned int line_arg); + + inline void set_thd(THD *thd_arg) { thd= thd_arg; }; /* SHOW PROFILES */ bool show_profiles(); /* SHOW PROFILE FOR QUERY query_id */ - bool show(uint options, uint query_id); + bool show(uint options, uint profiling_query_id); /* SHOW PROFILE */ bool show_last(uint options); + + /* ... from INFORMATION_SCHEMA.PROFILING ... */ + int fill_statistics_info(THD *thd, struct st_table_list *tables, Item *cond); }; -#endif /* SQL_PROFILE_H */ +# endif /* HAVE_PROFILING */ +#endif /* _SQL_PROFILE_H */ diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 07ae439cfb9..11c4d4464d8 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -645,7 +645,7 @@ impossible position"; if (read_packet) { - thd->proc_info = "Sending binlog event to slave"; + thd_proc_info(thd, "Sending binlog event to slave"); if (my_net_write(net, (char*)packet->ptr(), packet->length()) ) { errmsg = "Failed on my_net_write()"; @@ -683,7 +683,7 @@ impossible position"; bool loop_breaker = 0; /* need this to break out of the for loop from switch */ - thd->proc_info = "Finished reading one binlog; switching to next binlog"; + thd_proc_info(thd, "Finished reading one binlog; switching to next binlog"); switch (mysql_bin_log.find_next_log(&linfo, 1)) { case LOG_INFO_EOF: loop_breaker = (flags & BINLOG_DUMP_NON_BLOCK); @@ -729,14 +729,14 @@ end: (void)my_close(file, MYF(MY_WME)); send_eof(thd); - thd->proc_info = "Waiting to finalize termination"; + thd_proc_info(thd, "Waiting to finalize termination"); pthread_mutex_lock(&LOCK_thread_count); thd->current_linfo = 0; pthread_mutex_unlock(&LOCK_thread_count); DBUG_VOID_RETURN; err: - thd->proc_info = "Waiting to finalize termination"; + thd_proc_info(thd, "Waiting to finalize termination"); end_io_cache(&log); /* Exclude iteration through thread list @@ -888,7 +888,7 @@ int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report ) if (check_access(thd, SUPER_ACL, any_db,0,0,0,0)) return 1; - thd->proc_info = "Killing slave"; + thd_proc_info(thd, "Killing slave"); int thread_mask; lock_slave_threads(mi); // Get a mask of _running_ threads @@ -915,7 +915,7 @@ int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report ) ER(ER_SLAVE_WAS_NOT_RUNNING)); } unlock_slave_threads(mi); - thd->proc_info = 0; + thd_proc_info(thd, 0); if (slave_errno) { @@ -1071,7 +1071,7 @@ bool change_master(THD* thd, MASTER_INFO* mi) DBUG_RETURN(TRUE); } - thd->proc_info = "Changing master"; + thd_proc_info(thd, "Changing master"); LEX_MASTER_INFO* lex_mi= &thd->lex->mi; // TODO: see if needs re-write if (init_master_info(mi, master_info_file, relay_log_info_file, 0, @@ -1196,7 +1196,7 @@ bool change_master(THD* thd, MASTER_INFO* mi) if (need_relay_log_purge) { relay_log_purge= 1; - THD_PROC_INFO(thd, "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)) @@ -1259,7 +1259,7 @@ bool change_master(THD* thd, MASTER_INFO* mi) pthread_mutex_unlock(&mi->rli.data_lock); unlock_slave_threads(mi); - thd->proc_info = 0; + thd_proc_info(thd, 0); send_ok(thd); DBUG_RETURN(FALSE); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ada440fbc2d..c9e334b7784 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -598,7 +598,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"); + 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 */ @@ -745,7 +745,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(thd, "statistics"); + thd_proc_info(thd, "statistics"); if (make_join_statistics(this, select_lex->leaf_tables, conds, &keyuse) || thd->is_fatal_error) { @@ -755,7 +755,7 @@ JOIN::optimize() /* Remove distinct if only const tables */ select_distinct= select_distinct && (const_tables != tables); - THD_PROC_INFO(thd, "preparing"); + thd_proc_info(thd, "preparing"); if (result->initialize_tables(this)) { DBUG_PRINT("error",("Error: initialize_tables() failed")); @@ -1162,7 +1162,7 @@ JOIN::optimize() if (need_tmp) { DBUG_PRINT("info",("Creating tmp table")); - THD_PROC_INFO(thd, "creating temporary table"); + thd_proc_info(thd, "Creating tmp table"); init_items_ref_array(); @@ -1213,7 +1213,7 @@ JOIN::optimize() if (group_list && simple_group) { DBUG_PRINT("info",("Sorting for group")); - THD_PROC_INFO(thd, "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) || @@ -1234,9 +1234,8 @@ JOIN::optimize() if (!group_list && ! exec_tmp_table1->distinct && order && simple_order) { - DBUG_PRINT("info",("Sorting for order")); - THD_PROC_INFO(thd, "Sorting for order"); - if (create_sort_index(thd, this, order, + thd_proc_info(thd, "Sorting for order"); + if (create_sort_index(thd, this, order, HA_POS_ERROR, HA_POS_ERROR)) { DBUG_RETURN(1); @@ -1364,7 +1363,7 @@ JOIN::exec() int tmp_error; DBUG_ENTER("JOIN::exec"); - THD_PROC_INFO(thd, "executing"); + thd_proc_info(thd, "executing"); error= 0; if (procedure) { @@ -1504,7 +1503,7 @@ JOIN::exec() curr_tmp_table= exec_tmp_table1; /* Copy data to the temporary table */ - THD_PROC_INFO(thd, "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 *) 0, curr_tmp_table, 0))) { @@ -1627,7 +1626,7 @@ JOIN::exec() } if (curr_join->group_list) { - THD_PROC_INFO(thd, "Creating sort index"); + thd_proc_info(thd, "Creating sort index"); if (curr_join->join_tab == join_tab && save_join_tab()) { DBUG_VOID_RETURN; @@ -1641,7 +1640,7 @@ JOIN::exec() sortorder= curr_join->sortorder; } - THD_PROC_INFO(thd, "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) @@ -1697,7 +1696,7 @@ JOIN::exec() curr_join->join_free(); /* Free quick selects */ if (curr_join->select_distinct && ! curr_join->group_list) { - THD_PROC_INFO(thd, "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, @@ -1758,7 +1757,7 @@ JOIN::exec() if (curr_join->group_list || curr_join->order) { DBUG_PRINT("info",("Sorting for send_fields")); - THD_PROC_INFO(thd, "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) @@ -1882,7 +1881,7 @@ JOIN::exec() } else { - THD_PROC_INFO(thd, "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), @@ -2030,7 +2029,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array, { if (!(join= new JOIN(thd, fields, select_options, result))) DBUG_RETURN(TRUE); - THD_PROC_INFO(thd, "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, @@ -2075,9 +2074,9 @@ mysql_select(THD *thd, Item ***rref_pointer_array, err: if (free_join) { - THD_PROC_INFO(thd, "cleaning up"); + thd_proc_info(thd, "end"); err|= select_lex->cleanup(); - THD_PROC_INFO(thd, "end"); + thd_proc_info(thd, "end"); DBUG_RETURN(err || thd->net.report_error); } DBUG_RETURN(join->error); @@ -9807,7 +9806,7 @@ free_tmp_table(THD *thd, TABLE *entry) DBUG_PRINT("enter",("table: %s",entry->alias)); save_proc_info=thd->proc_info; - THD_PROC_INFO(thd, "removing tmp table"); + thd_proc_info(thd, "removing tmp table"); if (entry->file) { @@ -9835,7 +9834,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(thd, save_proc_info); + thd_proc_info(thd, save_proc_info); DBUG_VOID_RETURN; } @@ -9865,7 +9864,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(thd, "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)) @@ -9918,8 +9917,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(thd, (!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: @@ -9931,7 +9930,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(thd, 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 0a39640aa4f..133bee1c481 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -44,7 +44,7 @@ static void append_algorithm(TABLE_LIST *table, String *buff); static int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff); -static bool schema_table_store_record(THD *thd, TABLE *table); +bool schema_table_store_record(THD *thd, TABLE *table); /*************************************************************************** @@ -1349,7 +1349,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)) - THD_PROC_INFO(tmp, "*** 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; @@ -1847,7 +1847,7 @@ typedef struct st_index_field_values 1 error */ -static bool schema_table_store_record(THD *thd, TABLE *table) +bool schema_table_store_record(THD *thd, TABLE *table) { int error; if ((error= table->file->write_row(table->record[0]))) @@ -4305,6 +4305,8 @@ ST_SCHEMA_TABLE schema_tables[]= get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0}, {"OPEN_TABLES", open_tables_fields_info, create_schema_table, fill_open_tables, make_old_format, 0, -1, -1, 1}, + {"PROFILING", query_profile_statistics_info, create_schema_table, + fill_query_profile_statistics_info, NULL, NULL, -1, -1, false}, {"ROUTINES", proc_fields_info, create_schema_table, fill_schema_proc, make_proc_old_format, 0, -1, -1, 0}, {"SCHEMATA", schema_fields_info, create_schema_table, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 43fdd693a4b..dc474c080b4 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1729,7 +1729,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, } } - THD_PROC_INFO(thd, "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) @@ -1760,7 +1760,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, end: VOID(pthread_mutex_unlock(&LOCK_open)); - THD_PROC_INFO(thd, "After create"); + thd_proc_info(thd, "After create"); DBUG_RETURN(error); warn: @@ -2879,7 +2879,7 @@ mysql_discard_or_import_tablespace(THD *thd, ALTER TABLE */ - THD_PROC_INFO(thd, "discard_or_import_tablespace"); + thd_proc_info(thd, "discard_or_import_tablespace"); discard= test(tablespace_op == DISCARD_TABLESPACE); @@ -2896,7 +2896,7 @@ mysql_discard_or_import_tablespace(THD *thd, error=table->file->discard_or_import_tablespace(discard); - THD_PROC_INFO(thd, "end"); + thd_proc_info(thd, "end"); if (error) goto err; @@ -3007,7 +3007,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(thd, "init"); + thd_proc_info(thd, "init"); table_name=table_list->table_name; alias= (lower_case_table_names == 2) ? table_list->alias : table_name; @@ -3142,7 +3142,7 @@ view_err: DBUG_RETURN(TRUE); } - THD_PROC_INFO(thd, "setup"); + thd_proc_info(thd, "setup"); if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) && !table->s->tmp_table) // no need to touch frm { @@ -3173,7 +3173,7 @@ view_err: if (!error && (new_name != table_name || new_db != db)) { - THD_PROC_INFO(thd, "rename"); + thd_proc_info(thd, "rename"); /* Then do a 'simple' rename of the table */ if (!access(new_name_buff,F_OK)) { @@ -3627,7 +3627,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(thd, "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) @@ -3711,7 +3711,7 @@ view_err: from the cache, free all locks, close the old table and remove it. */ - THD_PROC_INFO(thd, "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) @@ -3822,7 +3822,7 @@ view_err: broadcast_refresh(); goto err; } - THD_PROC_INFO(thd, "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 0fdadd9e0db..62be615d3f6 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -166,7 +166,7 @@ int mysql_update(THD *thd, mysql_handle_derived(thd->lex, &mysql_derived_filling))) DBUG_RETURN(1); - THD_PROC_INFO(thd, "init"); + thd_proc_info(thd, "init"); table= table_list->table; table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); @@ -358,7 +358,7 @@ int mysql_update(THD *thd, else init_read_record_idx(&info, thd, table, 1, used_index); - THD_PROC_INFO(thd, "Searching rows for update"); + thd_proc_info(thd, "Searching rows for update"); uint tmp_limit= limit; while (!(error=info.read_record(&info)) && !thd->killed) @@ -423,7 +423,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(thd, "Updating"); + thd_proc_info(thd, "Updating"); query_id=thd->query_id; transactional_table= table->file->has_transactions(); @@ -511,7 +511,7 @@ int mysql_update(THD *thd, end_read_record(&info); free_io_cache(table); // If ORDER BY delete select; - THD_PROC_INFO(thd, "end"); + thd_proc_info(thd, "end"); VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY)); /* @@ -959,7 +959,7 @@ int multi_update::prepare(List ¬_used_values, thd->count_cuted_fields= CHECK_FIELD_WARN; thd->cuted_fields=0L; - THD_PROC_INFO(thd, "updating main table"); + thd_proc_info(thd, "updating main table"); tables_to_update= get_table_map(fields); @@ -1511,11 +1511,11 @@ err2: bool multi_update::send_eof() { char buff[STRING_BUFFER_USUAL_SIZE]; - THD_PROC_INFO(thd, "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(thd, "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 c03dd1f782e..c570c0e6570 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -588,7 +588,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, DBUG_RETURN(0); err: - THD_PROC_INFO(thd, "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 3372cfb3341..20c51360d51 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -928,7 +928,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); union_opt select_derived_init option_type2 %type - ulong_num raid_types merge_insert_types opt_profile_query_arg + ulong_num raid_types merge_insert_types %type ulonglong_num @@ -6678,36 +6678,52 @@ profile_defs: profile_def: CPU_SYM - { Lex->profile_options|= PROFILE_CPU; } + { + Lex->profile_options|= PROFILE_CPU; + } | MEMORY_SYM - { Lex->profile_options|= PROFILE_MEMORY; } + { + Lex->profile_options|= PROFILE_MEMORY; + } | BLOCK_SYM IO_SYM - { Lex->profile_options|= PROFILE_BLOCK_IO; } + { + Lex->profile_options|= PROFILE_BLOCK_IO; + } | CONTEXT_SYM SWITCHES_SYM - { Lex->profile_options|= PROFILE_CONTEXT; } + { + Lex->profile_options|= PROFILE_CONTEXT; + } | PAGE_SYM FAULTS_SYM - { Lex->profile_options|= PROFILE_PAGE_FAULTS; } + { + Lex->profile_options|= PROFILE_PAGE_FAULTS; + } | IPC_SYM - { Lex->profile_options|= PROFILE_IPC; } + { + Lex->profile_options|= PROFILE_IPC; + } | SWAPS_SYM - { Lex->profile_options|= PROFILE_SWAPS; } + { + Lex->profile_options|= PROFILE_SWAPS; + } | SOURCE_SYM - { Lex->profile_options|= PROFILE_SOURCE; } + { + Lex->profile_options|= PROFILE_SOURCE; + } | ALL - { Lex->profile_options|= PROFILE_ALL; } - ; - -opt_profile_query_arg: - /* empty */ - { $$= 0; } - | QUERY_SYM NUM - { $$= atoi($2.str); } + { + Lex->profile_options|= PROFILE_ALL; + } ; opt_profile_args: /* empty */ - | FOR_SYM opt_profile_query_arg - { Lex->profile_query_id = $2; } + { + Lex->profile_query_id= 0; + } + | FOR_SYM QUERY_SYM NUM + { + Lex->profile_query_id= atoi($3.str); + } ; /* Show things */ @@ -7940,7 +7956,7 @@ keyword_sp: | BERKELEY_DB_SYM {} | BINLOG_SYM {} | BIT_SYM {} - | BLOCK_SYM {} + | BLOCK_SYM {} | BOOL_SYM {} | BOOLEAN_SYM {} | BTREE_SYM {} @@ -7957,8 +7973,8 @@ keyword_sp: | COMPRESSED_SYM {} | CONCURRENT {} | CONSISTENT_SYM {} - | CONTEXT_SYM {} - | CPU_SYM {} + | CONTEXT_SYM {} + | CPU_SYM {} | CUBE_SYM {} | DATA_SYM {} | DATETIME {} @@ -7981,7 +7997,7 @@ keyword_sp: | EXPANSION_SYM {} | EXTENDED_SYM {} | FAST_SYM {} - | FAULTS_SYM {} + | FAULTS_SYM {} | FOUND_SYM {} | DISABLE_SYM {} | ENABLE_SYM {} @@ -8006,8 +8022,8 @@ keyword_sp: | ISSUER_SYM {} | INNOBASE_SYM {} | INSERT_METHOD {} - | IO_SYM {} - | IPC_SYM {} + | IO_SYM {} + | IPC_SYM {} | RELAY_THREAD {} | LAST_SYM {} | LEAVES {} @@ -8037,7 +8053,7 @@ keyword_sp: | MAX_UPDATES_PER_HOUR {} | MAX_USER_CONNECTIONS_SYM {} | MEDIUM_SYM {} - | MEMORY_SYM {} + | MEMORY_SYM {} | MERGE_SYM {} | MICROSECOND_SYM {} | MIGRATE_SYM {} @@ -8064,7 +8080,7 @@ keyword_sp: | ONE_SHOT_SYM {} | ONE_SYM {} | PACK_KEYS_SYM {} - | PAGE_SYM {} + | PAGE_SYM {} | PARTIAL {} | PASSWORD {} | PHASE_SYM {} @@ -8074,8 +8090,8 @@ keyword_sp: | PRIVILEGES {} | PROCESS {} | PROCESSLIST_SYM {} - | PROFILE_SYM {} - | PROFILES_SYM {} + | PROFILE_SYM {} + | PROFILES_SYM {} | QUARTER_SYM {} | QUERY_SYM {} | QUICK {} @@ -8109,7 +8125,7 @@ keyword_sp: | SHUTDOWN {} | SNAPSHOT_SYM {} | SOUNDS_SYM {} - | SOURCE_SYM {} + | SOURCE_SYM {} | SQL_CACHE_SYM {} | SQL_BUFFER_RESULT {} | SQL_NO_CACHE_SYM {} @@ -8121,8 +8137,8 @@ keyword_sp: | SUBJECT_SYM {} | SUPER_SYM {} | SUSPEND_SYM {} - | SWAPS_SYM {} - | SWITCHES_SYM {} + | SWAPS_SYM {} + | SWITCHES_SYM {} | TABLES {} | TABLESPACE {} | TEMPORARY {} diff --git a/sql/table.h b/sql/table.h index 70e64439af5..da0f2a48b10 100644 --- a/sql/table.h +++ b/sql/table.h @@ -308,6 +308,7 @@ enum enum_schema_tables SCH_COLUMN_PRIVILEGES, SCH_KEY_COLUMN_USAGE, SCH_OPEN_TABLES, + SCH_PROFILING, SCH_PROCEDURES, SCH_SCHEMATA, SCH_SCHEMA_PRIVILEGES, From cdacff2d95266965656a444adcbbfea241d70c60 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 22 Feb 2007 11:48:56 -0500 Subject: [PATCH 07/33] Enclose profiling in preprocessor conditions. include/config-win.h: Make profiling compiled-in by default on Windows too. --- BitKeeper/etc/collapsed | 2 ++ include/config-win.h | 3 +++ sql/sql_prepare.cc | 2 ++ 3 files changed, 7 insertions(+) diff --git a/BitKeeper/etc/collapsed b/BitKeeper/etc/collapsed index c79a4cf25cc..2b0df86d79c 100644 --- a/BitKeeper/etc/collapsed +++ b/BitKeeper/etc/collapsed @@ -43,3 +43,5 @@ 45db468b-DKE8kUTV42eYMYmk8_g9g 45dd21d1rVPnDfvZTNVHLalcjnbsZw 45ddaf15_Ld7IAEpUUP3FJjJ-oSEFg +45ddc763DodLG1BqH_wRBJXMbCSB5A +45ddc8282KnaNGuijqCTphlXV_eeog diff --git a/include/config-win.h b/include/config-win.h index a9977ec955a..8653c0a63f5 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -205,6 +205,9 @@ typedef uint rf_SetTimer; /* If LOAD DATA LOCAL INFILE should be enabled by default */ #define ENABLED_LOCAL_INFILE 1 +/* If query profiling should be enabled by default */ +#define ENABLED_PROFILING 1 + /* Convert some simple functions to Posix */ #define my_sigset(A,B) signal((A),(B)) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 83ddb9c9212..de08c43658c 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2222,7 +2222,9 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute"))) DBUG_VOID_RETURN; +#ifdef ENABLED_PROFILING thd->profiling.set_query_source(stmt->query, stmt->query_length); +#endif DBUG_PRINT("exec_query", ("%s", stmt->query)); DBUG_PRINT("info",("stmt: %p", stmt)); From f6d9570df16a863579704aeb9aa226c0a5ed9384 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 22 Feb 2007 12:27:15 -0500 Subject: [PATCH 08/33] Add profiling source file to cmake file. --- sql/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 7e26f62b5f7..b686288c4fe 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -73,6 +73,7 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc time.cc tztime.cc uniques.cc unireg.cc ../sql-common/my_user.c sql_locale.cc + sql_profiling.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h ${PROJECT_SOURCE_DIR}/include/mysqld_error.h From fe671b87041e95a1d90a86edfac6807661ac48f7 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 22 Feb 2007 13:17:02 -0500 Subject: [PATCH 09/33] Use correct filename for profiling code. --- sql/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index b686288c4fe..9058f9077d9 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -73,7 +73,7 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc time.cc tztime.cc uniques.cc unireg.cc ../sql-common/my_user.c sql_locale.cc - sql_profiling.cc + sql_profile.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h ${PROJECT_SOURCE_DIR}/include/mysqld_error.h From 633fb481c93ba6dc42d454060880753db149a007 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 22 Feb 2007 16:25:47 -0500 Subject: [PATCH 10/33] Disambiguate method call. (Windows compiler error.) --- sql/sql_profile.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index e9b6ef0b522..86f6854206d 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -453,7 +453,7 @@ bool QUERY_PROFILE::show(uint options) protocol->store(entry->function, strlen(entry->function), system_charset_info); protocol->store(entry->file, strlen(entry->file), system_charset_info); - protocol->store(entry->line); + protocol->store((uint32) entry->line); } else { protocol->store_null(); protocol->store_null(); From 9e2fd8caada234497a4f5c2c28aafeb66fe2b3b2 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Feb 2007 13:11:36 -0500 Subject: [PATCH 11/33] Some changes suggested Serg, from message <20070223210659.GA24202@janus.mylan> configure.in: Use smarter autoconf help macro. sql/set_var.cc: Make a local variable static. sql/sql_lex.cc: Don't include CPP condition where it saves little time and decreases legibility. sql/sql_parse.cc: Use the name of the query in the error, instead of describing the feature. sql/sql_profile.cc: Update copyright. Make I_S schema table columns uppercase. sql/sql_profile.h: Update copyright. sql/sql_select.cc: Chagne tab indentation to spaces. --- configure.in | 2 +- sql/set_var.cc | 2 +- sql/sql_lex.cc | 2 -- sql/sql_parse.cc | 4 +-- sql/sql_profile.cc | 90 ++++++++++++++++++++-------------------------- sql/sql_profile.h | 3 +- sql/sql_select.cc | 4 +-- 7 files changed, 45 insertions(+), 62 deletions(-) diff --git a/configure.in b/configure.in index 3e0e6c9762b..f81e70f6173 100644 --- a/configure.in +++ b/configure.in @@ -669,7 +669,7 @@ fi # Add query profiler AC_ARG_ENABLE(profiling, - [ --disable-profiling Build a version without query profiling code ], + AS_HELP_STRING([--disable-profiling], [Build a version without query profiling code]), [ ENABLED_PROFILING=$enableval ], [ ENABLED_PROFILING=yes ]) diff --git a/sql/set_var.cc b/sql/set_var.cc index c02561261c0..dad6be06aa2 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -548,7 +548,7 @@ static sys_var_thd_bit sys_unique_checks("unique_checks", 0, #ifdef ENABLED_PROFILING static sys_var_thd_bit sys_profiling("profiling", NULL, set_option_bit, ulonglong(OPTION_PROFILING)); -sys_var_thd_ulong sys_profiling_history_size("profiling_history_size", +static sys_var_thd_ulong sys_profiling_history_size("profiling_history_size", &SV::profiling_history_size); #endif diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 47fe2e8ac0e..8742a9630b6 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -173,9 +173,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); -#ifdef ENABLED_PROFILING lex->profile_options= PROFILE_NONE; -#endif lex->nest_level=0 ; lex->allow_sum_func= 0; lex->in_sum_func= NULL; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 449d57c2b2d..370fa4a19c5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2707,7 +2707,7 @@ mysql_execute_command(THD *thd) if (res) goto error; #else - my_error(ER_FEATURE_DISABLED, MYF(0), "query profiling", "enable-profiling"); + my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROFILES", "enable-profiling"); goto error; #endif break; @@ -2724,7 +2724,7 @@ mysql_execute_command(THD *thd) if (res) goto error; #else - my_error(ER_FEATURE_DISABLED, MYF(0), "query profiling", "enable-profiling"); + my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROFILE", "enable-profiling"); goto error; #endif break; diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 86f6854206d..1d38b313bd3 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2005 MySQL AB +/* Copyright (C) 2007 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. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -12,7 +11,7 @@ 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 */ + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mysql_priv.h" @@ -42,24 +41,24 @@ int fill_query_profile_statistics_info(THD *thd, struct st_table_list *tables, ST_FIELD_INFO query_profile_statistics_info[]= { /* name, length, type, value, maybe_null, old_name */ - {"Query_id", 20, MYSQL_TYPE_LONG, 0, false, NULL}, - {"Seq", 20, MYSQL_TYPE_LONG, 0, false, NULL}, - {"State", 30, MYSQL_TYPE_STRING, 0, false, NULL}, - {"Duration", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, false, NULL}, - {"CPU_user", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, - {"CPU_system", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, - {"Context_voluntary", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Context_involuntary", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Block_ops_in", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Block_ops_out", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Messages_sent", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Messages_received", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Page_faults_major", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Page_faults_minor", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Swaps", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Source_function", 30, MYSQL_TYPE_STRING, 0, true, NULL}, - {"Source_file", 20, MYSQL_TYPE_STRING, 0, true, NULL}, - {"Source_line", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"QUERY_ID", 20, MYSQL_TYPE_LONG, 0, false, NULL}, + {"SEQ", 20, MYSQL_TYPE_LONG, 0, false, NULL}, + {"STATE", 30, MYSQL_TYPE_STRING, 0, false, NULL}, + {"DURATION", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, false, NULL}, + {"CPU_USER", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, + {"CPU_SYSTEM", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, + {"CONTEXT_VOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"CONTEXT_INVOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"BLOCK_OPS_IN", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"BLOCK_OPS_OUT", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"MESSAGES_SENT", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"MESSAGES_RECEIVED", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"PAGE_FAULTS_MAJOR", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"PAGE_FAULTS_MINOR", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"SWAPS", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"SOURCE_FUNCTION", 30, MYSQL_TYPE_STRING, 0, true, NULL}, + {"SOURCE_FILE", 20, MYSQL_TYPE_STRING, 0, true, NULL}, + {"SOURCE_LINE", 20, MYSQL_TYPE_LONG, 0, true, NULL}, {NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL} }; @@ -107,20 +106,9 @@ void PROFILE_ENTRY::set_status(const char *status_arg, const char *function_arg, Compute all the space we'll need to allocate one block for everything we'll need, instead of N mallocs. */ - if (status_arg != NULL) - sizes[0]= strlen(status_arg) + 1; - else - sizes[0]= 0; - - if (function_arg != NULL) - sizes[1]= strlen(function_arg) + 1; - else - sizes[1]= 0; - - if (file_arg != NULL) - sizes[2]= strlen(file_arg) + 1; - else - sizes[2]= 0; + sizes[0]= (status_arg == NULL) ? 0 : strlen(status_arg) + 1; + sizes[1]= (function_arg == NULL) ? 0 : strlen(function_arg) + 1; + sizes[2]= (file_arg == NULL) ? 0 : strlen(file_arg) + 1; allocated_status_memory= (char *) my_malloc(sizes[0] + sizes[1] + sizes[2], MYF(0)); DBUG_ASSERT(allocated_status_memory != NULL); @@ -237,7 +225,6 @@ void QUERY_PROFILE::status(const char *status_arg, */ saved_mem_root= thd->mem_root; thd->mem_root= &profiling->mem_root; - //thd->mem_root= NULL; if (function_arg && file_arg) { @@ -375,7 +362,6 @@ bool QUERY_PROFILE::show(uint options) protocol->store(entry->status, strlen(entry->status), system_charset_info); protocol->store((double)(entry->time_usecs - last_time)/(1000.0*1000), (uint32) TIME_FLOAT_DIGITS-1, &elapsed); - //protocol->store((double)(entry->time - last_time)/(1000*1000*10)); if (options & PROFILE_CPU) { @@ -739,54 +725,54 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item #ifdef HAVE_GETRUSAGE table->field[4]->store((double)RUSAGE_DIFF_USEC(entry->rusage.ru_utime, last_rusage->ru_utime)/(1000.0*1000)); - table->field[4]->null_ptr= NULL; + table->field[4]->set_notnull(); table->field[5]->store((double)RUSAGE_DIFF_USEC(entry->rusage.ru_stime, last_rusage->ru_stime)/(1000.0*1000)); - table->field[5]->null_ptr= NULL; + table->field[5]->set_notnull(); #else /* TODO: Add CPU-usage info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE table->field[6]->store((uint32)(entry->rusage.ru_nvcsw - last_rusage->ru_nvcsw)); - table->field[6]->null_ptr= NULL; + table->field[6]->set_notnull(); table->field[7]->store((uint32)(entry->rusage.ru_nivcsw - last_rusage->ru_nivcsw)); - table->field[7]->null_ptr= NULL; + table->field[7]->set_notnull(); #else /* TODO: Add context switch info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE table->field[8]->store((uint32)(entry->rusage.ru_inblock - last_rusage->ru_inblock)); - table->field[8]->null_ptr= NULL; + table->field[8]->set_notnull(); table->field[9]->store((uint32)(entry->rusage.ru_oublock - last_rusage->ru_oublock)); - table->field[9]->null_ptr= NULL; + table->field[9]->set_notnull(); #else /* TODO: Add block IO info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE table->field[10]->store((uint32)(entry->rusage.ru_msgsnd - last_rusage->ru_msgsnd), true); - table->field[10]->null_ptr= NULL; + table->field[10]->set_notnull(); table->field[11]->store((uint32)(entry->rusage.ru_msgrcv - last_rusage->ru_msgrcv), true); - table->field[11]->null_ptr= NULL; + table->field[11]->set_notnull(); #else /* TODO: Add message info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE table->field[12]->store((uint32)(entry->rusage.ru_majflt - last_rusage->ru_majflt), true); - table->field[12]->null_ptr= NULL; + table->field[12]->set_notnull(); table->field[13]->store((uint32)(entry->rusage.ru_minflt - last_rusage->ru_minflt), true); - table->field[13]->null_ptr= NULL; + table->field[13]->set_notnull(); #else /* TODO: Add page fault info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE table->field[14]->store((uint32)(entry->rusage.ru_nswap - last_rusage->ru_nswap), true); - table->field[14]->null_ptr= NULL; + table->field[14]->set_notnull(); #else /* TODO: Add swap info for non-BSD systems */ #endif @@ -795,11 +781,11 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item { table->field[15]->store(entry->function, strlen(entry->function), system_charset_info); - table->field[15]->null_ptr= NULL; + table->field[15]->set_notnull(); table->field[16]->store(entry->file, strlen(entry->file), system_charset_info); - table->field[16]->null_ptr= NULL; + table->field[16]->set_notnull(); table->field[17]->store(entry->line, true); - table->field[17]->null_ptr= NULL; + table->field[17]->set_notnull(); } if (schema_table_store_record(thd, table)) diff --git a/sql/sql_profile.h b/sql/sql_profile.h index 006760cab79..944856a9f80 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -2,8 +2,7 @@ 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. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c9e334b7784..1ee84ca9e3d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1234,8 +1234,8 @@ JOIN::optimize() if (!group_list && ! exec_tmp_table1->distinct && order && simple_order) { - thd_proc_info(thd, "Sorting for order"); - if (create_sort_index(thd, this, order, + thd_proc_info(thd, "Sorting for order"); + if (create_sort_index(thd, this, order, HA_POS_ERROR, HA_POS_ERROR)) { DBUG_RETURN(1); From 89fd0e9f9e2fa26a3e46c5b48f278d395feba245 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 27 Feb 2007 11:30:03 -0500 Subject: [PATCH 12/33] Updated column names of I_S table to conform to other I_S uppercase scheme. --- mysql-test/r/information_schema.result | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 742d35d4ce7..d89514c6060 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1193,7 +1193,7 @@ COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME COLUMNS TABLE_SCHEMA COLUMN_PRIVILEGES TABLE_SCHEMA KEY_COLUMN_USAGE CONSTRAINT_SCHEMA -PROFILING Query_id +PROFILING QUERY_ID ROUTINES ROUTINE_SCHEMA SCHEMATA SCHEMA_NAME SCHEMA_PRIVILEGES TABLE_SCHEMA @@ -1225,7 +1225,7 @@ COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME COLUMNS TABLE_SCHEMA COLUMN_PRIVILEGES TABLE_SCHEMA KEY_COLUMN_USAGE CONSTRAINT_SCHEMA -PROFILING Query_id +PROFILING QUERY_ID ROUTINES ROUTINE_SCHEMA SCHEMATA SCHEMA_NAME SCHEMA_PRIVILEGES TABLE_SCHEMA From 4cb4899fa203a2c483188251e70e67d3ef00f682 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 27 Feb 2007 20:04:58 -0500 Subject: [PATCH 13/33] Update to I_S result that now contains PROFILING entry. --- mysql-test/r/information_schema.result | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 0371652b081..b01ed152e33 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1308,6 +1308,7 @@ COLLATION_CHARACTER_SET_APPLICABILITY information_schema.COLLATION_CHARACTER_SET COLUMNS information_schema.COLUMNS 1 COLUMN_PRIVILEGES information_schema.COLUMN_PRIVILEGES 1 KEY_COLUMN_USAGE information_schema.KEY_COLUMN_USAGE 1 +PROFILING information_schema.PROFILING 1 ROUTINES information_schema.ROUTINES 1 SCHEMATA information_schema.SCHEMATA 1 SCHEMA_PRIVILEGES information_schema.SCHEMA_PRIVILEGES 1 From 7a916c2f03a0d09845d9346ab3194375e09c4a6a Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 1 Mar 2007 09:38:09 +0100 Subject: [PATCH 14/33] mysqld.cc: fix profiling_history_size type sql/mysqld.cc: fix profiling_history_size type --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 49546c2fb4b..3bf5aa42472 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5277,7 +5277,7 @@ Disable with --skip-ndbcluster (will save memory).", {"profiling_history_size", OPT_PROFILING, "Limit of query profiling memory", (gptr*) &global_system_variables.profiling_history_size, (gptr*) &max_system_variables.profiling_history_size, - 0, GET_UINT, REQUIRED_ARG, 15, 0, 100, 0, 0, 0}, + 0, GET_ULONG, REQUIRED_ARG, 15, 0, 100, 0, 0, 0}, #endif {"relay-log", OPT_RELAY_LOG, "The location and name to use for relay logs.", From 014cfd7e31db7a36243bb1c8bf34ecf502bcc950 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 1 Mar 2007 10:45:55 +0100 Subject: [PATCH 15/33] File.cpp: fileno is a macro on some platforms ndb/src/common/util/File.cpp: fileno is a macro on some platforms --- ndb/src/common/util/File.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ndb/src/common/util/File.cpp b/ndb/src/common/util/File.cpp index 23bf3415df9..b26ed26b3bd 100644 --- a/ndb/src/common/util/File.cpp +++ b/ndb/src/common/util/File.cpp @@ -50,7 +50,7 @@ File_class::size(FILE* f) MY_STAT s; // Note that my_fstat behaves *differently* than my_stat. ARGGGHH! - if(my_fstat(::fileno(f), &s, MYF(0))) + if(my_fstat(fileno(f), &s, MYF(0))) return 0; return s.st_size; From 0723eb457eb05ae6d7eeef1907ceef0d52dd8f42 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 1 Mar 2007 21:56:51 +0100 Subject: [PATCH 16/33] add missing file to vs project VC++Files/sql/mysqld.vcproj: add sql_profile.cpp to mysqld project --- VC++Files/sql/mysqld.vcproj | 75 +++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/VC++Files/sql/mysqld.vcproj b/VC++Files/sql/mysqld.vcproj index e18a6364c8b..cb0efb10b19 100644 --- a/VC++Files/sql/mysqld.vcproj +++ b/VC++Files/sql/mysqld.vcproj @@ -4744,6 +4744,81 @@ PreprocessorDefinitions=""/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Date: Fri, 2 Mar 2007 09:14:33 -0500 Subject: [PATCH 17/33] Patch to release clone. Fixes two post-pushbuild discovered failures. Expand float size to avoid assert()ion failures. "_db_func_" isn't a known linked object on some platforms, possibly because it is occasionaly shadowed by DBUG variables. Avoid that confusion. sql/sql_profile.cc: Expand float size to avoid assert()ion failures. "_db_func_" isn't a known linked object on some platforms, possibly because it is occasionaly shadowed by DBUG variables. Avoid that confusion. sql/sql_profile.h: "_db_func_" isn't a known linked object on some platforms, possibly because it is occasionaly shadowed by DBUG variables. Avoid that confusion. --- sql/sql_profile.cc | 4 ++-- sql/sql_profile.h | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 1d38b313bd3..028363f167e 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -17,13 +17,13 @@ #include "mysql_priv.h" #include "my_sys.h" -#define TIME_FLOAT_DIGITS 7 +#define TIME_FLOAT_DIGITS 9 #define MAX_QUERY_LENGTH 300 bool schema_table_store_record(THD *thd, TABLE *table); /* Reserved for systems that can't record the function name in source. */ -const char *_db_func_= ""; +const char * const _unknown_func_ = ""; /** Connects Information_Schema and Profiling. diff --git a/sql/sql_profile.h b/sql/sql_profile.h index 944856a9f80..0b387f2a7cb 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -20,21 +20,21 @@ # if __GNUC__ >= 2 # define __func__ __FUNCTION__ # else -# define __func__ _db_func_ -extern const char *_db_func_; +# define __func__ _unknown_func_ +extern const char * const _unknown_func_; # endif #elif defined(_MSC_VER) # if _MSC_VER < 1300 -# define __func__ _db_func_ -extern const char *_db_func_; +# define __func__ _unknown_func_ +extern const char * const _unknown_func_; # else # define __func__ __FUNCTION__ # endif #elif defined(__BORLANDC__) # define __func__ __FUNC__ #else -# define __func__ _db_func_ -extern const char *_db_func_; +# define __func__ _unknown_func_ +extern const char * const _unknown_func_; #endif extern ST_FIELD_INFO query_profile_statistics_info[]; From c161bf3e572da50c0fcc50fe385bfa6c69506120 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Mar 2007 16:10:42 +0100 Subject: [PATCH 18/33] add ad support-files/mysql.spec.sh: add ad at %post --- support-files/mysql.spec.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index f60664bdefd..39866872514 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -539,6 +539,11 @@ chmod -R og-rw $mysql_datadir/mysql # Allow safe_mysqld to start mysqld and print a message before we exit sleep 2 +echo "Thank you for installing the MySQL Community Server! For Production +systems, we recommend MySQL Enterprise, which contains enterprise-ready +software, intelligent advisory services, and full production support with +scheduled service packs and more. Visit www.mysql.com/enterprise for more +information." %post ndb-storage mysql_clusterdir=/var/lib/mysql-cluster From 6246edf728c71a1d6dfd89e85e338c733a8a4096 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Mar 2007 20:25:57 +0100 Subject: [PATCH 19/33] adjust version string in mysql-5.0-community commit trigger BitKeeper/triggers/post-commit: adjust version string in trigger --- BitKeeper/triggers/post-commit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BitKeeper/triggers/post-commit b/BitKeeper/triggers/post-commit index 8051cf98b7a..ce6d60fb933 100755 --- a/BitKeeper/triggers/post-commit +++ b/BitKeeper/triggers/post-commit @@ -5,7 +5,7 @@ FROM=$USER@mysql.com COMMITS=commits@lists.mysql.com DOCS=docs-commit@mysql.com LIMIT=10000 -VERSION="5.0" +VERSION="5.0-community" BKROOT=`bk root` if [ -x /usr/sbin/sendmail ]; then From 8c302fb15718e1745f5d3bcfb080b1d23ccdbb8b Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 13:26:19 -0400 Subject: [PATCH 20/33] Listing all columns of a particular type tells us nothing at all. The test fails, and it shouldn't. mysql-test/r/information_schema.result: The query to generate this list is pretty bogus in any case. Listing all columns of a particular type tells us nothing at all. --- mysql-test/r/information_schema.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index b01ed152e33..97bb5e4e446 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1096,7 +1096,7 @@ table_schema='information_schema' and group by column_type order by num; column_type group_concat(table_schema, '.', table_name) num varchar(20) information_schema.COLUMNS,information_schema.PROFILING 2 -varchar(7) information_schema.PROFILING,information_schema.PROFILING,information_schema.PROFILING,information_schema.ROUTINES,information_schema.VIEWS 5 +varchar(7) information_schema.ROUTINES,information_schema.VIEWS 2 create table t1(f1 char(1) not null, f2 char(9) not null) default character set utf8; select CHARACTER_MAXIMUM_LENGTH, CHARACTER_OCTET_LENGTH from From 892c54a05812ece5d169b9726fea19598dafeea6 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 14:05:00 -0400 Subject: [PATCH 21/33] The test suite erroneously removes backslashes. --- mysql-test/r/profiling.result | 2 +- mysql-test/t/profiling.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/profiling.result b/mysql-test/r/profiling.result index f8aa060eee4..a1e994220b9 100644 --- a/mysql-test/r/profiling.result +++ b/mysql-test/r/profiling.result @@ -198,7 +198,7 @@ Query_ID Duration Query 38 # insert into t2 values (1), (2), (3) 39 # insert into t3 values (1), (2), (3) 40 # select * from t1 -This ^^ should end in "select * from t1;\" +This ^^ should end in "select * from t1;" delete from t1; insert into t1 values (1), (2), (3); insert into t1 values (1), (2), (3); diff --git a/mysql-test/t/profiling.test b/mysql-test/t/profiling.test index ebde8eeffd8..fd7562f6f16 100644 --- a/mysql-test/t/profiling.test +++ b/mysql-test/t/profiling.test @@ -113,7 +113,7 @@ show profiles; select * from t1; --replace_column 2 # show profiles; ---echo This ^^ should end in \"select * from t1;\" +--echo This ^^ should end in "select * from t1;" delete from t1; insert into t1 values (1), (2), (3); From 992fc6b22c5718fde62eb0c93c296eaec45228ac Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 14:08:09 -0400 Subject: [PATCH 22/33] Backport of Igor's patch for Bug#27362, March 22 2007. Fixed bug #27362: crash at evaluation of IN predicate when one of its argument happened to be a decimal expression returning the NULL value. The crash was due to the fact the function in_decimal::set did not take into account that val_decimal() could return 0 if the decimal expression had been evaluated to NULL. mysql-test/r/func_in.result: Added a test case for bug #27362. mysql-test/t/func_in.test: Added a test case for bug #27362. sql/item_cmpfunc.cc: Fixed bug #27362: crash at evaluation of IN predicate when one of its argument happened to be a decimal expression returning the NULL value. The crash was due to the fact the function in_decimal::set did not take into account that val_decimal() could return 0 if the decimal expression had been evaluated to NULL. --- mysql-test/r/func_in.result | 5 +++++ mysql-test/t/func_in.test | 11 +++++++++++ sql/item_cmpfunc.cc | 3 ++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index fad9a7157e1..87855091699 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -470,4 +470,9 @@ a Warnings: Warning 1292 Incorrect date value: '19772-07-29' for column 'a' at row 1 DROP TABLE t1,t2,t3,t4; +CREATE TABLE t1 (id int not null); +INSERT INTO t1 VALUES (1),(2); +SELECT id FROM t1 WHERE id IN(4564, (SELECT IF(1=0,1,1/0)) ); +id +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test index f9749662ec1..77592d015eb 100644 --- a/mysql-test/t/func_in.test +++ b/mysql-test/t/func_in.test @@ -360,4 +360,15 @@ SELECT * FROM t4 WHERE a IN ('1972-02-06','19772-07-29'); DROP TABLE t1,t2,t3,t4; +# +# BUG#27362: IN with a decimal expression that may return NULL +# + +CREATE TABLE t1 (id int not null); +INSERT INTO t1 VALUES (1),(2); + +SELECT id FROM t1 WHERE id IN(4564, (SELECT IF(1=0,1,1/0)) ); + +DROP TABLE t1; + --echo End of 5.0 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 77d08f79033..d4534abdbcf 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2423,7 +2423,8 @@ void in_decimal::set(uint pos, Item *item) dec->len= DECIMAL_BUFF_LENGTH; dec->fix_buffer_pointer(); my_decimal *res= item->val_decimal(dec); - if (res != dec) + /* if item->val_decimal() is evaluated to NULL then res == 0 */ + if (!item->null_value && res != dec) my_decimal2decimal(res, dec); } From 698d98bea0522c913ba67159673b8290805b1f33 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 17:59:52 -0400 Subject: [PATCH 23/33] Backport: B-g#24795: SHOW PROFILE implementation Don't use memory roots to store profiling information, because memory roots make freeing the data a no-op, and thus long-running processes with profiling turned on the whole time could eventually use all available memory. Instead, use regular heap allocation and deallocation calls to manage profiling data. Replace the leaky List usage with a similar- behaving structure named "Queue". sql/sql_profile.cc: Don't use C++ iterators on our simple Queue implementation. They're not implemented and we don't really need them. Rip out idea of swapping out the thd's mem_root. sql/sql_profile.h: Rip out idea of needing a mem_root. Implement a Queue that looks and behaves very similarly to memroot- using List. --- sql/sql_profile.cc | 111 ++++++++++++++++----------------------------- sql/sql_profile.h | 111 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 147 insertions(+), 75 deletions(-) diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 028363f167e..8ed3df9cd2e 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -175,11 +175,8 @@ void QUERY_PROFILE::set_query_source(char *query_source_arg, QUERY_PROFILE::~QUERY_PROFILE() { - PROFILE_ENTRY *entry; - List_iterator it(entries); - while ((entry= it++) != NULL) - delete entry; - entries.empty(); + while (! entries.is_empty()) + delete entries.pop(); if (query_source != NULL) my_free(query_source, MYF(0)); @@ -191,7 +188,6 @@ void QUERY_PROFILE::status(const char *status_arg, { THD *thd= profiling->thd; PROFILE_ENTRY *prof; - MEM_ROOT *saved_mem_root; DBUG_ENTER("QUERY_PROFILE::status"); /* Blank status. Just return, and thd->proc_info will be set blank later. */ @@ -210,22 +206,6 @@ void QUERY_PROFILE::status(const char *status_arg, if (unlikely((thd->query_id != server_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. - - The "entries" list allocates is memory from the current thd's mem_root. - We substitute our mem_root temporarily so that we intercept those - allocations into our own mem_root. - - The thd->mem_root structure is freed after each query is completed, - so temporarily override it. - */ - saved_mem_root= thd->mem_root; - thd->mem_root= &profiling->mem_root; - if (function_arg && file_arg) { if ((profile_end= prof= new PROFILE_ENTRY(this, status_arg, function_arg, @@ -238,9 +218,6 @@ void QUERY_PROFILE::status(const char *status_arg, entries.push_back(prof); } - /* Restore mem_root */ - thd->mem_root= saved_mem_root; - DBUG_VOID_RETURN; } @@ -252,11 +229,8 @@ void QUERY_PROFILE::reset() server_query_id= profiling->thd->query_id; /* despite name, is global */ profile_start.collect(); - PROFILE_ENTRY *entry; - List_iterator it(entries); - while ((entry= it++) != NULL) - delete entry; - entries.empty(); + while (! entries.is_empty()) + delete entries.pop(); } DBUG_VOID_RETURN; } @@ -344,10 +318,14 @@ bool QUERY_PROFILE::show(uint options) struct rusage *last_rusage= &(profile_start.rusage); #endif - List_iterator it(entries); PROFILE_ENTRY *entry; - while ((entry= it++) != NULL) + void *iterator; + for (iterator= entries.new_iterator(); + iterator != NULL; + iterator= entries.iterator_next(iterator)) { + entry= entries.iterator_value(iterator); + #ifdef HAVE_GETRUSAGE struct rusage *rusage= &(entry->rusage); #endif @@ -463,24 +441,15 @@ bool QUERY_PROFILE::show(uint options) PROFILING::PROFILING() :profile_id_counter(0), keeping(1), current(NULL), last(NULL) { - init_sql_alloc(&mem_root, - PROFILE_ALLOC_BLOCK_SIZE, - PROFILE_ALLOC_PREALLOC_SIZE); } PROFILING::~PROFILING() { - QUERY_PROFILE *prof; - - List_iterator it(history); - while ((prof= it++) != NULL) - delete prof; - history.empty(); + while (! history.is_empty()) + delete history.pop(); if (current != NULL) delete current; - - free_root(&mem_root, MYF(0)); } void PROFILING::status_change(const char *status_arg, @@ -505,7 +474,6 @@ void PROFILING::status_change(const char *status_arg, void PROFILING::store() { - MEM_ROOT *saved_mem_root; DBUG_ENTER("PROFILING::store"); /* Already stored */ @@ -517,22 +485,8 @@ void PROFILING::store() } while (history.elements > thd->variables.profiling_history_size) - { - QUERY_PROFILE *tmp= history.pop(); - delete tmp; - } + delete history.pop(); - /* - Switch out memory roots so that we're sure that we keep what we need - - The "history" list implementation allocates its memory in the current - thd's mem_root. We substitute our mem_root temporarily so that we - intercept those allocations into our own mem_root. - */ - - saved_mem_root= thd->mem_root; - thd->mem_root= &mem_root; - if (current != NULL) { if (keeping && @@ -556,9 +510,6 @@ void PROFILING::store() DBUG_ASSERT(current == NULL); current= new QUERY_PROFILE(this, thd->query, thd->query_length); - /* Restore memory root */ - thd->mem_root= saved_mem_root; - DBUG_VOID_RETURN; } @@ -598,9 +549,13 @@ bool PROFILING::show_profiles() unit->set_limit(sel); - List_iterator it(history); - while ((prof= it++) != NULL) + void *iterator; + for (iterator= history.new_iterator(); + iterator != NULL; + iterator= history.iterator_next(iterator)) { + prof= history.iterator_value(iterator); + String elapsed; PROFILE_ENTRY *ps= &prof->profile_start; @@ -651,9 +606,13 @@ bool PROFILING::show(uint options, uint profiling_query_id) DBUG_ENTER("PROFILING::show"); QUERY_PROFILE *prof; - List_iterator it(history); - while ((prof= it++) != NULL) + void *iterator; + for (iterator= history.new_iterator(); + iterator != NULL; + iterator= history.iterator_next(iterator)) { + prof= history.iterator_value(iterator); + if(prof->profiling_query_id == profiling_query_id) DBUG_RETURN(prof->show(options)); } @@ -681,11 +640,15 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item TABLE *table= tables->table; ulonglong row_number= 0; - List_iterator query_it(history); QUERY_PROFILE *query; /* Go through each query in this thread's stored history... */ - while ((query= query_it++) != NULL) + void *history_iterator; + for (history_iterator= history.new_iterator(); + history_iterator != NULL; + history_iterator= history.iterator_next(history_iterator)) { + query= history.iterator_value(history_iterator); + PROFILE_ENTRY *ps= &(query->profile_start); double last_time= ps->time_usecs; #ifdef HAVE_GETRUSAGE @@ -699,16 +662,20 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item */ ulonglong seq; - List_iterator step_it(query->entries); + void *entry_iterator; PROFILE_ENTRY *entry; /* ...and for each query, go through all its state-change steps. */ - for (seq= 0, entry= step_it++; - entry != NULL; + for (seq= 0, entry_iterator= query->entries.new_iterator(); + entry_iterator != NULL; + entry_iterator= query->entries.iterator_next(entry_iterator), #ifdef HAVE_GETRUSAGE last_rusage= &(entry->rusage), #endif - seq++, last_time= entry->time_usecs, entry= step_it++, row_number++) + seq++, last_time= entry->time_usecs, row_number++) { + entry= query->entries.iterator_value(entry_iterator); + + /* Set default values for this row. */ restore_record(table, s->default_values); diff --git a/sql/sql_profile.h b/sql/sql_profile.h index 0b387f2a7cb..7913d037551 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -83,6 +83,112 @@ class QUERY_PROFILE; class PROFILING; +/** + Implements a persistent FIFO using server List method names. Not + thread-safe. Intended to be used on thread-local data only. +*/ +template class Queue +{ +private: + + struct queue_item + { + T *payload; + struct queue_item *next, *previous; + }; + + struct queue_item *first, *last; + +public: + Queue() + { + elements= 0; + first= last= NULL; + } + + void empty() + { + struct queue_item *i, *after_i; + for (i= first; i != NULL; i= after_i) + { + after_i= i->next; + my_free((char *) i, MYF(0)); + } + elements= 0; + } + + ulong elements; /* The count of items in the Queue */ + + void push_back(T *payload) + { + struct queue_item *new_item; + + new_item= (struct queue_item *) my_malloc(sizeof(struct queue_item), MYF(0)); + + new_item->payload= payload; + + if (first == NULL) + first= new_item; + if (last != NULL) + { + DBUG_ASSERT(last->next == NULL); + last->next= new_item; + } + new_item->previous= last; + new_item->next= NULL; + last= new_item; + + elements++; + } + + T *pop() + { + struct queue_item *old_item= first; + T *ret= NULL; + + if (first == NULL) + { + DBUG_PRINT("warning", ("tried to pop nonexistent item from Queue")); + return NULL; + } + + ret= old_item->payload; + if (first->next != NULL) + first->next->previous= NULL; + else + last= NULL; + first= first->next; + + my_free((char *)old_item, MYF(0)); + elements--; + + return ret; + } + + bool is_empty() + { + DBUG_ASSERT(((elements > 0) && (first != NULL)) || ((elements == 0) || (first == NULL))); + return (elements == 0); + } + + void *new_iterator() + { + return first; + } + + void *iterator_next(void *current) + { + return ((struct queue_item *) current)->next; + } + + T *iterator_value(void *current) + { + return ((struct queue_item *) current)->payload; + } + +}; + + /** A single entry in a single profile. */ @@ -135,7 +241,7 @@ private: char *query_source; PROFILE_ENTRY profile_start; PROFILE_ENTRY *profile_end; - List entries; + Queue entries; QUERY_PROFILE(PROFILING *profiling_arg, char *query_source_arg, uint query_length_arg); @@ -169,13 +275,12 @@ private: Not the system query_id, but a counter unique to profiling. */ query_id_t profile_id_counter; - MEM_ROOT mem_root; THD *thd; bool keeping; QUERY_PROFILE *current; QUERY_PROFILE *last; - List history; + Queue history; query_id_t next_profile_id() { return(profile_id_counter++); } From 34a102d909f6bc0e0676e8bb6ff09da691dcbcb6 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 18:12:31 -0400 Subject: [PATCH 24/33] Backport: Patch contributed by Jocelyn Fournier. CLA received 2007-02-27. B-g#25347: mysqlcheck -A -r doesn't repair table marked as crashed mysqlcheck tests nullness of the engine type to know whether the "table" is a view or not. That also falsely catches tables that are severly damaged. Instead, use SHOW FULL TABLES to test whether a "table" is a view or not. (Don't add new function. Instead, get original data a smarter way.) Make it safe for use against databases before when views appeared. client/mysqlcheck.c: Use SHOW FULL TABLES to test better whether a name in the table list is one of a view. Checking that the engine is NULL is insufficient. Implemented suggestion from jimw that involved removing most of original patch and getting data a better way mysql-test/r/mysqlcheck.result: Verify that tables that have NULL/unreadable engine types are processed and not interpreted as views. mysql-test/t/mysqlcheck.test: Verify that tables that have NULL/unreadable engine types are processed and not interpreted as views. --- client/mysqlcheck.c | 27 +++++++++++++++------------ mysql-test/r/mysqlcheck.result | 10 ++++++++++ mysql-test/t/mysqlcheck.test | 16 ++++++++++++++++ 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index b69e9201a28..2c23a0bdd14 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -453,14 +453,17 @@ static int process_all_tables_in_db(char *database) { MYSQL_RES *res; MYSQL_ROW row; + uint num_columns; LINT_INIT(res); if (use_db(database)) return 1; - if (mysql_query(sock, "SHOW TABLE STATUS") || + if (mysql_query(sock, "SHOW /*!50002 FULL*/ TABLES") || !((res= mysql_store_result(sock)))) return 1; + num_columns= mysql_num_fields(res); + if (opt_all_in_1) { /* @@ -483,12 +486,11 @@ static int process_all_tables_in_db(char *database) } for (end = tables + 1; (row = mysql_fetch_row(res)) ;) { - /* Skip tables with an engine of NULL (probably a view). */ - if (row[1]) - { - end= fix_table_name(end, row[0]); - *end++= ','; - } + if ((num_columns == 2) && (strcmp(row[1], "VIEW") == 0)) + continue; + + end= fix_table_name(end, row[0]); + *end++= ','; } *--end = 0; if (tot_length) @@ -498,11 +500,12 @@ static int process_all_tables_in_db(char *database) else { while ((row = mysql_fetch_row(res))) - /* Skip tables with an engine of NULL (probably a view). */ - if (row[1]) - { - handle_request_for_tables(row[0], strlen(row[0])); - } + { + if ((num_columns == 2) && (strcmp(row[1], "VIEW") == 0)) + continue; + + handle_request_for_tables(row[0], strlen(row[0])); + } } mysql_free_result(res); return 0; diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result index b2820df8f4c..81a30267e04 100644 --- a/mysql-test/r/mysqlcheck.result +++ b/mysql-test/r/mysqlcheck.result @@ -41,4 +41,14 @@ test.t1 OK test.t1 OK drop view v1; drop table t1; +create database d_bug25347; +use d_bug25347; +create table t_bug25347 (a int); +create view v_bug25347 as select * from t_bug25347; +removing and creating +d_bug25347.t_bug25347 OK +drop view v_bug25347; +drop table t_bug25347; +drop database d_bug25347; +use test; End of 5.0 tests diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test index f4e18d4004f..eb732a05909 100644 --- a/mysql-test/t/mysqlcheck.test +++ b/mysql-test/t/mysqlcheck.test @@ -31,4 +31,20 @@ create view v1 as select * from t1; drop view v1; drop table t1; +# +# Bug#25347: mysqlcheck -A -r doesn't repair table marked as crashed +# +create database d_bug25347; +use d_bug25347; +create table t_bug25347 (a int); +create view v_bug25347 as select * from t_bug25347; +--echo removing and creating +--exec rm $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI; +--exec touch $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI; +--exec $MYSQL_CHECK --repair --databases d_bug25347 +drop view v_bug25347; +drop table t_bug25347; +drop database d_bug25347; +use test; + --echo End of 5.0 tests From 4eb0a55340353fa0545645bf4293f6e4dd92109e Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 19:45:28 -0400 Subject: [PATCH 25/33] Backport: B-g#27060: SQL Profile utility may not be reporting right duration \ for each step Whenever the profiler is reset at the beginning of a query, there's a "hidden" profiling entry that represents that point in time. It has no status description, as those are set by state changes and no such point has yet been encountered. That profiling entry is not in the list of entries generated when we change states. The profiling code had the problem that each step of printing profiling data subtracted the previous "step"'s data, but gave the label to that data of the current step, which is wrong. The label/ state refers to the period beginning with that profiling data, not ending with it. Now, give a label to the first profiling pseudo-entry, so that we have a name to assign to the period that ends with the first state change. Now also use the state name of the previous step in showing the delta values that end with this step. sql/sql_profile.cc: Store a status of "initializing" whenever we construct the first profile entry -- the one that gets reset whenever we're starting a new query, before the server sets a real status. Additionally, associate the previous status with the time period that ends with the current profile entry's stats. Since we need yet another piece of info from the previous profiling entry, take out the piecemeal ways we currently do it and make a general pointer to the whole thing. --- sql/sql_profile.cc | 107 ++++++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 46 deletions(-) diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 8ed3df9cd2e..4ee8d1ba9c8 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -72,6 +72,9 @@ PROFILE_ENTRY::PROFILE_ENTRY() time_usecs(0.0), allocated_status_memory(NULL) { collect(); + + /* The beginning of the query, before any state is set. */ + set_status("(initialization)", NULL, NULL, 0); } PROFILE_ENTRY::PROFILE_ENTRY(QUERY_PROFILE *profile_arg, const char *status_arg) @@ -313,10 +316,7 @@ bool QUERY_PROFILE::show(uint options) SELECT_LEX_UNIT *unit= &thd->lex->unit; ha_rows idx= 0; unit->set_limit(sel); - double last_time= profile_start.time_usecs; -#ifdef HAVE_GETRUSAGE - struct rusage *last_rusage= &(profile_start.rusage); -#endif + PROFILE_ENTRY *previous= &profile_start; PROFILE_ENTRY *entry; void *iterator; @@ -337,8 +337,18 @@ bool QUERY_PROFILE::show(uint options) break; protocol->prepare_for_resend(); - protocol->store(entry->status, strlen(entry->status), system_charset_info); - protocol->store((double)(entry->time_usecs - last_time)/(1000.0*1000), + + /* + This entry, n, has a point in time, T(n), and a status phrase, S(n). The + status phrase S(n) describes the period of time that begins at T(n). The + previous status phrase S(n-1) describes the period of time that starts at + T(n-1) and ends at T(n). Since we want to describe the time that a status + phrase took T(n)-T(n-1), this line must describe the previous status. + */ + protocol->store(previous->status, strlen(previous->status), + system_charset_info); + protocol->store((double)(entry->time_usecs - + previous->time_usecs)/(1000.0*1000), (uint32) TIME_FLOAT_DIGITS-1, &elapsed); if (options & PROFILE_CPU) @@ -346,10 +356,10 @@ bool QUERY_PROFILE::show(uint options) #ifdef HAVE_GETRUSAGE String cpu_utime, cpu_stime; protocol->store((double)(RUSAGE_DIFF_USEC(rusage->ru_utime, - last_rusage->ru_utime))/(1000.0*1000), + previous->rusage.ru_utime))/(1000.0*1000), (uint32) TIME_FLOAT_DIGITS-1, &cpu_utime); protocol->store((double)(RUSAGE_DIFF_USEC(rusage->ru_stime, - last_rusage->ru_stime))/(1000.0*1000), + previous->rusage.ru_stime))/(1000.0*1000), (uint32) TIME_FLOAT_DIGITS-1, &cpu_stime); #else protocol->store_null(); @@ -360,8 +370,8 @@ bool QUERY_PROFILE::show(uint options) if (options & PROFILE_CONTEXT) { #ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_nvcsw - last_rusage->ru_nvcsw)); - protocol->store((uint32)(rusage->ru_nivcsw - last_rusage->ru_nivcsw)); + protocol->store((uint32)(rusage->ru_nvcsw - previous->rusage.ru_nvcsw)); + protocol->store((uint32)(rusage->ru_nivcsw - previous->rusage.ru_nivcsw)); #else protocol->store_null(); protocol->store_null(); @@ -371,8 +381,8 @@ bool QUERY_PROFILE::show(uint options) if (options & PROFILE_BLOCK_IO) { #ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_inblock - last_rusage->ru_inblock)); - protocol->store((uint32)(rusage->ru_oublock - last_rusage->ru_oublock)); + protocol->store((uint32)(rusage->ru_inblock - previous->rusage.ru_inblock)); + protocol->store((uint32)(rusage->ru_oublock - previous->rusage.ru_oublock)); #else protocol->store_null(); protocol->store_null(); @@ -382,8 +392,8 @@ bool QUERY_PROFILE::show(uint options) if (options & PROFILE_IPC) { #ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_msgsnd - last_rusage->ru_msgsnd)); - protocol->store((uint32)(rusage->ru_msgrcv - last_rusage->ru_msgrcv)); + protocol->store((uint32)(rusage->ru_msgsnd - previous->rusage.ru_msgsnd)); + protocol->store((uint32)(rusage->ru_msgrcv - previous->rusage.ru_msgrcv)); #else protocol->store_null(); protocol->store_null(); @@ -393,8 +403,8 @@ bool QUERY_PROFILE::show(uint options) if (options & PROFILE_PAGE_FAULTS) { #ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_majflt - last_rusage->ru_majflt)); - protocol->store((uint32)(rusage->ru_minflt - last_rusage->ru_minflt)); + protocol->store((uint32)(rusage->ru_majflt - previous->rusage.ru_majflt)); + protocol->store((uint32)(rusage->ru_minflt - previous->rusage.ru_minflt)); #else protocol->store_null(); protocol->store_null(); @@ -404,7 +414,7 @@ bool QUERY_PROFILE::show(uint options) if (options & PROFILE_SWAPS) { #ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_nswap - last_rusage->ru_nswap)); + protocol->store((uint32)(rusage->ru_nswap - previous->rusage.ru_nswap)); #else protocol->store_null(); #endif @@ -428,11 +438,7 @@ bool QUERY_PROFILE::show(uint options) if (protocol->write()) DBUG_RETURN(TRUE); - last_time= entry->time_usecs; -#ifdef HAVE_GETRUSAGE - last_rusage= &(entry->rusage); -#endif - + previous= entry; } send_eof(thd); DBUG_RETURN(FALSE); @@ -648,12 +654,7 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item history_iterator= history.iterator_next(history_iterator)) { query= history.iterator_value(history_iterator); - - PROFILE_ENTRY *ps= &(query->profile_start); - double last_time= ps->time_usecs; -#ifdef HAVE_GETRUSAGE - struct rusage *last_rusage= &(ps->rusage); -#endif + PROFILE_ENTRY *previous= &(query->profile_start); /* Because we put all profiling info into a table that may be reordered, let @@ -668,14 +669,10 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item for (seq= 0, entry_iterator= query->entries.new_iterator(); entry_iterator != NULL; entry_iterator= query->entries.iterator_next(entry_iterator), -#ifdef HAVE_GETRUSAGE - last_rusage= &(entry->rusage), -#endif - seq++, last_time= entry->time_usecs, row_number++) + seq++, previous=entry, row_number++) { entry= query->entries.iterator_value(entry_iterator); - /* Set default values for this row. */ restore_record(table, s->default_values); @@ -685,16 +682,25 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item */ table->field[0]->store((ulonglong) query->profiling_query_id); table->field[1]->store((ulonglong) seq); /* the step in the sequence */ - table->field[2]->store(entry->status, strlen(entry->status), + /* + This entry, n, has a point in time, T(n), and a status phrase, S(n). + The status phrase S(n) describes the period of time that begins at + T(n). The previous status phrase S(n-1) describes the period of time + that starts at T(n-1) and ends at T(n). Since we want to describe the + time that a status phrase took T(n)-T(n-1), this line must describe the + previous status. + */ + table->field[2]->store(previous->status, strlen(previous->status), system_charset_info); - table->field[3]->store((double)(entry->time_usecs - last_time)/(1000*1000)); + table->field[3]->store((double)(entry->time_usecs - + previous->time_usecs)/(1000*1000)); #ifdef HAVE_GETRUSAGE table->field[4]->store((double)RUSAGE_DIFF_USEC(entry->rusage.ru_utime, - last_rusage->ru_utime)/(1000.0*1000)); + previous->rusage.ru_utime)/(1000.0*1000)); table->field[4]->set_notnull(); table->field[5]->store((double)RUSAGE_DIFF_USEC(entry->rusage.ru_stime, - last_rusage->ru_stime)/(1000.0*1000)); + previous->rusage.ru_stime)/(1000.0*1000)); table->field[5]->set_notnull(); #else @@ -702,43 +708,52 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item #endif #ifdef HAVE_GETRUSAGE - table->field[6]->store((uint32)(entry->rusage.ru_nvcsw - last_rusage->ru_nvcsw)); + table->field[6]->store((uint32)(entry->rusage.ru_nvcsw - + previous->rusage.ru_nvcsw)); table->field[6]->set_notnull(); - table->field[7]->store((uint32)(entry->rusage.ru_nivcsw - last_rusage->ru_nivcsw)); + table->field[7]->store((uint32)(entry->rusage.ru_nivcsw - + previous->rusage.ru_nivcsw)); table->field[7]->set_notnull(); #else /* TODO: Add context switch info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE - table->field[8]->store((uint32)(entry->rusage.ru_inblock - last_rusage->ru_inblock)); + table->field[8]->store((uint32)(entry->rusage.ru_inblock - + previous->rusage.ru_inblock)); table->field[8]->set_notnull(); - table->field[9]->store((uint32)(entry->rusage.ru_oublock - last_rusage->ru_oublock)); + table->field[9]->store((uint32)(entry->rusage.ru_oublock - + previous->rusage.ru_oublock)); table->field[9]->set_notnull(); #else /* TODO: Add block IO info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE - table->field[10]->store((uint32)(entry->rusage.ru_msgsnd - last_rusage->ru_msgsnd), true); + table->field[10]->store((uint32)(entry->rusage.ru_msgsnd - + previous->rusage.ru_msgsnd), true); table->field[10]->set_notnull(); - table->field[11]->store((uint32)(entry->rusage.ru_msgrcv - last_rusage->ru_msgrcv), true); + table->field[11]->store((uint32)(entry->rusage.ru_msgrcv - + previous->rusage.ru_msgrcv), true); table->field[11]->set_notnull(); #else /* TODO: Add message info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE - table->field[12]->store((uint32)(entry->rusage.ru_majflt - last_rusage->ru_majflt), true); + table->field[12]->store((uint32)(entry->rusage.ru_majflt - + previous->rusage.ru_majflt), true); table->field[12]->set_notnull(); - table->field[13]->store((uint32)(entry->rusage.ru_minflt - last_rusage->ru_minflt), true); + table->field[13]->store((uint32)(entry->rusage.ru_minflt - + previous->rusage.ru_minflt), true); table->field[13]->set_notnull(); #else /* TODO: Add page fault info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE - table->field[14]->store((uint32)(entry->rusage.ru_nswap - last_rusage->ru_nswap), true); + table->field[14]->store((uint32)(entry->rusage.ru_nswap - + previous->rusage.ru_nswap), true); table->field[14]->set_notnull(); #else /* TODO: Add swap info for non-BSD systems */ From 8abb73142b2d2066ca945fba9d01d3d3aac83665 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 19:47:19 -0400 Subject: [PATCH 26/33] Backport: B-g#26600: table PROFILING in INFORMATION SCHEMA has wrong data type B-g#27047[partial]: INFORMATION_SCHEMA table cannot have BIGINT \ fields No Information_schema table has ever needed floating-point data before. Transforming all floating point to a string and back to a number causes a real data problem on Windows, where the libc may pad the exponent with more leading zeroes than we expect and the significant digits are truncated away. This also makes interpreting an unimplemented type as a string into a fatal error in debug builds. Thus, we will catch problems when we try to use those types in new I_S tables. sql/sql_show.cc: Add floating-point types to Information_schema output. --- sql/sql_show.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index cc3dd79d2ae..7da4ac55e92 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3605,7 +3605,16 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) DBUG_RETURN(0); } break; + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + if ((item= new Item_float(fields_info->field_name, 0.0, NOT_FIXED_DEC, + fields_info->field_length)) == NULL) + DBUG_RETURN(NULL); + break; default: + /* Don't let unimplemented types pass through. Could be a grave error. */ + DBUG_ASSERT(fields_info->field_type == MYSQL_TYPE_STRING); + /* this should be changed when Item_empty_string is fixed(in 4.1) */ if (!(item= new Item_empty_string("", 0, cs))) { From 46503d161ecc5756f0dd7130969e9ae9df303b31 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 19:50:55 -0400 Subject: [PATCH 27/33] Backport: B-g#27501: 5.0 significantly more sys ("kernel") time than 4.1 \ due to getrusage() calls Even if profiling is turned off, the parser makes calls to reset the state at the beginning of each query. That would eventually instantiate a PROFILE_ENTRY, which does indeed capture resource usage. Instead, now check that profiling is active before progressing far into the storage/expiration of old entries in the history. This has the pleasant side-effect that queries to toggle profiling are not recorded in the history. mysql-test/r/profiling.result: Now after we turn off profiling, the beginning of the next query refuses to enter the profiling code and it discards the info. sql/sql_profile.cc: Add the same condition twice: Once to abort storing previous query information and the other to abort initialization for this query that is starting. We do this symmetrically, before and after expiring old history entries, so that the counts are correct. --- mysql-test/r/profiling.result | 2 +- sql/sql_profile.cc | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/profiling.result b/mysql-test/r/profiling.result index a1e994220b9..75977f7f2e8 100644 --- a/mysql-test/r/profiling.result +++ b/mysql-test/r/profiling.result @@ -248,6 +248,7 @@ sum(id) 12 show profiles; Query_ID Duration Query +15 # select count(*) from t1 16 # insert into t1 select * from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 @@ -277,7 +278,6 @@ Query_ID Duration Query 42 # insert into t1 values (1), (2), (3) 43 # insert into t1 values (1), (2), (3) 44 # select * from t1 -45 # set session profiling = OFF set session profiling = ON; select @@profiling; @@profiling diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 4ee8d1ba9c8..b17bb6daa0d 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -493,6 +493,9 @@ void PROFILING::store() while (history.elements > thd->variables.profiling_history_size) delete history.pop(); + if (likely(((thd)->options & OPTION_PROFILING) == 0)) + DBUG_VOID_RETURN; + if (current != NULL) { if (keeping && @@ -519,12 +522,20 @@ void PROFILING::store() DBUG_VOID_RETURN; } +/** + Store and clean up the old information and get ready to hold info about this + new query. This is called very often so it must be very lightweight if + profiling is not active. +*/ void PROFILING::reset() { DBUG_ENTER("PROFILING::reset"); store(); + if (likely(((thd)->options & OPTION_PROFILING) == 0)) + DBUG_VOID_RETURN; + if (current != NULL) current->reset(); keep(); From 2879da7f847eeda8ebf7cdad769f665fe95f5259 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 19:52:24 -0400 Subject: [PATCH 28/33] Unreported minor bug: We start numbering query IDs at zero, which is a special case in "SHOW PROFILE FOR QUERY n". No one can get the zero item (which is always the statement that turns on profiling), because zero represents the final item, internally. Now, order the queries starting at one. mysql-test/r/profiling.result: Renumber the query IDs. sql/sql_profile.cc: Start the profile_id_counter at 1, to overstep the special-case value of zero. Unrelated, but looks similar: don't use -1 to initialize an unsigned integer field. That causes warnings in some environments. --- mysql-test/r/profiling.result | 254 +++++++++++++++++----------------- sql/sql_profile.cc | 4 +- 2 files changed, 129 insertions(+), 129 deletions(-) diff --git a/mysql-test/r/profiling.result b/mysql-test/r/profiling.result index 75977f7f2e8..50b6fff82b8 100644 --- a/mysql-test/r/profiling.result +++ b/mysql-test/r/profiling.result @@ -69,34 +69,34 @@ big_string 012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890 show profiles; Query_ID Duration Query -0 # set session profiling = ON -1 # set session profiling_history_size=30 -2 # show session variables like 'profil%' -3 # select @@profiling -4 # create table t1 ( +1 # set session profiling = ON +2 # set session profiling_history_size=30 +3 # show session variables like 'profil%' +4 # select @@profiling +5 # create table t1 ( a int, b int ) -5 # insert into t1 values (1,1), (2,null), (3, 4) -6 # insert into t1 values (5,1), (6,null), (7, 4) -7 # insert into t1 values (1,1), (2,null), (3, 4) -8 # insert into t1 values (5,1), (6,null), (7, 4) -9 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -10 # insert into t1 select * from t1 -11 # select count(*) from t1 -12 # insert into t1 select * from t1 +6 # insert into t1 values (1,1), (2,null), (3, 4) +7 # insert into t1 values (5,1), (6,null), (7, 4) +8 # insert into t1 values (1,1), (2,null), (3, 4) +9 # insert into t1 values (5,1), (6,null), (7, 4) +10 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +11 # insert into t1 select * from t1 +12 # select count(*) from t1 13 # insert into t1 select * from t1 14 # insert into t1 select * from t1 -15 # select count(*) from t1 -16 # insert into t1 select * from t1 +15 # insert into t1 select * from t1 +16 # select count(*) from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # select count(*) from t1 -20 # select sum(a) from t1 -21 # select sum(a) from t1 group by b -22 # select sum(a) + sum(b) from t1 group by b -23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +19 # insert into t1 select * from t1 +20 # select count(*) from t1 +21 # select sum(a) from t1 +22 # select sum(a) from t1 group by b +23 # select sum(a) + sum(b) from t1 group by b +24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 show profile for query 15; show profile cpu for query 15; show profile cpu, block io for query 15; @@ -131,36 +131,36 @@ insert into t2 values (1), (2), (3); insert into t3 values (1), (2), (3); show profiles; Query_ID Duration Query -10 # insert into t1 select * from t1 -11 # select count(*) from t1 -12 # insert into t1 select * from t1 +11 # insert into t1 select * from t1 +12 # select count(*) from t1 13 # insert into t1 select * from t1 14 # insert into t1 select * from t1 -15 # select count(*) from t1 -16 # insert into t1 select * from t1 +15 # insert into t1 select * from t1 +16 # select count(*) from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # select count(*) from t1 -20 # select sum(a) from t1 -21 # select sum(a) from t1 group by b -22 # select sum(a) + sum(b) from t1 group by b -23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 -25 # select * from information_schema.profiling -26 # select query_id, state, duration from information_schema.profiling -27 # select query_id, sum(duration) from information_schema.profiling group by query_id -28 # select query_id, count(*) from information_schema.profiling group by query_id -29 # select sum(duration) from information_schema.profiling -30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id -31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling -32 # drop table if exists t1, t2, t3 -33 # SHOW WARNINGS -34 # create table t1 (id int ) -35 # create table t2 (id int not null) -36 # create table t3 (id int not null primary key) -37 # insert into t1 values (1), (2), (3) -38 # insert into t2 values (1), (2), (3) -39 # insert into t3 values (1), (2), (3) +19 # insert into t1 select * from t1 +20 # select count(*) from t1 +21 # select sum(a) from t1 +22 # select sum(a) from t1 group by b +23 # select sum(a) + sum(b) from t1 group by b +24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +26 # select * from information_schema.profiling +27 # select query_id, state, duration from information_schema.profiling +28 # select query_id, sum(duration) from information_schema.profiling group by query_id +29 # select query_id, count(*) from information_schema.profiling group by query_id +30 # select sum(duration) from information_schema.profiling +31 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +32 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +33 # drop table if exists t1, t2, t3 +34 # SHOW WARNINGS +35 # create table t1 (id int ) +36 # create table t2 (id int not null) +37 # create table t3 (id int not null primary key) +38 # insert into t1 values (1), (2), (3) +39 # insert into t2 values (1), (2), (3) +40 # insert into t3 values (1), (2), (3) select * from t1; id 1 @@ -168,36 +168,36 @@ id 3 show profiles; Query_ID Duration Query -11 # select count(*) from t1 -12 # insert into t1 select * from t1 +12 # select count(*) from t1 13 # insert into t1 select * from t1 14 # insert into t1 select * from t1 -15 # select count(*) from t1 -16 # insert into t1 select * from t1 +15 # insert into t1 select * from t1 +16 # select count(*) from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # select count(*) from t1 -20 # select sum(a) from t1 -21 # select sum(a) from t1 group by b -22 # select sum(a) + sum(b) from t1 group by b -23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 -25 # select * from information_schema.profiling -26 # select query_id, state, duration from information_schema.profiling -27 # select query_id, sum(duration) from information_schema.profiling group by query_id -28 # select query_id, count(*) from information_schema.profiling group by query_id -29 # select sum(duration) from information_schema.profiling -30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id -31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling -32 # drop table if exists t1, t2, t3 -33 # SHOW WARNINGS -34 # create table t1 (id int ) -35 # create table t2 (id int not null) -36 # create table t3 (id int not null primary key) -37 # insert into t1 values (1), (2), (3) -38 # insert into t2 values (1), (2), (3) -39 # insert into t3 values (1), (2), (3) -40 # select * from t1 +19 # insert into t1 select * from t1 +20 # select count(*) from t1 +21 # select sum(a) from t1 +22 # select sum(a) from t1 group by b +23 # select sum(a) + sum(b) from t1 group by b +24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +26 # select * from information_schema.profiling +27 # select query_id, state, duration from information_schema.profiling +28 # select query_id, sum(duration) from information_schema.profiling group by query_id +29 # select query_id, count(*) from information_schema.profiling group by query_id +30 # select sum(duration) from information_schema.profiling +31 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +32 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +33 # drop table if exists t1, t2, t3 +34 # SHOW WARNINGS +35 # create table t1 (id int ) +36 # create table t2 (id int not null) +37 # create table t3 (id int not null primary key) +38 # insert into t1 values (1), (2), (3) +39 # insert into t2 values (1), (2), (3) +40 # insert into t3 values (1), (2), (3) +41 # select * from t1 This ^^ should end in "select * from t1;" delete from t1; insert into t1 values (1), (2), (3); @@ -212,72 +212,72 @@ id 3 show profiles; Query_ID Duration Query -15 # select count(*) from t1 -16 # insert into t1 select * from t1 +16 # select count(*) from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # select count(*) from t1 -20 # select sum(a) from t1 -21 # select sum(a) from t1 group by b -22 # select sum(a) + sum(b) from t1 group by b -23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 -25 # select * from information_schema.profiling -26 # select query_id, state, duration from information_schema.profiling -27 # select query_id, sum(duration) from information_schema.profiling group by query_id -28 # select query_id, count(*) from information_schema.profiling group by query_id -29 # select sum(duration) from information_schema.profiling -30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id -31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling -32 # drop table if exists t1, t2, t3 -33 # SHOW WARNINGS -34 # create table t1 (id int ) -35 # create table t2 (id int not null) -36 # create table t3 (id int not null primary key) -37 # insert into t1 values (1), (2), (3) -38 # insert into t2 values (1), (2), (3) -39 # insert into t3 values (1), (2), (3) -40 # select * from t1 -41 # delete from t1 -42 # insert into t1 values (1), (2), (3) +19 # insert into t1 select * from t1 +20 # select count(*) from t1 +21 # select sum(a) from t1 +22 # select sum(a) from t1 group by b +23 # select sum(a) + sum(b) from t1 group by b +24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +26 # select * from information_schema.profiling +27 # select query_id, state, duration from information_schema.profiling +28 # select query_id, sum(duration) from information_schema.profiling group by query_id +29 # select query_id, count(*) from information_schema.profiling group by query_id +30 # select sum(duration) from information_schema.profiling +31 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +32 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +33 # drop table if exists t1, t2, t3 +34 # SHOW WARNINGS +35 # create table t1 (id int ) +36 # create table t2 (id int not null) +37 # create table t3 (id int not null primary key) +38 # insert into t1 values (1), (2), (3) +39 # insert into t2 values (1), (2), (3) +40 # insert into t3 values (1), (2), (3) +41 # select * from t1 +42 # delete from t1 43 # insert into t1 values (1), (2), (3) -44 # select * from t1 +44 # insert into t1 values (1), (2), (3) +45 # select * from t1 set session profiling = OFF; select sum(id) from t1; sum(id) 12 show profiles; Query_ID Duration Query -15 # select count(*) from t1 -16 # insert into t1 select * from t1 +16 # select count(*) from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # select count(*) from t1 -20 # select sum(a) from t1 -21 # select sum(a) from t1 group by b -22 # select sum(a) + sum(b) from t1 group by b -23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 -25 # select * from information_schema.profiling -26 # select query_id, state, duration from information_schema.profiling -27 # select query_id, sum(duration) from information_schema.profiling group by query_id -28 # select query_id, count(*) from information_schema.profiling group by query_id -29 # select sum(duration) from information_schema.profiling -30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id -31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling -32 # drop table if exists t1, t2, t3 -33 # SHOW WARNINGS -34 # create table t1 (id int ) -35 # create table t2 (id int not null) -36 # create table t3 (id int not null primary key) -37 # insert into t1 values (1), (2), (3) -38 # insert into t2 values (1), (2), (3) -39 # insert into t3 values (1), (2), (3) -40 # select * from t1 -41 # delete from t1 -42 # insert into t1 values (1), (2), (3) +19 # insert into t1 select * from t1 +20 # select count(*) from t1 +21 # select sum(a) from t1 +22 # select sum(a) from t1 group by b +23 # select sum(a) + sum(b) from t1 group by b +24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +26 # select * from information_schema.profiling +27 # select query_id, state, duration from information_schema.profiling +28 # select query_id, sum(duration) from information_schema.profiling group by query_id +29 # select query_id, count(*) from information_schema.profiling group by query_id +30 # select sum(duration) from information_schema.profiling +31 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +32 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +33 # drop table if exists t1, t2, t3 +34 # SHOW WARNINGS +35 # create table t1 (id int ) +36 # create table t2 (id int not null) +37 # create table t3 (id int not null primary key) +38 # insert into t1 values (1), (2), (3) +39 # insert into t2 values (1), (2), (3) +40 # insert into t3 values (1), (2), (3) +41 # select * from t1 +42 # delete from t1 43 # insert into t1 values (1), (2), (3) -44 # select * from t1 +44 # insert into t1 values (1), (2), (3) +45 # select * from t1 set session profiling = ON; select @@profiling; @@profiling diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index b17bb6daa0d..5fd83ce70c6 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -158,7 +158,7 @@ void PROFILE_ENTRY::collect() QUERY_PROFILE::QUERY_PROFILE(PROFILING *profiling_arg, char *query_source_arg, uint query_length_arg) - :profiling(profiling_arg), server_query_id(-1), profiling_query_id(-1), + :profiling(profiling_arg), server_query_id(0), profiling_query_id(0), query_source(NULL) { profile_end= &profile_start; @@ -445,7 +445,7 @@ bool QUERY_PROFILE::show(uint options) } PROFILING::PROFILING() - :profile_id_counter(0), keeping(1), current(NULL), last(NULL) + :profile_id_counter(1), keeping(1), current(NULL), last(NULL) { } From c717287c22f2e18b31338d6ac7af5bf9c97e0b1f Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Apr 2007 07:44:12 -0400 Subject: [PATCH 29/33] Backport: B-g#27427: resolveip fails on hostnames with a leading digit We need inet_aton for the extra/resolveip tool. Some OSes put this in nonstandard libraries. configure.in: We need inet_aton for the extra/resolveip tool. --- configure.in | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.in b/configure.in index 13d2b50d7fa..f1a71d49359 100644 --- a/configure.in +++ b/configure.in @@ -791,6 +791,7 @@ AC_CHECK_FUNC(p2open, , AC_CHECK_LIB(gen, p2open)) AC_CHECK_FUNC(bind, , AC_CHECK_LIB(bind, bind)) # Check if crypt() exists in libc or libcrypt, sets LIBS if needed AC_SEARCH_LIBS(crypt, crypt, AC_DEFINE(HAVE_CRYPT, 1, [crypt])) +AC_SEARCH_LIBS(inet_aton, [socket nsl resolv]) # For the sched_yield() function on Solaris AC_CHECK_FUNC(sched_yield, , AC_CHECK_LIB(posix4, sched_yield)) From fcb52609e4727cdf6f246e7817c0fa625749c5c4 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 6 Apr 2007 09:15:18 -0400 Subject: [PATCH 30/33] Changing the state of whether we're recording profiling information halfway through a query (as happens in "SET SESSION PROFILING = ...") has a few side-effects, the worst of which is a memory leak for prepared statements, which poke directly from the parser into the profiling code (we don't have the query text when we need it) and that overwrites a pointer to heap-allocated memory when the previous statement turns on profiling. Instead, now set a flag when we begin a new statement that tracks whether profiling is on _at the start_ of the query. Use that to track whether we gather info. Additionally, use that AND use the state of the profiling variable after the end of a query to know whether to store information about the query that just finished. mysql-test/r/profiling.result: Testing whether profiling is on at the beginning of a query and at the end of a query makes "SET SESSION PROFILING = ..." statements disappear from the profiling. They were never reliable before. sql/sql_profile.cc: Check to see if profiling was enabled at the beginning of this query before trying to store query_source. This avoids a memory leak for prepared statements, which get here by direct means. If profiling was toggled in this query, then don't store this query profile. sql/sql_profile.h: Keep track of whether profiling is on. --- mysql-test/r/profiling.result | 253 +++++++++++++++++----------------- sql/sql_profile.cc | 18 ++- sql/sql_profile.h | 1 + 3 files changed, 142 insertions(+), 130 deletions(-) diff --git a/mysql-test/r/profiling.result b/mysql-test/r/profiling.result index 50b6fff82b8..9f478d68b8d 100644 --- a/mysql-test/r/profiling.result +++ b/mysql-test/r/profiling.result @@ -69,34 +69,33 @@ big_string 012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890 show profiles; Query_ID Duration Query -1 # set session profiling = ON -2 # set session profiling_history_size=30 -3 # show session variables like 'profil%' -4 # select @@profiling -5 # create table t1 ( +1 # set session profiling_history_size=30 +2 # show session variables like 'profil%' +3 # select @@profiling +4 # create table t1 ( a int, b int ) -6 # insert into t1 values (1,1), (2,null), (3, 4) -7 # insert into t1 values (5,1), (6,null), (7, 4) -8 # insert into t1 values (1,1), (2,null), (3, 4) -9 # insert into t1 values (5,1), (6,null), (7, 4) -10 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -11 # insert into t1 select * from t1 -12 # select count(*) from t1 +5 # insert into t1 values (1,1), (2,null), (3, 4) +6 # insert into t1 values (5,1), (6,null), (7, 4) +7 # insert into t1 values (1,1), (2,null), (3, 4) +8 # insert into t1 values (5,1), (6,null), (7, 4) +9 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +10 # insert into t1 select * from t1 +11 # select count(*) from t1 +12 # insert into t1 select * from t1 13 # insert into t1 select * from t1 14 # insert into t1 select * from t1 -15 # insert into t1 select * from t1 -16 # select count(*) from t1 +15 # select count(*) from t1 +16 # insert into t1 select * from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # insert into t1 select * from t1 -20 # select count(*) from t1 -21 # select sum(a) from t1 -22 # select sum(a) from t1 group by b -23 # select sum(a) + sum(b) from t1 group by b -24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 show profile for query 15; show profile cpu for query 15; show profile cpu, block io for query 15; @@ -131,36 +130,36 @@ insert into t2 values (1), (2), (3); insert into t3 values (1), (2), (3); show profiles; Query_ID Duration Query -11 # insert into t1 select * from t1 -12 # select count(*) from t1 +10 # insert into t1 select * from t1 +11 # select count(*) from t1 +12 # insert into t1 select * from t1 13 # insert into t1 select * from t1 14 # insert into t1 select * from t1 -15 # insert into t1 select * from t1 -16 # select count(*) from t1 +15 # select count(*) from t1 +16 # insert into t1 select * from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # insert into t1 select * from t1 -20 # select count(*) from t1 -21 # select sum(a) from t1 -22 # select sum(a) from t1 group by b -23 # select sum(a) + sum(b) from t1 group by b -24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 -26 # select * from information_schema.profiling -27 # select query_id, state, duration from information_schema.profiling -28 # select query_id, sum(duration) from information_schema.profiling group by query_id -29 # select query_id, count(*) from information_schema.profiling group by query_id -30 # select sum(duration) from information_schema.profiling -31 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id -32 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling -33 # drop table if exists t1, t2, t3 -34 # SHOW WARNINGS -35 # create table t1 (id int ) -36 # create table t2 (id int not null) -37 # create table t3 (id int not null primary key) -38 # insert into t1 values (1), (2), (3) -39 # insert into t2 values (1), (2), (3) -40 # insert into t3 values (1), (2), (3) +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +25 # select * from information_schema.profiling +26 # select query_id, state, duration from information_schema.profiling +27 # select query_id, sum(duration) from information_schema.profiling group by query_id +28 # select query_id, count(*) from information_schema.profiling group by query_id +29 # select sum(duration) from information_schema.profiling +30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +32 # drop table if exists t1, t2, t3 +33 # SHOW WARNINGS +34 # create table t1 (id int ) +35 # create table t2 (id int not null) +36 # create table t3 (id int not null primary key) +37 # insert into t1 values (1), (2), (3) +38 # insert into t2 values (1), (2), (3) +39 # insert into t3 values (1), (2), (3) select * from t1; id 1 @@ -168,36 +167,36 @@ id 3 show profiles; Query_ID Duration Query -12 # select count(*) from t1 +11 # select count(*) from t1 +12 # insert into t1 select * from t1 13 # insert into t1 select * from t1 14 # insert into t1 select * from t1 -15 # insert into t1 select * from t1 -16 # select count(*) from t1 +15 # select count(*) from t1 +16 # insert into t1 select * from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # insert into t1 select * from t1 -20 # select count(*) from t1 -21 # select sum(a) from t1 -22 # select sum(a) from t1 group by b -23 # select sum(a) + sum(b) from t1 group by b -24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 -26 # select * from information_schema.profiling -27 # select query_id, state, duration from information_schema.profiling -28 # select query_id, sum(duration) from information_schema.profiling group by query_id -29 # select query_id, count(*) from information_schema.profiling group by query_id -30 # select sum(duration) from information_schema.profiling -31 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id -32 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling -33 # drop table if exists t1, t2, t3 -34 # SHOW WARNINGS -35 # create table t1 (id int ) -36 # create table t2 (id int not null) -37 # create table t3 (id int not null primary key) -38 # insert into t1 values (1), (2), (3) -39 # insert into t2 values (1), (2), (3) -40 # insert into t3 values (1), (2), (3) -41 # select * from t1 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +25 # select * from information_schema.profiling +26 # select query_id, state, duration from information_schema.profiling +27 # select query_id, sum(duration) from information_schema.profiling group by query_id +28 # select query_id, count(*) from information_schema.profiling group by query_id +29 # select sum(duration) from information_schema.profiling +30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +32 # drop table if exists t1, t2, t3 +33 # SHOW WARNINGS +34 # create table t1 (id int ) +35 # create table t2 (id int not null) +36 # create table t3 (id int not null primary key) +37 # insert into t1 values (1), (2), (3) +38 # insert into t2 values (1), (2), (3) +39 # insert into t3 values (1), (2), (3) +40 # select * from t1 This ^^ should end in "select * from t1;" delete from t1; insert into t1 values (1), (2), (3); @@ -212,72 +211,72 @@ id 3 show profiles; Query_ID Duration Query -16 # select count(*) from t1 +15 # select count(*) from t1 +16 # insert into t1 select * from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # insert into t1 select * from t1 -20 # select count(*) from t1 -21 # select sum(a) from t1 -22 # select sum(a) from t1 group by b -23 # select sum(a) + sum(b) from t1 group by b -24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 -26 # select * from information_schema.profiling -27 # select query_id, state, duration from information_schema.profiling -28 # select query_id, sum(duration) from information_schema.profiling group by query_id -29 # select query_id, count(*) from information_schema.profiling group by query_id -30 # select sum(duration) from information_schema.profiling -31 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id -32 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling -33 # drop table if exists t1, t2, t3 -34 # SHOW WARNINGS -35 # create table t1 (id int ) -36 # create table t2 (id int not null) -37 # create table t3 (id int not null primary key) -38 # insert into t1 values (1), (2), (3) -39 # insert into t2 values (1), (2), (3) -40 # insert into t3 values (1), (2), (3) -41 # select * from t1 -42 # delete from t1 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +25 # select * from information_schema.profiling +26 # select query_id, state, duration from information_schema.profiling +27 # select query_id, sum(duration) from information_schema.profiling group by query_id +28 # select query_id, count(*) from information_schema.profiling group by query_id +29 # select sum(duration) from information_schema.profiling +30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +32 # drop table if exists t1, t2, t3 +33 # SHOW WARNINGS +34 # create table t1 (id int ) +35 # create table t2 (id int not null) +36 # create table t3 (id int not null primary key) +37 # insert into t1 values (1), (2), (3) +38 # insert into t2 values (1), (2), (3) +39 # insert into t3 values (1), (2), (3) +40 # select * from t1 +41 # delete from t1 +42 # insert into t1 values (1), (2), (3) 43 # insert into t1 values (1), (2), (3) -44 # insert into t1 values (1), (2), (3) -45 # select * from t1 +44 # select * from t1 set session profiling = OFF; select sum(id) from t1; sum(id) 12 show profiles; Query_ID Duration Query -16 # select count(*) from t1 +15 # select count(*) from t1 +16 # insert into t1 select * from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # insert into t1 select * from t1 -20 # select count(*) from t1 -21 # select sum(a) from t1 -22 # select sum(a) from t1 group by b -23 # select sum(a) + sum(b) from t1 group by b -24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 -26 # select * from information_schema.profiling -27 # select query_id, state, duration from information_schema.profiling -28 # select query_id, sum(duration) from information_schema.profiling group by query_id -29 # select query_id, count(*) from information_schema.profiling group by query_id -30 # select sum(duration) from information_schema.profiling -31 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id -32 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling -33 # drop table if exists t1, t2, t3 -34 # SHOW WARNINGS -35 # create table t1 (id int ) -36 # create table t2 (id int not null) -37 # create table t3 (id int not null primary key) -38 # insert into t1 values (1), (2), (3) -39 # insert into t2 values (1), (2), (3) -40 # insert into t3 values (1), (2), (3) -41 # select * from t1 -42 # delete from t1 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +25 # select * from information_schema.profiling +26 # select query_id, state, duration from information_schema.profiling +27 # select query_id, sum(duration) from information_schema.profiling group by query_id +28 # select query_id, count(*) from information_schema.profiling group by query_id +29 # select sum(duration) from information_schema.profiling +30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +32 # drop table if exists t1, t2, t3 +33 # SHOW WARNINGS +34 # create table t1 (id int ) +35 # create table t2 (id int not null) +36 # create table t3 (id int not null primary key) +37 # insert into t1 values (1), (2), (3) +38 # insert into t2 values (1), (2), (3) +39 # insert into t3 values (1), (2), (3) +40 # select * from t1 +41 # delete from t1 +42 # insert into t1 values (1), (2), (3) 43 # insert into t1 values (1), (2), (3) -44 # insert into t1 values (1), (2), (3) -45 # select * from t1 +44 # select * from t1 set session profiling = ON; select @@profiling; @@profiling diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 5fd83ce70c6..91b0b062e4f 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -168,10 +168,14 @@ QUERY_PROFILE::QUERY_PROFILE(PROFILING *profiling_arg, char *query_source_arg, void QUERY_PROFILE::set_query_source(char *query_source_arg, uint query_length_arg) { + if (! profiling->enabled) + return; + /* Truncate to avoid DoS attacks. */ uint length= min(MAX_QUERY_LENGTH, query_length_arg); /* TODO?: Provide a way to include the full text, as in SHOW PROCESSLIST. */ + DBUG_ASSERT(query_source == NULL); if (query_source_arg != NULL) query_source= my_strdup_with_length(query_source_arg, length, MYF(0)); } @@ -445,7 +449,7 @@ bool QUERY_PROFILE::show(uint options) } PROFILING::PROFILING() - :profile_id_counter(1), keeping(1), current(NULL), last(NULL) + :profile_id_counter(1), keeping(TRUE), enabled(FALSE), current(NULL), last(NULL) { } @@ -464,7 +468,7 @@ void PROFILING::status_change(const char *status_arg, { DBUG_ENTER("PROFILING::status_change"); - if (unlikely((thd->options & OPTION_PROFILING) != 0)) + if (unlikely(enabled)) { if (unlikely(current == NULL)) reset(); @@ -499,6 +503,8 @@ void PROFILING::store() if (current != NULL) { if (keeping && + (enabled) && /* ON at start? */ + (((thd)->options & OPTION_PROFILING) != 0) && /* and ON at end? */ (current->query_source != NULL) && (current->query_source[0] != '\0') && (!current->entries.is_empty())) @@ -517,7 +523,8 @@ void PROFILING::store() } DBUG_ASSERT(current == NULL); - current= new QUERY_PROFILE(this, thd->query, thd->query_length); + if (enabled) + current= new QUERY_PROFILE(this, thd->query, thd->query_length); DBUG_VOID_RETURN; } @@ -534,7 +541,12 @@ void PROFILING::reset() store(); if (likely(((thd)->options & OPTION_PROFILING) == 0)) + { + enabled= FALSE; DBUG_VOID_RETURN; + } + else + enabled= TRUE; if (current != NULL) current->reset(); diff --git a/sql/sql_profile.h b/sql/sql_profile.h index 7913d037551..b82b5ce090c 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -277,6 +277,7 @@ private: query_id_t profile_id_counter; THD *thd; bool keeping; + bool enabled; QUERY_PROFILE *current; QUERY_PROFILE *last; From d1c5f54ba5420f5b0c286c1ca74abd8989c7cbf9 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 10 Apr 2007 16:47:07 -0400 Subject: [PATCH 31/33] Use platform-independent mysqltest language. --- mysql-test/t/mysqlcheck.test | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test index eb732a05909..5efe6ade6bb 100644 --- a/mysql-test/t/mysqlcheck.test +++ b/mysql-test/t/mysqlcheck.test @@ -39,8 +39,9 @@ use d_bug25347; create table t_bug25347 (a int); create view v_bug25347 as select * from t_bug25347; --echo removing and creating ---exec rm $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI; ---exec touch $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI; +--remove_file $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI +--write_file $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI EOF +EOF --exec $MYSQL_CHECK --repair --databases d_bug25347 drop view v_bug25347; drop table t_bug25347; From a318c75af76c8676cfe45dc154685a6e0e283cfa Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 16 Apr 2007 15:00:16 -0400 Subject: [PATCH 32/33] Bug#25347: mysqlcheck -A -r doesn't repair table marked as crashed Additional changes to test: "flush tables" so that Windows releases the files. mysql-test/r/mysqlcheck.result: Add "flush tables" to get windows to release the files, so that we can test truncation properly. mysql-test/t/mysqlcheck.test: Add "flush tables" to get windows to release the files, so that we can test truncation properly. --- mysql-test/r/mysqlcheck.result | 27 ++++++++++++++++++++++++++- mysql-test/t/mysqlcheck.test | 8 ++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result index 81a30267e04..1c42b0060f7 100644 --- a/mysql-test/r/mysqlcheck.result +++ b/mysql-test/r/mysqlcheck.result @@ -45,8 +45,33 @@ create database d_bug25347; use d_bug25347; create table t_bug25347 (a int); create view v_bug25347 as select * from t_bug25347; +insert into t_bug25347 values (1),(2),(3); +flush tables; removing and creating -d_bug25347.t_bug25347 OK +d_bug25347.t_bug25347 +error : Incorrect file format 't_bug25347' +insert into t_bug25347 values (4),(5),(6); +ERROR HY000: Incorrect file format 't_bug25347' +d_bug25347.t_bug25347 +warning : Number of rows changed from 0 to 3 +status : OK +insert into t_bug25347 values (7),(8),(9); +select * from t_bug25347; +a +1 +2 +3 +7 +8 +9 +select * from v_bug25347; +a +1 +2 +3 +7 +8 +9 drop view v_bug25347; drop table t_bug25347; drop database d_bug25347; diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test index 5efe6ade6bb..655ff39001c 100644 --- a/mysql-test/t/mysqlcheck.test +++ b/mysql-test/t/mysqlcheck.test @@ -38,11 +38,19 @@ create database d_bug25347; use d_bug25347; create table t_bug25347 (a int); create view v_bug25347 as select * from t_bug25347; +insert into t_bug25347 values (1),(2),(3); +flush tables; --echo removing and creating --remove_file $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI --write_file $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI EOF EOF --exec $MYSQL_CHECK --repair --databases d_bug25347 +--error 130 +insert into t_bug25347 values (4),(5),(6); +--exec $MYSQL_CHECK --repair --use-frm --databases d_bug25347 +insert into t_bug25347 values (7),(8),(9); +select * from t_bug25347; +select * from v_bug25347; drop view v_bug25347; drop table t_bug25347; drop database d_bug25347; From 2b4a89561378fb1dca2a70e52afb2ca0562e12ee Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 24 Apr 2007 18:11:55 -0400 Subject: [PATCH 33/33] Wrap code specific to the comunity-server in additional CPP #ifdef . Add a new autoconf paremeter --{en,dis}able-community-features . The default is disable for enterprise servers. Though this is a 5.0 tree, it is only to be merged into the 5.0-community tree and the global 5.1 tree, never to the 5.0-enterprise tree. configure.in: Add a new configure parameter, --enable-community-features for community features. mysql-test/t/profiling.test: Add testing for whether profiling is enabled or not. sql/mysqld.cc: Add additional "COMMUNITY_SERVER" cpp definition test. sql/set_var.cc: Add additional "COMMUNITY_SERVER" cpp definition test. sql/sql_class.cc: Add additional "COMMUNITY_SERVER" cpp definition test. sql/sql_class.h: Add additional "COMMUNITY_SERVER" cpp definition test. sql/sql_parse.cc: Add additional "COMMUNITY_SERVER" cpp definition test. sql/sql_prepare.cc: Add additional "COMMUNITY_SERVER" cpp definition test. sql/sql_profile.cc: Add additional "COMMUNITY_SERVER" cpp definition test. sql/sql_profile.h: Add additional "COMMUNITY_SERVER" cpp definition test. sql/sql_show.cc: Add "COMMUNITY_SERVER" cpp definition test. mysql-test/include/profiling.inc: Add testing for whether profiling is enabled or not. mysql-test/r/profiling.require: Add testing for whether profiling is enabled or not. --- configure.in | 33 ++++++++++++++++++++++++++++---- mysql-test/include/profiling.inc | 4 ++++ mysql-test/r/profiling.require | 2 ++ mysql-test/t/profiling.test | 2 ++ sql/mysqld.cc | 4 +++- sql/set_var.cc | 6 +++--- sql/sql_class.cc | 2 +- sql/sql_class.h | 2 +- sql/sql_parse.cc | 8 ++++---- sql/sql_prepare.cc | 2 +- sql/sql_profile.cc | 4 ++-- sql/sql_profile.h | 2 +- sql/sql_show.cc | 2 ++ 13 files changed, 55 insertions(+), 18 deletions(-) create mode 100644 mysql-test/include/profiling.inc create mode 100644 mysql-test/r/profiling.require diff --git a/configure.in b/configure.in index f1a71d49359..a4ad7b5d875 100644 --- a/configure.in +++ b/configure.in @@ -9,6 +9,7 @@ AC_CANONICAL_SYSTEM # remember to also change ndb version below and update version.c in ndb AM_INIT_AUTOMAKE(mysql, 5.0.39) AM_CONFIG_HEADER(config.h) +is_this_community_tree=yes PROTOCOL_VERSION=10 DOT_FRM_VERSION=6 @@ -612,6 +613,23 @@ then fi fi +AC_MSG_CHECKING(whether features provided by the user community should be included.) +AC_ARG_ENABLE(community-features, + AC_HELP_STRING( + [--enable-community-features], + [Enable additional features provided by the user community.]), + [ ENABLE_COMMUNITY_FEATURES=$enableval ], + [ ENABLE_COMMUNITY_FEATURES=$is_this_community_tree ] + ) + +if test "$ENABLE_COMMUNITY_FEATURES" = "yes" +then + AC_DEFINE([COMMUNITY_SERVER], [1], + [Whether features provided by the user community should be included]) + AC_MSG_RESULT([yes, community server]) +else + AC_MSG_RESULT([no, enterprise server]) +fi AC_ARG_WITH(server-suffix, [ --with-server-suffix Append value to the version string.], @@ -676,16 +694,23 @@ else fi # Add query profiler +AC_MSG_CHECKING(if SHOW PROFILE should be enabled.) AC_ARG_ENABLE(profiling, AS_HELP_STRING([--disable-profiling], [Build a version without query profiling code]), [ ENABLED_PROFILING=$enableval ], - [ ENABLED_PROFILING=yes ]) + [ ENABLED_PROFILING=$is_this_community_tree ]) if test "$ENABLED_PROFILING" = "yes" then - AC_DEFINE([ENABLED_PROFILING], [1], - [If SHOW PROFILE should be enabled]) - AC_MSG_RESULT([yes]) + if test "$ENABLE_COMMUNITY_FEATURES" = "yes"; + then + AC_DEFINE([ENABLED_PROFILING], [1], + [If SHOW PROFILE should be enabled]) + AC_MSG_RESULT([yes]) + else + ENABLED_PROFILING="no" + AC_MSG_RESULT([no, overridden by community-features disabled]) + fi else AC_MSG_RESULT([no]) fi diff --git a/mysql-test/include/profiling.inc b/mysql-test/include/profiling.inc new file mode 100644 index 00000000000..bc2228eaa10 --- /dev/null +++ b/mysql-test/include/profiling.inc @@ -0,0 +1,4 @@ +-- require r/profiling.require +disable_query_log; +show variables like "profiling"; +enable_query_log; diff --git a/mysql-test/r/profiling.require b/mysql-test/r/profiling.require new file mode 100644 index 00000000000..a5f2b71f22a --- /dev/null +++ b/mysql-test/r/profiling.require @@ -0,0 +1,2 @@ +Variable_name Value +profiling OFF diff --git a/mysql-test/t/profiling.test b/mysql-test/t/profiling.test index fd7562f6f16..549d075d227 100644 --- a/mysql-test/t/profiling.test +++ b/mysql-test/t/profiling.test @@ -1,3 +1,5 @@ +--source include/profiling.inc + # default is OFF show session variables like 'profil%'; select @@profiling; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 864570f67b4..8ea6d99c0e1 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5346,7 +5346,7 @@ Disable with --skip-ndbcluster (will save memory).", "Maximum time in seconds to wait for the port to become free. " "(Default: no wait)", (gptr*) &mysqld_port_timeout, (gptr*) &mysqld_port_timeout, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) {"profiling_history_size", OPT_PROFILING, "Limit of query profiling memory", (gptr*) &global_system_variables.profiling_history_size, (gptr*) &max_system_variables.profiling_history_size, @@ -7685,7 +7685,9 @@ void refresh_status(THD *thd) /* Reset the counters of all key caches (default and named). */ process_key_caches(reset_key_cache_counters); +#ifdef COMMUNITY_SERVER flush_status_time= time((time_t*) 0); +#endif pthread_mutex_unlock(&LOCK_status); /* diff --git a/sql/set_var.cc b/sql/set_var.cc index 49d224595c5..7c79dd0be5c 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -544,7 +544,7 @@ static sys_var_thd_bit sys_unique_checks("unique_checks", 0, set_option_bit, OPTION_RELAXED_UNIQUE_CHECKS, 1); -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) static sys_var_thd_bit sys_profiling("profiling", NULL, set_option_bit, ulonglong(OPTION_PROFILING)); static sys_var_thd_ulong sys_profiling_history_size("profiling_history_size", @@ -706,7 +706,7 @@ sys_var *sys_variables[]= &sys_optimizer_prune_level, &sys_optimizer_search_depth, &sys_preload_buff_size, -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) &sys_profiling, &sys_profiling_history_size, #endif @@ -1021,7 +1021,7 @@ struct show_var_st init_vars[]= { {"pid_file", (char*) pidfile_name, SHOW_CHAR}, {"port", (char*) &mysqld_port, SHOW_INT}, {sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS}, -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) {sys_profiling.name, (char*) &sys_profiling, SHOW_SYS}, {sys_profiling_history_size.name, (char*) &sys_profiling_history_size, SHOW_SYS}, #endif diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 7a2f58a1376..2d056328220 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -253,7 +253,7 @@ THD::THD() init(); /* Initialize sub structures */ init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE); -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) profiling.set_thd(this); #endif user_connect=(USER_CONN *)0; diff --git a/sql/sql_class.h b/sql/sql_class.h index a9a828e80c8..34d230ae5a7 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1360,7 +1360,7 @@ public: List warn_list; uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END]; uint total_warn_count; -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) PROFILING profiling; #endif diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 3eb61e29270..14a84abd7ae 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2746,7 +2746,7 @@ mysql_execute_command(THD *thd) } case SQLCOM_SHOW_PROFILES: { -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.store(); thd->profiling.discard(); res= thd->profiling.show_profiles(); @@ -2760,7 +2760,7 @@ mysql_execute_command(THD *thd) } case SQLCOM_SHOW_PROFILE: { -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.store(); thd->profiling.discard(); // will get re-enabled by reset() if (lex->profile_query_id != 0) @@ -5730,7 +5730,7 @@ mysql_init_query(THD *thd, uchar *buf, uint length) DBUG_ENTER("mysql_init_query"); lex_start(thd, buf, length); mysql_reset_thd_for_next_command(thd); -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.reset(); #endif DBUG_VOID_RETURN; @@ -5774,7 +5774,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; -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.reset(); #endif } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 9d2c23c720f..99cd5638d40 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2231,7 +2231,7 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute"))) DBUG_VOID_RETURN; -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.set_query_source(stmt->query, stmt->query_length); #endif DBUG_PRINT("exec_query", ("%s", stmt->query)); diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 91b0b062e4f..77dea4f9954 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -31,7 +31,7 @@ const char * const _unknown_func_ = ""; int fill_query_profile_statistics_info(THD *thd, struct st_table_list *tables, Item *cond) { -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) return(thd->profiling.fill_statistics_info(thd, tables, cond)); #else return(1); @@ -62,7 +62,7 @@ ST_FIELD_INFO query_profile_statistics_info[]= {NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL} }; -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) #define RUSAGE_USEC(tv) ((tv).tv_sec*1000*1000 + (tv).tv_usec) #define RUSAGE_DIFF_USEC(tv1, tv2) (RUSAGE_USEC((tv1))-RUSAGE_USEC((tv2))) diff --git a/sql/sql_profile.h b/sql/sql_profile.h index b82b5ce090c..c070f2f72d7 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -53,7 +53,7 @@ int fill_query_profile_statistics_info(THD *thd, struct st_table_list *tables, I #define PROFILE_ALL (~0) -#ifndef ENABLED_PROFILING +#if !defined(ENABLED_PROFILING) || !defined(COMMUNITY_SERVER) # define thd_proc_info(thd, msg) do { (thd)->proc_info= (msg); } while (0) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 7da4ac55e92..8022efbc71d 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1496,10 +1496,12 @@ static bool show_status_array(THD *thd, const char *wild, nr= (long) (thd->query_start() - server_start_time); end= int10_to_str(nr, buff, 10); break; +#ifdef COMMUNITY_SERVER case SHOW_FLUSHTIME: nr= (long) (thd->query_start() - flush_status_time); end= int10_to_str(nr, buff, 10); break; +#endif case SHOW_QUESTION: end= int10_to_str((long) thd->query_id, buff, 10); break;