diff options
62 files changed, 2150 insertions, 315 deletions
diff --git a/BitKeeper/etc/collapsed b/BitKeeper/etc/collapsed index 8dcf561b845..64dfcb27d17 100644 --- a/BitKeeper/etc/collapsed +++ b/BitKeeper/etc/collapsed @@ -35,9 +35,25 @@ 459a70691aYIfU2ohV0a3P5iTLpO2A 459a7422KF_P7PuU3YQ5qG6ZLEVpiA 459a74e4nRcXppMSBYeQQ5efDkTADg +459c03b9N_mqF2XJKK6DwSrIt7e6_g +459c1965_BQMBzBO8S_gVqjTHYQrmw +459c2098XoAUsUn8N07IVRDD6CTM-A +459ea845XenN-uWqEM5LFvUT60tW_A 45ae6628gqKTsUFfnoNExadETVIkbA +45af88c9RIIJWPfBxs3o7zekI-ELPQ 45ba4faf2oqu6eR8fqecR3LfSNcYUg 45ba5238-NKl80QVXzdGo8hO9M75Xg 45c0fdfb2mz6NdOIsLenJtf6_ZelTA +45c38d90tNwOTSaYKHXd3ccLtnytlQ +45c390d6BbWrwyEi5T5VsWKYxl06Rg +45c39d31g0iik6UE_oTK5N55ry-ycA 45d1ffcd-r3v8A7uh92hQaMfQM9UPQ 45d21437Vg_-i4uOWyvzYWHESXDP6A +45da6370nnZlAAIieMCrXkxF9toOyQ +45da6551zUuplwxuqcT2fhRgceC0CQ +45db0d4bkGtxBk21sZFJgbCV1FcNRg +45db468b-DKE8kUTV42eYMYmk8_g9g +45dd21d1rVPnDfvZTNVHLalcjnbsZw +45ddaf15_Ld7IAEpUUP3FJjJ-oSEFg +45ddc763DodLG1BqH_wRBJXMbCSB5A +45ddc8282KnaNGuijqCTphlXV_eeog diff --git a/BitKeeper/triggers/post-commit b/BitKeeper/triggers/post-commit index d8fabe59bba..468f60bbe21 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 diff --git a/VC++Files/sql/mysqld.vcproj b/VC++Files/sql/mysqld.vcproj index 97468c2045b..802ca638c90 100644 --- a/VC++Files/sql/mysqld.vcproj +++ b/VC++Files/sql/mysqld.vcproj @@ -1017,6 +1017,9 @@ RelativePath="sql_prepare.cpp"> </File> <File + RelativePath="sql_profile.cpp"> + </File> + <File RelativePath="sql_rename.cpp"> </File> <File 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/configure.in b/configure.in index 6cf8dbd4e47..7774e53bedf 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.44) +AM_INIT_AUTOMAKE(mysql, 5.0.45) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 @@ -23,7 +23,7 @@ NDB_SHARED_LIB_VERSION=$NDB_SHARED_LIB_MAJOR_VERSION:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=44 +NDB_VERSION_BUILD=45 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? @@ -703,6 +703,20 @@ else AC_MSG_RESULT([no]) fi +# Add query profiler +AC_ARG_ENABLE(profiling, + AS_HELP_STRING([--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, @@ -806,6 +820,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)) @@ -1127,7 +1142,6 @@ case $SYSTEM_TYPE in fi ;; *darwin*) - AC_DEFINE([DEFAULT_SKIP_THREAD_PRIORITY], [1], [default to skip thread priority]) if test "$ac_cv_prog_gcc" = "yes" then FLAGS="-D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT" @@ -2627,14 +2641,12 @@ thread_dirs= dnl This probably should be cleaned up more - for now the threaded dnl client is just using plain-old libs. -sql_client_dirs= +sql_client_dirs="strings regex mysys libmysql client" linked_client_targets="linked_libmysql_sources" -if test "$THREAD_SAFE_CLIENT" = "no" +if test "$THREAD_SAFE_CLIENT" != "no" then - sql_client_dirs="strings regex mysys dbug extra libmysql client" -else - sql_client_dirs="strings regex mysys dbug extra libmysql libmysql_r client" + sql_client_dirs="libmysql_r $sql_client_dirs" linked_client_targets="$linked_client_targets linked_libmysql_r_sources" AC_CONFIG_FILES(libmysql_r/Makefile) AC_DEFINE([THREAD_SAFE_CLIENT], [1], [Should be client be thread safe]) @@ -2663,17 +2675,13 @@ AM_CONDITIONAL(HAVE_NETWARE, test "$netware_dir" = "netware") export CC CXX CFLAGS CXXFLAGS LD LDFLAGS AR ac_configure_args="$ac_configure_args CFLAGS='$CFLAGS' CXXFLAGS='$CXXFLAGS'" -if test "$with_server" != "no" -o "$THREAD_SAFE_CLIENT" != "no" +if test "$with_server" = "yes" -o "$THREAD_SAFE_CLIENT" != "no" then AC_DEFINE([THREAD], [1], [Define if you want to have threaded code. This may be undef on client code]) # Avoid _PROGRAMS names THREAD_LOBJECTS="thr_alarm.o thr_lock.o thr_mutex.o thr_rwlock.o my_pthread.o my_thr_init.o mf_keycache.o" AC_SUBST(THREAD_LOBJECTS) -fi - -if test "$with_server" != "no" -then server_scripts="mysqld_safe mysql_install_db" sql_server_dirs="strings mysys dbug extra regex" diff --git a/include/config-win.h b/include/config-win.h index 279be7aa5e4..a45ee5e4eb3 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/include/my_dbug.h b/include/my_dbug.h index 31fd507ec73..9aa8ef3c197 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) #define IF_DBUG(A) A #else /* No debugger */ diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index 81da1e43cc9..17e308b3324 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/myisam/mi_open.c b/myisam/mi_open.c index 274933679ef..81867d997aa 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/bdb_notembedded.result b/mysql-test/r/bdb_notembedded.result deleted file mode 100644 index 14cb5fad915..00000000000 --- a/mysql-test/r/bdb_notembedded.result +++ /dev/null @@ -1,35 +0,0 @@ -set autocommit=1; -reset master; -create table bug16206 (a int); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -show binlog events; -Log_name Pos Event_type Server_id End_log_pos Info -f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4 -f n Query 1 n use `test`; create table bug16206 (a int) -f n Query 1 n use `test`; insert into bug16206 values(1) -f n Query 1 n use `test`; insert into bug16206 values(2) -drop table bug16206; -reset master; -create table bug16206 (a int) engine= bdb; -insert into bug16206 values(0); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -insert into bug16206 values(3); -show binlog events; -Log_name Pos Event_type Server_id End_log_pos Info -f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4 -f n Query 1 n use `test`; create table bug16206 (a int) engine= bdb -f n Query 1 n use `test`; insert into bug16206 values(0) -f n Query 1 n use `test`; insert into bug16206 values(1) -f n Query 1 n use `test`; BEGIN -f n Query 1 n use `test`; insert into bug16206 values(2) -f n Query 1 n use `test`; COMMIT -f n Query 1 n use `test`; insert into bug16206 values(3) -drop table bug16206; -set autocommit=0; -End of 5.0 tests diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 4947fd7aecc..aff0ba94f13 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,7 +1095,7 @@ 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(20) information_schema.COLUMNS,information_schema.PROFILING 2 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; @@ -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 @@ -1305,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 @@ -1326,3 +1330,10 @@ v2 YES delete from v1; drop view v1,v2; drop table t1,t2; +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/r/information_schema_db.result b/mysql-test/r/information_schema_db.result index 2d330dda333..3243c0aa4c9 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/mysqlcheck.result b/mysql-test/r/mysqlcheck.result index b2820df8f4c..1c42b0060f7 100644 --- a/mysql-test/r/mysqlcheck.result +++ b/mysql-test/r/mysqlcheck.result @@ -41,4 +41,39 @@ 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; +insert into t_bug25347 values (1),(2),(3); +flush tables; +removing and creating +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; +use test; End of 5.0 tests 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/profiling.result b/mysql-test/r/profiling.result new file mode 100644 index 00000000000..b99870e3564 --- /dev/null +++ b/mysql-test/r/profiling.result @@ -0,0 +1,368 @@ +show profiles; +Query_ID Duration Query +show profile all; +Status Duration 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 +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 +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 +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 = 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/bdb_notembedded.test b/mysql-test/t/bdb_notembedded.test deleted file mode 100644 index 24e64ebbfb2..00000000000 --- a/mysql-test/t/bdb_notembedded.test +++ /dev/null @@ -1,38 +0,0 @@ --- source include/not_embedded.inc --- source include/have_bdb.inc - -# -# Bug #16206: Superfluous COMMIT event in binlog when updating BDB in autocommit mode -# -set autocommit=1; - -let $VERSION=`select version()`; - -reset master; -create table bug16206 (a int); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; ---replace_result $VERSION VERSION ---replace_column 1 f 2 n 5 n -show binlog events; -drop table bug16206; - -reset master; -create table bug16206 (a int) engine= bdb; -insert into bug16206 values(0); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -insert into bug16206 values(3); ---replace_result $VERSION VERSION ---replace_column 1 f 2 n 5 n -show binlog events; -drop table bug16206; - -set autocommit=0; - - ---echo End of 5.0 tests diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 1d368ac6075..bdbe2a264e5 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 # @@ -1022,6 +1019,14 @@ where t.table_schema = 'information_schema' and (c2.column_type = 'varchar(7)' or c2.column_type = 'varchar(20)') group by c2.column_type order by num limit 1) group by t.table_name order by num1, t.table_name; +# 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 + # # Bug#28266 IS_UPDATABLE field on VIEWS table in I_S database is wrong diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test index f4e18d4004f..655ff39001c 100644 --- a/mysql-test/t/mysqlcheck.test +++ b/mysql-test/t/mysqlcheck.test @@ -31,4 +31,29 @@ 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; +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; +use test; + --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..960aa496731 --- /dev/null +++ b/mysql-test/t/profiling.test @@ -0,0 +1,200 @@ +# Verify that the protocol isn't violated if we ask for profiling info +# before profiling has recorded anything. +show profiles; +show profile all; + +# 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/common/util/File.cpp b/ndb/src/common/util/File.cpp index a75fa5ae463..4c96319eed7 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; diff --git a/ndb/src/ndbapi/DictCache.cpp b/ndb/src/ndbapi/DictCache.cpp index 6a815067233..725eab24f5f 100644 --- a/ndb/src/ndbapi/DictCache.cpp +++ b/ndb/src/ndbapi/DictCache.cpp @@ -293,7 +293,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/CMakeLists.txt b/sql/CMakeLists.txt index 1f02e3afc67..f5282b030f1 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -74,6 +74,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_profile.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h ${PROJECT_SOURCE_DIR}/include/mysqld_error.h diff --git a/sql/Makefile.am b/sql/Makefile.am index fae35222128..25a593a39b4 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -53,6 +53,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 ha_ndbcluster_cond.h \ @@ -82,6 +83,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 e2a2211259f..1ff9ec0130e 100644 --- a/sql/ha_archive.cc +++ b/sql/ha_archive.cc @@ -1209,7 +1209,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); @@ -1233,7 +1233,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_berkeley.cc b/sql/ha_berkeley.cc index 2a5fe775ca6..5e0c2ff51fd 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -1865,8 +1865,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 9a397ffbbac..4250e2befc4 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -673,7 +673,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"; @@ -747,7 +747,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; } @@ -1029,22 +1029,22 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool do_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); @@ -1058,7 +1058,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool do_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)) @@ -1066,14 +1066,14 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool do_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)) @@ -1111,7 +1111,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool do_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 : @@ -1336,7 +1336,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 | @@ -1361,7 +1361,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/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 1202a733a16..389df51f693 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -108,7 +108,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 47815f0fbf1..801bc095cdc 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -6025,14 +6025,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 ed0c09f0b32..95e62aa62e9 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -3932,7 +3932,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 ab4a9c50332..990991ad387 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3399,7 +3399,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; @@ -3424,7 +3424,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); @@ -3511,7 +3511,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; @@ -3554,7 +3554,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 352d80da5c6..33217ee4bc4 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -87,6 +87,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)}, @@ -125,8 +126,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)}, @@ -192,6 +195,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)}, @@ -251,7 +255,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)}, @@ -309,6 +315,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 */ @@ -356,6 +363,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)}, @@ -370,6 +378,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)}, @@ -437,6 +447,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)}, @@ -471,6 +482,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 9298b33b4d2..4992e8b7b67 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="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="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=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=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 6eb247488b0..a898540e9a1 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4434,7 +4434,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, @@ -4488,7 +4488,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) */ @@ -4608,7 +4608,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 @@ -4642,7 +4642,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 0aaa1744fe1..1ce8822cb6f 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -193,6 +193,8 @@ MY_LOCALE *my_locale_by_number(uint number); #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 @@ -360,6 +362,8 @@ MY_LOCALE *my_locale_by_number(uint number); fulltext functions when reading from it. */ #define TMP_TABLE_FORCE_MYISAM (ULL(1) << 32) +#define OPTION_PROFILING (ULL(1) << 33) + /* @@ -562,6 +566,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 @@ -1245,7 +1251,7 @@ void my_dbopt_free(void); External variables */ -extern time_t server_start_time; +extern time_t server_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 ec32e237a01..d09eb7a7739 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -445,7 +445,7 @@ ulong slow_launch_threads = 0, sync_binlog_period; ulong expire_logs_days = 0; ulong rpl_recovery_rank=0; -time_t server_start_time; +time_t server_start_time, flush_status_time; char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], system_time_zone[30]; char *default_tz_name; @@ -1688,7 +1688,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); @@ -2664,7 +2664,7 @@ static int init_common_variables(const char *conf_file_name, int argc, tzset(); // Set tzname max_system_variables.pseudo_thread_id= (ulong)~0; - server_start_time= time((time_t*) 0); + server_start_time= flush_status_time= time((time_t*) 0); if (init_thread_environment()) return 1; mysql_init_variables(); @@ -4818,6 +4818,7 @@ enum options_mysqld OPT_TABLE_LOCK_WAIT_TIMEOUT, OPT_PORT_OPEN_TIMEOUT, OPT_MERGE, + OPT_PROFILING, OPT_INNODB_ROLLBACK_ON_TIMEOUT, OPT_SECURE_FILE_PRIV }; @@ -5396,6 +5397,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_ULONG, 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, @@ -6423,6 +6430,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} }; @@ -7729,6 +7737,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/repl_failsafe.cc b/sql/repl_failsafe.cc index 1dc16b6e566..6c403065d19 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); @@ -600,7 +600,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) { @@ -944,7 +944,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)) @@ -971,7 +971,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 */, @@ -983,7 +983,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 09cdc34f803..7524af44a52 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -546,6 +546,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)); +static sys_var_thd_ulong sys_profiling_history_size("profiling_history_size", + &SV::profiling_history_size); +#endif /* Local state variables */ @@ -702,6 +708,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, @@ -1015,6 +1025,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}, @@ -2894,7 +2908,7 @@ 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; + thd->options&= ~OPTION_BEGIN; thd->no_trans_update.all= FALSE; thd->server_status|= SERVER_STATUS_AUTOCOMMIT; if (ha_commit(thd)) diff --git a/sql/slave.cc b/sql/slave.cc index 84f409d7f34..43032db576d 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1561,8 +1561,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; @@ -1576,7 +1576,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)) { @@ -1585,7 +1585,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)) { @@ -1597,7 +1597,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 @@ -2927,9 +2927,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); @@ -3490,7 +3490,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)) { @@ -3517,7 +3517,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; @@ -3528,7 +3528,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; } @@ -3537,7 +3537,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()"); @@ -3549,7 +3549,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 @@ -3573,7 +3573,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, @@ -3600,7 +3600,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"); event_len= read_event(mysql, mi, &suppress_warnings); if (io_slave_killed(thd,mi)) { @@ -3628,7 +3628,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 @@ -3647,7 +3647,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, @@ -3664,7 +3664,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)) { @@ -3746,7 +3746,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 */ @@ -3923,7 +3923,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)) @@ -3955,7 +3955,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 a98fe5027c9..9584bd94dc0 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2400,9 +2400,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 ed006714143..54b44670f3c 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -361,7 +361,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, @@ -417,7 +417,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); @@ -618,7 +618,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; @@ -1188,7 +1188,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); @@ -1196,7 +1196,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; } @@ -2304,7 +2304,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) { @@ -2320,12 +2320,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); } @@ -2626,7 +2626,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 @@ -2854,7 +2854,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) @@ -2928,7 +2928,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; @@ -2962,7 +2962,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); } @@ -3182,7 +3182,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); @@ -3215,7 +3215,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); } } @@ -6140,7 +6140,7 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order) List_iterator<Item_func_match> li(*(select_lex->ftfunc_list)); Item_func_match *ifm; DBUG_PRINT("info",("Performing FULLTEXT search")); - thd->proc_info="FULLTEXT initialization"; + thd_proc_info(thd, "FULLTEXT initialization"); while ((ifm=li++)) ifm->init_search(no_order); diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 33d658ce6a1..04521cf727b 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"));} @@ -669,6 +669,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) @@ -687,6 +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"); DUMP(&query_cache); BLOCK_LOCK_WR(query_block); // The following call will remove the lock on query_block @@ -724,6 +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"); DUMP(&query_cache); BLOCK_LOCK_WR(query_block); Query_cache_query *header= query_block->query(); @@ -1093,6 +1096,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); @@ -1172,6 +1177,7 @@ def_week_frmt: %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++) @@ -1264,6 +1270,7 @@ def_week_frmt: %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)", @@ -1341,9 +1348,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) { @@ -1374,9 +1383,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) { @@ -1426,6 +1437,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 010dc101e0d..8a97cf7f82d 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -253,6 +253,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, diff --git a/sql/sql_class.h b/sql/sql_class.h index 50c45d461e0..3061ac7ddc7 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -534,6 +534,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; @@ -1215,6 +1216,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; @@ -1369,6 +1373,10 @@ public: List <MYSQL_ERROR> 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 query_id is global in context of the whole MySQL server. diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index bccd4d4cafe..8bc2d7a63cc 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="init"; + thd_proc_info(thd, "init"); table->map=1; if (mysql_prepare_delete(thd, table_list, &conds)) @@ -214,7 +214,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) { @@ -282,7 +282,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) @@ -512,7 +512,7 @@ multi_delete::prepare(List<Item> &values, SELECT_LEX_UNIT *u) DBUG_ENTER("multi_delete::prepare"); unit= u; do_delete= 1; - thd->proc_info="deleting from main table"; + thd_proc_info(thd, "deleting from main table"); DBUG_RETURN(0); } @@ -788,7 +788,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 @@ -797,7 +797,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 @@ -942,7 +942,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 228fc8860ae..dff6f591a81 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -615,7 +615,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, DBUG_RETURN(TRUE); } - thd->proc_info="init"; + thd_proc_info(thd, "init"); thd->used_tables=0; values= its++; value_count= values->elements; @@ -701,7 +701,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) @@ -925,7 +925,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 @@ -1697,7 +1697,7 @@ I_List<Delayed_insert> delayed_threads; static Delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list) { - thd->proc_info="waiting for delay_list"; + thd_proc_info(thd, "waiting for delay_list"); pthread_mutex_lock(&LOCK_delayed_insert); // Protect master list I_List_iterator<Delayed_insert> it(delayed_threads); Delayed_insert *tmp; @@ -1759,7 +1759,7 @@ bool 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. @@ -1804,13 +1804,13 @@ bool 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.net.report_error) @@ -1882,13 +1882,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) @@ -1905,7 +1905,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); @@ -1986,11 +1986,11 @@ int write_delayed(THD *thd,TABLE *table,enum_duplicates duplic, bool ignore, 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; @@ -2212,7 +2212,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) @@ -2247,7 +2247,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) { @@ -2366,7 +2366,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 */ @@ -2374,7 +2374,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->needs_reopen_or_name_lock()) { @@ -2492,7 +2492,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))) { @@ -2511,14 +2511,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 cbfba3d4d80..35569df5809 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -201,7 +201,7 @@ void lex_start(THD *thd) 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; lex->in_sum_func= NULL; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index f8405ef14ca..8ad0b48ee25 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -94,8 +94,13 @@ 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, - /* This should be the last !!! */ + SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES, + /* + 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 }; @@ -1062,6 +1067,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_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 cf8209978a3..9b0fce13678 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -141,14 +141,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; + thd->options&= ~OPTION_BEGIN; thd->no_trans_update.all= FALSE; } DBUG_RETURN(error); @@ -174,7 +174,7 @@ static bool begin_trans(THD *thd) { LEX *lex= thd->lex; thd->no_trans_update.all= FALSE; - thd->options|= (ulong) OPTION_BEGIN; + thd->options|= OPTION_BEGIN; thd->server_status|= SERVER_STATUS_IN_TRANS; if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT) error= ha_start_consistent_snapshot(thd); @@ -1062,7 +1062,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 @@ -1166,7 +1166,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->init_for_queries(); @@ -1182,7 +1182,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->init_for_queries(); } @@ -1269,7 +1269,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)); @@ -1470,7 +1470,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; + thd->options&= ~OPTION_BEGIN; thd->no_trans_update.all= FALSE; break; case COMMIT_RELEASE: @@ -1488,7 +1488,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; + thd->options&= ~OPTION_BEGIN; thd->no_trans_update.all= FALSE; if (!res && (completion == ROLLBACK_AND_CHAIN)) res= begin_trans(thd); @@ -2143,7 +2143,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 */ } /* @@ -2166,9 +2166,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; @@ -2201,7 +2201,7 @@ void log_slow_statement(THD *thd) */ if (thd->enable_slow_log && !thd->user_time) { - thd->proc_info="logging slow query"; + thd_proc_info(thd, "logging slow query"); if ((ulong) (thd->start_time - thd->time_after_lock) > thd->variables.long_query_time || @@ -2211,6 +2211,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); } @@ -2318,6 +2319,15 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, break; } #endif + case SCH_PROFILES: + /* + Mark this current profiling record to be discarded. We don't + wish to have SHOW commands show up in profiling. + */ +#ifdef ENABLED_PROFILING + thd->profiling.discard(); +#endif + break; case SCH_OPEN_TABLES: case SCH_VARIABLES: case SCH_STATUS: @@ -2747,6 +2757,20 @@ mysql_execute_command(THD *thd) (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)); break; } + 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), "SHOW PROFILES", "enable-profiling"); + goto error; +#endif + break; + } case SQLCOM_SHOW_NEW_MASTER: { if (check_global_access(thd, REPL_SLAVE_ACL)) @@ -3669,7 +3693,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; @@ -3829,7 +3853,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); @@ -3855,7 +3879,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: @@ -4955,7 +4979,7 @@ create_sp_error: thd->transaction.xid_state.xid.set(thd->lex->xid); xid_cache_insert(&thd->transaction.xid_state); thd->no_trans_update.all= FALSE; - thd->options|= (ulong) OPTION_BEGIN; + thd->options|= OPTION_BEGIN; thd->server_status|= SERVER_STATUS_IN_TRANS; send_ok(thd); break; @@ -5048,7 +5072,7 @@ create_sp_error: xa_state_names[thd->transaction.xid_state.xa_state]); break; } - thd->options&= ~(ulong) OPTION_BEGIN; + thd->options&= ~OPTION_BEGIN; thd->no_trans_update.all= FALSE; thd->server_status&= ~SERVER_STATUS_IN_TRANS; xid_cache_delete(&thd->transaction.xid_state); @@ -5079,7 +5103,7 @@ create_sp_error: my_error(ER_XAER_RMERR, MYF(0)); else send_ok(thd); - thd->options&= ~(ulong) OPTION_BEGIN; + thd->options&= ~OPTION_BEGIN; thd->no_trans_update.all= FALSE; thd->server_status&= ~SERVER_STATUS_IN_TRANS; xid_cache_delete(&thd->transaction.xid_state); @@ -5095,7 +5119,7 @@ create_sp_error: send_ok(thd); break; } - thd->proc_info="query end"; + thd_proc_info(thd, "query end"); /* Two binlog-related cleanups: */ /* @@ -5279,6 +5303,7 @@ 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")); @@ -5841,6 +5866,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; } @@ -6084,7 +6112,7 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, thd->lex->sphead= 0; } 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_prepare.cc b/sql/sql_prepare.cc index f781d1372ad..951231537d8 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2245,6 +2245,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)); diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc new file mode 100644 index 00000000000..fbb05a988c5 --- /dev/null +++ b/sql/sql_profile.cc @@ -0,0 +1,646 @@ +/* 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; 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 + 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 "my_sys.h" + +#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 * const _unknown_func_ = "<unknown>"; + +/** + 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, "Query_id"}, + {"SEQ", 20, MYSQL_TYPE_LONG, 0, false, "Seq"}, + {"STATE", 30, MYSQL_TYPE_STRING, 0, false, "Status"}, + {"DURATION", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, false, "Duration"}, + {"CPU_USER", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, "CPU_user"}, + {"CPU_SYSTEM", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, "CPU_system"}, + {"CONTEXT_VOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, "Context_voluntary"}, + {"CONTEXT_INVOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, "Context_involuntary"}, + {"BLOCK_OPS_IN", 20, MYSQL_TYPE_LONG, 0, true, "Block_ops_in"}, + {"BLOCK_OPS_OUT", 20, MYSQL_TYPE_LONG, 0, true, "Block_ops_out"}, + {"MESSAGES_SENT", 20, MYSQL_TYPE_LONG, 0, true, "Messages_sent"}, + {"MESSAGES_RECEIVED", 20, MYSQL_TYPE_LONG, 0, true, "Messages_received"}, + {"PAGE_FAULTS_MAJOR", 20, MYSQL_TYPE_LONG, 0, true, "Page_faults_major"}, + {"PAGE_FAULTS_MINOR", 20, MYSQL_TYPE_LONG, 0, true, "Page_faults_minor"}, + {"SWAPS", 20, MYSQL_TYPE_LONG, 0, true, "Swaps"}, + {"SOURCE_FUNCTION", 30, MYSQL_TYPE_STRING, 0, true, "Source_function"}, + {"SOURCE_FILE", 20, MYSQL_TYPE_STRING, 0, true, "Source_file"}, + {"SOURCE_LINE", 20, MYSQL_TYPE_LONG, 0, true, "Source_line"}, + {NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL} +}; + + +int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table) +{ + int profile_options = thd->lex->profile_options; + int fields_include_condition_truth_values[]= { + FALSE, /* Query_id */ + FALSE, /* Seq */ + TRUE, /* Status */ + TRUE, /* Duration */ + profile_options & PROFILE_CPU, /* CPU_user */ + profile_options & PROFILE_CPU, /* CPU_system */ + profile_options & PROFILE_CONTEXT, /* Context_voluntary */ + profile_options & PROFILE_CONTEXT, /* Context_involuntary */ + profile_options & PROFILE_BLOCK_IO, /* Block_ops_in */ + profile_options & PROFILE_BLOCK_IO, /* Block_ops_out */ + profile_options & PROFILE_IPC, /* Messages_sent */ + profile_options & PROFILE_IPC, /* Messages_received */ + profile_options & PROFILE_PAGE_FAULTS, /* Page_faults_major */ + profile_options & PROFILE_PAGE_FAULTS, /* Page_faults_minor */ + profile_options & PROFILE_SWAPS, /* Swaps */ + profile_options & PROFILE_SOURCE, /* Source_function */ + profile_options & PROFILE_SOURCE, /* Source_file */ + profile_options & PROFILE_SOURCE, /* Source_line */ + }; + + ST_FIELD_INFO *field_info; + Name_resolution_context *context= &thd->lex->select_lex.context; + int i; + + for (i= 0; schema_table->fields_info[i].field_name != NULL; i++) + { + if (! fields_include_condition_truth_values[i]) + continue; + + field_info= &schema_table->fields_info[i]; + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); + if (field) + { + field->set_name(field_info->old_name, + strlen(field_info->old_name), + system_charset_info); + if (add_item_to_list(thd, field)) + return 1; + } + } + return 0; +} + + +#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() + :profile(NULL), status(NULL), function(NULL), file(NULL), line(0), + 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) + :profile(profile_arg) +{ + collect(); + set_status(status_arg, NULL, NULL, 0); +} + +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(); + set_status(status_arg, function_arg, file_arg, line_arg); +} + +PROFILE_ENTRY::~PROFILE_ENTRY() +{ + 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, const char *function_arg, const char *file_arg, unsigned int line_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. + */ + 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); + + 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_usecs= (double) my_getsystime() / 10.0; /* 1 sec was 1e7, now is 1e6 */ +#ifdef HAVE_GETRUSAGE + getrusage(RUSAGE_SELF, &rusage); +#endif +} + +QUERY_PROFILE::QUERY_PROFILE(PROFILING *profiling_arg, char *query_source_arg, + uint query_length_arg) + :profiling(profiling_arg), server_query_id(0), profiling_query_id(0), + query_source(NULL) +{ + profile_end= &profile_start; + set_query_source(query_source_arg, query_length_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)); +} + +QUERY_PROFILE::~QUERY_PROFILE() +{ + while (! entries.is_empty()) + delete entries.pop(); + + if (query_source != NULL) + my_free(query_source, MYF(0)); +} + +void QUERY_PROFILE::status(const char *status_arg, + const char *function_arg= NULL, + const char *file_arg= NULL, unsigned int line_arg= 0) +{ + THD *thd= profiling->thd; + PROFILE_ENTRY *prof; + DBUG_ENTER("QUERY_PROFILE::status"); + + /* Blank status. Just return, and thd->proc_info will be set blank later. */ + if (unlikely(status_arg == NULL)) + DBUG_VOID_RETURN; + + /* If thd->proc_info is currently set to status_arg, don't profile twice. */ + 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 != server_query_id) && !thd->spcont)) + reset(); + + 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); + } + + DBUG_VOID_RETURN; +} + +void QUERY_PROFILE::reset() +{ + DBUG_ENTER("QUERY_PROFILE::reset"); + if (likely(profiling->thd->query_id != server_query_id)) + { + server_query_id= profiling->thd->query_id; /* despite name, is global */ + profile_start.collect(); + + while (! entries.is_empty()) + delete entries.pop(); + } + DBUG_VOID_RETURN; +} + +PROFILING::PROFILING() + :profile_id_counter(1), keeping(TRUE), enabled(FALSE), current(NULL), last(NULL) +{ +} + +PROFILING::~PROFILING() +{ + while (! history.is_empty()) + delete history.pop(); + + if (current != NULL) + delete current; +} + +void PROFILING::status_change(const char *status_arg, + const char *function_arg, + const char *file_arg, unsigned int line_arg) +{ + DBUG_ENTER("PROFILING::status_change"); + + if (unlikely(enabled)) + { + if (unlikely(current == NULL)) + reset(); + + DBUG_ASSERT(current != NULL); + + current->status(status_arg, function_arg, file_arg, line_arg); + } + + thd->proc_info= status_arg; + DBUG_VOID_RETURN; +} + +void PROFILING::store() +{ + DBUG_ENTER("PROFILING::store"); + + /* Already stored */ + if (unlikely((last != NULL) && + (current != NULL) && + (last->server_query_id == current->server_query_id))) + { + DBUG_VOID_RETURN; + } + + 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 && + (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())) + { + 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 + { + delete current; + current= NULL; + } + } + + DBUG_ASSERT(current == NULL); + if (enabled) + current= new QUERY_PROFILE(this, thd->query, thd->query_length); + + 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)) + { + enabled= FALSE; + DBUG_VOID_RETURN; + } + else + enabled= TRUE; + + if (current != NULL) + current->reset(); + keep(); + + DBUG_VOID_RETURN; +} + +bool PROFILING::show_profiles() +{ + DBUG_ENTER("PROFILING::show_profiles"); + QUERY_PROFILE *prof; + List<Item> field_list; + + field_list.push_back(new Item_return_int("Query_ID", 10, + MYSQL_TYPE_LONG)); + 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)) + 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); + + 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; + 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->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); + } + send_eof(thd); + DBUG_RETURN(FALSE); +} + +/* + 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; +} + + +/** + Fill the information schema table, "query_profile", as defined in show.cc . + There are two ways to get to this function: Selecting from the information + schema, and a SHOW command. +*/ +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; + + QUERY_PROFILE *query; + /* Go through each query in this thread's stored history... */ + 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 *previous= &(query->profile_start); + + /* + 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; + + void *entry_iterator; + PROFILE_ENTRY *entry; + /* ...and for each query, go through all its state-change steps. */ + for (seq= 0, entry_iterator= query->entries.new_iterator(); + entry_iterator != NULL; + entry_iterator= query->entries.iterator_next(entry_iterator), + seq++, previous=entry, row_number++) + { + entry= query->entries.iterator_value(entry_iterator); + + if (thd->lex->orig_sql_command == SQLCOM_SHOW_PROFILE) + { + /* + We got here via a SHOW command. That means that we stored + information about the query we wish to show and that isn't + in a WHERE clause at a higher level to filter out rows we + wish to exclude. + + Because that functionality isn't available in the server yet, + we must filter here, at the wrong level. Once one can con- + struct where and having conditions at the SQL layer, then this + condition should be ripped out. + */ + if (thd->lex->profile_query_id == 0) /* 0 == show final query */ + { + if (query != last) + continue; + } + else + { + if (thd->lex->profile_query_id != query->profiling_query_id) + continue; + } + } + + /* 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 */ + /* + 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 - + previous->time_usecs)/(1000*1000)); + +#ifdef HAVE_GETRUSAGE + table->field[4]->store((double)RUSAGE_DIFF_USEC(entry->rusage.ru_utime, + previous->rusage.ru_utime)/(1000.0*1000)); + table->field[4]->set_notnull(); + table->field[5]->store((double)RUSAGE_DIFF_USEC(entry->rusage.ru_stime, + previous->rusage.ru_stime)/(1000.0*1000)); + + 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 - + previous->rusage.ru_nvcsw)); + table->field[6]->set_notnull(); + 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 - + previous->rusage.ru_inblock)); + table->field[8]->set_notnull(); + 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 - + previous->rusage.ru_msgsnd), true); + table->field[10]->set_notnull(); + 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 - + previous->rusage.ru_majflt), true); + table->field[12]->set_notnull(); + 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 - + previous->rusage.ru_nswap), true); + table->field[14]->set_notnull(); +#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]->set_notnull(); + table->field[16]->store(entry->file, strlen(entry->file), system_charset_info); + table->field[16]->set_notnull(); + table->field[17]->store(entry->line, true); + table->field[17]->set_notnull(); + } + + 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 new file mode 100644 index 00000000000..56022de0dcc --- /dev/null +++ b/sql/sql_profile.h @@ -0,0 +1,341 @@ +/* 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; 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 + 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 + +#if __STDC_VERSION__ < 199901L +# if __GNUC__ >= 2 +# define __func__ __FUNCTION__ +# else +# define __func__ _unknown_func_ +extern const char * const _unknown_func_; +# endif +#elif defined(_MSC_VER) +# if _MSC_VER < 1300 +# define __func__ _unknown_func_ +extern const char * const _unknown_func_; +# else +# define __func__ __FUNCTION__ +# endif +#elif defined(__BORLANDC__) +# define __func__ __FUNC__ +#else +# define __func__ _unknown_func_ +extern const char * const _unknown_func_; +#endif + +extern ST_FIELD_INFO query_profile_statistics_info[]; +int fill_query_profile_statistics_info(THD *thd, struct st_table_list *tables, Item *cond); +int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table); + + +#define PROFILE_NONE 0 +#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 <sys/resource.h> +#endif + + +class PROFILE_ENTRY; +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 T> 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. +*/ +class PROFILE_ENTRY +{ +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(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 collect(); +}; + + +/** + The full profile for a single query, and includes multiple PROFILE_ENTRY + objects. +*/ +class QUERY_PROFILE +{ +private: + friend class PROFILING; + + PROFILING *profiling; + + 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; + Queue<PROFILE_ENTRY> entries; + + + 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, + 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 QUERY_PROFILE objects. +*/ +class PROFILING +{ +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; + THD *thd; + bool keeping; + bool enabled; + + QUERY_PROFILE *current; + QUERY_PROFILE *last; + Queue<QUERY_PROFILE> 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); + + /** Reset the current profile and state of profiling for the next query. */ + void reset(); + + /** + 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= true; }; + + /** + Do we intend to keep the currently collected profile? + @see keep() + */ + inline void discard() { keeping= false; }; + + /** + 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(); + + /** + 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(); + + /* ... from INFORMATION_SCHEMA.PROFILING ... */ + int fill_statistics_info(THD *thd, struct st_table_list *tables, Item *cond); +}; + +# endif /* HAVE_PROFILING */ +#endif /* _SQL_PROFILE_H */ diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 86ededd5587..380585497e3 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -647,7 +647,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()"; @@ -685,7 +685,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); @@ -731,14 +731,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 @@ -892,7 +892,7 @@ int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report ) if (check_access(thd, SUPER_ACL, any_db,0,0,0,0)) DBUG_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 @@ -919,7 +919,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) { @@ -1075,7 +1075,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, @@ -1200,7 +1200,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)) @@ -1263,7 +1263,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 36c0988021f..11f9be66891 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -742,6 +742,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 */ @@ -857,7 +858,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); } DBUG_PRINT("info",("Select tables optimized away")); zero_result_cause= "Select tables optimized away"; @@ -893,7 +901,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) { @@ -903,7 +911,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")); @@ -1273,8 +1281,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) && @@ -1332,7 +1341,7 @@ JOIN::optimize() if (need_tmp) { DBUG_PRINT("info",("Creating tmp table")); - thd->proc_info="Creating tmp table"; + thd_proc_info(thd, "Creating tmp table"); init_items_ref_array(); @@ -1361,7 +1370,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: @@ -1381,28 +1392,34 @@ 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, + 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; } } @@ -1545,6 +1562,7 @@ JOIN::exec() int tmp_error; DBUG_ENTER("JOIN::exec"); + thd_proc_info(thd, "executing"); error= 0; if (procedure) { @@ -1684,7 +1702,7 @@ JOIN::exec() curr_tmp_table= exec_tmp_table1; /* Copy data to the temporary table */ - thd->proc_info= "Copying to tmp table"; + thd_proc_info(thd, "Copying to tmp table"); DBUG_PRINT("info", ("%s", thd->proc_info)); if ((tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table, 0))) { @@ -1807,7 +1825,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; @@ -1821,7 +1839,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) @@ -1877,7 +1895,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, @@ -1938,7 +1956,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) @@ -2062,7 +2080,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), @@ -2221,7 +2239,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, @@ -2266,8 +2284,9 @@ mysql_select(THD *thd, Item ***rref_pointer_array, err: if (free_join) { - thd->proc_info="end"; + thd_proc_info(thd, "end"); err|= select_lex->cleanup(); + thd_proc_info(thd, "end"); DBUG_RETURN(err || thd->net.report_error); } DBUG_RETURN(join->error); @@ -10061,7 +10080,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) { @@ -10089,7 +10108,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; } @@ -10119,7 +10138,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)) @@ -10174,8 +10193,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: @@ -10187,7 +10206,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); table->mem_root= new_table.mem_root; DBUG_RETURN(1); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 902b298e423..d37fb3fb6a9 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); /*************************************************************************** @@ -1354,7 +1354,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; @@ -1499,6 +1499,10 @@ 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; + 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; @@ -1851,7 +1855,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]))) @@ -4384,6 +4388,9 @@ 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, make_profile_table_for_show, + 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 997864e8e39..50bc59c9eee 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1775,7 +1775,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) @@ -1806,7 +1806,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: @@ -2939,7 +2939,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); @@ -2956,7 +2956,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; @@ -3083,7 +3083,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, create_field *new_datetime_field= 0; 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; @@ -3223,7 +3223,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 { @@ -3274,7 +3274,7 @@ view_err: if (!error && (new_name != table_name || new_db != db)) { - thd->proc_info="rename"; + thd_proc_info(thd, "rename"); /* Then do a 'simple' rename of the table. First we need to close all instances of 'source' table. @@ -3774,7 +3774,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) @@ -3862,7 +3862,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) @@ -3968,7 +3968,7 @@ view_err: 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 8be495fd0fb..888bafeea0d 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -164,7 +164,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); @@ -361,7 +361,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) @@ -426,7 +426,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(); @@ -557,7 +557,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)); /* @@ -1006,7 +1006,7 @@ int multi_update::prepare(List<Item> ¬_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); @@ -1653,11 +1653,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 40f54799295..964cffaccbd 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -603,7 +603,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 924a8bd6d7d..75383e03c5d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -501,6 +501,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 @@ -541,10 +542,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 @@ -618,6 +621,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 @@ -687,6 +691,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 @@ -755,6 +761,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 @@ -813,6 +820,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 @@ -830,6 +838,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 @@ -900,6 +910,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 @@ -930,6 +941,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 @@ -6826,6 +6839,64 @@ 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_args: + /* empty */ + { + Lex->profile_query_id= 0; + } + | FOR_SYM QUERY_SYM NUM + { + Lex->profile_query_id= atoi($3.str); + } + ; + /* Show things */ show: SHOW @@ -6961,6 +7032,16 @@ 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 *lex= Lex; + lex->sql_command= SQLCOM_SELECT; + lex->orig_sql_command= SQLCOM_SHOW_PROFILE; + if (prepare_schema_table(YYTHD, lex, NULL, SCH_PROFILES) != 0) + YYABORT; + } | opt_var_type STATUS_SYM wild_and_where { LEX *lex= Lex; @@ -8065,6 +8146,7 @@ keyword_sp: | BERKELEY_DB_SYM {} | BINLOG_SYM {} | BIT_SYM {} + | BLOCK_SYM {} | BOOL_SYM {} | BOOLEAN_SYM {} | BTREE_SYM {} @@ -8082,6 +8164,8 @@ keyword_sp: | CONCURRENT {} | CONNECTION_SYM {} | CONSISTENT_SYM {} + | CONTEXT_SYM {} + | CPU_SYM {} | CUBE_SYM {} | DATA_SYM {} | DATETIME {} @@ -8104,6 +8188,7 @@ keyword_sp: | EXPANSION_SYM {} | EXTENDED_SYM {} | FAST_SYM {} + | FAULTS_SYM {} | FOUND_SYM {} | DISABLE_SYM {} | ENABLE_SYM {} @@ -8128,6 +8213,8 @@ keyword_sp: | ISSUER_SYM {} | INNOBASE_SYM {} | INSERT_METHOD {} + | IO_SYM {} + | IPC_SYM {} | RELAY_THREAD {} | LAST_SYM {} | LEAVES {} @@ -8157,6 +8244,7 @@ keyword_sp: | MAX_UPDATES_PER_HOUR {} | MAX_USER_CONNECTIONS_SYM {} | MEDIUM_SYM {} + | MEMORY_SYM {} | MERGE_SYM {} | MICROSECOND_SYM {} | MIGRATE_SYM {} @@ -8183,6 +8271,7 @@ keyword_sp: | ONE_SHOT_SYM {} | ONE_SYM {} | PACK_KEYS_SYM {} + | PAGE_SYM {} | PARTIAL {} | PASSWORD {} | PHASE_SYM {} @@ -8192,6 +8281,8 @@ keyword_sp: | PRIVILEGES {} | PROCESS {} | PROCESSLIST_SYM {} + | PROFILE_SYM {} + | PROFILES_SYM {} | QUARTER_SYM {} | QUERY_SYM {} | QUICK {} @@ -8225,6 +8316,7 @@ keyword_sp: | SHUTDOWN {} | SNAPSHOT_SYM {} | SOUNDS_SYM {} + | SOURCE_SYM {} | SQL_CACHE_SYM {} | SQL_BUFFER_RESULT {} | SQL_NO_CACHE_SYM {} @@ -8236,6 +8328,8 @@ keyword_sp: | SUBJECT_SYM {} | SUPER_SYM {} | SUSPEND_SYM {} + | SWAPS_SYM {} + | SWITCHES_SYM {} | TABLES {} | TABLESPACE {} | TEMPORARY {} diff --git a/sql/structs.h b/sql/structs.h index 28bdd8c1519..e7072bec9c3 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -173,6 +173,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, diff --git a/sql/table.h b/sql/table.h index d4dc3e8c0b8..0617363ec3e 100644 --- a/sql/table.h +++ b/sql/table.h @@ -365,6 +365,7 @@ enum enum_schema_tables SCH_COLUMN_PRIVILEGES, SCH_KEY_COLUMN_USAGE, SCH_OPEN_TABLES, + SCH_PROFILES, SCH_PROCEDURES, SCH_SCHEMATA, SCH_SCHEMA_PRIVILEGES, diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index ddeb29bec8c..c49fa645a90 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -315,7 +315,7 @@ for servertype in '--with-debug=full' ' ' do BuildMySQL "\ %if %{STATIC_BUILD} - --disable-shared \ + --enable-shared \ --with-mysqld-ldflags='-all-static' \ --with-client-ldflags='-all-static' \ $USE_OTHER_LIBC_DIR \ @@ -347,6 +347,22 @@ done ./libtool --mode=execute nm --numeric-sort sql/mysqld > sql/mysqld.sym +# Include libgcc.a in the devel subpackage (BUG 4921) +if expr "$CC" : ".*gcc.*" > /dev/null ; +then + libgcc=`$CC $CFLAGS --print-libgcc-file` + if [ -f $libgcc ] + then + %define have_libgcc 1 + install -m 644 $libgcc $RBR%{_libdir}/mysql/libmygcc.a + fi +fi + +# Save the libraries +(cd libmysql/.libs; tar cf $RBR/shared-libs.tar *.so*) +(cd libmysql_r/.libs; tar rf $RBR/shared-libs.tar *.so*) +(cd ndb/src/.libs; tar rf $RBR/shared-libs.tar *.so*) + # We might want to save the config log file if test -n "$MYSQL_CONFLOG_DEST" then @@ -379,18 +395,7 @@ make install-strip DESTDIR=$RBR benchdir_root=%{_datadir} install -s -m 755 $MBD/sql/mysqld-debug $RBR%{_sbindir}/mysqld-debug # Install shared libraries (Disable for architectures that don't support it) -# (cd $RBR%{_libdir}; tar xf $RBR/shared-libs.tar; rm -f $RBR/shared-libs.tar) - -# Include libgcc.a in the devel subpackage (BUG 4921) -if expr "$CC" : ".*gcc.*" > /dev/null ; -then - libgcc=`$CC $CFLAGS --print-libgcc-file` - if [ -f $libgcc ] - then - %define have_libgcc 1 - install -m 644 $libgcc $RBR%{_libdir}/mysql/libmygcc.a - fi -fi +(cd $RBR%{_libdir}; tar xf $RBR/shared-libs.tar; rm -f $RBR/shared-libs.tar) # install symbol files ( for stack trace resolution) # install -m 644 $MBD/sql/mysqld-max.sym $RBR%{_libdir}/mysql/mysqld-max.sym @@ -481,6 +486,12 @@ 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 diff --git a/win/mysql_manifest.cmake b/win/mysql_manifest.cmake index b5bb6fda8fb..b5bb6fda8fb 100755..100644 --- a/win/mysql_manifest.cmake +++ b/win/mysql_manifest.cmake |