From 66dfd85cf4d55e6d87e8bb81b8fc8450eb9b3f67 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 3 Jan 2007 17:15:10 -0500 Subject: [PATCH 01/99] Bug#24795: Add SHOW PROFILE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Patch contributed by Jeremy Cole. CLA received Oct 2006 by Kaj Arnö Add rudimentary query profiling support. libmysqld/Makefile.am: Add profile file to source list. sql/Makefile.am: Add profiling files to source and header lists. sql/ha_archive.cc: Macro-ized other discovered instances of setting proc_info. sql/ha_myisam.cc: Macroize setting thread-state info sql/item_func.cc: Macro-ized other discovered instances of setting proc_info. sql/lex.h: Add lexer info for profiling. sql/lock.cc: Macroize setting thread-state info sql/log_event.cc: Macro-ized other discovered instances of setting proc_info. sql/mysql_priv.h: Set constants for profiling. sql/repl_failsafe.cc: Macro-ized other discovered instances of setting proc_info. sql/slave.cc: Macro-ized other discovered instances of setting proc_info. sql/sp_head.cc: Macro-ized other discovered instances of setting proc_info. sql/sql_base.cc: Macroize setting thread-state info --- Macro-ized other discovered instances of setting proc_info. sql/sql_cache.cc: Macroize setting thread-state info sql/sql_class.cc: Integrate profiling. sql/sql_class.h: Instantiate profiling object. sql/sql_delete.cc: Macroize setting thread-state info sql/sql_insert.cc: Macroize setting thread-state info --- Macro-ized other discovered instances of setting proc_info. sql/sql_lex.cc: Initialize profiling. sql/sql_lex.h: Define lex tokens and allocate space for profiling options. sql/sql_parse.cc: Integrate profiling. --- Macro-ized other discovered instances of setting proc_info. sql/sql_repl.cc: Macro-ized other discovered instances of setting proc_info. sql/sql_select.cc: Macroize setting thread-state info. Clean up some lines. sql/sql_show.cc: Macro-ized other discovered instances of setting proc_info. --- Revert bad use of macro. sql/sql_table.cc: Macroize setting thread-state info sql/sql_update.cc: Macroize setting thread-state info sql/sql_view.cc: Macro-ized other discovered instances of setting proc_info. sql/sql_yacc.yy: Add parser info for profiling. --- Fix new YACC shift/reduce conflict. (Now at 249.) mysql-test/r/profile.result: Test profiling code. --- A not-very-useful result. mysql-test/t/profile.test: Test profiling code. --- Test syntax, but not values of profiles code. sql/sql_profile.cc: Add profiling code. --- Add wishlist comment. sql/sql_profile.h: Add profiling code. --- Changed the value of the macro so that it's syntactically equivalent to a single statement. --- BitKeeper/etc/collapsed | 3 + libmysqld/Makefile.am | 1 + mysql-test/r/profile.result | 30 +++ mysql-test/t/profile.test | 39 ++++ sql/Makefile.am | 2 + sql/ha_archive.cc | 4 +- sql/ha_myisam.cc | 24 +- sql/item_func.cc | 8 +- sql/lex.h | 13 ++ sql/lock.cc | 8 +- sql/log_event.cc | 8 +- sql/mysql_priv.h | 4 + sql/repl_failsafe.cc | 6 +- sql/slave.cc | 6 +- sql/sp_head.cc | 4 +- sql/sql_base.cc | 24 +- sql/sql_cache.cc | 12 + sql/sql_class.cc | 2 + sql/sql_class.h | 3 + sql/sql_delete.cc | 12 +- sql/sql_insert.cc | 38 ++-- sql/sql_lex.cc | 1 + sql/sql_lex.h | 3 + sql/sql_parse.cc | 40 +++- sql/sql_profile.cc | 441 ++++++++++++++++++++++++++++++++++++ sql/sql_profile.h | 187 +++++++++++++++ sql/sql_repl.cc | 2 +- sql/sql_select.cc | 73 +++--- sql/sql_show.cc | 2 +- sql/sql_table.cc | 20 +- sql/sql_update.cc | 14 +- sql/sql_view.cc | 2 +- sql/sql_yacc.yy | 74 +++++- 33 files changed, 976 insertions(+), 134 deletions(-) create mode 100644 mysql-test/r/profile.result create mode 100644 mysql-test/t/profile.test create mode 100644 sql/sql_profile.cc create mode 100644 sql/sql_profile.h diff --git a/BitKeeper/etc/collapsed b/BitKeeper/etc/collapsed index 10bc7a2182a..63e4bff0331 100644 --- a/BitKeeper/etc/collapsed +++ b/BitKeeper/etc/collapsed @@ -19,3 +19,6 @@ 4538a7b0EbDHHkWPbIwxO6ZIDdg6Dg 454a7ef8gdvE_ddMlJyghvOAkKPNOQ 454f8960jsVT_kMKJtZ9OCgXoba0xQ +459c03b9N_mqF2XJKK6DwSrIt7e6_g +459c1965_BQMBzBO8S_gVqjTHYQrmw +459c2098XoAUsUn8N07IVRDD6CTM-A diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index cdd71724166..2b54bf6a386 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -53,6 +53,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \ protocol.cc net_serv.cc opt_range.cc \ opt_sum.cc procedure.cc records.cc sql_acl.cc \ sql_load.cc discover.cc sql_locale.cc \ + sql_profile.cc \ sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \ sql_crypt.cc sql_db.cc sql_delete.cc sql_error.cc sql_insert.cc \ sql_lex.cc sql_list.cc sql_manager.cc sql_map.cc sql_parse.cc \ diff --git a/mysql-test/r/profile.result b/mysql-test/r/profile.result new file mode 100644 index 00000000000..8a4db348445 --- /dev/null +++ b/mysql-test/r/profile.result @@ -0,0 +1,30 @@ +create table t1 ( +a int, +b int +); +insert into t1 values (1,1), (2,null), (3, 4); +insert into t1 values (5,1), (6,null), (7, 4); +insert into t1 values (1,1), (2,null), (3, 4); +insert into t1 values (5,1), (6,null), (7, 4); +insert into t1 values (5,1), (6,null), (7, 4); +select sum(a) from t1; +select sum(a) from t1 group by b; +select sum(a) + sum(b) from t1 group by b; +select max(x) from (select sum(a) as x from t1 group by b) as teeone; +show profiles; +show profile for query 8; +show profile cpu, block io for query 8; +show profile cpu for query 8; +show profile cpu for query 9 limit 2 offset 2; +show profile cpu for query 10 limit 0; +show profile cpu for query 65534; +show profile memory; +show profile block io; +show profile context switches; +show profile page faults; +show profile ipc; +show profile swaps limit 1 offset 2; +show profile source; +show profile all for query 0 limit 0; +drop table t1; +End of 5.0 tests diff --git a/mysql-test/t/profile.test b/mysql-test/t/profile.test new file mode 100644 index 00000000000..4cf2a3aa92f --- /dev/null +++ b/mysql-test/t/profile.test @@ -0,0 +1,39 @@ + +create table t1 ( + a int, + b int +); +--disable_result_log +insert into t1 values (1,1), (2,null), (3, 4); +insert into t1 values (5,1), (6,null), (7, 4); +insert into t1 values (1,1), (2,null), (3, 4); +insert into t1 values (5,1), (6,null), (7, 4); +insert into t1 values (5,1), (6,null), (7, 4); +select sum(a) from t1; +select sum(a) from t1 group by b; +select sum(a) + sum(b) from t1 group by b; +select max(x) from (select sum(a) as x from t1 group by b) as teeone; + +# Merely verify that commands work. Checking values is impossible, right? +show profiles; +show profile for query 8; +show profile cpu, block io for query 8; +show profile cpu for query 8; +show profile cpu for query 9 limit 2 offset 2; +show profile cpu for query 10 limit 0; +show profile cpu for query 65534; +show profile memory; +show profile block io; +show profile context switches; +show profile page faults; +show profile ipc; +show profile swaps limit 1 offset 2; +show profile source; +show profile all for query 0 limit 0; +--enable_result_log + +drop table t1; + + +## +--echo End of 5.0 tests diff --git a/sql/Makefile.am b/sql/Makefile.am index cbb87f16d80..597ab49a135 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -52,6 +52,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ procedure.h sql_class.h sql_lex.h sql_list.h \ sql_manager.h sql_map.h sql_string.h unireg.h \ sql_error.h field.h handler.h mysqld_suffix.h \ + sql_profile.h \ ha_myisammrg.h\ ha_heap.h ha_myisam.h ha_berkeley.h ha_innodb.h \ ha_ndbcluster.h opt_range.h protocol.h \ @@ -80,6 +81,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \ set_var.cc sql_parse.cc sql_yacc.yy \ sql_base.cc table.cc sql_select.cc sql_insert.cc \ sql_prepare.cc sql_error.cc sql_locale.cc \ + sql_profile.cc \ sql_update.cc sql_delete.cc uniques.cc sql_do.cc \ procedure.cc item_uniq.cc sql_test.cc \ log.cc log_event.cc init.cc derror.cc sql_acl.cc \ diff --git a/sql/ha_archive.cc b/sql/ha_archive.cc index e3f979952e0..da879915d72 100644 --- a/sql/ha_archive.cc +++ b/sql/ha_archive.cc @@ -1206,7 +1206,7 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt) ha_rows count= share->rows_recorded; DBUG_ENTER("ha_archive::check"); - thd->proc_info= "Checking table"; + THD_PROC_INFO(thd, "Checking table"); /* Flush any waiting data */ gzflush(share->archive_write, Z_SYNC_FLUSH); @@ -1230,7 +1230,7 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt) my_free((char*)buf, MYF(0)); - thd->proc_info= old_proc_info; + THD_PROC_INFO(thd, old_proc_info); if ((rc && rc != HA_ERR_END_OF_FILE) || count) { diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 19ec1b29da3..a09682cc0ab 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -340,7 +340,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt) MYISAM_SHARE* share = file->s; const char *old_proc_info=thd->proc_info; - thd->proc_info="Checking table"; + THD_PROC_INFO(thd, "Checking table"); myisamchk_init(¶m); param.thd = thd; param.op_name = "check"; @@ -414,7 +414,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt) file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; } - thd->proc_info=old_proc_info; + THD_PROC_INFO(thd, old_proc_info); return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK; } @@ -680,22 +680,22 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) char buf[40]; /* TODO: respect myisam_repair_threads variable */ my_snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map)); - thd->proc_info=buf; + THD_PROC_INFO(thd, buf); error = mi_repair_parallel(¶m, file, fixed_name, param.testflag & T_QUICK); - thd->proc_info="Repair done"; // to reset proc_info, as + THD_PROC_INFO(thd, "Repair done"); // to reset proc_info, as // it was pointing to local buffer } else { - thd->proc_info="Repair by sorting"; + THD_PROC_INFO(thd, "Repair by sorting"); error = mi_repair_by_sort(¶m, file, fixed_name, param.testflag & T_QUICK); } } else { - thd->proc_info="Repair with keycache"; + THD_PROC_INFO(thd, "Repair with keycache"); param.testflag &= ~T_REP_BY_SORT; error= mi_repair(¶m, file, fixed_name, param.testflag & T_QUICK); @@ -709,7 +709,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) (share->state.changed & STATE_NOT_SORTED_PAGES)) { optimize_done=1; - thd->proc_info="Sorting index"; + THD_PROC_INFO(thd, "Sorting index"); error=mi_sort_index(¶m,file,fixed_name); } if (!statistics_done && (local_testflag & T_STATISTICS)) @@ -717,14 +717,14 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) if (share->state.changed & STATE_NOT_ANALYZED) { optimize_done=1; - thd->proc_info="Analyzing"; + THD_PROC_INFO(thd, "Analyzing"); error = chk_key(¶m, file); } else local_testflag&= ~T_STATISTICS; // Don't update statistics } } - thd->proc_info="Saving state"; + THD_PROC_INFO(thd, "Saving state"); if (!error) { if ((share->state.changed & STATE_CHANGED) || mi_is_crashed(file)) @@ -762,7 +762,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; update_state_info(¶m, file, 0); } - thd->proc_info=old_proc_info; + THD_PROC_INFO(thd, old_proc_info); if (!thd->locked_tables) mi_lock_database(file,F_UNLCK); DBUG_RETURN(error ? HA_ADMIN_FAILED : @@ -987,7 +987,7 @@ int ha_myisam::enable_indexes(uint mode) THD *thd=current_thd; MI_CHECK param; const char *save_proc_info=thd->proc_info; - thd->proc_info="Creating index"; + THD_PROC_INFO(thd, "Creating index"); myisamchk_init(¶m); param.op_name= "recreating_index"; param.testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK | @@ -1012,7 +1012,7 @@ int ha_myisam::enable_indexes(uint mode) thd->clear_error(); } info(HA_STATUS_CONST); - thd->proc_info=save_proc_info; + THD_PROC_INFO(thd, save_proc_info); } else { diff --git a/sql/item_func.cc b/sql/item_func.cc index 659a214e9c2..ddd2f28c5a5 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3193,7 +3193,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout) Structure is now initialized. Try to get the lock. Set up control struct to allow others to abort locks */ - thd->proc_info="User lock"; + THD_PROC_INFO(thd, "User lock"); thd->mysys_var->current_mutex= &LOCK_user_locks; thd->mysys_var->current_cond= &ull->cond; @@ -3218,7 +3218,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout) } pthread_mutex_unlock(&LOCK_user_locks); pthread_mutex_lock(&thd->mysys_var->mutex); - thd->proc_info=0; + THD_PROC_INFO(thd, 0); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; pthread_mutex_unlock(&thd->mysys_var->mutex); @@ -3299,7 +3299,7 @@ longlong Item_func_get_lock::val_int() Structure is now initialized. Try to get the lock. Set up control struct to allow others to abort locks. */ - thd->proc_info="User lock"; + THD_PROC_INFO(thd, "User lock"); thd->mysys_var->current_mutex= &LOCK_user_locks; thd->mysys_var->current_cond= &ull->cond; @@ -3337,7 +3337,7 @@ longlong Item_func_get_lock::val_int() pthread_mutex_unlock(&LOCK_user_locks); pthread_mutex_lock(&thd->mysys_var->mutex); - thd->proc_info=0; + THD_PROC_INFO(thd, 0); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; pthread_mutex_unlock(&thd->mysys_var->mutex); diff --git a/sql/lex.h b/sql/lex.h index 68f34d8de93..11791457b8d 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -88,6 +88,7 @@ static SYMBOL symbols[] = { { "BINLOG", SYM(BINLOG_SYM)}, { "BIT", SYM(BIT_SYM)}, { "BLOB", SYM(BLOB_SYM)}, + { "BLOCK", SYM(BLOCK_SYM)}, { "BOOL", SYM(BOOL_SYM)}, { "BOOLEAN", SYM(BOOLEAN_SYM)}, { "BOTH", SYM(BOTH)}, @@ -126,8 +127,10 @@ static SYMBOL symbols[] = { { "CONSISTENT", SYM(CONSISTENT_SYM)}, { "CONSTRAINT", SYM(CONSTRAINT)}, { "CONTAINS", SYM(CONTAINS_SYM)}, + { "CONTEXT", SYM(CONTEXT_SYM)}, { "CONTINUE", SYM(CONTINUE_SYM)}, { "CONVERT", SYM(CONVERT_SYM)}, + { "CPU", SYM(CPU_SYM)}, { "CREATE", SYM(CREATE)}, { "CROSS", SYM(CROSS)}, { "CUBE", SYM(CUBE_SYM)}, @@ -193,6 +196,7 @@ static SYMBOL symbols[] = { { "EXTENDED", SYM(EXTENDED_SYM)}, { "FALSE", SYM(FALSE_SYM)}, { "FAST", SYM(FAST_SYM)}, + { "FAULTS", SYM(FAULTS_SYM)}, { "FETCH", SYM(FETCH_SYM)}, { "FIELDS", SYM(COLUMNS)}, { "FILE", SYM(FILE_SYM)}, @@ -252,7 +256,9 @@ static SYMBOL symbols[] = { { "INTEGER", SYM(INT_SYM)}, { "INTERVAL", SYM(INTERVAL_SYM)}, { "INTO", SYM(INTO)}, + { "IO", SYM(IO_SYM)}, { "IO_THREAD", SYM(RELAY_THREAD)}, + { "IPC", SYM(IPC_SYM)}, { "IS", SYM(IS)}, { "ISOLATION", SYM(ISOLATION)}, { "ISSUER", SYM(ISSUER_SYM)}, @@ -310,6 +316,7 @@ static SYMBOL symbols[] = { { "MEDIUMBLOB", SYM(MEDIUMBLOB)}, { "MEDIUMINT", SYM(MEDIUMINT)}, { "MEDIUMTEXT", SYM(MEDIUMTEXT)}, + { "MEMORY", SYM(MEMORY_SYM)}, { "MERGE", SYM(MERGE_SYM)}, { "MICROSECOND", SYM(MICROSECOND_SYM)}, { "MIDDLEINT", SYM(MEDIUMINT)}, /* For powerbuilder */ @@ -357,6 +364,7 @@ static SYMBOL symbols[] = { { "OUT", SYM(OUT_SYM)}, { "OUTER", SYM(OUTER)}, { "OUTFILE", SYM(OUTFILE)}, + { "PAGE", SYM(PAGE_SYM)}, { "PACK_KEYS", SYM(PACK_KEYS_SYM)}, { "PARTIAL", SYM(PARTIAL)}, { "PASSWORD", SYM(PASSWORD)}, @@ -371,6 +379,8 @@ static SYMBOL symbols[] = { { "PROCEDURE", SYM(PROCEDURE)}, { "PROCESS" , SYM(PROCESS)}, { "PROCESSLIST", SYM(PROCESSLIST_SYM)}, + { "PROFILE", SYM(PROFILE_SYM)}, + { "PROFILES", SYM(PROFILES_SYM)}, { "PURGE", SYM(PURGE)}, { "QUARTER", SYM(QUARTER_SYM)}, { "QUERY", SYM(QUERY_SYM)}, @@ -438,6 +448,7 @@ static SYMBOL symbols[] = { { "SOME", SYM(ANY_SYM)}, { "SONAME", SYM(UDF_SONAME_SYM)}, { "SOUNDS", SYM(SOUNDS_SYM)}, + { "SOURCE", SYM(SOURCE_SYM)}, { "SPATIAL", SYM(SPATIAL_SYM)}, { "SPECIFIC", SYM(SPECIFIC_SYM)}, { "SQL", SYM(SQL_SYM)}, @@ -472,6 +483,8 @@ static SYMBOL symbols[] = { { "SUBJECT", SYM(SUBJECT_SYM)}, { "SUPER", SYM(SUPER_SYM)}, { "SUSPEND", SYM(SUSPEND_SYM)}, + { "SWAPS", SYM(SWAPS_SYM)}, + { "SWITCHES", SYM(SWITCHES_SYM)}, { "TABLE", SYM(TABLE_SYM)}, { "TABLES", SYM(TABLES)}, { "TABLESPACE", SYM(TABLESPACE)}, diff --git a/sql/lock.cc b/sql/lock.cc index 90ddcc957a2..71c0b753b2a 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -151,7 +151,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, } } - thd->proc_info="System lock"; + THD_PROC_INFO(thd, "System lock"); if (lock_external(thd, tables, count)) { /* Clear the lock type of all lock data to avoid reusage. */ @@ -160,7 +160,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, sql_lock=0; break; } - thd->proc_info="Table lock"; + THD_PROC_INFO(thd, "Table lock"); thd->locked=1; /* Copy the lock data array. thr_multi_lock() reorders its contens. */ memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks, @@ -194,7 +194,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, thd->locked=0; break; } - thd->proc_info=0; + THD_PROC_INFO(thd, 0); /* some table was altered or deleted. reopen tables marked deleted */ mysql_unlock_tables(thd,sql_lock); @@ -209,7 +209,7 @@ retry: if (wait_for_tables(thd)) break; // Couldn't open tables } - thd->proc_info=0; + THD_PROC_INFO(thd, 0); if (thd->killed) { thd->send_kill_message(); diff --git a/sql/log_event.cc b/sql/log_event.cc index 0d7ef7e8f2a..e6f4665d49b 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4266,7 +4266,7 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli) bzero((char*)&file, sizeof(file)); fname_buf= strmov(proc_info, "Making temp file "); ext= slave_load_file_stem(fname_buf, file_id, server_id, ".info"); - thd->proc_info= proc_info; + THD_PROC_INFO(thd, proc_info); my_delete(fname_buf, MYF(0)); // old copy may exist already if ((fd= my_create(fname_buf, CREATE_MODE, O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW, @@ -4320,7 +4320,7 @@ err: end_io_cache(&file); if (fd >= 0) my_close(fd, MYF(0)); - thd->proc_info= 0; + THD_PROC_INFO(thd, 0); return error ? 1 : Log_event::exec_event(rli); } #endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ @@ -4440,7 +4440,7 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli) fname= strmov(proc_info, "Making temp file "); slave_load_file_stem(fname, file_id, server_id, ".data"); - thd->proc_info= proc_info; + THD_PROC_INFO(thd, proc_info); if (get_create_or_append()) { my_delete(fname, MYF(0)); // old copy may exist already @@ -4474,7 +4474,7 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli) err: if (fd >= 0) my_close(fd, MYF(0)); - thd->proc_info= 0; + THD_PROC_INFO(thd, 0); DBUG_RETURN(error ? error : Log_event::exec_event(rli)); } #endif diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index c5ec6f02cdd..06762516f76 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -174,6 +174,8 @@ MY_LOCALE *my_locale_by_name(const char *name); #define BDB_LOG_ALLOC_BLOCK_SIZE 1024 #define WARN_ALLOC_BLOCK_SIZE 2048 #define WARN_ALLOC_PREALLOC_SIZE 1024 +#define PROFILE_ALLOC_BLOCK_SIZE 2048 +#define PROFILE_ALLOC_PREALLOC_SIZE 1024 /* The following parameters is to decide when to use an extra cache to @@ -542,6 +544,8 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key, #include "field.h" /* Field definitions */ #include "protocol.h" #include "sql_udf.h" +#include "sql_profile.h" + class user_var_entry; class Security_context; enum enum_var_type diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 21e46e71825..e085ebc77b2 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -92,7 +92,7 @@ static int init_failsafe_rpl_thread(THD* thd) if (thd->variables.max_join_size == HA_POS_ERROR) thd->options|= OPTION_BIG_SELECTS; - thd->proc_info="Thread initialized"; + THD_PROC_INFO(thd, "Thread initialized"); thd->version=refresh_version; thd->set_time(); DBUG_RETURN(0); @@ -598,7 +598,7 @@ pthread_handler_t handle_failsafe_rpl(void *arg) { bool break_req_chain = 0; pthread_cond_wait(&COND_rpl_status, &LOCK_rpl_status); - thd->proc_info="Processing request"; + THD_PROC_INFO(thd, "Processing request"); while (!break_req_chain) { switch (rpl_status) { @@ -942,7 +942,7 @@ bool load_master_data(THD* thd) goto err; } } - thd->proc_info="purging old relay logs"; + THD_PROC_INFO(thd, "purging old relay logs"); if (purge_relay_logs(&active_mi->rli,thd, 0 /* not only reset, but also reinit */, &errmsg)) diff --git a/sql/slave.cc b/sql/slave.cc index d0396444ace..eaa53a15ac3 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2925,9 +2925,9 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) #endif if (thd_type == SLAVE_THD_SQL) - thd->proc_info= "Waiting for the next event in relay log"; + THD_PROC_INFO(thd, "Waiting for the next event in relay log"); else - thd->proc_info= "Waiting for master update"; + THD_PROC_INFO(thd, "Waiting for master update"); thd->version=refresh_version; thd->set_time(); DBUG_RETURN(0); @@ -3546,7 +3546,7 @@ dump"); } mi->slave_running= MYSQL_SLAVE_RUN_NOT_CONNECT; - thd->proc_info= "Waiting to reconnect after a failed binlog dump request"; + THD_PROC_INFO(thd, "Waiting to reconnect after a failed binlog dump request"); #ifdef SIGNAL_WITH_VIO_CLOSE thd->clear_active_vio(); #endif diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 152bc87aead..badd8c3f9cf 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2372,9 +2372,9 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, m_lex->unit.cleanup(); - thd->proc_info="closing tables"; + THD_PROC_INFO(thd, "closing tables"); close_thread_tables(thd); - thd->proc_info= 0; + THD_PROC_INFO(thd, 0); if (m_lex->query_tables_own_last) { diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 90043e45052..54af1064088 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -309,7 +309,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, */ thd->mysys_var->current_mutex= &LOCK_open; thd->mysys_var->current_cond= &COND_refresh; - thd->proc_info="Flushing tables"; + THD_PROC_INFO(thd, "Flushing tables"); close_old_data_files(thd,thd->open_tables,1,1); mysql_ha_flush(thd, tables, MYSQL_HA_REOPEN_ON_USAGE | MYSQL_HA_FLUSH_ALL, @@ -351,7 +351,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, pthread_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; - thd->proc_info=0; + THD_PROC_INFO(thd, 0); pthread_mutex_unlock(&thd->mysys_var->mutex); } DBUG_RETURN(result); @@ -1065,7 +1065,7 @@ void wait_for_refresh(THD *thd) thd->mysys_var->current_mutex= &LOCK_open; thd->mysys_var->current_cond= &COND_refresh; proc_info=thd->proc_info; - thd->proc_info="Waiting for table"; + THD_PROC_INFO(thd, "Waiting for table"); if (!thd->killed) (void) pthread_cond_wait(&COND_refresh,&LOCK_open); @@ -1073,7 +1073,7 @@ void wait_for_refresh(THD *thd) pthread_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; - thd->proc_info= proc_info; + THD_PROC_INFO(thd, proc_info); pthread_mutex_unlock(&thd->mysys_var->mutex); DBUG_VOID_RETURN; } @@ -1778,7 +1778,7 @@ bool wait_for_tables(THD *thd) bool result; DBUG_ENTER("wait_for_tables"); - thd->proc_info="Waiting for tables"; + THD_PROC_INFO(thd, "Waiting for tables"); pthread_mutex_lock(&LOCK_open); while (!thd->killed) { @@ -1794,12 +1794,12 @@ bool wait_for_tables(THD *thd) else { /* Now we can open all tables without any interference */ - thd->proc_info="Reopen tables"; + THD_PROC_INFO(thd, "Reopen tables"); thd->version= refresh_version; result=reopen_tables(thd,0,0); } pthread_mutex_unlock(&LOCK_open); - thd->proc_info=0; + THD_PROC_INFO(thd, 0); DBUG_RETURN(result); } @@ -2098,7 +2098,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) restart: *counter= 0; query_tables_last_own= 0; - thd->proc_info="Opening tables"; + THD_PROC_INFO(thd, "Opening tables"); /* If we are not already executing prelocked statement and don't have @@ -2278,7 +2278,7 @@ process_view_routines: } err: - thd->proc_info=0; + THD_PROC_INFO(thd, 0); free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block if (query_tables_last_own) @@ -2352,7 +2352,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type) bool refresh; DBUG_ENTER("open_ltable"); - thd->proc_info="Opening table"; + THD_PROC_INFO(thd, "Opening table"); thd->current_tablenr= 0; /* open_ltable can be used only for BASIC TABLEs */ table_list->required_type= FRMTYPE_TABLE; @@ -2386,7 +2386,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type) table= 0; } } - thd->proc_info=0; + THD_PROC_INFO(thd, 0); DBUG_RETURN(table); } @@ -5387,7 +5387,7 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order) List_iterator li(*(select_lex->ftfunc_list)); Item_func_match *ifm; DBUG_PRINT("info",("Performing FULLTEXT search")); - thd->proc_info="FULLTEXT initialization"; + THD_PROC_INFO(thd, "FULLTEXT initialization"); while ((ifm=li++)) ifm->init_search(no_order); diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 2c77e0ef230..3f9a41fecd9 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -670,6 +670,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length) void query_cache_abort(NET *net) { DBUG_ENTER("query_cache_abort"); + THD *thd= current_thd; /* See the comment on double-check locking usage above. */ if (net->query_cache_query == 0) @@ -688,6 +689,7 @@ void query_cache_abort(NET *net) net->query_cache_query); if (query_block) // Test if changed by other thread { + THD_PROC_INFO(thd, "storing result in query cache"); DUMP(&query_cache); BLOCK_LOCK_WR(query_block); // The following call will remove the lock on query_block @@ -725,6 +727,7 @@ void query_cache_end_of_result(THD *thd) query_block= ((Query_cache_block*) thd->net.query_cache_query); if (query_block) { + THD_PROC_INFO(thd, "storing result in query cache"); DUMP(&query_cache); BLOCK_LOCK_WR(query_block); Query_cache_query *header= query_block->query(); @@ -1089,6 +1092,8 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) DBUG_PRINT("qcache", ("No active database")); } + THD_PROC_INFO(thd, "checking query cache for query"); + // fill all gaps between fields with 0 to get repeatable key bzero(&flags, QUERY_CACHE_FLAGS_SIZE); flags.client_long_flag= test(thd->client_capabilities & CLIENT_LONG_FLAG); @@ -1163,6 +1168,7 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu", } // Check access; + THD_PROC_INFO(thd, "checking privileges on cached query"); block_table= query_block->table(0); block_table_end= block_table+query_block->n_tables; for (; block_table != block_table_end; block_table++) @@ -1255,6 +1261,7 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu", Send cached result to client */ #ifndef EMBEDDED_LIBRARY + THD_PROC_INFO(thd, "sending cached result to client"); do { DBUG_PRINT("qcache", ("Results (len: %lu used: %lu headers: %lu)", @@ -1332,9 +1339,11 @@ void Query_cache::invalidate(THD *thd, TABLE_LIST *tables_used, void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used) { + THD *thd= current_thd; DBUG_ENTER("Query_cache::invalidate (changed table list)"); if (tables_used) { + THD_PROC_INFO(thd, "invalidating query cache entries (table list)"); STRUCT_LOCK(&structure_guard_mutex); if (query_cache_size > 0 && !flush_in_progress) { @@ -1365,9 +1374,11 @@ void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used) */ void Query_cache::invalidate_locked_for_write(TABLE_LIST *tables_used) { + THD *thd= current_thd; DBUG_ENTER("Query_cache::invalidate_locked_for_write"); if (tables_used) { + THD_PROC_INFO(thd, "invalidating query cache entries (table)"); STRUCT_LOCK(&structure_guard_mutex); if (query_cache_size > 0 && !flush_in_progress) { @@ -1417,6 +1428,7 @@ void Query_cache::invalidate(THD *thd, const char *key, uint32 key_length, STRUCT_LOCK(&structure_guard_mutex); if (query_cache_size > 0 && !flush_in_progress) { + THD_PROC_INFO(thd, "invalidating query cache entries (key)"); using_transactions= using_transactions && (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)); if (using_transactions) // used for innodb => has_transactions() is TRUE diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d2f1e9ed0d9..3745f537612 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -248,6 +248,7 @@ THD::THD() init(); /* Initialize sub structures */ init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE); + profiling.set_thd(this); user_connect=(USER_CONN *)0; hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0, (hash_get_key) get_var_key, @@ -330,6 +331,7 @@ void THD::init_for_queries() variables.trans_alloc_block_size, variables.trans_prealloc_size); #endif + profiling.reset(); transaction.xid_state.xid.null(); transaction.xid_state.in_thd=1; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 9ad67524998..cbccaf884b0 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1309,6 +1309,9 @@ public: List warn_list; uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END]; uint total_warn_count; + + PROFILING profiling; + /* Id of current query. Statement can be reused to execute several queries query_id is global in context of the whole MySQL server. diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index b665113dd18..ecb0f498812 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -55,7 +55,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table->file->print_error(error, MYF(0)); DBUG_RETURN(error); } - thd->proc_info="init"; + THD_PROC_INFO(thd, "init"); table->map=1; if (mysql_prepare_delete(thd, table_list, &conds)) @@ -206,7 +206,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, deleted=0L; init_ftfuncs(thd, select_lex, 1); - thd->proc_info="updating"; + THD_PROC_INFO(thd, "updating"); if (table->triggers) table->triggers->mark_fields_used(thd, TRG_EVENT_DELETE); @@ -262,7 +262,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, } if (thd->killed && !error) error= 1; // Aborted - thd->proc_info="end"; + THD_PROC_INFO(thd, "end"); end_read_record(&info); free_io_cache(table); // Will not do any harm if (options & OPTION_QUICK) @@ -486,7 +486,7 @@ multi_delete::prepare(List &values, SELECT_LEX_UNIT *u) DBUG_ENTER("multi_delete::prepare"); unit= u; do_delete= 1; - thd->proc_info="deleting from main table"; + THD_PROC_INFO(thd, "deleting from main table"); DBUG_RETURN(0); } @@ -750,7 +750,7 @@ int multi_delete::do_deletes() bool multi_delete::send_eof() { - thd->proc_info="deleting from reference tables"; + THD_PROC_INFO(thd, "deleting from reference tables"); /* Does deletes for the last n - 1 tables, returns 0 if ok */ int local_error= do_deletes(); // returns 0 if success @@ -759,7 +759,7 @@ bool multi_delete::send_eof() local_error= local_error || error; /* reset used flags */ - thd->proc_info="end"; + THD_PROC_INFO(thd, "end"); /* We must invalidate the query cache before binlog writing and diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 2ce83caa369..48bb8305e02 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -398,7 +398,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, if (res || thd->is_fatal_error) DBUG_RETURN(TRUE); - thd->proc_info="init"; + THD_PROC_INFO(thd, "init"); thd->used_tables=0; values= its++; @@ -471,7 +471,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, error=0; id=0; - thd->proc_info="update"; + THD_PROC_INFO(thd, "update"); if (duplic != DUP_ERROR || ignore) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); if (duplic == DUP_REPLACE) @@ -677,7 +677,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, thd->lock=0; } } - thd->proc_info="end"; + THD_PROC_INFO(thd, "end"); table->next_number_field=0; thd->count_cuted_fields= CHECK_FIELD_IGNORE; thd->next_insert_id=0; // Reset this if wrongly used @@ -1408,7 +1408,7 @@ I_List delayed_threads; delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list) { - thd->proc_info="waiting for delay_list"; + THD_PROC_INFO(thd, "waiting for delay_list"); pthread_mutex_lock(&LOCK_delayed_insert); // Protect master list I_List_iterator it(delayed_threads); delayed_insert *tmp; @@ -1445,7 +1445,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) */ if (delayed_insert_threads >= thd->variables.max_insert_delayed_threads) DBUG_RETURN(0); - thd->proc_info="Creating delayed handler"; + THD_PROC_INFO(thd, "Creating delayed handler"); pthread_mutex_lock(&LOCK_delayed_create); /* The first search above was done without LOCK_delayed_create. @@ -1487,13 +1487,13 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) } /* Wait until table is open */ - thd->proc_info="waiting for handler open"; + THD_PROC_INFO(thd, "waiting for handler open"); while (!tmp->thd.killed && !tmp->table && !thd->killed) { pthread_cond_wait(&tmp->cond_client,&tmp->mutex); } pthread_mutex_unlock(&tmp->mutex); - thd->proc_info="got old table"; + THD_PROC_INFO(thd, "got old table"); if (tmp->thd.killed) { if (tmp->thd.is_fatal_error) @@ -1553,13 +1553,13 @@ TABLE *delayed_insert::get_local_table(THD* client_thd) tables_in_use++; if (!thd.lock) // Table is not locked { - client_thd->proc_info="waiting for handler lock"; + THD_PROC_INFO(client_thd, "waiting for handler lock"); pthread_cond_signal(&cond); // Tell handler to lock table while (!dead && !thd.lock && ! client_thd->killed) { pthread_cond_wait(&cond_client,&mutex); } - client_thd->proc_info="got handler lock"; + THD_PROC_INFO(client_thd, "got handler lock"); if (client_thd->killed) goto error; if (dead) @@ -1577,7 +1577,7 @@ TABLE *delayed_insert::get_local_table(THD* client_thd) bytes. Since the table copy is used for creating one record only, the other record buffers and alignment are unnecessary. */ - client_thd->proc_info="allocating local table"; + THD_PROC_INFO(client_thd, "allocating local table"); copy= (TABLE*) client_thd->alloc(sizeof(*copy)+ (table->s->fields+1)*sizeof(Field**)+ table->s->reclength); @@ -1657,11 +1657,11 @@ static int write_delayed(THD *thd,TABLE *table,enum_duplicates duplic, bool igno delayed_insert *di=thd->di; DBUG_ENTER("write_delayed"); - thd->proc_info="waiting for handler insert"; + THD_PROC_INFO(thd, "waiting for handler insert"); pthread_mutex_lock(&di->mutex); while (di->stacked_inserts >= delayed_queue_size && !thd->killed) pthread_cond_wait(&di->cond_client,&di->mutex); - thd->proc_info="storing row into queue"; + THD_PROC_INFO(thd, "storing row into queue"); if (thd->killed || !(row= new delayed_row(duplic, ignore, log_on))) goto err; @@ -1873,7 +1873,7 @@ pthread_handler_t handle_delayed_insert(void *arg) /* Information for pthread_kill */ di->thd.mysys_var->current_mutex= &di->mutex; di->thd.mysys_var->current_cond= &di->cond; - di->thd.proc_info="Waiting for INSERT"; + THD_PROC_INFO(&(di->thd), "Waiting for INSERT"); DBUG_PRINT("info",("Waiting for someone to insert rows")); while (!thd->killed) @@ -1908,7 +1908,7 @@ pthread_handler_t handle_delayed_insert(void *arg) pthread_mutex_unlock(&di->thd.mysys_var->mutex); pthread_mutex_lock(&di->mutex); } - di->thd.proc_info=0; + THD_PROC_INFO(&(di->thd), 0); if (di->tables_in_use && ! thd->lock) { @@ -2027,7 +2027,7 @@ bool delayed_insert::handle_inserts(void) table->next_number_field=table->found_next_number_field; - thd.proc_info="upgrading lock"; + THD_PROC_INFO(&thd, "upgrading lock"); if (thr_upgrade_write_delay_lock(*thd.lock->locks)) { /* This can only happen if thread is killed by shutdown */ @@ -2035,7 +2035,7 @@ bool delayed_insert::handle_inserts(void) goto err; } - thd.proc_info="insert"; + THD_PROC_INFO(&thd, "insert"); max_rows= delayed_insert_limit; if (thd.killed || table->s->version != refresh_version) { @@ -2153,7 +2153,7 @@ bool delayed_insert::handle_inserts(void) { if (tables_in_use) pthread_cond_broadcast(&cond_client); // If waiting clients - thd.proc_info="reschedule"; + THD_PROC_INFO(&thd, "reschedule"); pthread_mutex_unlock(&mutex); if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) { @@ -2172,14 +2172,14 @@ bool delayed_insert::handle_inserts(void) if (!using_bin_log) table->file->extra(HA_EXTRA_WRITE_CACHE); pthread_mutex_lock(&mutex); - thd.proc_info="insert"; + THD_PROC_INFO(&thd, "insert"); } if (tables_in_use) pthread_cond_broadcast(&cond_client); // If waiting clients } } - thd.proc_info=0; + THD_PROC_INFO(&thd, 0); table->next_number_field=0; pthread_mutex_unlock(&mutex); if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 3de842c8551..7e775cfffdd 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -174,6 +174,7 @@ void lex_start(THD *thd, uchar *buf,uint length) lex->proc_list.first= 0; lex->escape_used= FALSE; lex->reset_query_tables_list(FALSE); + lex->profile_options= PROFILE_NONE; lex->nest_level=0 ; lex->allow_sum_func= 0; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index be12467d097..a918188a4bc 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -95,6 +95,7 @@ enum enum_sql_command { SQLCOM_XA_START, SQLCOM_XA_END, SQLCOM_XA_PREPARE, SQLCOM_XA_COMMIT, SQLCOM_XA_ROLLBACK, SQLCOM_XA_RECOVER, SQLCOM_SHOW_PROC_CODE, SQLCOM_SHOW_FUNC_CODE, + SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES, /* This should be the last !!! */ SQLCOM_END @@ -940,6 +941,8 @@ typedef struct st_lex : public Query_tables_list enum enum_var_type option_type; enum enum_view_create_mode create_view_mode; enum enum_drop_mode drop_mode; + uint profile_options; + uint profile_query_id; uint uint_geom_type; uint grant, grant_tot_col, which_columns; uint fk_delete_opt, fk_update_opt, fk_match_option; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fec7e5ab20d..4124db36b7f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1059,7 +1059,7 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var, Vio* save_vio; ulong save_client_capabilities; - thd->proc_info= "Execution of init_command"; + THD_PROC_INFO(thd, "Execution of init_command"); /* We need to lock init_command_var because during execution of init_command_var query @@ -1159,7 +1159,7 @@ pthread_handler_t handle_one_connection(void *arg) net->compress=1; // Use compression thd->version= refresh_version; - thd->proc_info= 0; + THD_PROC_INFO(thd, 0); thd->command= COM_SLEEP; thd->set_time(); thd->init_for_queries(); @@ -1176,7 +1176,7 @@ pthread_handler_t handle_one_connection(void *arg) sctx->host_or_ip, "init_connect command failed"); sql_print_warning("%s", net->last_error); } - thd->proc_info=0; + THD_PROC_INFO(thd, 0); thd->set_time(); thd->init_for_queries(); } @@ -1259,7 +1259,7 @@ pthread_handler_t handle_bootstrap(void *arg) if (thd->variables.max_join_size == HA_POS_ERROR) thd->options |= OPTION_BIG_SELECTS; - thd->proc_info=0; + THD_PROC_INFO(thd, 0); thd->version=refresh_version; thd->security_ctx->priv_user= thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME)); @@ -2106,7 +2106,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (thd->lock || thd->open_tables || thd->derived_tables || thd->prelocked_mode) { - thd->proc_info="closing tables"; + THD_PROC_INFO(thd, "closing tables"); close_thread_tables(thd); /* Free tables */ } /* @@ -2129,9 +2129,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, log_slow_statement(thd); - thd->proc_info="cleaning up"; + THD_PROC_INFO(thd, "cleaning up"); VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list - thd->proc_info=0; + THD_PROC_INFO(thd, 0); thd->command=COM_SLEEP; thd->query=0; thd->query_length=0; @@ -2164,8 +2164,6 @@ void log_slow_statement(THD *thd) */ if (thd->enable_slow_log && !thd->user_time) { - thd->proc_info="logging slow query"; - if ((ulong) (thd->start_time - thd->time_after_lock) > thd->variables.long_query_time || (thd->server_status & @@ -2174,6 +2172,7 @@ void log_slow_statement(THD *thd) /* == SQLCOM_END unless this is a SHOW command */ thd->lex->orig_sql_command == SQLCOM_END) { + THD_PROC_INFO(thd, "logging slow query"); thd->status_var.long_query_count++; mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query); } @@ -2697,6 +2696,20 @@ mysql_execute_command(THD *thd) (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)); break; } + case SQLCOM_SHOW_PROFILES: + { + thd->profiling.store(); + thd->profiling.discard(); + res= thd->profiling.show_profiles(); + break; + } + case SQLCOM_SHOW_PROFILE: + { + thd->profiling.store(); + thd->profiling.discard(); // will get re-enabled by reset() + res= thd->profiling.show_last(lex->profile_options); + break; + } case SQLCOM_SHOW_NEW_MASTER: { if (check_global_access(thd, REPL_SLAVE_ACL)) @@ -3544,7 +3557,7 @@ end_with_restore_list: if (add_item_to_list(thd, new Item_null())) goto error; - thd->proc_info="init"; + THD_PROC_INFO(thd, "init"); if ((res= open_and_lock_tables(thd, all_tables))) break; @@ -4972,7 +4985,7 @@ end_with_restore_list: send_ok(thd); break; } - thd->proc_info="query end"; + THD_PROC_INFO(thd, "query end"); /* Two binlog-related cleanups: */ /* @@ -5143,6 +5156,8 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, else save_priv= &dummy; + THD_PROC_INFO(thd, "checking permissions"); + if ((!db || !db[0]) && !thd->db && !dont_check_global_grants) { DBUG_PRINT("error",("No database")); @@ -5630,6 +5645,7 @@ void mysql_reset_thd_for_next_command(THD *thd) thd->total_warn_count=0; // Warnings for this query thd->rand_used= 0; thd->sent_row_count= thd->examined_row_count= 0; + thd->profiling.reset(); } DBUG_VOID_RETURN; } @@ -5853,7 +5869,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length) query_cache_abort(&thd->net); lex->unit.cleanup(); } - thd->proc_info="freeing items"; + THD_PROC_INFO(thd, "freeing items"); thd->end_statement(); thd->cleanup_after_query(); DBUG_ASSERT(thd->change_list.is_empty()); diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc new file mode 100644 index 00000000000..98a5f8d7576 --- /dev/null +++ b/sql/sql_profile.cc @@ -0,0 +1,441 @@ +/* Copyright (C) 2005 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "mysql_priv.h" +#include "sp_rcontext.h" + +#define RUSAGE_USEC(tv) ((tv).tv_sec*1000000 + (tv).tv_usec) +#define RUSAGE_DIFF_USEC(tv1, tv2) (RUSAGE_USEC((tv1))-RUSAGE_USEC((tv2))) + +PROFILE_ENTRY::PROFILE_ENTRY() + :status(NULL), time(0), function(NULL), file(NULL), line(0) +{ + collect(); +} + +PROFILE_ENTRY::PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg) + :profile(profile_arg), function(NULL), file(NULL), line(0) +{ + collect(); + if (status_arg) + set_status(status_arg); +} + +PROFILE_ENTRY::PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg, + const char *function_arg, + const char *file_arg, unsigned int line_arg) + :profile(profile_arg) +{ + collect(); + if (status_arg) + set_status(status_arg); + if (function_arg) + function= strdup_root(&profile->profiling->root, function_arg); + if (file_arg) + file= strdup_root(&profile->profiling->root, file_arg); + line= line_arg; +} + +PROFILE_ENTRY::~PROFILE_ENTRY() +{ + if (status) + free(status); + if (function) + free(function); + if (file) + free(file); +} + +void PROFILE_ENTRY::set_status(const char *status_arg) +{ + status= strdup_root(&profile->profiling->root, status_arg); +} + +void PROFILE_ENTRY::collect() +{ + time= my_getsystime(); + getrusage(RUSAGE_SELF, &rusage); +} + +PROFILE::PROFILE(PROFILING *profiling_arg) + :profiling(profiling_arg) +{ + profile_end= &profile_start; +} + +PROFILE::~PROFILE() +{ + entries.empty(); +} + +void PROFILE::status(const char *status_arg, + const char *function_arg=NULL, + const char *file_arg=NULL, unsigned int line_arg=0) +{ + PROFILE_ENTRY *prof= NULL; + MEM_ROOT *old_root= NULL; + THD *thd= profiling->thd; + + DBUG_ENTER("PROFILE::status"); + + /* Blank status. Just return, and thd->proc_info will be set blank later. */ + if (unlikely(!status_arg)) + DBUG_VOID_RETURN; + + /* If thd->proc_info is currently set to status_arg, don't profile twice. */ + if (unlikely(thd->proc_info && !(strcmp(thd->proc_info, status_arg)))) + DBUG_VOID_RETURN; + + /* Is this the same query as our profile currently contains? */ + if (unlikely(thd->query_id != query_id && !thd->spcont)) + reset(); + + /* + In order to keep the profile information between queries (i.e. from + SELECT to the following SHOW PROFILE command) the following code is + necessary to keep the profile from getting freed automatically when + mysqld cleans up after the query. This code is shamelessly stolen + from SHOW WARNINGS. + + The thd->mem_root structure is freed after each query is completed, + so temporarily override it. + */ + old_root= thd->mem_root; + thd->mem_root= &profiling->root; + if (function_arg && file_arg) { + if ((profile_end= prof= new PROFILE_ENTRY(this, status_arg, function_arg, file_arg, line_arg))) + entries.push_back(prof); + } else { + if ((profile_end= prof= new PROFILE_ENTRY(this, status_arg))) + entries.push_back(prof); + } + thd->mem_root= old_root; + + DBUG_VOID_RETURN; +} + +void PROFILE::reset() +{ + DBUG_ENTER("PROFILE::reset"); + if (profiling->thd->query_id != query_id) + { + query_id= profiling->thd->query_id; + profile_start.collect(); + entries.empty(); + } + DBUG_VOID_RETURN; +} + +bool PROFILE::show(uint options) +{ + PROFILE_ENTRY *prof; + THD *thd= profiling->thd; + PROFILE_ENTRY *ps= &profile_start; + List field_list; + DBUG_ENTER("PROFILE::show"); + + field_list.push_back(new Item_empty_string("Status", MYSQL_ERRMSG_SIZE)); + field_list.push_back(new Item_return_int("Time_elapsed", 20, + MYSQL_TYPE_LONGLONG)); + + if (options & PROFILE_CPU) + { + field_list.push_back(new Item_return_int("CPU_user", 20, + MYSQL_TYPE_LONGLONG)); + field_list.push_back(new Item_return_int("CPU_system", 20, + MYSQL_TYPE_LONGLONG)); + } + + if (options & PROFILE_MEMORY) + { + } + + if (options & PROFILE_CONTEXT) + { + field_list.push_back(new Item_return_int("Context_voluntary", 10, + MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Context_involuntary", 10, + MYSQL_TYPE_LONG)); + } + + if (options & PROFILE_BLOCK_IO) + { + field_list.push_back(new Item_return_int("Block_ops_in", 10, + MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Block_ops_out", 10, + MYSQL_TYPE_LONG)); + } + + if (options & PROFILE_IPC) + { + field_list.push_back(new Item_return_int("Messages_sent", 10, + MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Messages_received", 10, + MYSQL_TYPE_LONG)); + } + + if (options & PROFILE_PAGE_FAULTS) + { + field_list.push_back(new Item_return_int("Page_faults_major", 10, + MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Page_faults_minor", 10, + MYSQL_TYPE_LONG)); + } + + if (options & PROFILE_SWAPS) + { + field_list.push_back(new Item_return_int("Swaps", 10, MYSQL_TYPE_LONG)); + } + + if(options & PROFILE_SOURCE) + { + field_list.push_back(new Item_empty_string("Source_function", + MYSQL_ERRMSG_SIZE)); + field_list.push_back(new Item_empty_string("Source_file", + MYSQL_ERRMSG_SIZE)); + field_list.push_back(new Item_return_int("Source_line", 10, + MYSQL_TYPE_LONG)); + } + + if (thd->protocol->send_fields(&field_list, + Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) + DBUG_RETURN(TRUE); + + SELECT_LEX *sel= &thd->lex->select_lex; + SELECT_LEX_UNIT *unit= &thd->lex->unit; + ha_rows idx= 0; + Protocol *protocol=thd->protocol; + + unit->set_limit(sel); + + List_iterator it(entries); + ulonglong last_time= ps->time; + while ((prof= it++)) + { + if (++idx <= unit->offset_limit_cnt) + continue; + if (idx > unit->select_limit_cnt) + break; + + protocol->prepare_for_resend(); + protocol->store(prof->status, strlen(prof->status), system_charset_info); + protocol->store((ulonglong)(prof->time - ps->time)/10); + + if (options & PROFILE_CPU) + { + protocol->store((ulonglong)RUSAGE_DIFF_USEC(prof->rusage.ru_utime, + ps->rusage.ru_utime)); + protocol->store((ulonglong)RUSAGE_DIFF_USEC(prof->rusage.ru_stime, + ps->rusage.ru_stime)); + } + + if (options & PROFILE_CONTEXT) + { + protocol->store((uint32)(prof->rusage.ru_nvcsw - ps->rusage.ru_nvcsw)); + protocol->store((uint32)(prof->rusage.ru_nivcsw - ps->rusage.ru_nivcsw)); + } + + if (options & PROFILE_BLOCK_IO) + { + protocol->store((uint32)(prof->rusage.ru_inblock-ps->rusage.ru_inblock)); + protocol->store((uint32)(prof->rusage.ru_oublock-ps->rusage.ru_oublock)); + } + + if (options & PROFILE_IPC) + { + protocol->store((uint32)(prof->rusage.ru_msgsnd - ps->rusage.ru_msgsnd)); + protocol->store((uint32)(prof->rusage.ru_msgrcv - ps->rusage.ru_msgrcv)); + } + + if (options & PROFILE_PAGE_FAULTS) + { + protocol->store((uint32)(prof->rusage.ru_majflt - ps->rusage.ru_majflt)); + protocol->store((uint32)(prof->rusage.ru_minflt - ps->rusage.ru_minflt)); + } + + if (options & PROFILE_SWAPS) + { + protocol->store((uint32)(prof->rusage.ru_nswap - ps->rusage.ru_nswap)); + } + + if (options & PROFILE_SOURCE) + { + if(prof->function && prof->file) + { + protocol->store(prof->function, strlen(prof->function), system_charset_info); + protocol->store(prof->file, strlen(prof->file), system_charset_info); + protocol->store(prof->line); + } else { + protocol->store("(unknown)", 10, system_charset_info); + protocol->store("(unknown)", 10, system_charset_info); + protocol->store((uint32) 0); + } + } + + if (protocol->write()) + DBUG_RETURN(TRUE); + last_time= prof->time; + } + send_eof(thd); + DBUG_RETURN(FALSE); +} + +/* XXX: enabled should be set to the current global profiling setting */ +PROFILING::PROFILING() + :enabled(1), keeping(1), current(NULL), last(NULL) +{ + init_sql_alloc(&root, + PROFILE_ALLOC_BLOCK_SIZE, + PROFILE_ALLOC_PREALLOC_SIZE); +} + +PROFILING::~PROFILING() +{ + free_root(&root, MYF(0)); +} + +void PROFILING::status(const char *status_arg, + const char *function_arg, + const char *file_arg, unsigned int line_arg) +{ + DBUG_ENTER("PROFILING::status"); + + if(!current) + reset(); + + if(unlikely(enabled)) + current->status(status_arg, function_arg, file_arg, line_arg); + + thd->proc_info= status_arg; + + DBUG_VOID_RETURN; +} + +void PROFILING::store() +{ + MEM_ROOT *old_root; + DBUG_ENTER("PROFILING::store"); + + if (last && current && (last->query_id == current->query_id)) + DBUG_VOID_RETURN; + + if (history.elements > 10) /* XXX: global/session var */ + { + PROFILE *tmp= history.pop(); + delete tmp; + } + + old_root= thd->mem_root; + thd->mem_root= &root; + + if (current) + { + if (keeping && (!current->entries.is_empty())) { + last= current; + history.push_back(current); + current= NULL; + } else { + delete current; + } + } + + current= new PROFILE(this); + thd->mem_root= old_root; + + DBUG_VOID_RETURN; +} + +void PROFILING::reset() +{ + DBUG_ENTER("PROFILING::reset"); + + store(); + + current->reset(); + /*free_root(&root, MYF(0));*/ + keep(); + + DBUG_VOID_RETURN; +} + +bool PROFILING::show_profiles() +{ + PROFILE *prof; + List field_list; + DBUG_ENTER("PROFILING::list_all"); + + field_list.push_back(new Item_return_int("Query_ID", 10, + MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Time", 20, + MYSQL_TYPE_LONGLONG)); + /* TODO: Add another field that lists the query. */ + + if (thd->protocol->send_fields(&field_list, + Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) + DBUG_RETURN(TRUE); + + SELECT_LEX *sel= &thd->lex->select_lex; + SELECT_LEX_UNIT *unit= &thd->lex->unit; + ha_rows idx= 0; + Protocol *protocol=thd->protocol; + + unit->set_limit(sel); + + List_iterator it(history); + while ((prof= it++)) + { + PROFILE_ENTRY *ps= &prof->profile_start; + PROFILE_ENTRY *pe= prof->profile_end; + + if (++idx <= unit->offset_limit_cnt) + continue; + if (idx > unit->select_limit_cnt) + break; + + protocol->prepare_for_resend(); + protocol->store((uint32)(prof->query_id)); + protocol->store((ulonglong)((pe->time - ps->time)/10)); + + if (protocol->write()) + DBUG_RETURN(TRUE); + } + send_eof(thd); + DBUG_RETURN(FALSE); +} + +bool PROFILING::show(uint options, uint query_id) +{ + DBUG_ENTER("PROFILING::show"); + PROFILE *prof; + + List_iterator it(history); + while ((prof= it++)) + { + if(prof->query_id == query_id) + prof->show(options); + } + + DBUG_RETURN(TRUE); +} + +bool PROFILING::show_last(uint options) +{ + DBUG_ENTER("PROFILING::show_last"); + if (!history.is_empty()) { + DBUG_RETURN(last->show(options)); + } + DBUG_RETURN(TRUE); +} diff --git a/sql/sql_profile.h b/sql/sql_profile.h new file mode 100644 index 00000000000..698a80f07e4 --- /dev/null +++ b/sql/sql_profile.h @@ -0,0 +1,187 @@ +/* Copyright (C) 2005 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef SQL_PROFILE_H +#define SQL_PROFILE_H + +#include +#include + +#if 1 +#define THD_PROC_INFO(thd, msg) do { if(unlikely((thd)->profiling.enabled)) { (thd)->profiling.status((msg), __FUNCTION__, __FILE__, __LINE__); } else { (thd)->proc_info= (msg); } } while (0) +#else +#define THD_PROC_INFO(thd, msg) do { (thd)->proc_info= (msg); } while (0) +#endif + +#if 0 + + struct rusage { + struct timeval ru_utime; /* user time used */ + struct timeval ru_stime; /* system time used */ + long ru_maxrss; /* integral max resident set size */ + long ru_ixrss; /* integral shared text memory size */ + long ru_idrss; /* integral unshared data size */ + long ru_isrss; /* integral unshared stack size */ + long ru_minflt; /* page reclaims */ + long ru_majflt; /* page faults */ + long ru_nswap; /* swaps */ + long ru_inblock; /* block input operations */ + long ru_oublock; /* block output operations */ + long ru_msgsnd; /* messages sent */ + long ru_msgrcv; /* messages received */ + long ru_nsignals; /* signals received */ + long ru_nvcsw; /* voluntary context switches */ + long ru_nivcsw; /* involuntary context switches */ + }; + +#endif + +#define PROFILE_NONE 0 +#define PROFILE_CPU 1 +#define PROFILE_MEMORY 2 +#define PROFILE_BLOCK_IO 4 +#define PROFILE_CONTEXT 8 +#define PROFILE_PAGE_FAULTS 16 +#define PROFILE_IPC 32 +#define PROFILE_SWAPS 64 +#define PROFILE_SOURCE 16384 +#define PROFILE_ALL 32767 + +class PROFILE_ENTRY; +class PROFILE; +class PROFILING; + +/* + A single entry in a single profile. +*/ + +class PROFILE_ENTRY: public Sql_alloc +{ +public: + PROFILE *profile; + char *status; + ulonglong time; + struct rusage rusage; + + char *function; + char *file; + unsigned int line; + + PROFILE_ENTRY(); + PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg); + PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg, + const char *function_arg, + const char *file_arg, unsigned int line_arg); + ~PROFILE_ENTRY(); + + void set_status(const char *status_arg); + void collect(); +}; + +/* + The full profile for a single query. Includes multiple PROFILE_ENTRY + objects. +*/ + +class PROFILE: public Sql_alloc +{ +public: + PROFILING *profiling; + query_id_t query_id; + PROFILE_ENTRY profile_start; + PROFILE_ENTRY *profile_end; + List entries; + + PROFILE(PROFILING *profiling_arg); + ~PROFILE(); + + /* Add a profile status change to the current profile. */ + void status(const char *status_arg, + const char *function_arg, + const char *file_arg, unsigned int line_arg); + + /* Reset the contents of this profile entry. */ + void reset(); + + /* Show this profile. This is called by PROFILING. */ + bool show(uint options); +}; + +/* + Profiling state for a single THD. Contains multiple PROFILE objects. +*/ + +class PROFILING: public Sql_alloc +{ +public: + MEM_ROOT root; + THD *thd; + bool enabled; + bool keeping; + + PROFILE *current; + PROFILE *last; + List history; + + PROFILING(); + ~PROFILING(); + + inline void set_thd(THD *thd_arg) { thd= thd_arg; }; + + /* + Should we try to collect profiling information at all? + + If we disable profiling, we cannot later decide to turn it back + on for the same query. + */ + inline void enable() { enabled= 1; }; + inline void disable() { enabled= 0; }; + + /* + Do we intend to keep the currently collected profile? + + We don't keep profiles for some commands, such as SHOW PROFILE, + SHOW PROFILES, and some SQLCOM commands which aren't useful to + profile. The keep() and discard() functions can be called many + times, only the final setting when the query finishes is used + to decide whether to discard the profile. + + The default is to keep the profile for all queries. + */ + inline void keep() { keeping= 1; }; + inline void discard() { keeping= 0; }; + + void status(const char *status_arg, + const char *function_arg, + const char *file_arg, unsigned int line_arg); + + /* Stash this profile in the profile history. */ + void store(); + + /* Reset the current profile and state of profiling for the next query. */ + void reset(); + + /* SHOW PROFILES */ + bool show_profiles(); + + /* SHOW PROFILE FOR QUERY query_id */ + bool show(uint options, uint query_id); + + /* SHOW PROFILE */ + bool show_last(uint options); +}; + +#endif /* SQL_PROFILE_H */ diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 8da8bbe25ca..5da31ed479a 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1197,7 +1197,7 @@ bool change_master(THD* thd, MASTER_INFO* mi) if (need_relay_log_purge) { relay_log_purge= 1; - thd->proc_info="Purging old relay logs"; + THD_PROC_INFO(thd, "Purging old relay logs"); if (purge_relay_logs(&mi->rli, thd, 0 /* not only reset, but also reinit */, &errmsg)) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3d2f46a9982..cb8f39084df 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -599,6 +599,7 @@ JOIN::optimize() if (thd->lex->orig_sql_command != SQLCOM_SHOW_STATUS) thd->status_var.last_query_cost= 0.0; + THD_PROC_INFO(thd, "optimizing"); row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR : unit->select_limit_cnt); /* select_limit is used to decide if we are likely to scan the whole table */ @@ -702,14 +703,14 @@ JOIN::optimize() thd->fatal_error(); error= res; DBUG_PRINT("error",("Error from opt_sum_query")); - DBUG_RETURN(1); + DBUG_RETURN(1); } if (res < 0) { DBUG_PRINT("info",("No matching min/max row")); - zero_result_cause= "No matching min/max row"; - error=0; - DBUG_RETURN(0); + zero_result_cause= "No matching min/max row"; + error=0; + DBUG_RETURN(0); } DBUG_PRINT("info",("Select tables optimized away")); zero_result_cause= "Select tables optimized away"; @@ -745,7 +746,7 @@ JOIN::optimize() sort_by_table= get_sort_by_table(order, group_list, select_lex->leaf_tables); /* Calculate how to do the join */ - thd->proc_info= "statistics"; + THD_PROC_INFO(thd, "statistics"); if (make_join_statistics(this, select_lex->leaf_tables, conds, &keyuse) || thd->is_fatal_error) { @@ -755,7 +756,7 @@ JOIN::optimize() /* Remove distinct if only const tables */ select_distinct= select_distinct && (const_tables != tables); - thd->proc_info= "preparing"; + THD_PROC_INFO(thd, "preparing"); if (result->initialize_tables(this)) { DBUG_PRINT("error",("Error: initialize_tables() failed")); @@ -1102,8 +1103,9 @@ JOIN::optimize() join_tab[const_tables].type != JT_REF_OR_NULL && (order && simple_order || group_list && simple_group)) { - if (add_ref_to_table_cond(thd,&join_tab[const_tables])) + if (add_ref_to_table_cond(thd,&join_tab[const_tables])) { DBUG_RETURN(1); + } } if (!(select_options & SELECT_BIG_RESULT) && @@ -1161,7 +1163,7 @@ JOIN::optimize() if (need_tmp) { DBUG_PRINT("info",("Creating tmp table")); - thd->proc_info="Creating tmp table"; + THD_PROC_INFO(thd, "creating temporary table"); init_items_ref_array(); @@ -1190,7 +1192,9 @@ JOIN::optimize() select_options, tmp_rows_limit, (char *) ""))) + { DBUG_RETURN(1); + } /* We don't have to store rows in temp table that doesn't match HAVING if: @@ -1210,28 +1214,35 @@ JOIN::optimize() if (group_list && simple_group) { DBUG_PRINT("info",("Sorting for group")); - thd->proc_info="Sorting for group"; + THD_PROC_INFO(thd, "sorting for group"); if (create_sort_index(thd, this, group_list, HA_POS_ERROR, HA_POS_ERROR) || alloc_group_fields(this, group_list) || make_sum_func_list(all_fields, fields_list, 1) || setup_sum_funcs(thd, sum_funcs)) - DBUG_RETURN(1); + { + DBUG_RETURN(1); + } group_list=0; } else { if (make_sum_func_list(all_fields, fields_list, 0) || setup_sum_funcs(thd, sum_funcs)) - DBUG_RETURN(1); + { + DBUG_RETURN(1); + } + if (!group_list && ! exec_tmp_table1->distinct && order && simple_order) { - DBUG_PRINT("info",("Sorting for order")); - thd->proc_info="Sorting for order"; - if (create_sort_index(thd, this, order, + DBUG_PRINT("info",("Sorting for order")); + THD_PROC_INFO(thd, "Sorting for order"); + if (create_sort_index(thd, this, order, HA_POS_ERROR, HA_POS_ERROR)) - DBUG_RETURN(1); - order=0; + { + DBUG_RETURN(1); + } + order=0; } } @@ -1354,6 +1365,7 @@ JOIN::exec() int tmp_error; DBUG_ENTER("JOIN::exec"); + THD_PROC_INFO(thd, "executing"); error= 0; if (procedure) { @@ -1493,7 +1505,7 @@ JOIN::exec() curr_tmp_table= exec_tmp_table1; /* Copy data to the temporary table */ - thd->proc_info= "Copying to tmp table"; + THD_PROC_INFO(thd, "Copying to tmp table"); DBUG_PRINT("info", ("%s", thd->proc_info)); if ((tmp_error= do_select(curr_join, (List *) 0, curr_tmp_table, 0))) { @@ -1616,7 +1628,7 @@ JOIN::exec() } if (curr_join->group_list) { - thd->proc_info= "Creating sort index"; + THD_PROC_INFO(thd, "Creating sort index"); if (curr_join->join_tab == join_tab && save_join_tab()) { DBUG_VOID_RETURN; @@ -1630,7 +1642,7 @@ JOIN::exec() sortorder= curr_join->sortorder; } - thd->proc_info="Copying to group table"; + THD_PROC_INFO(thd, "Copying to group table"); DBUG_PRINT("info", ("%s", thd->proc_info)); tmp_error= -1; if (curr_join != this) @@ -1686,7 +1698,7 @@ JOIN::exec() curr_join->join_free(); /* Free quick selects */ if (curr_join->select_distinct && ! curr_join->group_list) { - thd->proc_info="Removing duplicates"; + THD_PROC_INFO(thd, "Removing duplicates"); if (curr_join->tmp_having) curr_join->tmp_having->update_used_tables(); if (remove_duplicates(curr_join, curr_tmp_table, @@ -1747,7 +1759,7 @@ JOIN::exec() if (curr_join->group_list || curr_join->order) { DBUG_PRINT("info",("Sorting for send_fields")); - thd->proc_info="Sorting result"; + THD_PROC_INFO(thd, "Sorting result"); /* If we have already done the group, add HAVING to sorted table */ if (curr_join->tmp_having && ! curr_join->group_list && ! curr_join->sort_and_group) @@ -1871,7 +1883,7 @@ JOIN::exec() } else { - thd->proc_info="Sending data"; + THD_PROC_INFO(thd, "Sending data"); DBUG_PRINT("info", ("%s", thd->proc_info)); result->send_fields((procedure ? curr_join->procedure_fields_list : *curr_fields_list), @@ -2019,7 +2031,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array, { if (!(join= new JOIN(thd, fields, select_options, result))) DBUG_RETURN(TRUE); - thd->proc_info="init"; + THD_PROC_INFO(thd, "init"); thd->used_tables=0; // Updated by setup_fields if (err= join->prepare(rref_pointer_array, tables, wild_num, conds, og_num, order, group, having, proc_param, @@ -2064,8 +2076,9 @@ mysql_select(THD *thd, Item ***rref_pointer_array, err: if (free_join) { - thd->proc_info="end"; + THD_PROC_INFO(thd, "cleaning up"); err|= select_lex->cleanup(); + THD_PROC_INFO(thd, "end"); DBUG_RETURN(err || thd->net.report_error); } DBUG_RETURN(join->error); @@ -9745,7 +9758,7 @@ free_tmp_table(THD *thd, TABLE *entry) DBUG_PRINT("enter",("table: %s",entry->alias)); save_proc_info=thd->proc_info; - thd->proc_info="removing tmp table"; + THD_PROC_INFO(thd, "removing tmp table"); if (entry->file) { @@ -9773,7 +9786,7 @@ free_tmp_table(THD *thd, TABLE *entry) bitmap_clear_bit(&temp_pool, entry->temp_pool_slot); free_root(&own_root, MYF(0)); /* the table is allocated in its own root */ - thd->proc_info=save_proc_info; + THD_PROC_INFO(thd, save_proc_info); DBUG_VOID_RETURN; } @@ -9803,7 +9816,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, DBUG_RETURN(1); // End of memory save_proc_info=thd->proc_info; - thd->proc_info="converting HEAP to MyISAM"; + THD_PROC_INFO(thd, "converting HEAP to MyISAM"); if (create_myisam_tmp_table(&new_table,param, thd->lex->select_lex.options | thd->options)) @@ -9856,8 +9869,8 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, table->s= &table->share_not_to_be_used; table->file->change_table_ptr(table); if (save_proc_info) - thd->proc_info= (!strcmp(save_proc_info,"Copying to tmp table") ? - "Copying to tmp table on disk" : save_proc_info); + THD_PROC_INFO(thd, (!strcmp(save_proc_info,"Copying to tmp table") ? + "Copying to tmp table on disk" : save_proc_info)); DBUG_RETURN(0); err: @@ -9869,7 +9882,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, new_table.file->delete_table(new_table.s->table_name); delete new_table.file; err2: - thd->proc_info=save_proc_info; + THD_PROC_INFO(thd, save_proc_info); DBUG_RETURN(1); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index ee310ea6fe4..f4e67fc24f4 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1350,7 +1350,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) #if !defined(DONT_USE_THR_ALARM) && ! defined(SCO) if (pthread_kill(tmp->real_id,0)) - tmp->proc_info="*** DEAD ***"; // This shouldn't happen + THD_PROC_INFO(tmp, "*** DEAD ***"); // This shouldn't happen #endif #ifdef EXTRA_DEBUG thd_info->start_time= tmp->time_after_lock; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c14529f6eb1..0e2fd67965f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1728,7 +1728,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, } } - thd->proc_info="creating table"; + THD_PROC_INFO(thd, "creating table"); create_info->table_existed= 0; // Mark that table is created if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) @@ -1759,7 +1759,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, end: VOID(pthread_mutex_unlock(&LOCK_open)); - thd->proc_info="After create"; + THD_PROC_INFO(thd, "After create"); DBUG_RETURN(error); warn: @@ -2878,7 +2878,7 @@ mysql_discard_or_import_tablespace(THD *thd, ALTER TABLE */ - thd->proc_info="discard_or_import_tablespace"; + THD_PROC_INFO(thd, "discard_or_import_tablespace"); discard= test(tablespace_op == DISCARD_TABLESPACE); @@ -2895,7 +2895,7 @@ mysql_discard_or_import_tablespace(THD *thd, error=table->file->discard_or_import_tablespace(discard); - thd->proc_info="end"; + THD_PROC_INFO(thd, "end"); if (error) goto err; @@ -2958,7 +2958,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, frm_type_enum frm_type; DBUG_ENTER("mysql_alter_table"); - thd->proc_info="init"; + THD_PROC_INFO(thd, "init"); table_name=table_list->table_name; alias= (lower_case_table_names == 2) ? table_list->alias : table_name; @@ -3093,7 +3093,7 @@ view_err: DBUG_RETURN(TRUE); } - thd->proc_info="setup"; + THD_PROC_INFO(thd, "setup"); if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) && !table->s->tmp_table) // no need to touch frm { @@ -3101,7 +3101,7 @@ view_err: VOID(pthread_mutex_lock(&LOCK_open)); if (new_name != table_name || new_db != db) { - thd->proc_info="rename"; + THD_PROC_INFO(thd, "rename"); /* Then do a 'simple' rename of the table */ error=0; if (!access(new_name_buff,F_OK)) @@ -3573,7 +3573,7 @@ view_err: /* We don't want update TIMESTAMP fields during ALTER TABLE. */ thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields thd->cuted_fields=0L; - thd->proc_info="copy to tmp table"; + THD_PROC_INFO(thd, "copy to tmp table"); next_insert_id=thd->next_insert_id; // Remember for logging copied=deleted=0; if (new_table && !new_table->s->is_view) @@ -3645,7 +3645,7 @@ view_err: from the cache, free all locks, close the old table and remove it. */ - thd->proc_info="rename result table"; + THD_PROC_INFO(thd, "rename result table"); my_snprintf(old_name, sizeof(old_name), "%s2-%lx-%lx", tmp_file_prefix, current_pid, thd->thread_id); if (lower_case_table_names) @@ -3756,7 +3756,7 @@ view_err: broadcast_refresh(); goto err; } - thd->proc_info="end"; + THD_PROC_INFO(thd, "end"); if (mysql_bin_log.is_open()) { thd->clear_error(); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 3b6aa5f1aa2..6d3e29516ba 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -167,7 +167,7 @@ int mysql_update(THD *thd, mysql_handle_derived(thd->lex, &mysql_derived_filling))) DBUG_RETURN(1); - thd->proc_info="init"; + THD_PROC_INFO(thd, "init"); table= table_list->table; table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); @@ -359,7 +359,7 @@ int mysql_update(THD *thd, else init_read_record_idx(&info, thd, table, 1, used_index); - thd->proc_info="Searching rows for update"; + THD_PROC_INFO(thd, "Searching rows for update"); uint tmp_limit= limit; while (!(error=info.read_record(&info)) && !thd->killed) @@ -424,7 +424,7 @@ int mysql_update(THD *thd, updated= found= 0; thd->count_cuted_fields= CHECK_FIELD_WARN; /* calc cuted fields */ thd->cuted_fields=0L; - thd->proc_info="Updating"; + THD_PROC_INFO(thd, "Updating"); query_id=thd->query_id; transactional_table= table->file->has_transactions(); @@ -512,7 +512,7 @@ int mysql_update(THD *thd, end_read_record(&info); free_io_cache(table); // If ORDER BY delete select; - thd->proc_info="end"; + THD_PROC_INFO(thd, "end"); VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY)); /* @@ -960,7 +960,7 @@ int multi_update::prepare(List ¬_used_values, thd->count_cuted_fields= CHECK_FIELD_WARN; thd->cuted_fields=0L; - thd->proc_info="updating main table"; + THD_PROC_INFO(thd, "updating main table"); tables_to_update= get_table_map(fields); @@ -1512,11 +1512,11 @@ err2: bool multi_update::send_eof() { char buff[STRING_BUFFER_USUAL_SIZE]; - thd->proc_info="updating reference tables"; + THD_PROC_INFO(thd, "updating reference tables"); /* Does updates for the last n - 1 tables, returns 0 if ok */ int local_error = (table_count) ? do_updates(0) : 0; - thd->proc_info= "end"; + THD_PROC_INFO(thd, "end"); /* We must invalidate the query cache before binlog writing and ha_autocommit_... */ diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 53844eb0fd2..15c58bd0673 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -589,7 +589,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, DBUG_RETURN(0); err: - thd->proc_info= "end"; + THD_PROC_INFO(thd, "end"); lex->link_first_table_back(view, link_to_local); unit->cleanup(); DBUG_RETURN(res || thd->net.report_error); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a362d1ce4ea..9c60630fd50 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -181,6 +181,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token BIT_SYM %token BIT_XOR %token BLOB_SYM +%token BLOCK_SYM %token BOOLEAN_SYM %token BOOL_SYM %token BOTH @@ -221,10 +222,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token CONSISTENT_SYM %token CONSTRAINT %token CONTAINS_SYM +%token CONTEXT_SYM %token CONTINUE_SYM %token CONVERT_SYM %token CONVERT_TZ_SYM %token COUNT_SYM +%token CPU_SYM %token CREATE %token CROSS %token CUBE_SYM @@ -298,6 +301,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token EXTRACT_SYM %token FALSE_SYM %token FAST_SYM +%token FAULTS_SYM %token FETCH_SYM %token FIELD_FUNC %token FILE_SYM @@ -367,6 +371,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token INT_SYM %token INVOKER_SYM %token IN_SYM +%token IO_SYM +%token IPC_SYM %token IS %token ISOLATION %token ISSUER_SYM @@ -435,6 +441,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token MEDIUMINT %token MEDIUMTEXT %token MEDIUM_SYM +%token MEMORY_SYM %token MERGE_SYM %token MICROSECOND_SYM %token MIGRATE_SYM @@ -493,6 +500,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token OUTFILE %token OUT_SYM %token PACK_KEYS_SYM +%token PAGE_SYM %token PARTIAL %token PASSWORD %token PARAM_MARKER @@ -510,6 +518,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token PROCEDURE %token PROCESS %token PROCESSLIST_SYM +%token PROFILE_SYM +%token PROFILES_SYM %token PURGE %token QUARTER_SYM %token QUERY_SYM @@ -580,6 +590,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token SMALLINT %token SNAPSHOT_SYM %token SOUNDS_SYM +%token SOURCE_SYM %token SPATIAL_SYM %token SPECIFIC_SYM %token SQLEXCEPTION_SYM @@ -610,6 +621,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token SUM_SYM %token SUPER_SYM %token SUSPEND_SYM +%token SWAPS_SYM +%token SWITCHES_SYM %token SYSDATE %token TABLES %token TABLESPACE @@ -735,7 +748,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); union_opt select_derived_init option_type2 %type - ulong_num raid_types merge_insert_types + ulong_num raid_types merge_insert_types opt_profile_query_arg %type ulonglong_num @@ -6472,6 +6485,48 @@ opt_table_sym: /* empty */ | TABLE_SYM; +opt_profile_defs: + /* empty */ + | profile_defs + +profile_defs: + profile_def + | profile_defs ',' profile_def + +profile_def: + CPU_SYM + { Lex->profile_options|= PROFILE_CPU; } + | MEMORY_SYM + { Lex->profile_options|= PROFILE_MEMORY; } + | BLOCK_SYM IO_SYM + { Lex->profile_options|= PROFILE_BLOCK_IO; } + | CONTEXT_SYM SWITCHES_SYM + { Lex->profile_options|= PROFILE_CONTEXT; } + | PAGE_SYM FAULTS_SYM + { Lex->profile_options|= PROFILE_PAGE_FAULTS; } + | IPC_SYM + { Lex->profile_options|= PROFILE_IPC; } + | SWAPS_SYM + { Lex->profile_options|= PROFILE_SWAPS; } + | SOURCE_SYM + { Lex->profile_options|= PROFILE_SOURCE; } + | ALL + { Lex->profile_options|= PROFILE_ALL; } + ; + +opt_profile_query_arg: + /* empty */ + { $$= 0; } + | QUERY_SYM NUM + { $$= atoi($2.str); } + ; + +opt_profile_args: + /* empty */ + | FOR_SYM opt_profile_query_arg + { Lex->profile_query_id = $2; } + ; + /* Show things */ show: SHOW @@ -6607,6 +6662,10 @@ show_param: { Lex->sql_command = SQLCOM_SHOW_WARNS;} | ERRORS opt_limit_clause_init { Lex->sql_command = SQLCOM_SHOW_ERRORS;} + | PROFILES_SYM + { Lex->sql_command = SQLCOM_SHOW_PROFILES; } + | PROFILE_SYM opt_profile_defs opt_profile_args opt_limit_clause_init + { Lex->sql_command = SQLCOM_SHOW_PROFILE; } | opt_var_type STATUS_SYM wild_and_where { LEX *lex= Lex; @@ -7698,6 +7757,7 @@ keyword_sp: | BERKELEY_DB_SYM {} | BINLOG_SYM {} | BIT_SYM {} + | BLOCK_SYM {} | BOOL_SYM {} | BOOLEAN_SYM {} | BTREE_SYM {} @@ -7714,6 +7774,8 @@ keyword_sp: | COMPRESSED_SYM {} | CONCURRENT {} | CONSISTENT_SYM {} + | CONTEXT_SYM {} + | CPU_SYM {} | CUBE_SYM {} | DATA_SYM {} | DATETIME {} @@ -7736,6 +7798,7 @@ keyword_sp: | EXPANSION_SYM {} | EXTENDED_SYM {} | FAST_SYM {} + | FAULTS_SYM {} | FOUND_SYM {} | DISABLE_SYM {} | ENABLE_SYM {} @@ -7760,6 +7823,8 @@ keyword_sp: | ISSUER_SYM {} | INNOBASE_SYM {} | INSERT_METHOD {} + | IO_SYM {} + | IPC_SYM {} | RELAY_THREAD {} | LAST_SYM {} | LEAVES {} @@ -7789,6 +7854,7 @@ keyword_sp: | MAX_UPDATES_PER_HOUR {} | MAX_USER_CONNECTIONS_SYM {} | MEDIUM_SYM {} + | MEMORY_SYM {} | MERGE_SYM {} | MICROSECOND_SYM {} | MIGRATE_SYM {} @@ -7815,6 +7881,7 @@ keyword_sp: | ONE_SHOT_SYM {} | ONE_SYM {} | PACK_KEYS_SYM {} + | PAGE_SYM {} | PARTIAL {} | PASSWORD {} | PHASE_SYM {} @@ -7824,6 +7891,8 @@ keyword_sp: | PRIVILEGES {} | PROCESS {} | PROCESSLIST_SYM {} + | PROFILE_SYM {} + | PROFILES_SYM {} | QUARTER_SYM {} | QUERY_SYM {} | QUICK {} @@ -7857,6 +7926,7 @@ keyword_sp: | SHUTDOWN {} | SNAPSHOT_SYM {} | SOUNDS_SYM {} + | SOURCE_SYM {} | SQL_CACHE_SYM {} | SQL_BUFFER_RESULT {} | SQL_NO_CACHE_SYM {} @@ -7868,6 +7938,8 @@ keyword_sp: | SUBJECT_SYM {} | SUPER_SYM {} | SUSPEND_SYM {} + | SWAPS_SYM {} + | SWITCHES_SYM {} | TABLES {} | TABLESPACE {} | TEMPORARY {} From 03490a842ee9d272f40df8ba447f5aae462bb010 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 8 Jan 2007 15:57:03 -0500 Subject: [PATCH 02/99] Community version numbering. --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 49e295eeebb..2a3e5988385 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.34) +AM_INIT_AUTOMAKE(mysql, 5.0.33) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 From 4369b5f36e2f91ab7a4d641ec8e8554f0db4a363 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 9 Jan 2007 13:02:15 +0100 Subject: [PATCH 03/99] configure.in: raise version to 5.0.33 configure.in: raise version to 5.0.33 --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index f6a6eedac70..f72476cd4cf 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.32) +AM_INIT_AUTOMAKE(mysql, 5.0.33) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 @@ -19,7 +19,7 @@ SHARED_LIB_VERSION=$SHARED_LIB_MAJOR_VERSION:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=32 +NDB_VERSION_BUILD=33 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From 8326c2c25dd9038781951b00ed6e6e04e612e8ff Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 9 Jan 2007 14:42:56 +0100 Subject: [PATCH 04/99] raise version number after cloning 5.0.33 --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index f72476cd4cf..fddf2dc8192 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.33) +AM_INIT_AUTOMAKE(mysql, 5.0.35) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 @@ -19,7 +19,7 @@ SHARED_LIB_VERSION=$SHARED_LIB_MAJOR_VERSION:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=33 +NDB_VERSION_BUILD=35 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From 351b966462232060eb27288275508453406b6401 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 18 Jan 2007 09:50:16 -0500 Subject: [PATCH 05/99] Bug#24822: Patch: uptime_since_flush_status Provide the number of seconds since flush as a new status variable named "Uptime_since_flush_status". --- Override the post-flush value, as a second could pass between the two statements. mysql-test/r/information_schema.result: Test new status variable. --- Override the post-flush value, as a second could pass between the two statements. mysql-test/t/information_schema.test: Test new status variable. --- Override the post-flush value, as a second could pass between the two statements. sql/mysql_priv.h: Add variable to hold previous flush time. sql/mysqld.cc: Add variable to hold previous flush time. Insert name for referring to it, and initialize the value. sql/sql_show.cc: Yield value of elapsed time since flush when asked. sql/structs.h: Add new show-flush-time to SHOW types enumeration. --- BitKeeper/etc/collapsed | 2 ++ mysql-test/r/information_schema.result | 7 +++++++ mysql-test/t/information_schema.test | 13 ++++++++++--- sql/mysql_priv.h | 2 +- sql/mysqld.cc | 6 ++++-- sql/sql_show.cc | 4 ++++ sql/structs.h | 1 + 7 files changed, 29 insertions(+), 6 deletions(-) diff --git a/BitKeeper/etc/collapsed b/BitKeeper/etc/collapsed index e754ac133ea..43292906ddd 100644 --- a/BitKeeper/etc/collapsed +++ b/BitKeeper/etc/collapsed @@ -32,3 +32,5 @@ 459c03b9N_mqF2XJKK6DwSrIt7e6_g 459c1965_BQMBzBO8S_gVqjTHYQrmw 459c2098XoAUsUn8N07IVRDD6CTM-A +459ea845XenN-uWqEM5LFvUT60tW_A +45af88c9RIIJWPfBxs3o7zekI-ELPQ diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 21d7bfb1b21..d4fd536003a 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1269,3 +1269,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 0 const row not found 2 DERIVED tables ALL NULL NULL NULL NULL 2 drop view v1; +show global status like "Uptime_%"; +Variable_name Value +Uptime_since_flush_status # +flush status; +show global status like "Uptime_%"; +Variable_name Value +Uptime_since_flush_status # diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 623ccee49e4..a4cf3b497be 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -971,9 +971,6 @@ SELECT COLUMN_NAME, MD5(COLUMN_DEFAULT), LENGTH(COLUMN_DEFAULT), COLUMN_DEFAULT= DROP TABLE bug23037; DROP FUNCTION get_value; - - - # # Bug#22413: EXPLAIN SELECT FROM view with ORDER BY yield server crash # @@ -987,4 +984,14 @@ explain select * from v1; explain select * from (select table_name from information_schema.tables) as a; drop view v1; +# +# Bug#24822: Patch: uptime_since_flush_status +# +--replace_column 2 # +show global status like "Uptime_%"; +flush status; +--replace_column 2 # +show global status like "Uptime_%"; # Almost certainly zero + + # End of 5.0 tests. diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b28e885e2a5..e8fd84beaf9 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1190,7 +1190,7 @@ void my_dbopt_free(void); External variables */ -extern time_t start_time; +extern time_t start_time, flush_status_time; extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH], mysql_real_data_home[], *opt_mysql_tmpdir, mysql_charsets_dir[], def_ft_boolean_syntax[sizeof(ft_boolean_syntax)]; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 95de1f91ecf..4a07cd0be0d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -428,7 +428,7 @@ ulong expire_logs_days = 0; ulong rpl_recovery_rank=0; double log_10[32]; /* 10 potences */ -time_t start_time; +time_t start_time, flush_status_time; char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], system_time_zone[30]; char *default_tz_name; @@ -2589,7 +2589,7 @@ static int init_common_variables(const char *conf_file_name, int argc, tzset(); // Set tzname max_system_variables.pseudo_thread_id= (ulong)~0; - start_time=time((time_t*) 0); + start_time= flush_status_time= time((time_t*) 0); if (init_thread_environment()) return 1; mysql_init_variables(); @@ -6264,6 +6264,7 @@ struct show_var_st status_vars[]= { {"Threads_created", (char*) &thread_created, SHOW_LONG_CONST}, {"Threads_running", (char*) &thread_running, SHOW_INT_CONST}, {"Uptime", (char*) 0, SHOW_STARTTIME}, + {"Uptime_since_flush_status",(char*) 0, SHOW_FLUSHTIME}, {NullS, NullS, SHOW_LONG} }; @@ -7534,6 +7535,7 @@ void refresh_status(THD *thd) /* Reset the counters of all key caches (default and named). */ process_key_caches(reset_key_cache_counters); + flush_status_time= time((time_t*) 0); pthread_mutex_unlock(&LOCK_status); /* diff --git a/sql/sql_show.cc b/sql/sql_show.cc index ac3acd5c986..0a39640aa4f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1492,6 +1492,10 @@ static bool show_status_array(THD *thd, const char *wild, nr= (long) (thd->query_start() - start_time); end= int10_to_str(nr, buff, 10); break; + case SHOW_FLUSHTIME: + nr= (long) (thd->query_start() - flush_status_time); + end= int10_to_str(nr, buff, 10); + break; case SHOW_QUESTION: end= int10_to_str((long) thd->query_id, buff, 10); break; diff --git a/sql/structs.h b/sql/structs.h index 2dcafdef615..4bb4d625cb4 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -174,6 +174,7 @@ enum SHOW_TYPE SHOW_BOOL, SHOW_MY_BOOL, SHOW_OPENTABLES, SHOW_STARTTIME, SHOW_QUESTION, SHOW_LONG_CONST, SHOW_INT_CONST, SHOW_HAVE, SHOW_SYS, SHOW_HA_ROWS, SHOW_VARS, + SHOW_FLUSHTIME, #ifdef HAVE_OPENSSL SHOW_SSL_CTX_SESS_ACCEPT, SHOW_SSL_CTX_SESS_ACCEPT_GOOD, SHOW_SSL_GET_VERSION, SHOW_SSL_CTX_GET_SESSION_CACHE_MODE, From 607c224969df2aa13f6b236440e02713a18e6c34 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 22 Feb 2007 10:03:08 -0500 Subject: [PATCH 06/99] Prevent bugs by making DBUG_* expressions syntactically equivalent to a single statement. --- Bug#24795: SHOW PROFILE Profiling is only partially functional on some architectures. Where there is no getrusage() system call, presently Null values are returned where it would be required. Notably, Windows needs some love applied to make it as useful. Syntax this adds: SHOW PROFILES SHOW PROFILE [types] [FOR QUERY n] [OFFSET n] [LIMIT n] where "n" is an integer and "types" is zero or many (comma-separated) of "CPU" "MEMORY" (not presently supported) "BLOCK IO" "CONTEXT SWITCHES" "PAGE FAULTS" "IPC" "SWAPS" "SOURCE" "ALL" It also adds a session variable (boolean) "profiling", set to "no" by default, and (integer) profiling_history_size, set to 15 by default. This patch abstracts setting THDs' "proc_info" behind a macro that can be used as a hook into the profiling code when profiling support is compiled in. All future code in this line should use that mechanism for setting thd->proc_info. --- Tests are now set to omit the statistics. --- Adds an Information_schema table, "profiling" for access to "show profile" data. --- Merge zippy.cornsilk.net:/home/cmiller/work/mysql/mysql-5.0-community-3--bug24795 into zippy.cornsilk.net:/home/cmiller/work/mysql/mysql-5.0-community --- Fix merge problems. --- Fixed one bug in the query_source being NULL. Updated test results. --- Include more thorough profiling tests. Improve support for prepared statements. Use session-specific query IDs, starting at zero. --- Selecting from I_S.profiling is no longer quashed in profiling, as requested by Giuseppe. Limit the size of captured query text. No longer log queries that are zero length. BitKeeper/deleted/.del-profile.result: Rename: mysql-test/r/profile.result -> BitKeeper/deleted/.del-profile.result BitKeeper/deleted/.del-profile.test: Rename: mysql-test/t/profile.test -> BitKeeper/deleted/.del-profile.test BitKeeper/deleted/.del-sql_profile.cc: Rename: sql/sql_profile.cc -> BitKeeper/deleted/.del-sql_profile.cc BitKeeper/deleted/.del-sql_profile.h: Rename: sql/sql_profile.h -> BitKeeper/deleted/.del-sql_profile.h configure.in: Add a configure-time option to enable/disable query profiling. The default is enabled. include/my_dbug.h: DBUG_* statements should be syntactically equivalent to a single statement. myisam/mi_open.c: DBUG_* statements should be syntactically equivalent to a single statement. mysql-test/r/information_schema.result: Updated (re-recorded) tests that I missed somehow. I verified these for correctness. mysql-test/r/information_schema_db.result: Updated test results I missed. mysql-test/r/mysqlshow.result: Fix merge problems. ndb/src/ndbapi/DictCache.cpp: DBUG_* statements should be syntactically equivalent to a single statement. sql/ha_archive.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/ha_berkeley.cc: Include patch backported to 5.0-global. THD::options is a ulonglong, not ulong. sql/ha_myisam.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/ha_myisammrg.cc: DBUG_* statements should be syntactically equivalent to a single statement. sql/ha_ndbcluster.cc: DBUG_* statements should be syntactically equivalent to a single statement. sql/item_cmpfunc.cc: DBUG_* statements should be syntactically equivalent to a single statement. sql/item_func.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/lock.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/log_event.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/mysql_priv.h: Use 64-bit constants for the 64-bit bit field. Add a new option bit for whether profiling is active or not. sql/mysqld.cc: Add semicolon to DBUG statement. Add a new system variable and set it. --- Set the minimum, which is zero and not 50. sql/repl_failsafe.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/set_var.cc: Make a new system global variable and session variable, to determine behavior of profiling. --- Include patch backported to 5.0-global. THD::options is a ulonglong, not ulong. sql/set_var.h: The THD::options bit field is ulonglong, not ulong. sql/slave.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. --- Include patch backported to 5.0-global. THD::options is a ulonglong, not ulong. sql/sp_head.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/sql_base.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. --- Include patch backported to 5.0-global. THD::options is a ulonglong, not ulong. sql/sql_cache.cc: DBUG_* statements should be syntactically equivalent to a single statement. --- Fix merge problems. sql/sql_class.cc: Insert a pointer to the current thread in the profiling code. --- Manual merge, undoing first patch. --- Fix merge problems. sql/sql_class.h: Create a new system variable, profiling_history_size, and add a member to THD to hold profiling information about this thread's execution. --- Manual merge, undoing first patch. sql/sql_delete.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. --- Include patch backported to 5.0-global. THD::options is a ulonglong, not ulong. sql/sql_insert.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. --- Fix merge problems. sql/sql_lex.cc: Initialize profiling options to empty. --- Manual merge, undoing first patch. sql/sql_lex.h: Add info to the lexer object so that we can hold data that comes from parsing statements. Reuse memory addresses of uints that can't occur in the same state- ment. This is dangerous because it involves knowledge of what symbols are never used together, which is information stored obliquely in another file. --- Manual merge, undoing first patch. sql/sql_parse.cc: Add hooks to the parser to jump to profiling code. If profiling is not present, then return an error message upon being used. --- Manual merge, undoing first patch. --- Fix merge problems. --- Include patch backported to 5.0-global. THD::options is a ulonglong, not ulong. sql/sql_prepare.cc: From prepared statement execution, set the query source in the profiler, as we can't get it from thd . --- Make it less expensive to limit the size of the queries. sql/sql_repl.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/sql_select.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. --- Fix merge problems. sql/sql_show.cc: Abstract setting thread-info into a function or macro. Also, remove "static" qualification on schema_table_store_record() so that external functions may use it. --- Manual merge, undoing first patch. sql/sql_table.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/sql_update.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/sql_view.cc: Abstract setting thread-info into a function or macro. --- Manual merge, undoing first patch. sql/sql_yacc.yy: Add new lexer symbols and insert new grammatical rules necessary to retreive profiling information. --- Manual merge, undoing first patch. --- Fix merge problems. sql/table.h: Add enum item for query profiling. BitKeeper/deleted/.del-profiling-master.opt: New BitKeeper file ``mysql-test/t/profiling-master.opt'' mysql-test/r/profiling.result: New BitKeeper file ``mysql-test/r/profiling.result'' --- Include more verbose that describes the queries so far. Include Giuseppe's tests. --- Selecting from I_S.profiling is no longer quashed in profiling, as requested by Giuseppe. mysql-test/t/profiling.test: New BitKeeper file ``mysql-test/t/profiling.test'' --- Include more verbose that describes the queries so far. Include Giuseppe's tests. --- Selecting from I_S.profiling is no longer quashed in profiling, as requested by Giuseppe. sql/sql_profile.cc: New BitKeeper file ``sql/sql_profile.cc'' --- If query_source is NULL, as can sometimes happen, then don't try to copy that memory. --- Make each new session use its own numbering of query_ids, and not show the global-pool numbers to the user. Provide a way for prepared statements to set the query_source. --- Selecting from I_S.profiling is no longer quashed in profiling, as requested by Giuseppe. Limit the size of captured query text. No longer log queries that are zero length. sql/sql_profile.h: New BitKeeper file ``sql/sql_profile.h'' --- Make each new session use its own numbering of query_ids, and not show the global-pool numbers to the user. Provide a way for prepared statements to set the query_source. --- Make it less expensive to limit the size of the queries. --- BitKeeper/etc/collapsed | 9 + configure.in | 14 + include/my_dbug.h | 12 +- myisam/mi_open.c | 2 +- mysql-test/r/information_schema.result | 11 +- mysql-test/r/information_schema_db.result | 1 + mysql-test/r/mysqlshow.result | 2 + mysql-test/r/profile.result | 30 - mysql-test/r/profiling.result | 365 +++++++++++++ mysql-test/t/profile.test | 39 -- mysql-test/t/profiling.test | 195 +++++++ ndb/src/ndbapi/DictCache.cpp | 2 +- sql/ha_archive.cc | 4 +- sql/ha_berkeley.cc | 4 +- sql/ha_myisam.cc | 24 +- sql/ha_myisammrg.cc | 2 +- sql/ha_ndbcluster.cc | 4 +- sql/item_cmpfunc.cc | 2 +- sql/item_func.cc | 8 +- sql/lock.cc | 8 +- sql/log_event.cc | 8 +- sql/mysql_priv.h | 73 +-- sql/mysqld.cc | 9 +- sql/repl_failsafe.cc | 10 +- sql/set_var.cc | 18 +- sql/set_var.h | 4 +- sql/slave.cc | 40 +- sql/sp_head.cc | 4 +- sql/sql_base.cc | 30 +- sql/sql_cache.cc | 22 +- sql/sql_class.cc | 3 +- sql/sql_class.h | 7 +- sql/sql_delete.cc | 14 +- sql/sql_insert.cc | 38 +- sql/sql_lex.cc | 3 +- sql/sql_lex.h | 9 +- sql/sql_parse.cc | 71 ++- sql/sql_prepare.cc | 1 + sql/sql_profile.cc | 638 +++++++++++++++++----- sql/sql_profile.h | 246 +++++---- sql/sql_repl.cc | 18 +- sql/sql_select.cc | 47 +- sql/sql_show.cc | 8 +- sql/sql_table.cc | 20 +- sql/sql_update.cc | 14 +- sql/sql_view.cc | 2 +- sql/sql_yacc.yy | 80 +-- sql/table.h | 1 + 48 files changed, 1602 insertions(+), 574 deletions(-) delete mode 100644 mysql-test/r/profile.result create mode 100644 mysql-test/r/profiling.result delete mode 100644 mysql-test/t/profile.test create mode 100644 mysql-test/t/profiling.test diff --git a/BitKeeper/etc/collapsed b/BitKeeper/etc/collapsed index 43292906ddd..c79a4cf25cc 100644 --- a/BitKeeper/etc/collapsed +++ b/BitKeeper/etc/collapsed @@ -34,3 +34,12 @@ 459c2098XoAUsUn8N07IVRDD6CTM-A 459ea845XenN-uWqEM5LFvUT60tW_A 45af88c9RIIJWPfBxs3o7zekI-ELPQ +45c38d90tNwOTSaYKHXd3ccLtnytlQ +45c390d6BbWrwyEi5T5VsWKYxl06Rg +45c39d31g0iik6UE_oTK5N55ry-ycA +45da6370nnZlAAIieMCrXkxF9toOyQ +45da6551zUuplwxuqcT2fhRgceC0CQ +45db0d4bkGtxBk21sZFJgbCV1FcNRg +45db468b-DKE8kUTV42eYMYmk8_g9g +45dd21d1rVPnDfvZTNVHLalcjnbsZw +45ddaf15_Ld7IAEpUUP3FJjJ-oSEFg diff --git a/configure.in b/configure.in index b86353d6b79..3e0e6c9762b 100644 --- a/configure.in +++ b/configure.in @@ -667,6 +667,20 @@ else AC_MSG_RESULT([no]) fi +# Add query profiler +AC_ARG_ENABLE(profiling, + [ --disable-profiling Build a version without query profiling code ], + [ ENABLED_PROFILING=$enableval ], + [ ENABLED_PROFILING=yes ]) + +if test "$ENABLED_PROFILING" = "yes" +then + AC_DEFINE([ENABLED_PROFILING], [1], + [If SHOW PROFILE should be enabled]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi # Use this to set the place used for unix socket used to local communication. AC_ARG_WITH(unix-socket-path, diff --git a/include/my_dbug.h b/include/my_dbug.h index a3591f0151a..ba5bddad1bc 100644 --- a/include/my_dbug.h +++ b/include/my_dbug.h @@ -50,12 +50,12 @@ extern void _db_unlock_file(void); &_db_framep_) #define DBUG_LEAVE \ (_db_return_ (__LINE__, &_db_func_, &_db_file_, &_db_level_)) -#define DBUG_RETURN(a1) {DBUG_LEAVE; return(a1);} -#define DBUG_VOID_RETURN {DBUG_LEAVE; return;} +#define DBUG_RETURN(a1) do {DBUG_LEAVE; return(a1);} while(0) +#define DBUG_VOID_RETURN do {DBUG_LEAVE; return;} while(0) #define DBUG_EXECUTE(keyword,a1) \ - {if (_db_on_) {if (_db_keyword_ (keyword)) { a1 }}} + do {if (_db_on_) {if (_db_keyword_ (keyword)) { a1 }}} while(0) #define DBUG_PRINT(keyword,arglist) \ - {if (_db_on_) {_db_pargs_(__LINE__,keyword); _db_doprnt_ arglist;}} + do {if (_db_on_) {_db_pargs_(__LINE__,keyword); _db_doprnt_ arglist;}} while(0) #define DBUG_PUSH(a1) _db_push_ (a1) #define DBUG_POP() _db_pop_ () #define DBUG_PROCESS(a1) (_db_process_ = a1) @@ -63,7 +63,7 @@ extern void _db_unlock_file(void); #define DBUG_SETJMP(a1) (_db_setjmp_ (), setjmp (a1)) #define DBUG_LONGJMP(a1,a2) (_db_longjmp_ (), longjmp (a1, a2)) #define DBUG_DUMP(keyword,a1,a2)\ - {if (_db_on_) {_db_dump_(__LINE__,keyword,a1,a2);}} + do {if (_db_on_) {_db_dump_(__LINE__,keyword,a1,a2);}} while(0) #define DBUG_IN_USE (_db_fp_ && _db_fp_ != stderr) #define DEBUGGER_OFF _no_db_=1;_db_on_=0; #define DEBUGGER_ON _no_db_=0 @@ -73,7 +73,7 @@ extern void _db_unlock_file(void); #define DBUG_OUTPUT(A) { _db_output_(A); } #define DBUG_ASSERT(A) assert(A) #define DBUG_EXECUTE_IF(keyword,a1) \ - {if (_db_on_) {if (_db_strict_keyword_ (keyword)) { a1 }}} + do {if (_db_on_) {if (_db_strict_keyword_ (keyword)) { a1 }}} while(0) #else /* No debugger */ #define DBUG_ENTER(a1) diff --git a/myisam/mi_open.c b/myisam/mi_open.c index 20a50fff9d7..b911826a976 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -196,7 +196,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) if (len != MI_BASE_INFO_SIZE) { DBUG_PRINT("warning",("saved_base_info_length: %d base_info_length: %d", - len,MI_BASE_INFO_SIZE)) + len,MI_BASE_INFO_SIZE)); } disk_pos= (char*) my_n_base_info_read((uchar*) disk_cache + base_pos, &share->base); diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index d4fd536003a..742d35d4ce7 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -42,6 +42,7 @@ COLLATION_CHARACTER_SET_APPLICABILITY COLUMNS COLUMN_PRIVILEGES KEY_COLUMN_USAGE +PROFILING ROUTINES SCHEMATA SCHEMA_PRIVILEGES @@ -730,7 +731,7 @@ CREATE TABLE t_crashme ( f1 BIGINT); CREATE VIEW a1 (t_CRASHME) AS SELECT f1 FROM t_crashme GROUP BY f1; CREATE VIEW a2 AS SELECT t_CRASHME FROM a1; count(*) -101 +102 drop view a2, a1; drop table t_crashme; select table_schema,table_name, column_name from @@ -801,7 +802,7 @@ delete from mysql.db where user='mysqltest_4'; flush privileges; SELECT table_schema, count(*) FROM information_schema.TABLES GROUP BY TABLE_SCHEMA; table_schema count(*) -information_schema 16 +information_schema 17 mysql 17 create table t1 (i int, j int); create trigger trg1 before insert on t1 for each row @@ -1094,8 +1095,8 @@ table_schema='information_schema' and (column_type = 'varchar(7)' or column_type = 'varchar(20)') group by column_type order by num; column_type group_concat(table_schema, '.', table_name) num -varchar(20) information_schema.COLUMNS 1 -varchar(7) information_schema.ROUTINES,information_schema.VIEWS 2 +varchar(20) information_schema.COLUMNS,information_schema.PROFILING 2 +varchar(7) information_schema.PROFILING,information_schema.PROFILING,information_schema.PROFILING,information_schema.ROUTINES,information_schema.VIEWS 5 create table t1(f1 char(1) not null, f2 char(9) not null) default character set utf8; select CHARACTER_MAXIMUM_LENGTH, CHARACTER_OCTET_LENGTH from @@ -1192,6 +1193,7 @@ COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME COLUMNS TABLE_SCHEMA COLUMN_PRIVILEGES TABLE_SCHEMA KEY_COLUMN_USAGE CONSTRAINT_SCHEMA +PROFILING Query_id ROUTINES ROUTINE_SCHEMA SCHEMATA SCHEMA_NAME SCHEMA_PRIVILEGES TABLE_SCHEMA @@ -1223,6 +1225,7 @@ COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME COLUMNS TABLE_SCHEMA COLUMN_PRIVILEGES TABLE_SCHEMA KEY_COLUMN_USAGE CONSTRAINT_SCHEMA +PROFILING Query_id ROUTINES ROUTINE_SCHEMA SCHEMATA SCHEMA_NAME SCHEMA_PRIVILEGES TABLE_SCHEMA diff --git a/mysql-test/r/information_schema_db.result b/mysql-test/r/information_schema_db.result index 40773a7afc1..dcd48d3aa46 100644 --- a/mysql-test/r/information_schema_db.result +++ b/mysql-test/r/information_schema_db.result @@ -11,6 +11,7 @@ COLLATION_CHARACTER_SET_APPLICABILITY COLUMNS COLUMN_PRIVILEGES KEY_COLUMN_USAGE +PROFILING ROUTINES SCHEMATA SCHEMA_PRIVILEGES diff --git a/mysql-test/r/mysqlshow.result b/mysql-test/r/mysqlshow.result index 2bf8a58de4e..31b4940ec53 100644 --- a/mysql-test/r/mysqlshow.result +++ b/mysql-test/r/mysqlshow.result @@ -85,6 +85,7 @@ Database: information_schema | COLUMNS | | COLUMN_PRIVILEGES | | KEY_COLUMN_USAGE | +| PROFILING | | ROUTINES | | SCHEMATA | | SCHEMA_PRIVILEGES | @@ -106,6 +107,7 @@ Database: INFORMATION_SCHEMA | COLUMNS | | COLUMN_PRIVILEGES | | KEY_COLUMN_USAGE | +| PROFILING | | ROUTINES | | SCHEMATA | | SCHEMA_PRIVILEGES | diff --git a/mysql-test/r/profile.result b/mysql-test/r/profile.result deleted file mode 100644 index 8a4db348445..00000000000 --- a/mysql-test/r/profile.result +++ /dev/null @@ -1,30 +0,0 @@ -create table t1 ( -a int, -b int -); -insert into t1 values (1,1), (2,null), (3, 4); -insert into t1 values (5,1), (6,null), (7, 4); -insert into t1 values (1,1), (2,null), (3, 4); -insert into t1 values (5,1), (6,null), (7, 4); -insert into t1 values (5,1), (6,null), (7, 4); -select sum(a) from t1; -select sum(a) from t1 group by b; -select sum(a) + sum(b) from t1 group by b; -select max(x) from (select sum(a) as x from t1 group by b) as teeone; -show profiles; -show profile for query 8; -show profile cpu, block io for query 8; -show profile cpu for query 8; -show profile cpu for query 9 limit 2 offset 2; -show profile cpu for query 10 limit 0; -show profile cpu for query 65534; -show profile memory; -show profile block io; -show profile context switches; -show profile page faults; -show profile ipc; -show profile swaps limit 1 offset 2; -show profile source; -show profile all for query 0 limit 0; -drop table t1; -End of 5.0 tests diff --git a/mysql-test/r/profiling.result b/mysql-test/r/profiling.result new file mode 100644 index 00000000000..f8aa060eee4 --- /dev/null +++ b/mysql-test/r/profiling.result @@ -0,0 +1,365 @@ +show session variables like 'profil%'; +Variable_name Value +profiling OFF +profiling_history_size 15 +select @@profiling; +@@profiling +0 +set global profiling = ON; +ERROR HY000: Variable 'profiling' is a SESSION variable and can't be used with SET GLOBAL +set global profiling_history_size=100; +show global variables like 'profil%'; +Variable_name Value +profiling OFF +profiling_history_size 100 +set session profiling = ON; +set session profiling_history_size=30; +show session variables like 'profil%'; +Variable_name Value +profiling ON +profiling_history_size 30 +select @@profiling; +@@profiling +1 +create table t1 ( +a int, +b int +); +insert into t1 values (1,1), (2,null), (3, 4); +insert into t1 values (5,1), (6,null), (7, 4); +insert into t1 values (1,1), (2,null), (3, 4); +insert into t1 values (5,1), (6,null), (7, 4); +select max(x) from (select sum(a) as x from t1 group by b) as teeone; +max(x) +20 +insert into t1 select * from t1; +select count(*) from t1; +count(*) +24 +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +select count(*) from t1; +count(*) +192 +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +select count(*) from t1; +count(*) +1536 +select sum(a) from t1; +sum(a) +6144 +select sum(a) from t1 group by b; +sum(a) +2048 +1536 +2560 +select sum(a) + sum(b) from t1 group by b; +sum(a) + sum(b) +NULL +2048 +4608 +select max(x) from (select sum(a) as x from t1 group by b) as teeone; +max(x) +2560 +select '012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890' as big_string; +big_string +012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890 +show profiles; +Query_ID Duration Query +0 # set session profiling = ON +1 # set session profiling_history_size=30 +2 # show session variables like 'profil%' +3 # select @@profiling +4 # create table t1 ( +a int, +b int +) +5 # insert into t1 values (1,1), (2,null), (3, 4) +6 # insert into t1 values (5,1), (6,null), (7, 4) +7 # insert into t1 values (1,1), (2,null), (3, 4) +8 # insert into t1 values (5,1), (6,null), (7, 4) +9 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +10 # insert into t1 select * from t1 +11 # select count(*) from t1 +12 # insert into t1 select * from t1 +13 # insert into t1 select * from t1 +14 # insert into t1 select * from t1 +15 # select count(*) from t1 +16 # insert into t1 select * from t1 +17 # insert into t1 select * from t1 +18 # insert into t1 select * from t1 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +show profile for query 15; +show profile cpu for query 15; +show profile cpu, block io for query 15; +show profile cpu for query 9 limit 2 offset 2; +show profile cpu for query 10 limit 0; +show profile cpu for query 65534; +show profile memory; +show profile block io; +show profile context switches; +show profile page faults; +show profile ipc; +show profile swaps limit 1 offset 2; +show profile source; +show profile all for query 0 limit 0; +show profile all for query 15; +select * from information_schema.profiling; +select query_id, state, duration from information_schema.profiling; +select query_id, sum(duration) from information_schema.profiling group by query_id; +select query_id, count(*) from information_schema.profiling group by query_id; +select sum(duration) from information_schema.profiling; +select query_id, count(*), sum(duration) from information_schema.profiling group by query_id; +select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling; +drop table if exists t1, t2, t3; +Warnings: +Note 1051 Unknown table 't2' +Note 1051 Unknown table 't3' +create table t1 (id int ); +create table t2 (id int not null); +create table t3 (id int not null primary key); +insert into t1 values (1), (2), (3); +insert into t2 values (1), (2), (3); +insert into t3 values (1), (2), (3); +show profiles; +Query_ID Duration Query +10 # insert into t1 select * from t1 +11 # select count(*) from t1 +12 # insert into t1 select * from t1 +13 # insert into t1 select * from t1 +14 # insert into t1 select * from t1 +15 # select count(*) from t1 +16 # insert into t1 select * from t1 +17 # insert into t1 select * from t1 +18 # insert into t1 select * from t1 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +25 # select * from information_schema.profiling +26 # select query_id, state, duration from information_schema.profiling +27 # select query_id, sum(duration) from information_schema.profiling group by query_id +28 # select query_id, count(*) from information_schema.profiling group by query_id +29 # select sum(duration) from information_schema.profiling +30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +32 # drop table if exists t1, t2, t3 +33 # SHOW WARNINGS +34 # create table t1 (id int ) +35 # create table t2 (id int not null) +36 # create table t3 (id int not null primary key) +37 # insert into t1 values (1), (2), (3) +38 # insert into t2 values (1), (2), (3) +39 # insert into t3 values (1), (2), (3) +select * from t1; +id +1 +2 +3 +show profiles; +Query_ID Duration Query +11 # select count(*) from t1 +12 # insert into t1 select * from t1 +13 # insert into t1 select * from t1 +14 # insert into t1 select * from t1 +15 # select count(*) from t1 +16 # insert into t1 select * from t1 +17 # insert into t1 select * from t1 +18 # insert into t1 select * from t1 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +25 # select * from information_schema.profiling +26 # select query_id, state, duration from information_schema.profiling +27 # select query_id, sum(duration) from information_schema.profiling group by query_id +28 # select query_id, count(*) from information_schema.profiling group by query_id +29 # select sum(duration) from information_schema.profiling +30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +32 # drop table if exists t1, t2, t3 +33 # SHOW WARNINGS +34 # create table t1 (id int ) +35 # create table t2 (id int not null) +36 # create table t3 (id int not null primary key) +37 # insert into t1 values (1), (2), (3) +38 # insert into t2 values (1), (2), (3) +39 # insert into t3 values (1), (2), (3) +40 # select * from t1 +This ^^ should end in "select * from t1;\" +delete from t1; +insert into t1 values (1), (2), (3); +insert into t1 values (1), (2), (3); +select * from t1; +id +1 +2 +3 +1 +2 +3 +show profiles; +Query_ID Duration Query +15 # select count(*) from t1 +16 # insert into t1 select * from t1 +17 # insert into t1 select * from t1 +18 # insert into t1 select * from t1 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +25 # select * from information_schema.profiling +26 # select query_id, state, duration from information_schema.profiling +27 # select query_id, sum(duration) from information_schema.profiling group by query_id +28 # select query_id, count(*) from information_schema.profiling group by query_id +29 # select sum(duration) from information_schema.profiling +30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +32 # drop table if exists t1, t2, t3 +33 # SHOW WARNINGS +34 # create table t1 (id int ) +35 # create table t2 (id int not null) +36 # create table t3 (id int not null primary key) +37 # insert into t1 values (1), (2), (3) +38 # insert into t2 values (1), (2), (3) +39 # insert into t3 values (1), (2), (3) +40 # select * from t1 +41 # delete from t1 +42 # insert into t1 values (1), (2), (3) +43 # insert into t1 values (1), (2), (3) +44 # select * from t1 +set session profiling = OFF; +select sum(id) from t1; +sum(id) +12 +show profiles; +Query_ID Duration Query +16 # insert into t1 select * from t1 +17 # insert into t1 select * from t1 +18 # insert into t1 select * from t1 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +25 # select * from information_schema.profiling +26 # select query_id, state, duration from information_schema.profiling +27 # select query_id, sum(duration) from information_schema.profiling group by query_id +28 # select query_id, count(*) from information_schema.profiling group by query_id +29 # select sum(duration) from information_schema.profiling +30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +32 # drop table if exists t1, t2, t3 +33 # SHOW WARNINGS +34 # create table t1 (id int ) +35 # create table t2 (id int not null) +36 # create table t3 (id int not null primary key) +37 # insert into t1 values (1), (2), (3) +38 # insert into t2 values (1), (2), (3) +39 # insert into t3 values (1), (2), (3) +40 # select * from t1 +41 # delete from t1 +42 # insert into t1 values (1), (2), (3) +43 # insert into t1 values (1), (2), (3) +44 # select * from t1 +45 # set session profiling = OFF +set session profiling = ON; +select @@profiling; +@@profiling +1 +create function f1() returns varchar(50) return 'hello'; +select @@profiling; +@@profiling +1 +select * from t1 where id <> f1(); +id +1 +2 +3 +1 +2 +3 +select @@profiling; +@@profiling +1 +set session profiling = ON; +drop table if exists t2; +create table t2 (id int not null); +create trigger t2_bi before insert on t2 for each row set @x=0; +select @@profiling; +@@profiling +1 +insert into t2 values (1), (2), (3); +select @@profiling; +@@profiling +1 +set session profiling = ON; +drop table if exists t1, t2; +create table t1 (id int not null primary key); +create table t2 (id int not null primary key, id1 int not null); +select @@profiling; +@@profiling +1 +alter table t2 add foreign key (id1) references t1 (id) on delete cascade; +select @@profiling; +@@profiling +1 +lock table t1 write; +select @@profiling; +@@profiling +1 +unlock table; +select @@profiling; +@@profiling +1 +set autocommit=0; +select @@profiling, @@autocommit; +@@profiling @@autocommit +1 0 +begin; +select @@profiling; +@@profiling +1 +insert into t1 values (1); +insert into t2 values (1,1); +testing referential integrity cascade +delete from t1 where id = 1; +select @@profiling; +@@profiling +1 +testing rollback +rollback; +select @@profiling; +@@profiling +1 +testing commit +begin; +select @@profiling; +@@profiling +1 +commit; +select @@profiling; +@@profiling +1 +drop table if exists t1, t2, t3; +drop view if exists v1; +Warnings: +Note 1051 Unknown table 'test.v1' +drop function if exists f1; +set session profiling = OFF; +End of 5.0 tests diff --git a/mysql-test/t/profile.test b/mysql-test/t/profile.test deleted file mode 100644 index 4cf2a3aa92f..00000000000 --- a/mysql-test/t/profile.test +++ /dev/null @@ -1,39 +0,0 @@ - -create table t1 ( - a int, - b int -); ---disable_result_log -insert into t1 values (1,1), (2,null), (3, 4); -insert into t1 values (5,1), (6,null), (7, 4); -insert into t1 values (1,1), (2,null), (3, 4); -insert into t1 values (5,1), (6,null), (7, 4); -insert into t1 values (5,1), (6,null), (7, 4); -select sum(a) from t1; -select sum(a) from t1 group by b; -select sum(a) + sum(b) from t1 group by b; -select max(x) from (select sum(a) as x from t1 group by b) as teeone; - -# Merely verify that commands work. Checking values is impossible, right? -show profiles; -show profile for query 8; -show profile cpu, block io for query 8; -show profile cpu for query 8; -show profile cpu for query 9 limit 2 offset 2; -show profile cpu for query 10 limit 0; -show profile cpu for query 65534; -show profile memory; -show profile block io; -show profile context switches; -show profile page faults; -show profile ipc; -show profile swaps limit 1 offset 2; -show profile source; -show profile all for query 0 limit 0; ---enable_result_log - -drop table t1; - - -## ---echo End of 5.0 tests diff --git a/mysql-test/t/profiling.test b/mysql-test/t/profiling.test new file mode 100644 index 00000000000..ebde8eeffd8 --- /dev/null +++ b/mysql-test/t/profiling.test @@ -0,0 +1,195 @@ +# default is OFF +show session variables like 'profil%'; +select @@profiling; + +# setting global variable is an error +--error ER_LOCAL_VARIABLE +set global profiling = ON; + +# But size is okay +set global profiling_history_size=100; +show global variables like 'profil%'; + +# turn on for testing +set session profiling = ON; +set session profiling_history_size=30; # small enough to overflow + +# verify it is active +show session variables like 'profil%'; +select @@profiling; + +# Profiling is a descriptive look into the way the server operated +# in retrospect. Chad doesn't think it's wise to include the result +# log, as this creates a proscriptive specification about how the +# server should work in the future -- or it forces everyone who +# changes the server significantly to record the test results again, +# and that violates the spirit of our tests. Please don't include +# execution-specific data here, as in all of the "show profile" and +# information_schema.profiling results. + +create table t1 ( + a int, + b int +); +insert into t1 values (1,1), (2,null), (3, 4); +insert into t1 values (5,1), (6,null), (7, 4); +insert into t1 values (1,1), (2,null), (3, 4); +insert into t1 values (5,1), (6,null), (7, 4); +select max(x) from (select sum(a) as x from t1 group by b) as teeone; +insert into t1 select * from t1; +select count(*) from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +select count(*) from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +select count(*) from t1; +select sum(a) from t1; +select sum(a) from t1 group by b; +select sum(a) + sum(b) from t1 group by b; +select max(x) from (select sum(a) as x from t1 group by b) as teeone; +select '012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890' as big_string; + +--enable_result_log +--replace_column 2 # +show profiles; + +--disable_result_log +###--replace_column 2 # 3 # 4 # +show profile for query 15; +###--replace_column 2 # 3 # 4 # +show profile cpu for query 15; +###--replace_column 2 # 3 # 4 # 5 # 6 # +show profile cpu, block io for query 15; +###--replace_column 2 # 3 # 4 # +show profile cpu for query 9 limit 2 offset 2; +show profile cpu for query 10 limit 0; +--error 0,ER_WRONG_ARGUMENTS +show profile cpu for query 65534; +###--replace_column 2 # +show profile memory; +###--replace_column 2 # 3 # 4 # +show profile block io; +###--replace_column 2 # 3 # 4 # +show profile context switches; +###--replace_column 2 # 3 # 4 # +show profile page faults; +###--replace_column 2 # 3 # 4 # +show profile ipc; +###--replace_column 2 # +show profile swaps limit 1 offset 2; +###--replace_column 2 # 5 # +show profile source; +show profile all for query 0 limit 0; +###--replace_column 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 11 # 12 # 13 # 16 # +show profile all for query 15; +###--replace_column 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 11 # 12 # 13 # 16 # + +select * from information_schema.profiling; +select query_id, state, duration from information_schema.profiling; +select query_id, sum(duration) from information_schema.profiling group by query_id; +select query_id, count(*) from information_schema.profiling group by query_id; +select sum(duration) from information_schema.profiling; + +# Broken down into number of stages and duration of each query. +select query_id, count(*), sum(duration) from information_schema.profiling group by query_id; +select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling; + + +--enable_result_log +drop table if exists t1, t2, t3; +create table t1 (id int ); +create table t2 (id int not null); +create table t3 (id int not null primary key); +insert into t1 values (1), (2), (3); +insert into t2 values (1), (2), (3); +insert into t3 values (1), (2), (3); + +--replace_column 2 # +show profiles; + +select * from t1; +--replace_column 2 # +show profiles; +--echo This ^^ should end in \"select * from t1;\" + +delete from t1; +insert into t1 values (1), (2), (3); +insert into t1 values (1), (2), (3); + +select * from t1; +--replace_column 2 # +show profiles; + +# Turning profiling off does freeze it +set session profiling = OFF; +select sum(id) from t1; +--replace_column 2 # +show profiles; + +## Verify that the various juggling of THD contexts doesn't affect profiling. + +## Functions +set session profiling = ON; +select @@profiling; +create function f1() returns varchar(50) return 'hello'; +select @@profiling; +select * from t1 where id <> f1(); +select @@profiling; + +## Triggers +set session profiling = ON; +drop table if exists t2; +create table t2 (id int not null); +create trigger t2_bi before insert on t2 for each row set @x=0; +select @@profiling; +insert into t2 values (1), (2), (3); +select @@profiling; + +## ALTER TABLE +set session profiling = ON; +drop table if exists t1, t2; +create table t1 (id int not null primary key); +create table t2 (id int not null primary key, id1 int not null); +select @@profiling; +alter table t2 add foreign key (id1) references t1 (id) on delete cascade; +select @@profiling; + +## Table LOCKing +lock table t1 write; +select @@profiling; +unlock table; +select @@profiling; + +## Transactions +set autocommit=0; +select @@profiling, @@autocommit; +begin; +select @@profiling; +insert into t1 values (1); +insert into t2 values (1,1); +--echo testing referential integrity cascade +delete from t1 where id = 1; +select @@profiling; +--echo testing rollback +--disable_warnings +rollback; +--enable_warnings +select @@profiling; +--echo testing commit +begin; +select @@profiling; +commit; +select @@profiling; + +drop table if exists t1, t2, t3; +drop view if exists v1; +drop function if exists f1; + +## last thing in the file +set session profiling = OFF; + +## +--echo End of 5.0 tests diff --git a/ndb/src/ndbapi/DictCache.cpp b/ndb/src/ndbapi/DictCache.cpp index 82e8d82bc24..226243ba7a0 100644 --- a/ndb/src/ndbapi/DictCache.cpp +++ b/ndb/src/ndbapi/DictCache.cpp @@ -284,7 +284,7 @@ GlobalDictCache::drop(NdbTableImpl * tab) ver.m_refCount--; ver.m_status = DROPPED; if(ver.m_refCount == 0){ - DBUG_PRINT("info", ("refCount is zero, deleting m_impl")) + DBUG_PRINT("info", ("refCount is zero, deleting m_impl")); delete ver.m_impl; vers->erase(i); } diff --git a/sql/ha_archive.cc b/sql/ha_archive.cc index 6a4d372c43a..70d16f65699 100644 --- a/sql/ha_archive.cc +++ b/sql/ha_archive.cc @@ -1205,7 +1205,7 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt) ha_rows count= share->rows_recorded; DBUG_ENTER("ha_archive::check"); - THD_PROC_INFO(thd, "Checking table"); + thd_proc_info(thd, "Checking table"); /* Flush any waiting data */ gzflush(share->archive_write, Z_SYNC_FLUSH); @@ -1229,7 +1229,7 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt) my_free((char*)buf, MYF(0)); - THD_PROC_INFO(thd, old_proc_info); + thd_proc_info(thd, old_proc_info); if ((rc && rc != HA_ERR_END_OF_FILE) || count) { diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index d63935f1a9c..e8cff05dac9 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -1855,8 +1855,8 @@ int ha_berkeley::external_lock(THD *thd, int lock_type) OPTION_TABLE_LOCK)) && !trx->all) { /* We have to start a master transaction */ - DBUG_PRINT("trans",("starting transaction all: options: 0x%lx", - (ulong) thd->options)); + DBUG_PRINT("trans",("starting transaction all: options: 0x%llx", + thd->options)); if ((error=txn_begin(db_env, 0, &trx->all, 0))) { trx->bdb_lock_count--; // We didn't get the lock diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 7bb597ccf4f..4d562f5347c 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -339,7 +339,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt) MYISAM_SHARE* share = file->s; const char *old_proc_info=thd->proc_info; - THD_PROC_INFO(thd, "Checking table"); + thd_proc_info(thd, "Checking table"); myisamchk_init(¶m); param.thd = thd; param.op_name = "check"; @@ -413,7 +413,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt) file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; } - THD_PROC_INFO(thd, old_proc_info); + thd_proc_info(thd, old_proc_info); return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK; } @@ -679,22 +679,22 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) char buf[40]; /* TODO: respect myisam_repair_threads variable */ my_snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map)); - THD_PROC_INFO(thd, buf); + thd_proc_info(thd, buf); error = mi_repair_parallel(¶m, file, fixed_name, param.testflag & T_QUICK); - THD_PROC_INFO(thd, "Repair done"); // to reset proc_info, as + thd_proc_info(thd, "Repair done"); // to reset proc_info, as // it was pointing to local buffer } else { - THD_PROC_INFO(thd, "Repair by sorting"); + thd_proc_info(thd, "Repair by sorting"); error = mi_repair_by_sort(¶m, file, fixed_name, param.testflag & T_QUICK); } } else { - THD_PROC_INFO(thd, "Repair with keycache"); + thd_proc_info(thd, "Repair with keycache"); param.testflag &= ~T_REP_BY_SORT; error= mi_repair(¶m, file, fixed_name, param.testflag & T_QUICK); @@ -708,7 +708,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) (share->state.changed & STATE_NOT_SORTED_PAGES)) { optimize_done=1; - THD_PROC_INFO(thd, "Sorting index"); + thd_proc_info(thd, "Sorting index"); error=mi_sort_index(¶m,file,fixed_name); } if (!statistics_done && (local_testflag & T_STATISTICS)) @@ -716,14 +716,14 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) if (share->state.changed & STATE_NOT_ANALYZED) { optimize_done=1; - THD_PROC_INFO(thd, "Analyzing"); + thd_proc_info(thd, "Analyzing"); error = chk_key(¶m, file); } else local_testflag&= ~T_STATISTICS; // Don't update statistics } } - THD_PROC_INFO(thd, "Saving state"); + thd_proc_info(thd, "Saving state"); if (!error) { if ((share->state.changed & STATE_CHANGED) || mi_is_crashed(file)) @@ -761,7 +761,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; update_state_info(¶m, file, 0); } - THD_PROC_INFO(thd, old_proc_info); + thd_proc_info(thd, old_proc_info); if (!thd->locked_tables) mi_lock_database(file,F_UNLCK); DBUG_RETURN(error ? HA_ADMIN_FAILED : @@ -986,7 +986,7 @@ int ha_myisam::enable_indexes(uint mode) THD *thd=current_thd; MI_CHECK param; const char *save_proc_info=thd->proc_info; - THD_PROC_INFO(thd, "Creating index"); + thd_proc_info(thd, "Creating index"); myisamchk_init(¶m); param.op_name= "recreating_index"; param.testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK | @@ -1011,7 +1011,7 @@ int ha_myisam::enable_indexes(uint mode) thd->clear_error(); } info(HA_STATUS_CONST); - THD_PROC_INFO(thd, save_proc_info); + thd_proc_info(thd, save_proc_info); } else { diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 09445f775de..c943627a9b5 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -96,7 +96,7 @@ int ha_myisammrg::open(const char *name, int mode, uint test_if_locked) DBUG_PRINT("info", ("ha_myisammrg::open exit %d", my_errno)); return (my_errno ? my_errno : -1); } - DBUG_PRINT("info", ("ha_myisammrg::open myrg_extrafunc...")) + DBUG_PRINT("info", ("ha_myisammrg::open myrg_extrafunc...")); myrg_extrafunc(file, query_cache_invalidate_by_MyISAM_filename_ref); if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED || test_if_locked == HA_OPEN_ABORT_IF_LOCKED)) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 0f580c833a9..37203076bb6 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -5821,14 +5821,14 @@ ha_ndbcluster::register_query_cache_table(THD *thd, if (!is_autocommit) { - DBUG_PRINT("exit", ("Can't register table during transaction")) + DBUG_PRINT("exit", ("Can't register table during transaction")); DBUG_RETURN(FALSE); } if (ndb_get_commitcount(thd, m_dbname, m_tabname, &commit_count)) { *engine_data= 0; - DBUG_PRINT("exit", ("Error, could not get commitcount")) + DBUG_PRINT("exit", ("Error, could not get commitcount")); DBUG_RETURN(FALSE); } *engine_data= commit_count; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 936ae04e93d..4492d629f8a 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -3006,7 +3006,7 @@ longlong Item_is_not_null_test::val_int() } if (args[0]->is_null()) { - DBUG_PRINT("info", ("null")) + DBUG_PRINT("info", ("null")); owner->was_null|= 1; DBUG_RETURN(0); } diff --git a/sql/item_func.cc b/sql/item_func.cc index 0b1d959b6a4..fa6f92ef9f6 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3204,7 +3204,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout) Structure is now initialized. Try to get the lock. Set up control struct to allow others to abort locks */ - THD_PROC_INFO(thd, "User lock"); + thd_proc_info(thd, "User lock"); thd->mysys_var->current_mutex= &LOCK_user_locks; thd->mysys_var->current_cond= &ull->cond; @@ -3229,7 +3229,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout) } pthread_mutex_unlock(&LOCK_user_locks); pthread_mutex_lock(&thd->mysys_var->mutex); - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; pthread_mutex_unlock(&thd->mysys_var->mutex); @@ -3310,7 +3310,7 @@ longlong Item_func_get_lock::val_int() Structure is now initialized. Try to get the lock. Set up control struct to allow others to abort locks. */ - THD_PROC_INFO(thd, "User lock"); + thd_proc_info(thd, "User lock"); thd->mysys_var->current_mutex= &LOCK_user_locks; thd->mysys_var->current_cond= &ull->cond; @@ -3348,7 +3348,7 @@ longlong Item_func_get_lock::val_int() pthread_mutex_unlock(&LOCK_user_locks); pthread_mutex_lock(&thd->mysys_var->mutex); - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; pthread_mutex_unlock(&thd->mysys_var->mutex); diff --git a/sql/lock.cc b/sql/lock.cc index daf07e16dc5..8c9de2cd317 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -150,7 +150,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, } } - THD_PROC_INFO(thd, "System lock"); + thd_proc_info(thd, "System lock"); if (lock_external(thd, tables, count)) { /* Clear the lock type of all lock data to avoid reusage. */ @@ -159,7 +159,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, sql_lock=0; break; } - THD_PROC_INFO(thd, "Table lock"); + thd_proc_info(thd, "Table lock"); thd->locked=1; /* Copy the lock data array. thr_multi_lock() reorders its contens. */ memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks, @@ -193,7 +193,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, thd->locked=0; break; } - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); /* some table was altered or deleted. reopen tables marked deleted */ mysql_unlock_tables(thd,sql_lock); @@ -208,7 +208,7 @@ retry: if (wait_for_tables(thd)) break; // Couldn't open tables } - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); if (thd->killed) { thd->send_kill_message(); diff --git a/sql/log_event.cc b/sql/log_event.cc index d493cdfbae9..e0711d687e8 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4265,7 +4265,7 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli) bzero((char*)&file, sizeof(file)); fname_buf= strmov(proc_info, "Making temp file "); ext= slave_load_file_stem(fname_buf, file_id, server_id, ".info"); - THD_PROC_INFO(thd, proc_info); + thd_proc_info(thd, proc_info); my_delete(fname_buf, MYF(0)); // old copy may exist already if ((fd= my_create(fname_buf, CREATE_MODE, O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW, @@ -4319,7 +4319,7 @@ err: end_io_cache(&file); if (fd >= 0) my_close(fd, MYF(0)); - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); return error ? 1 : Log_event::exec_event(rli); } #endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ @@ -4439,7 +4439,7 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli) fname= strmov(proc_info, "Making temp file "); slave_load_file_stem(fname, file_id, server_id, ".data"); - THD_PROC_INFO(thd, proc_info); + thd_proc_info(thd, proc_info); if (get_create_or_append()) { my_delete(fname, MYF(0)); // old copy may exist already @@ -4473,7 +4473,7 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli) err: if (fd >= 0) my_close(fd, MYF(0)); - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); DBUG_RETURN(error ? error : Log_event::exec_event(rli)); } #endif diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 458d5faa857..bd69a137a2d 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -20,6 +20,9 @@ except the part which must be in the server and in the client. */ +#ifndef MYSQL_PRIV_H_INCLUDED +#define MYSQL_PRIV_H_INCLUDED + #ifndef MYSQL_CLIENT #include @@ -298,55 +301,57 @@ MY_LOCALE *my_locale_by_name(const char *name); TODO: separate three contexts above, move them to separate bitfields. */ -#define SELECT_DISTINCT (1L << 0) // SELECT, user -#define SELECT_STRAIGHT_JOIN (1L << 1) // SELECT, user -#define SELECT_DESCRIBE (1L << 2) // SELECT, user -#define SELECT_SMALL_RESULT (1L << 3) // SELECT, user -#define SELECT_BIG_RESULT (1L << 4) // SELECT, user -#define OPTION_FOUND_ROWS (1L << 5) // SELECT, user -#define OPTION_TO_QUERY_CACHE (1L << 6) // SELECT, user -#define SELECT_NO_JOIN_CACHE (1L << 7) // intern -#define OPTION_BIG_TABLES (1L << 8) // THD, user -#define OPTION_BIG_SELECTS (1L << 9) // THD, user -#define OPTION_LOG_OFF (1L << 10) // THD, user -#define OPTION_UPDATE_LOG (1L << 11) // THD, user, unused -#define TMP_TABLE_ALL_COLUMNS (1L << 12) // SELECT, intern -#define OPTION_WARNINGS (1L << 13) // THD, user -#define OPTION_AUTO_IS_NULL (1L << 14) // THD, user, binlog -#define OPTION_FOUND_COMMENT (1L << 15) // SELECT, intern, parser -#define OPTION_SAFE_UPDATES (1L << 16) // THD, user -#define OPTION_BUFFER_RESULT (1L << 17) // SELECT, user -#define OPTION_BIN_LOG (1L << 18) // THD, user -#define OPTION_NOT_AUTOCOMMIT (1L << 19) // THD, user -#define OPTION_BEGIN (1L << 20) // THD, intern -#define OPTION_TABLE_LOCK (1L << 21) // THD, intern -#define OPTION_QUICK (1L << 22) // SELECT (for DELETE) -#define OPTION_QUOTE_SHOW_CREATE (1L << 23) // THD, user +#define SELECT_DISTINCT (ULL(1) << 0) // SELECT, user +#define SELECT_STRAIGHT_JOIN (ULL(1) << 1) // SELECT, user +#define SELECT_DESCRIBE (ULL(1) << 2) // SELECT, user +#define SELECT_SMALL_RESULT (ULL(1) << 3) // SELECT, user +#define SELECT_BIG_RESULT (ULL(1) << 4) // SELECT, user +#define OPTION_FOUND_ROWS (ULL(1) << 5) // SELECT, user +#define OPTION_TO_QUERY_CACHE (ULL(1) << 6) // SELECT, user +#define SELECT_NO_JOIN_CACHE (ULL(1) << 7) // intern +#define OPTION_BIG_TABLES (ULL(1) << 8) // THD, user +#define OPTION_BIG_SELECTS (ULL(1) << 9) // THD, user +#define OPTION_LOG_OFF (ULL(1) << 10) // THD, user +#define OPTION_UPDATE_LOG (ULL(1) << 11) // THD, user, unused +#define TMP_TABLE_ALL_COLUMNS (ULL(1) << 12) // SELECT, intern +#define OPTION_WARNINGS (ULL(1) << 13) // THD, user +#define OPTION_AUTO_IS_NULL (ULL(1) << 14) // THD, user, binlog +#define OPTION_FOUND_COMMENT (ULL(1) << 15) // SELECT, intern, parser +#define OPTION_SAFE_UPDATES (ULL(1) << 16) // THD, user +#define OPTION_BUFFER_RESULT (ULL(1) << 17) // SELECT, user +#define OPTION_BIN_LOG (ULL(1) << 18) // THD, user +#define OPTION_NOT_AUTOCOMMIT (ULL(1) << 19) // THD, user +#define OPTION_BEGIN (ULL(1) << 20) // THD, intern +#define OPTION_TABLE_LOCK (ULL(1) << 21) // THD, intern +#define OPTION_QUICK (ULL(1) << 22) // SELECT (for DELETE) +#define OPTION_QUOTE_SHOW_CREATE (ULL(1) << 23) // THD, user /* Thr following is used to detect a conflict with DISTINCT in the user query has requested */ -#define SELECT_ALL (1L << 24) // SELECT, user, parser +#define SELECT_ALL (ULL(1) << 24) // SELECT, user, parser /* Set if we are updating a non-transaction safe table */ -#define OPTION_STATUS_NO_TRANS_UPDATE (1L << 25) // THD, intern +#define OPTION_STATUS_NO_TRANS_UPDATE (ULL(1) << 25) // THD, intern /* The following can be set when importing tables in a 'wrong order' to suppress foreign key checks */ -#define OPTION_NO_FOREIGN_KEY_CHECKS (1L << 26) // THD, user, binlog +#define OPTION_NO_FOREIGN_KEY_CHECKS (ULL(1) << 26) // THD, user, binlog /* The following speeds up inserts to InnoDB tables by suppressing unique key checks in some cases */ -#define OPTION_RELAXED_UNIQUE_CHECKS (1L << 27) // THD, user, binlog -#define SELECT_NO_UNLOCK (1L << 28) // SELECT, intern -#define OPTION_SCHEMA_TABLE (1L << 29) // SELECT, intern +#define OPTION_RELAXED_UNIQUE_CHECKS (ULL(1) << 27) // THD, user, binlog +#define SELECT_NO_UNLOCK (ULL(1) << 28) // SELECT, intern +#define OPTION_SCHEMA_TABLE (ULL(1) << 29) // SELECT, intern /* Flag set if setup_tables already done */ -#define OPTION_SETUP_TABLES_DONE (1L << 30) // intern +#define OPTION_SETUP_TABLES_DONE (ULL(1) << 30) // intern /* If not set then the thread will ignore all warnings with level notes. */ -#define OPTION_SQL_NOTES (1UL << 31) // THD, user +#define OPTION_SQL_NOTES (ULL(1) << 31) // THD, user /* Force the used temporary table to be a MyISAM table (because we will use fulltext functions when reading from it. */ -#define TMP_TABLE_FORCE_MYISAM (LL(1) << 32) +#define TMP_TABLE_FORCE_MYISAM (ULL(1) << 32) +#define OPTION_PROFILING (ULL(1) << 33) + /* Maximum length of time zone name that we support @@ -1686,3 +1691,5 @@ inline void kill_delayed_threads(void) {} #endif #endif /* MYSQL_CLIENT */ + +#endif diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 29590cdd6a0..a2afc3449cd 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1657,7 +1657,7 @@ void end_thread(THD *thd, bool put_in_cache) ! abort_loop && !kill_cached_threads) { /* Don't kill the thread, just put it in cache for reuse */ - DBUG_PRINT("info", ("Adding thread to cache")) + DBUG_PRINT("info", ("Adding thread to cache")); cached_thread_count++; while (!abort_loop && ! wake_thread && ! kill_cached_threads) (void) pthread_cond_wait(&COND_thread_cache, &LOCK_thread_count); @@ -4696,6 +4696,7 @@ enum options_mysqld OPT_TABLE_LOCK_WAIT_TIMEOUT, OPT_PORT_OPEN_TIMEOUT, OPT_MERGE, + OPT_PROFILING, OPT_INNODB_ROLLBACK_ON_TIMEOUT }; @@ -5257,6 +5258,12 @@ Disable with --skip-ndbcluster (will save memory).", "Maximum time in seconds to wait for the port to become free. " "(Default: no wait)", (gptr*) &mysqld_port_timeout, (gptr*) &mysqld_port_timeout, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef ENABLED_PROFILING + {"profiling_history_size", OPT_PROFILING, "Limit of query profiling memory", + (gptr*) &global_system_variables.profiling_history_size, + (gptr*) &max_system_variables.profiling_history_size, + 0, GET_UINT, REQUIRED_ARG, 15, 0, 100, 0, 0, 0}, +#endif {"relay-log", OPT_RELAY_LOG, "The location and name to use for relay logs.", (gptr*) &opt_relay_logname, (gptr*) &opt_relay_logname, 0, diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 88b45caf354..3d8a4ebd547 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -91,7 +91,7 @@ static int init_failsafe_rpl_thread(THD* thd) if (thd->variables.max_join_size == HA_POS_ERROR) thd->options|= OPTION_BIG_SELECTS; - THD_PROC_INFO(thd, "Thread initialized"); + thd_proc_info(thd, "Thread initialized"); thd->version=refresh_version; thd->set_time(); DBUG_RETURN(0); @@ -597,7 +597,7 @@ pthread_handler_t handle_failsafe_rpl(void *arg) { bool break_req_chain = 0; pthread_cond_wait(&COND_rpl_status, &LOCK_rpl_status); - THD_PROC_INFO(thd, "Processing request"); + thd_proc_info(thd, "Processing request"); while (!break_req_chain) { switch (rpl_status) { @@ -941,7 +941,7 @@ bool load_master_data(THD* thd) goto err; } } - THD_PROC_INFO(thd, "purging old relay logs"); + thd_proc_info(thd, "purging old relay logs"); if (purge_relay_logs(&active_mi->rli,thd, 0 /* not only reset, but also reinit */, &errmsg)) @@ -968,7 +968,7 @@ bool load_master_data(THD* thd) flush_relay_log_info(&active_mi->rli); pthread_cond_broadcast(&active_mi->rli.data_cond); pthread_mutex_unlock(&active_mi->rli.data_lock); - thd->proc_info = "starting slave"; + thd_proc_info(thd, "starting slave"); if (restart_thread_mask) { error=start_slave_threads(0 /* mutex not needed */, @@ -980,7 +980,7 @@ bool load_master_data(THD* thd) err: unlock_slave_threads(active_mi); pthread_mutex_unlock(&LOCK_active_mi); - thd->proc_info = 0; + thd_proc_info(thd, 0); mysql_close(&mysql); // safe to call since we always do mysql_init() if (!error) diff --git a/sql/set_var.cc b/sql/set_var.cc index b4fd6b90d18..c02561261c0 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -545,6 +545,12 @@ static sys_var_thd_bit sys_unique_checks("unique_checks", 0, set_option_bit, OPTION_RELAXED_UNIQUE_CHECKS, 1); +#ifdef ENABLED_PROFILING +static sys_var_thd_bit sys_profiling("profiling", NULL, set_option_bit, + ulonglong(OPTION_PROFILING)); +sys_var_thd_ulong sys_profiling_history_size("profiling_history_size", + &SV::profiling_history_size); +#endif /* Local state variables */ @@ -696,6 +702,10 @@ sys_var *sys_variables[]= &sys_optimizer_prune_level, &sys_optimizer_search_depth, &sys_preload_buff_size, +#ifdef ENABLED_PROFILING + &sys_profiling, + &sys_profiling_history_size, +#endif &sys_pseudo_thread_id, &sys_query_alloc_block_size, &sys_query_cache_size, @@ -1003,6 +1013,10 @@ struct show_var_st init_vars[]= { {"pid_file", (char*) pidfile_name, SHOW_CHAR}, {"port", (char*) &mysqld_port, SHOW_INT}, {sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS}, +#ifdef ENABLED_PROFILING + {sys_profiling.name, (char*) &sys_profiling, SHOW_SYS}, + {sys_profiling_history_size.name, (char*) &sys_profiling_history_size, SHOW_SYS}, +#endif {"protocol_version", (char*) &protocol_version, SHOW_INT}, {sys_query_alloc_block_size.name, (char*) &sys_query_alloc_block_size, SHOW_SYS}, @@ -2842,14 +2856,14 @@ static bool set_option_autocommit(THD *thd, set_var *var) if ((org_options & OPTION_NOT_AUTOCOMMIT)) { /* We changed to auto_commit mode */ - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); thd->server_status|= SERVER_STATUS_AUTOCOMMIT; if (ha_commit(thd)) return 1; } else { - thd->options&= ~(ulong) (OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(OPTION_STATUS_NO_TRANS_UPDATE); thd->server_status&= ~SERVER_STATUS_AUTOCOMMIT; } } diff --git a/sql/set_var.h b/sql/set_var.h index 3304f552a97..d55ca4d289f 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -457,11 +457,11 @@ class sys_var_thd_bit :public sys_var_thd sys_check_func check_func; sys_update_func update_func; public: - ulong bit_flag; + ulonglong bit_flag; bool reverse; sys_var_thd_bit(const char *name_arg, sys_check_func c_func, sys_update_func u_func, - ulong bit, bool reverse_arg=0) + ulonglong bit, bool reverse_arg=0) :sys_var_thd(name_arg), check_func(c_func), update_func(u_func), bit_flag(bit), reverse(reverse_arg) {} diff --git a/sql/slave.cc b/sql/slave.cc index 94e4fb7b6bd..83bd6b7bd2d 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1557,8 +1557,8 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, /* Create the table. We do not want to log the "create table" statement */ save_options = thd->options; - thd->options &= ~(ulong) (OPTION_BIN_LOG); - thd->proc_info = "Creating table from master dump"; + thd->options &= ~ (OPTION_BIN_LOG); + thd_proc_info(thd, "Creating table from master dump"); // save old db in case we are creating in a different database save_db = thd->db; save_db_length= thd->db_length; @@ -1572,7 +1572,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, if (thd->query_error) goto err; // mysql_parse took care of the error send - thd->proc_info = "Opening master dump table"; + thd_proc_info(thd, "Opening master dump table"); tables.lock_type = TL_WRITE; if (!open_ltable(thd, &tables, TL_WRITE)) { @@ -1581,7 +1581,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, } file = tables.table->file; - thd->proc_info = "Reading master dump table data"; + thd_proc_info(thd, "Reading master dump table data"); /* Copy the data file */ if (file->net_read_dump(net)) { @@ -1593,7 +1593,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, check_opt.init(); check_opt.flags|= T_VERY_SILENT | T_CALC_CHECKSUM | T_QUICK; - thd->proc_info = "Rebuilding the index on master dump table"; + thd_proc_info(thd, "Rebuilding the index on master dump table"); /* We do not want repair() to spam us with messages just send them to the error log, and report the failure in case of @@ -2924,9 +2924,9 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) #endif if (thd_type == SLAVE_THD_SQL) - THD_PROC_INFO(thd, "Waiting for the next event in relay log"); + thd_proc_info(thd, "Waiting for the next event in relay log"); else - THD_PROC_INFO(thd, "Waiting for master update"); + thd_proc_info(thd, "Waiting for master update"); thd->version=refresh_version; thd->set_time(); DBUG_RETURN(0); @@ -3486,7 +3486,7 @@ slave_begin: goto err; } - thd->proc_info = "Connecting to master"; + thd_proc_info(thd, "Connecting to master"); // we can get killed during safe_connect if (!safe_connect(thd, mysql, mi)) { @@ -3513,7 +3513,7 @@ connected: // TODO: the assignment below should be under mutex (5.0) mi->slave_running= MYSQL_SLAVE_RUN_CONNECT; thd->slave_net = &mysql->net; - thd->proc_info = "Checking master version"; + thd_proc_info(thd, "Checking master version"); if (get_master_version_and_clock(mysql, mi)) goto err; @@ -3524,7 +3524,7 @@ connected: If fails, this is not fatal - we just print the error message and go on with life. */ - thd->proc_info = "Registering slave on master"; + thd_proc_info(thd, "Registering slave on master"); if (register_slave_on_master(mysql) || update_slave_list(mysql, mi)) goto err; } @@ -3533,7 +3533,7 @@ connected: while (!io_slave_killed(thd,mi)) { bool suppress_warnings= 0; - thd->proc_info = "Requesting binlog dump"; + thd_proc_info(thd, "Requesting binlog dump"); if (request_dump(mysql, mi, &suppress_warnings)) { sql_print_error("Failed on request_dump()"); @@ -3545,7 +3545,7 @@ dump"); } mi->slave_running= MYSQL_SLAVE_RUN_NOT_CONNECT; - THD_PROC_INFO(thd, "Waiting to reconnect after a failed binlog dump request"); + thd_proc_info(thd, "Waiting to reconnect after a failed binlog dump request"); #ifdef SIGNAL_WITH_VIO_CLOSE thd->clear_active_vio(); #endif @@ -3569,7 +3569,7 @@ dump"); goto err; } - thd->proc_info = "Reconnecting after a failed binlog dump request"; + thd_proc_info(thd, "Reconnecting after a failed binlog dump request"); if (!suppress_warnings) sql_print_error("Slave I/O thread: failed dump request, \ reconnecting to try again, log '%s' at postion %s", IO_RPL_LOG_NAME, @@ -3594,7 +3594,7 @@ after reconnect"); important thing is to not confuse users by saying "reading" whereas we're in fact receiving nothing. */ - thd->proc_info = "Waiting for master to send event"; + thd_proc_info(thd, "Waiting for master to send event"); ulong event_len = read_event(mysql, mi, &suppress_warnings); if (io_slave_killed(thd,mi)) { @@ -3622,7 +3622,7 @@ max_allowed_packet", goto err; } mi->slave_running= MYSQL_SLAVE_RUN_NOT_CONNECT; - thd->proc_info = "Waiting to reconnect after a failed master event read"; + thd_proc_info(thd, "Waiting to reconnect after a failed master event read"); #ifdef SIGNAL_WITH_VIO_CLOSE thd->clear_active_vio(); #endif @@ -3641,7 +3641,7 @@ max_allowed_packet", reconnect after a failed read"); goto err; } - thd->proc_info = "Reconnecting after a failed master event read"; + thd_proc_info(thd, "Reconnecting after a failed master event read"); if (!suppress_warnings) sql_print_information("Slave I/O thread: Failed reading log event, \ reconnecting to retry, log '%s' position %s", IO_RPL_LOG_NAME, @@ -3658,7 +3658,7 @@ reconnect done to recover from failed read"); } // if (event_len == packet_error) retry_count=0; // ok event, reset retry counter - thd->proc_info = "Queueing master event to the relay log"; + thd_proc_info(thd, "Queueing master event to the relay log"); if (queue_event(mi,(const char*)mysql->net.read_pos + 1, event_len)) { @@ -3740,7 +3740,7 @@ err: mi->mysql=0; } write_ignored_events_info_to_relay_log(thd, mi); - thd->proc_info = "Waiting for slave mutex on exit"; + thd_proc_info(thd, "Waiting for slave mutex on exit"); pthread_mutex_lock(&mi->run_lock); /* Forget the relay log's format */ @@ -3912,7 +3912,7 @@ Slave SQL thread aborted. Can't execute init_slave query"); while (!sql_slave_killed(thd,rli)) { - thd->proc_info = "Reading event from the relay log"; + thd_proc_info(thd, "Reading event from the relay log"); DBUG_ASSERT(rli->sql_thd == thd); THD_CHECK_SENTRY(thd); if (exec_relay_log_event(thd,rli)) @@ -3944,7 +3944,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ thd->query= 0; thd->query_length= 0; VOID(pthread_mutex_unlock(&LOCK_thread_count)); - thd->proc_info = "Waiting for slave mutex on exit"; + thd_proc_info(thd, "Waiting for slave mutex on exit"); pthread_mutex_lock(&rli->run_lock); /* We need data_lock, at least to wake up any waiting master_pos_wait() */ pthread_mutex_lock(&rli->data_lock); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index c6e49fae801..c0d24a5afdc 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2387,9 +2387,9 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, m_lex->unit.cleanup(); - THD_PROC_INFO(thd, "closing tables"); + thd_proc_info(thd, "closing tables"); close_thread_tables(thd); - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); if (m_lex->query_tables_own_last) { diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 636006ea7c2..11cc1584780 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -306,7 +306,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, */ thd->mysys_var->current_mutex= &LOCK_open; thd->mysys_var->current_cond= &COND_refresh; - THD_PROC_INFO(thd, "Flushing tables"); + thd_proc_info(thd, "Flushing tables"); close_old_data_files(thd,thd->open_tables,1,1); mysql_ha_flush(thd, tables, MYSQL_HA_REOPEN_ON_USAGE | MYSQL_HA_FLUSH_ALL, @@ -348,7 +348,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, pthread_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); pthread_mutex_unlock(&thd->mysys_var->mutex); } DBUG_RETURN(result); @@ -549,7 +549,7 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) good idea to turn off OPTION_TABLE_LOCK flag. */ DBUG_ASSERT(thd->lex->requires_prelocking()); - thd->options&= ~(ulong) (OPTION_TABLE_LOCK); + thd->options&= ~(OPTION_TABLE_LOCK); } DBUG_VOID_RETURN; @@ -1070,7 +1070,7 @@ void wait_for_refresh(THD *thd) thd->mysys_var->current_mutex= &LOCK_open; thd->mysys_var->current_cond= &COND_refresh; proc_info=thd->proc_info; - THD_PROC_INFO(thd, "Waiting for table"); + thd_proc_info(thd, "Waiting for table"); if (!thd->killed) (void) pthread_cond_wait(&COND_refresh,&LOCK_open); @@ -1078,7 +1078,7 @@ void wait_for_refresh(THD *thd) pthread_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; - THD_PROC_INFO(thd, proc_info); + thd_proc_info(thd, proc_info); pthread_mutex_unlock(&thd->mysys_var->mutex); DBUG_VOID_RETURN; } @@ -1783,7 +1783,7 @@ bool wait_for_tables(THD *thd) bool result; DBUG_ENTER("wait_for_tables"); - THD_PROC_INFO(thd, "Waiting for tables"); + thd_proc_info(thd, "Waiting for tables"); pthread_mutex_lock(&LOCK_open); while (!thd->killed) { @@ -1799,12 +1799,12 @@ bool wait_for_tables(THD *thd) else { /* Now we can open all tables without any interference */ - THD_PROC_INFO(thd, "Reopen tables"); + thd_proc_info(thd, "Reopen tables"); thd->version= refresh_version; result=reopen_tables(thd,0,0); } pthread_mutex_unlock(&LOCK_open); - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); DBUG_RETURN(result); } @@ -2103,7 +2103,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) restart: *counter= 0; query_tables_last_own= 0; - THD_PROC_INFO(thd, "Opening tables"); + thd_proc_info(thd, "Opening tables"); /* If we are not already executing prelocked statement and don't have @@ -2283,7 +2283,7 @@ process_view_routines: } err: - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block if (query_tables_last_own) @@ -2357,7 +2357,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type) bool refresh; DBUG_ENTER("open_ltable"); - THD_PROC_INFO(thd, "Opening table"); + thd_proc_info(thd, "Opening table"); thd->current_tablenr= 0; /* open_ltable can be used only for BASIC TABLEs */ table_list->required_type= FRMTYPE_TABLE; @@ -2391,7 +2391,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type) table= 0; } } - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); DBUG_RETURN(table); } @@ -2611,7 +2611,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) { if (thd->lex->requires_prelocking()) { - thd->options&= ~(ulong) (OPTION_TABLE_LOCK); + thd->options&= ~(OPTION_TABLE_LOCK); thd->in_lock_tables=0; } DBUG_RETURN(-1); @@ -2644,7 +2644,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) ha_rollback_stmt(thd); mysql_unlock_tables(thd, thd->locked_tables); thd->locked_tables= 0; - thd->options&= ~(ulong) (OPTION_TABLE_LOCK); + thd->options&= ~(OPTION_TABLE_LOCK); DBUG_RETURN(-1); } } @@ -5436,7 +5436,7 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order) List_iterator li(*(select_lex->ftfunc_list)); Item_func_match *ifm; DBUG_PRINT("info",("Performing FULLTEXT search")); - THD_PROC_INFO(thd, "FULLTEXT initialization"); + thd_proc_info(thd, "FULLTEXT initialization"); while ((ifm=li++)) ifm->init_search(no_order); diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 7340da5ce93..cb65eb562a2 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -315,13 +315,13 @@ TODO list: #define MUTEX_UNLOCK(M) {DBUG_PRINT("lock", ("mutex unlock 0x%lx",\ (ulong)(M))); pthread_mutex_unlock(M);} #define RW_WLOCK(M) {DBUG_PRINT("lock", ("rwlock wlock 0x%lx",(ulong)(M))); \ - if (!rw_wrlock(M)) DBUG_PRINT("lock", ("rwlock wlock ok")) \ + if (!rw_wrlock(M)) DBUG_PRINT("lock", ("rwlock wlock ok")); \ else DBUG_PRINT("lock", ("rwlock wlock FAILED %d", errno)); } #define RW_RLOCK(M) {DBUG_PRINT("lock", ("rwlock rlock 0x%lx", (ulong)(M))); \ - if (!rw_rdlock(M)) DBUG_PRINT("lock", ("rwlock rlock ok")) \ + if (!rw_rdlock(M)) DBUG_PRINT("lock", ("rwlock rlock ok")); \ else DBUG_PRINT("lock", ("rwlock wlock FAILED %d", errno)); } #define RW_UNLOCK(M) {DBUG_PRINT("lock", ("rwlock unlock 0x%lx",(ulong)(M))); \ - if (!rw_unlock(M)) DBUG_PRINT("lock", ("rwlock unlock ok")) \ + if (!rw_unlock(M)) DBUG_PRINT("lock", ("rwlock unlock ok")); \ else DBUG_PRINT("lock", ("rwlock unlock FAILED %d", errno)); } #define STRUCT_LOCK(M) {DBUG_PRINT("lock", ("%d struct lock...",__LINE__)); \ pthread_mutex_lock(M);DBUG_PRINT("lock", ("struct lock OK"));} @@ -688,7 +688,7 @@ void query_cache_abort(NET *net) net->query_cache_query); if (query_block) // Test if changed by other thread { - THD_PROC_INFO(thd, "storing result in query cache"); + thd_proc_info(thd, "storing result in query cache"); DUMP(&query_cache); BLOCK_LOCK_WR(query_block); // The following call will remove the lock on query_block @@ -726,7 +726,7 @@ void query_cache_end_of_result(THD *thd) query_block= ((Query_cache_block*) thd->net.query_cache_query); if (query_block) { - THD_PROC_INFO(thd, "storing result in query cache"); + thd_proc_info(thd, "storing result in query cache"); DUMP(&query_cache); BLOCK_LOCK_WR(query_block); Query_cache_query *header= query_block->query(); @@ -1091,7 +1091,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) DBUG_PRINT("qcache", ("No active database")); } - THD_PROC_INFO(thd, "checking query cache for query"); + thd_proc_info(thd, "checking query cache for query"); // fill all gaps between fields with 0 to get repeatable key bzero(&flags, QUERY_CACHE_FLAGS_SIZE); @@ -1167,7 +1167,7 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu", } // Check access; - THD_PROC_INFO(thd, "checking privileges on cached query"); + thd_proc_info(thd, "checking privileges on cached query"); block_table= query_block->table(0); block_table_end= block_table+query_block->n_tables; for (; block_table != block_table_end; block_table++) @@ -1260,7 +1260,7 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu", Send cached result to client */ #ifndef EMBEDDED_LIBRARY - THD_PROC_INFO(thd, "sending cached result to client"); + thd_proc_info(thd, "sending cached result to client"); do { DBUG_PRINT("qcache", ("Results (len: %lu used: %lu headers: %lu)", @@ -1342,7 +1342,7 @@ void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used) DBUG_ENTER("Query_cache::invalidate (changed table list)"); if (tables_used) { - THD_PROC_INFO(thd, "invalidating query cache entries (table list)"); + thd_proc_info(thd, "invalidating query cache entries (table list)"); STRUCT_LOCK(&structure_guard_mutex); if (query_cache_size > 0 && !flush_in_progress) { @@ -1377,7 +1377,7 @@ void Query_cache::invalidate_locked_for_write(TABLE_LIST *tables_used) DBUG_ENTER("Query_cache::invalidate_locked_for_write"); if (tables_used) { - THD_PROC_INFO(thd, "invalidating query cache entries (table)"); + thd_proc_info(thd, "invalidating query cache entries (table)"); STRUCT_LOCK(&structure_guard_mutex); if (query_cache_size > 0 && !flush_in_progress) { @@ -1427,7 +1427,7 @@ void Query_cache::invalidate(THD *thd, const char *key, uint32 key_length, STRUCT_LOCK(&structure_guard_mutex); if (query_cache_size > 0 && !flush_in_progress) { - THD_PROC_INFO(thd, "invalidating query cache entries (key)"); + thd_proc_info(thd, "invalidating query cache entries (key)"); using_transactions= using_transactions && (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)); if (using_transactions) // used for innodb => has_transactions() is TRUE diff --git a/sql/sql_class.cc b/sql/sql_class.cc index fc9ec55f54a..4878acabbb2 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -247,7 +247,9 @@ THD::THD() init(); /* Initialize sub structures */ init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE); +#ifdef ENABLED_PROFILING profiling.set_thd(this); +#endif user_connect=(USER_CONN *)0; hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0, (hash_get_key) get_var_key, @@ -330,7 +332,6 @@ void THD::init_for_queries() variables.trans_alloc_block_size, variables.trans_prealloc_size); #endif - profiling.reset(); transaction.xid_state.xid.null(); transaction.xid_state.in_thd=1; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 582d6afe51c..3795627fd58 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -521,6 +521,7 @@ struct system_variables ulong optimizer_prune_level; ulong optimizer_search_depth; ulong preload_buff_size; + ulong profiling_history_size; ulong query_cache_type; ulong read_buff_size; ulong read_rnd_buff_size; @@ -1154,6 +1155,9 @@ public: Points to info-string that we show in SHOW PROCESSLIST You are supposed to update thd->proc_info only if you have coded a time-consuming piece that MySQL can get stuck in for a long time. + + Set it using the thd_proc_info(THD *thread, const char *message) + macro/function. */ const char *proc_info; @@ -1308,8 +1312,9 @@ public: List warn_list; uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END]; uint total_warn_count; - +#ifdef ENABLED_PROFILING PROFILING profiling; +#endif /* Id of current query. Statement can be reused to execute several queries diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index d02bc89068e..ac290a50b9b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -54,7 +54,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table->file->print_error(error, MYF(0)); DBUG_RETURN(error); } - THD_PROC_INFO(thd, "init"); + thd_proc_info(thd, "init"); table->map=1; if (mysql_prepare_delete(thd, table_list, &conds)) @@ -205,7 +205,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, deleted=0L; init_ftfuncs(thd, select_lex, 1); - THD_PROC_INFO(thd, "updating"); + thd_proc_info(thd, "updating"); if (table->triggers) table->triggers->mark_fields_used(thd, TRG_EVENT_DELETE); @@ -261,7 +261,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, } if (thd->killed && !error) error= 1; // Aborted - THD_PROC_INFO(thd, "end"); + thd_proc_info(thd, "end"); end_read_record(&info); free_io_cache(table); // Will not do any harm if (options & OPTION_QUICK) @@ -485,7 +485,7 @@ multi_delete::prepare(List &values, SELECT_LEX_UNIT *u) DBUG_ENTER("multi_delete::prepare"); unit= u; do_delete= 1; - THD_PROC_INFO(thd, "deleting from main table"); + thd_proc_info(thd, "deleting from main table"); DBUG_RETURN(0); } @@ -749,7 +749,7 @@ int multi_delete::do_deletes() bool multi_delete::send_eof() { - THD_PROC_INFO(thd, "deleting from reference tables"); + thd_proc_info(thd, "deleting from reference tables"); /* Does deletes for the last n - 1 tables, returns 0 if ok */ int local_error= do_deletes(); // returns 0 if success @@ -758,7 +758,7 @@ bool multi_delete::send_eof() local_error= local_error || error; /* reset used flags */ - THD_PROC_INFO(thd, "end"); + thd_proc_info(thd, "end"); /* We must invalidate the query cache before binlog writing and @@ -903,7 +903,7 @@ end: /* Probably InnoDB table */ ulonglong save_options= thd->options; table_list->lock_type= TL_WRITE; - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT); + thd->options&= ~(OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT); ha_enable_transaction(thd, FALSE); mysql_init_select(thd->lex); error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0, diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index c2e30c47cfb..b384098bc00 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -397,7 +397,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, if (res || thd->is_fatal_error) DBUG_RETURN(TRUE); - THD_PROC_INFO(thd, "init"); + thd_proc_info(thd, "init"); thd->used_tables=0; values= its++; @@ -470,7 +470,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, error=0; id=0; - THD_PROC_INFO(thd, "update"); + thd_proc_info(thd, "update"); if (duplic != DUP_ERROR || ignore) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); if (duplic == DUP_REPLACE) @@ -676,7 +676,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, thd->lock=0; } } - THD_PROC_INFO(thd, "end"); + thd_proc_info(thd, "end"); table->next_number_field=0; thd->count_cuted_fields= CHECK_FIELD_IGNORE; thd->next_insert_id=0; // Reset this if wrongly used @@ -1407,7 +1407,7 @@ I_List delayed_threads; delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list) { - THD_PROC_INFO(thd, "waiting for delay_list"); + thd_proc_info(thd, "waiting for delay_list"); pthread_mutex_lock(&LOCK_delayed_insert); // Protect master list I_List_iterator it(delayed_threads); delayed_insert *tmp; @@ -1444,7 +1444,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) */ if (delayed_insert_threads >= thd->variables.max_insert_delayed_threads) DBUG_RETURN(0); - THD_PROC_INFO(thd, "Creating delayed handler"); + thd_proc_info(thd, "Creating delayed handler"); pthread_mutex_lock(&LOCK_delayed_create); /* The first search above was done without LOCK_delayed_create. @@ -1486,13 +1486,13 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) } /* Wait until table is open */ - THD_PROC_INFO(thd, "waiting for handler open"); + thd_proc_info(thd, "waiting for handler open"); while (!tmp->thd.killed && !tmp->table && !thd->killed) { pthread_cond_wait(&tmp->cond_client,&tmp->mutex); } pthread_mutex_unlock(&tmp->mutex); - THD_PROC_INFO(thd, "got old table"); + thd_proc_info(thd, "got old table"); if (tmp->thd.killed) { if (tmp->thd.is_fatal_error) @@ -1552,13 +1552,13 @@ TABLE *delayed_insert::get_local_table(THD* client_thd) tables_in_use++; if (!thd.lock) // Table is not locked { - THD_PROC_INFO(client_thd, "waiting for handler lock"); + thd_proc_info(client_thd, "waiting for handler lock"); pthread_cond_signal(&cond); // Tell handler to lock table while (!dead && !thd.lock && ! client_thd->killed) { pthread_cond_wait(&cond_client,&mutex); } - THD_PROC_INFO(client_thd, "got handler lock"); + thd_proc_info(client_thd, "got handler lock"); if (client_thd->killed) goto error; if (dead) @@ -1576,7 +1576,7 @@ TABLE *delayed_insert::get_local_table(THD* client_thd) bytes. Since the table copy is used for creating one record only, the other record buffers and alignment are unnecessary. */ - THD_PROC_INFO(client_thd, "allocating local table"); + thd_proc_info(client_thd, "allocating local table"); copy= (TABLE*) client_thd->alloc(sizeof(*copy)+ (table->s->fields+1)*sizeof(Field**)+ table->s->reclength); @@ -1656,11 +1656,11 @@ static int write_delayed(THD *thd,TABLE *table,enum_duplicates duplic, bool igno delayed_insert *di=thd->di; DBUG_ENTER("write_delayed"); - THD_PROC_INFO(thd, "waiting for handler insert"); + thd_proc_info(thd, "waiting for handler insert"); pthread_mutex_lock(&di->mutex); while (di->stacked_inserts >= delayed_queue_size && !thd->killed) pthread_cond_wait(&di->cond_client,&di->mutex); - THD_PROC_INFO(thd, "storing row into queue"); + thd_proc_info(thd, "storing row into queue"); if (thd->killed || !(row= new delayed_row(duplic, ignore, log_on))) goto err; @@ -1869,7 +1869,7 @@ pthread_handler_t handle_delayed_insert(void *arg) /* Information for pthread_kill */ di->thd.mysys_var->current_mutex= &di->mutex; di->thd.mysys_var->current_cond= &di->cond; - THD_PROC_INFO(&(di->thd), "Waiting for INSERT"); + thd_proc_info(&(di->thd), "Waiting for INSERT"); DBUG_PRINT("info",("Waiting for someone to insert rows")); while (!thd->killed) @@ -1904,7 +1904,7 @@ pthread_handler_t handle_delayed_insert(void *arg) pthread_mutex_unlock(&di->thd.mysys_var->mutex); pthread_mutex_lock(&di->mutex); } - THD_PROC_INFO(&(di->thd), 0); + thd_proc_info(&(di->thd), 0); if (di->tables_in_use && ! thd->lock) { @@ -2023,7 +2023,7 @@ bool delayed_insert::handle_inserts(void) table->next_number_field=table->found_next_number_field; - THD_PROC_INFO(&thd, "upgrading lock"); + thd_proc_info(&thd, "upgrading lock"); if (thr_upgrade_write_delay_lock(*thd.lock->locks)) { /* This can only happen if thread is killed by shutdown */ @@ -2031,7 +2031,7 @@ bool delayed_insert::handle_inserts(void) goto err; } - THD_PROC_INFO(&thd, "insert"); + thd_proc_info(&thd, "insert"); max_rows= delayed_insert_limit; if (thd.killed || table->s->version != refresh_version) { @@ -2149,7 +2149,7 @@ bool delayed_insert::handle_inserts(void) { if (tables_in_use) pthread_cond_broadcast(&cond_client); // If waiting clients - THD_PROC_INFO(&thd, "reschedule"); + thd_proc_info(&thd, "reschedule"); pthread_mutex_unlock(&mutex); if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) { @@ -2168,14 +2168,14 @@ bool delayed_insert::handle_inserts(void) if (!using_bin_log) table->file->extra(HA_EXTRA_WRITE_CACHE); pthread_mutex_lock(&mutex); - THD_PROC_INFO(&thd, "insert"); + thd_proc_info(&thd, "insert"); } if (tables_in_use) pthread_cond_broadcast(&cond_client); // If waiting clients } } - THD_PROC_INFO(&thd, 0); + thd_proc_info(&thd, 0); table->next_number_field=0; pthread_mutex_unlock(&mutex); if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index da562babea1..47fe2e8ac0e 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -173,8 +173,9 @@ void lex_start(THD *thd, uchar *buf,uint length) lex->proc_list.first= 0; lex->escape_used= FALSE; lex->reset_query_tables_list(FALSE); +#ifdef ENABLED_PROFILING lex->profile_options= PROFILE_NONE; - +#endif lex->nest_level=0 ; lex->allow_sum_func= 0; lex->in_sum_func= NULL; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 96ce02f7409..22f9d6026f9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -95,8 +95,12 @@ enum enum_sql_command { SQLCOM_XA_COMMIT, SQLCOM_XA_ROLLBACK, SQLCOM_XA_RECOVER, SQLCOM_SHOW_PROC_CODE, SQLCOM_SHOW_FUNC_CODE, SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES, - /* This should be the last !!! */ + /* + When a command is added here, be sure it's also added in mysqld.cc + in "struct show_var_st status_vars[]= {" ... + */ + /* This should be the last !!! */ SQLCOM_END }; @@ -939,8 +943,9 @@ typedef struct st_lex : public Query_tables_list enum enum_var_type option_type; enum enum_view_create_mode create_view_mode; enum enum_drop_mode drop_mode; - uint profile_options; + uint profile_query_id; + uint profile_options; uint uint_geom_type; uint grant, grant_tot_col, which_columns; uint fk_delete_opt, fk_update_opt, fk_match_option; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 779db99a4ff..449d57c2b2d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -140,14 +140,14 @@ static bool end_active_trans(THD *thd) if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN | OPTION_TABLE_LOCK)) { - DBUG_PRINT("info",("options: 0x%lx", (ulong) thd->options)); + DBUG_PRINT("info",("options: 0x%llx", thd->options)); /* Safety if one did "drop table" on locked tables */ if (!thd->locked_tables) thd->options&= ~OPTION_TABLE_LOCK; thd->server_status&= ~SERVER_STATUS_IN_TRANS; if (ha_commit(thd)) error=1; - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); } DBUG_RETURN(error); } @@ -171,7 +171,7 @@ static bool begin_trans(THD *thd) else { LEX *lex= thd->lex; - thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) | + thd->options= ((thd->options & ~(OPTION_STATUS_NO_TRANS_UPDATE)) | OPTION_BEGIN); thd->server_status|= SERVER_STATUS_IN_TRANS; if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT) @@ -1058,7 +1058,7 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var, Vio* save_vio; ulong save_client_capabilities; - THD_PROC_INFO(thd, "Execution of init_command"); + thd_proc_info(thd, "Execution of init_command"); /* We need to lock init_command_var because during execution of init_command_var query @@ -1158,7 +1158,7 @@ pthread_handler_t handle_one_connection(void *arg) net->compress=1; // Use compression thd->version= refresh_version; - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); thd->command= COM_SLEEP; thd->set_time(); thd->init_for_queries(); @@ -1175,7 +1175,7 @@ pthread_handler_t handle_one_connection(void *arg) sctx->host_or_ip, "init_connect command failed"); sql_print_warning("%s", net->last_error); } - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); thd->set_time(); thd->init_for_queries(); } @@ -1258,7 +1258,7 @@ pthread_handler_t handle_bootstrap(void *arg) if (thd->variables.max_join_size == HA_POS_ERROR) thd->options |= OPTION_BIG_SELECTS; - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); thd->version=refresh_version; thd->security_ctx->priv_user= thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME)); @@ -1447,7 +1447,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) */ thd->server_status&= ~SERVER_STATUS_IN_TRANS; res= ha_commit(thd); - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); break; case COMMIT_RELEASE: do_release= 1; /* fall through */ @@ -1464,7 +1464,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) thd->server_status&= ~SERVER_STATUS_IN_TRANS; if (ha_rollback(thd)) res= -1; - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); if (!res && (completion == ROLLBACK_AND_CHAIN)) res= begin_trans(thd); break; @@ -2105,7 +2105,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (thd->lock || thd->open_tables || thd->derived_tables || thd->prelocked_mode) { - THD_PROC_INFO(thd, "closing tables"); + thd_proc_info(thd, "closing tables"); close_thread_tables(thd); /* Free tables */ } /* @@ -2128,9 +2128,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, log_slow_statement(thd); - THD_PROC_INFO(thd, "cleaning up"); + thd_proc_info(thd, "cleaning up"); VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list - THD_PROC_INFO(thd, 0); + thd_proc_info(thd, 0); thd->command=COM_SLEEP; thd->query=0; thd->query_length=0; @@ -2163,6 +2163,8 @@ void log_slow_statement(THD *thd) */ if (thd->enable_slow_log && !thd->user_time) { + thd_proc_info(thd, "logging slow query"); + if ((ulong) (thd->start_time - thd->time_after_lock) > thd->variables.long_query_time || (thd->server_status & @@ -2171,7 +2173,7 @@ void log_slow_statement(THD *thd) /* == SQLCOM_END unless this is a SHOW command */ thd->lex->orig_sql_command == SQLCOM_END) { - THD_PROC_INFO(thd, "logging slow query"); + thd_proc_info(thd, "logging slow query"); thd->status_var.long_query_count++; mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query); } @@ -2698,16 +2700,33 @@ mysql_execute_command(THD *thd) } case SQLCOM_SHOW_PROFILES: { +#ifdef ENABLED_PROFILING thd->profiling.store(); thd->profiling.discard(); res= thd->profiling.show_profiles(); + if (res) + goto error; +#else + my_error(ER_FEATURE_DISABLED, MYF(0), "query profiling", "enable-profiling"); + goto error; +#endif break; } case SQLCOM_SHOW_PROFILE: { +#ifdef ENABLED_PROFILING thd->profiling.store(); thd->profiling.discard(); // will get re-enabled by reset() - res= thd->profiling.show_last(lex->profile_options); + if (lex->profile_query_id != 0) + res= thd->profiling.show(lex->profile_options, lex->profile_query_id); + else + res= thd->profiling.show_last(lex->profile_options); + if (res) + goto error; +#else + my_error(ER_FEATURE_DISABLED, MYF(0), "query profiling", "enable-profiling"); + goto error; +#endif break; } case SQLCOM_SHOW_NEW_MASTER: @@ -3557,7 +3576,7 @@ end_with_restore_list: if (add_item_to_list(thd, new Item_null())) goto error; - THD_PROC_INFO(thd, "init"); + thd_proc_info(thd, "init"); if ((res= open_and_lock_tables(thd, all_tables))) break; @@ -3721,7 +3740,7 @@ end_with_restore_list: if (thd->options & OPTION_TABLE_LOCK) { end_active_trans(thd); - thd->options&= ~(ulong) (OPTION_TABLE_LOCK); + thd->options&= ~(OPTION_TABLE_LOCK); } if (thd->global_read_lock) unlock_global_read_lock(thd); @@ -3747,7 +3766,7 @@ end_with_restore_list: send_ok(thd); } else - thd->options&= ~(ulong) (OPTION_TABLE_LOCK); + thd->options&= ~(OPTION_TABLE_LOCK); thd->in_lock_tables=0; break; case SQLCOM_CREATE_DB: @@ -4847,7 +4866,7 @@ create_sp_error: thd->transaction.xid_state.xa_state=XA_ACTIVE; thd->transaction.xid_state.xid.set(thd->lex->xid); xid_cache_insert(&thd->transaction.xid_state); - thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) | + thd->options= ((thd->options & ~(OPTION_STATUS_NO_TRANS_UPDATE)) | OPTION_BEGIN); thd->server_status|= SERVER_STATUS_IN_TRANS; send_ok(thd); @@ -4941,7 +4960,7 @@ create_sp_error: xa_state_names[thd->transaction.xid_state.xa_state]); break; } - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); thd->server_status&= ~SERVER_STATUS_IN_TRANS; xid_cache_delete(&thd->transaction.xid_state); thd->transaction.xid_state.xa_state=XA_NOTR; @@ -4971,7 +4990,7 @@ create_sp_error: my_error(ER_XAER_RMERR, MYF(0)); else send_ok(thd); - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); + thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); thd->server_status&= ~SERVER_STATUS_IN_TRANS; xid_cache_delete(&thd->transaction.xid_state); thd->transaction.xid_state.xa_state=XA_NOTR; @@ -4986,7 +5005,7 @@ create_sp_error: send_ok(thd); break; } - THD_PROC_INFO(thd, "query end"); + thd_proc_info(thd, "query end"); /* Two binlog-related cleanups: */ /* @@ -5157,8 +5176,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, else save_priv= &dummy; - THD_PROC_INFO(thd, "checking permissions"); - + thd_proc_info(thd, "checking permissions"); if ((!db || !db[0]) && !thd->db && !dont_check_global_grants) { DBUG_PRINT("error",("No database")); @@ -5605,6 +5623,9 @@ mysql_init_query(THD *thd, uchar *buf, uint length) DBUG_ENTER("mysql_init_query"); lex_start(thd, buf, length); mysql_reset_thd_for_next_command(thd); +#ifdef ENABLED_PROFILING + thd->profiling.reset(); +#endif DBUG_VOID_RETURN; } @@ -5646,7 +5667,9 @@ void mysql_reset_thd_for_next_command(THD *thd) thd->total_warn_count=0; // Warnings for this query thd->rand_used= 0; thd->sent_row_count= thd->examined_row_count= 0; +#ifdef ENABLED_PROFILING thd->profiling.reset(); +#endif } DBUG_VOID_RETURN; } @@ -5870,7 +5893,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length) query_cache_abort(&thd->net); lex->unit.cleanup(); } - THD_PROC_INFO(thd, "freeing items"); + thd_proc_info(thd, "freeing items"); thd->end_statement(); thd->cleanup_after_query(); DBUG_ASSERT(thd->change_list.is_empty()); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 152cc3aa385..83ddb9c9212 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2222,6 +2222,7 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute"))) DBUG_VOID_RETURN; + thd->profiling.set_query_source(stmt->query, stmt->query_length); DBUG_PRINT("exec_query", ("%s", stmt->query)); DBUG_PRINT("info",("stmt: %p", stmt)); diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 98a5f8d7576..e9b6ef0b522 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -14,149 +14,282 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "mysql_priv.h" -#include "sp_rcontext.h" -#define RUSAGE_USEC(tv) ((tv).tv_sec*1000000 + (tv).tv_usec) +#include "mysql_priv.h" +#include "my_sys.h" + +#define TIME_FLOAT_DIGITS 7 +#define MAX_QUERY_LENGTH 300 + +bool schema_table_store_record(THD *thd, TABLE *table); + +/* Reserved for systems that can't record the function name in source. */ +const char *_db_func_= ""; + +/** + Connects Information_Schema and Profiling. +*/ +int fill_query_profile_statistics_info(THD *thd, struct st_table_list *tables, + Item *cond) +{ +#ifdef ENABLED_PROFILING + return(thd->profiling.fill_statistics_info(thd, tables, cond)); +#else + return(1); +#endif +} + +ST_FIELD_INFO query_profile_statistics_info[]= +{ + /* name, length, type, value, maybe_null, old_name */ + {"Query_id", 20, MYSQL_TYPE_LONG, 0, false, NULL}, + {"Seq", 20, MYSQL_TYPE_LONG, 0, false, NULL}, + {"State", 30, MYSQL_TYPE_STRING, 0, false, NULL}, + {"Duration", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, false, NULL}, + {"CPU_user", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, + {"CPU_system", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, + {"Context_voluntary", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Context_involuntary", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Block_ops_in", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Block_ops_out", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Messages_sent", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Messages_received", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Page_faults_major", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Page_faults_minor", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Swaps", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"Source_function", 30, MYSQL_TYPE_STRING, 0, true, NULL}, + {"Source_file", 20, MYSQL_TYPE_STRING, 0, true, NULL}, + {"Source_line", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL} +}; + +#ifdef ENABLED_PROFILING + +#define RUSAGE_USEC(tv) ((tv).tv_sec*1000*1000 + (tv).tv_usec) #define RUSAGE_DIFF_USEC(tv1, tv2) (RUSAGE_USEC((tv1))-RUSAGE_USEC((tv2))) PROFILE_ENTRY::PROFILE_ENTRY() - :status(NULL), time(0), function(NULL), file(NULL), line(0) + :profile(NULL), status(NULL), function(NULL), file(NULL), line(0), + time_usecs(0.0), allocated_status_memory(NULL) { collect(); } -PROFILE_ENTRY::PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg) - :profile(profile_arg), function(NULL), file(NULL), line(0) +PROFILE_ENTRY::PROFILE_ENTRY(QUERY_PROFILE *profile_arg, const char *status_arg) + :profile(profile_arg) { collect(); - if (status_arg) - set_status(status_arg); + set_status(status_arg, NULL, NULL, 0); } -PROFILE_ENTRY::PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg, +PROFILE_ENTRY::PROFILE_ENTRY(QUERY_PROFILE *profile_arg, const char *status_arg, const char *function_arg, const char *file_arg, unsigned int line_arg) :profile(profile_arg) { collect(); - if (status_arg) - set_status(status_arg); - if (function_arg) - function= strdup_root(&profile->profiling->root, function_arg); - if (file_arg) - file= strdup_root(&profile->profiling->root, file_arg); - line= line_arg; + set_status(status_arg, function_arg, file_arg, line_arg); } PROFILE_ENTRY::~PROFILE_ENTRY() { - if (status) - free(status); - if (function) - free(function); - if (file) - free(file); + if (allocated_status_memory != NULL) + my_free(allocated_status_memory, MYF(0)); + status= function= file= NULL; } -void PROFILE_ENTRY::set_status(const char *status_arg) +void PROFILE_ENTRY::set_status(const char *status_arg, const char *function_arg, const char *file_arg, unsigned int line_arg) { - status= strdup_root(&profile->profiling->root, status_arg); + size_t sizes[3]; /* 3 == status+function+file */ + char *cursor; + + /* + Compute all the space we'll need to allocate one block for everything + we'll need, instead of N mallocs. + */ + if (status_arg != NULL) + sizes[0]= strlen(status_arg) + 1; + else + sizes[0]= 0; + + if (function_arg != NULL) + sizes[1]= strlen(function_arg) + 1; + else + sizes[1]= 0; + + if (file_arg != NULL) + sizes[2]= strlen(file_arg) + 1; + else + sizes[2]= 0; + + allocated_status_memory= (char *) my_malloc(sizes[0] + sizes[1] + sizes[2], MYF(0)); + DBUG_ASSERT(allocated_status_memory != NULL); + + cursor= allocated_status_memory; + + if (status_arg != NULL) + { + strcpy(cursor, status_arg); + status= cursor; + cursor+= sizes[0]; + } + else + status= NULL; + + if (function_arg != NULL) + { + strcpy(cursor, function_arg); + function= cursor; + cursor+= sizes[1]; + } + else + function= NULL; + + if (file_arg != NULL) + { + strcpy(cursor, file_arg); + file= cursor; + cursor+= sizes[2]; + } + else + file= NULL; + + line= line_arg; } void PROFILE_ENTRY::collect() { - time= my_getsystime(); + time_usecs= (double) my_getsystime() / 10.0; /* 1 sec was 1e7, now is 1e6 */ +#ifdef HAVE_GETRUSAGE getrusage(RUSAGE_SELF, &rusage); +#endif } -PROFILE::PROFILE(PROFILING *profiling_arg) - :profiling(profiling_arg) +QUERY_PROFILE::QUERY_PROFILE(PROFILING *profiling_arg, char *query_source_arg, + uint query_length_arg) + :profiling(profiling_arg), server_query_id(-1), profiling_query_id(-1), + query_source(NULL) { profile_end= &profile_start; + set_query_source(query_source_arg, query_length_arg); } -PROFILE::~PROFILE() +void QUERY_PROFILE::set_query_source(char *query_source_arg, + uint query_length_arg) { + /* Truncate to avoid DoS attacks. */ + uint length= min(MAX_QUERY_LENGTH, query_length_arg); + /* TODO?: Provide a way to include the full text, as in SHOW PROCESSLIST. */ + + if (query_source_arg != NULL) + query_source= my_strdup_with_length(query_source_arg, length, MYF(0)); +} + +QUERY_PROFILE::~QUERY_PROFILE() +{ + PROFILE_ENTRY *entry; + List_iterator it(entries); + while ((entry= it++) != NULL) + delete entry; entries.empty(); + + if (query_source != NULL) + my_free(query_source, MYF(0)); } -void PROFILE::status(const char *status_arg, - const char *function_arg=NULL, - const char *file_arg=NULL, unsigned int line_arg=0) +void QUERY_PROFILE::status(const char *status_arg, + const char *function_arg= NULL, + const char *file_arg= NULL, unsigned int line_arg= 0) { - PROFILE_ENTRY *prof= NULL; - MEM_ROOT *old_root= NULL; THD *thd= profiling->thd; - - DBUG_ENTER("PROFILE::status"); + PROFILE_ENTRY *prof; + MEM_ROOT *saved_mem_root; + DBUG_ENTER("QUERY_PROFILE::status"); /* Blank status. Just return, and thd->proc_info will be set blank later. */ - if (unlikely(!status_arg)) + if (unlikely(status_arg == NULL)) DBUG_VOID_RETURN; /* If thd->proc_info is currently set to status_arg, don't profile twice. */ - if (unlikely(thd->proc_info && !(strcmp(thd->proc_info, status_arg)))) + if (likely((thd->proc_info != NULL) && + ((thd->proc_info == status_arg) || + (strcmp(thd->proc_info, status_arg) == 0)))) + { DBUG_VOID_RETURN; + } /* Is this the same query as our profile currently contains? */ - if (unlikely(thd->query_id != query_id && !thd->spcont)) + if (unlikely((thd->query_id != server_query_id) && !thd->spcont)) reset(); /* In order to keep the profile information between queries (i.e. from SELECT to the following SHOW PROFILE command) the following code is necessary to keep the profile from getting freed automatically when - mysqld cleans up after the query. This code is shamelessly stolen - from SHOW WARNINGS. + mysqld cleans up after the query. + + The "entries" list allocates is memory from the current thd's mem_root. + We substitute our mem_root temporarily so that we intercept those + allocations into our own mem_root. The thd->mem_root structure is freed after each query is completed, so temporarily override it. */ - old_root= thd->mem_root; - thd->mem_root= &profiling->root; - if (function_arg && file_arg) { - if ((profile_end= prof= new PROFILE_ENTRY(this, status_arg, function_arg, file_arg, line_arg))) + saved_mem_root= thd->mem_root; + thd->mem_root= &profiling->mem_root; + //thd->mem_root= NULL; + + if (function_arg && file_arg) + { + if ((profile_end= prof= new PROFILE_ENTRY(this, status_arg, function_arg, + file_arg, line_arg))) entries.push_back(prof); - } else { + } + else + { if ((profile_end= prof= new PROFILE_ENTRY(this, status_arg))) entries.push_back(prof); } - thd->mem_root= old_root; + + /* Restore mem_root */ + thd->mem_root= saved_mem_root; DBUG_VOID_RETURN; } -void PROFILE::reset() +void QUERY_PROFILE::reset() { - DBUG_ENTER("PROFILE::reset"); - if (profiling->thd->query_id != query_id) + DBUG_ENTER("QUERY_PROFILE::reset"); + if (likely(profiling->thd->query_id != server_query_id)) { - query_id= profiling->thd->query_id; + server_query_id= profiling->thd->query_id; /* despite name, is global */ profile_start.collect(); + + PROFILE_ENTRY *entry; + List_iterator it(entries); + while ((entry= it++) != NULL) + delete entry; entries.empty(); } DBUG_VOID_RETURN; } -bool PROFILE::show(uint options) +bool QUERY_PROFILE::show(uint options) { - PROFILE_ENTRY *prof; THD *thd= profiling->thd; - PROFILE_ENTRY *ps= &profile_start; List field_list; - DBUG_ENTER("PROFILE::show"); + DBUG_ENTER("QUERY_PROFILE::show"); field_list.push_back(new Item_empty_string("Status", MYSQL_ERRMSG_SIZE)); - field_list.push_back(new Item_return_int("Time_elapsed", 20, - MYSQL_TYPE_LONGLONG)); + field_list.push_back(new Item_return_int("Duration", TIME_FLOAT_DIGITS, + MYSQL_TYPE_DOUBLE)); if (options & PROFILE_CPU) { - field_list.push_back(new Item_return_int("CPU_user", 20, - MYSQL_TYPE_LONGLONG)); - field_list.push_back(new Item_return_int("CPU_system", 20, - MYSQL_TYPE_LONGLONG)); + field_list.push_back(new Item_return_int("CPU_user", TIME_FLOAT_DIGITS, + MYSQL_TYPE_DOUBLE)); + field_list.push_back(new Item_return_int("CPU_system", TIME_FLOAT_DIGITS, + MYSQL_TYPE_DOUBLE)); } if (options & PROFILE_MEMORY) @@ -200,7 +333,7 @@ bool PROFILE::show(uint options) field_list.push_back(new Item_return_int("Swaps", 10, MYSQL_TYPE_LONG)); } - if(options & PROFILE_SOURCE) + if (options & PROFILE_SOURCE) { field_list.push_back(new Item_empty_string("Source_function", MYSQL_ERRMSG_SIZE)); @@ -214,146 +347,231 @@ bool PROFILE::show(uint options) Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); + Protocol *protocol= thd->protocol; SELECT_LEX *sel= &thd->lex->select_lex; SELECT_LEX_UNIT *unit= &thd->lex->unit; ha_rows idx= 0; - Protocol *protocol=thd->protocol; - unit->set_limit(sel); + double last_time= profile_start.time_usecs; +#ifdef HAVE_GETRUSAGE + struct rusage *last_rusage= &(profile_start.rusage); +#endif List_iterator it(entries); - ulonglong last_time= ps->time; - while ((prof= it++)) + PROFILE_ENTRY *entry; + while ((entry= it++) != NULL) { +#ifdef HAVE_GETRUSAGE + struct rusage *rusage= &(entry->rusage); +#endif + String elapsed; + if (++idx <= unit->offset_limit_cnt) continue; if (idx > unit->select_limit_cnt) break; protocol->prepare_for_resend(); - protocol->store(prof->status, strlen(prof->status), system_charset_info); - protocol->store((ulonglong)(prof->time - ps->time)/10); + protocol->store(entry->status, strlen(entry->status), system_charset_info); + protocol->store((double)(entry->time_usecs - last_time)/(1000.0*1000), + (uint32) TIME_FLOAT_DIGITS-1, &elapsed); + //protocol->store((double)(entry->time - last_time)/(1000*1000*10)); if (options & PROFILE_CPU) { - protocol->store((ulonglong)RUSAGE_DIFF_USEC(prof->rusage.ru_utime, - ps->rusage.ru_utime)); - protocol->store((ulonglong)RUSAGE_DIFF_USEC(prof->rusage.ru_stime, - ps->rusage.ru_stime)); +#ifdef HAVE_GETRUSAGE + String cpu_utime, cpu_stime; + protocol->store((double)(RUSAGE_DIFF_USEC(rusage->ru_utime, + last_rusage->ru_utime))/(1000.0*1000), + (uint32) TIME_FLOAT_DIGITS-1, &cpu_utime); + protocol->store((double)(RUSAGE_DIFF_USEC(rusage->ru_stime, + last_rusage->ru_stime))/(1000.0*1000), + (uint32) TIME_FLOAT_DIGITS-1, &cpu_stime); +#else + protocol->store_null(); + protocol->store_null(); +#endif } if (options & PROFILE_CONTEXT) { - protocol->store((uint32)(prof->rusage.ru_nvcsw - ps->rusage.ru_nvcsw)); - protocol->store((uint32)(prof->rusage.ru_nivcsw - ps->rusage.ru_nivcsw)); +#ifdef HAVE_GETRUSAGE + protocol->store((uint32)(rusage->ru_nvcsw - last_rusage->ru_nvcsw)); + protocol->store((uint32)(rusage->ru_nivcsw - last_rusage->ru_nivcsw)); +#else + protocol->store_null(); + protocol->store_null(); +#endif } if (options & PROFILE_BLOCK_IO) { - protocol->store((uint32)(prof->rusage.ru_inblock-ps->rusage.ru_inblock)); - protocol->store((uint32)(prof->rusage.ru_oublock-ps->rusage.ru_oublock)); +#ifdef HAVE_GETRUSAGE + protocol->store((uint32)(rusage->ru_inblock - last_rusage->ru_inblock)); + protocol->store((uint32)(rusage->ru_oublock - last_rusage->ru_oublock)); +#else + protocol->store_null(); + protocol->store_null(); +#endif } if (options & PROFILE_IPC) { - protocol->store((uint32)(prof->rusage.ru_msgsnd - ps->rusage.ru_msgsnd)); - protocol->store((uint32)(prof->rusage.ru_msgrcv - ps->rusage.ru_msgrcv)); +#ifdef HAVE_GETRUSAGE + protocol->store((uint32)(rusage->ru_msgsnd - last_rusage->ru_msgsnd)); + protocol->store((uint32)(rusage->ru_msgrcv - last_rusage->ru_msgrcv)); +#else + protocol->store_null(); + protocol->store_null(); +#endif } if (options & PROFILE_PAGE_FAULTS) { - protocol->store((uint32)(prof->rusage.ru_majflt - ps->rusage.ru_majflt)); - protocol->store((uint32)(prof->rusage.ru_minflt - ps->rusage.ru_minflt)); +#ifdef HAVE_GETRUSAGE + protocol->store((uint32)(rusage->ru_majflt - last_rusage->ru_majflt)); + protocol->store((uint32)(rusage->ru_minflt - last_rusage->ru_minflt)); +#else + protocol->store_null(); + protocol->store_null(); +#endif } if (options & PROFILE_SWAPS) { - protocol->store((uint32)(prof->rusage.ru_nswap - ps->rusage.ru_nswap)); +#ifdef HAVE_GETRUSAGE + protocol->store((uint32)(rusage->ru_nswap - last_rusage->ru_nswap)); +#else + protocol->store_null(); +#endif } if (options & PROFILE_SOURCE) { - if(prof->function && prof->file) + if ((entry->function != NULL) && (entry->file != NULL)) { - protocol->store(prof->function, strlen(prof->function), system_charset_info); - protocol->store(prof->file, strlen(prof->file), system_charset_info); - protocol->store(prof->line); + protocol->store(entry->function, strlen(entry->function), + system_charset_info); + protocol->store(entry->file, strlen(entry->file), system_charset_info); + protocol->store(entry->line); } else { - protocol->store("(unknown)", 10, system_charset_info); - protocol->store("(unknown)", 10, system_charset_info); - protocol->store((uint32) 0); + protocol->store_null(); + protocol->store_null(); + protocol->store_null(); } } if (protocol->write()) DBUG_RETURN(TRUE); - last_time= prof->time; + + last_time= entry->time_usecs; +#ifdef HAVE_GETRUSAGE + last_rusage= &(entry->rusage); +#endif + } send_eof(thd); DBUG_RETURN(FALSE); } -/* XXX: enabled should be set to the current global profiling setting */ PROFILING::PROFILING() - :enabled(1), keeping(1), current(NULL), last(NULL) + :profile_id_counter(0), keeping(1), current(NULL), last(NULL) { - init_sql_alloc(&root, + init_sql_alloc(&mem_root, PROFILE_ALLOC_BLOCK_SIZE, PROFILE_ALLOC_PREALLOC_SIZE); } PROFILING::~PROFILING() { - free_root(&root, MYF(0)); + QUERY_PROFILE *prof; + + List_iterator it(history); + while ((prof= it++) != NULL) + delete prof; + history.empty(); + + if (current != NULL) + delete current; + + free_root(&mem_root, MYF(0)); } -void PROFILING::status(const char *status_arg, - const char *function_arg, - const char *file_arg, unsigned int line_arg) +void PROFILING::status_change(const char *status_arg, + const char *function_arg, + const char *file_arg, unsigned int line_arg) { - DBUG_ENTER("PROFILING::status"); + DBUG_ENTER("PROFILING::status_change"); - if(!current) - reset(); + if (unlikely((thd->options & OPTION_PROFILING) != 0)) + { + if (unlikely(current == NULL)) + reset(); + + DBUG_ASSERT(current != NULL); - if(unlikely(enabled)) current->status(status_arg, function_arg, file_arg, line_arg); - + } + thd->proc_info= status_arg; - DBUG_VOID_RETURN; } void PROFILING::store() { - MEM_ROOT *old_root; + MEM_ROOT *saved_mem_root; DBUG_ENTER("PROFILING::store"); - if (last && current && (last->query_id == current->query_id)) - DBUG_VOID_RETURN; - - if (history.elements > 10) /* XXX: global/session var */ + /* Already stored */ + if (unlikely((last != NULL) && + (current != NULL) && + (last->server_query_id == current->server_query_id))) { - PROFILE *tmp= history.pop(); + DBUG_VOID_RETURN; + } + + while (history.elements > thd->variables.profiling_history_size) + { + QUERY_PROFILE *tmp= history.pop(); delete tmp; } - old_root= thd->mem_root; - thd->mem_root= &root; + /* + Switch out memory roots so that we're sure that we keep what we need + + The "history" list implementation allocates its memory in the current + thd's mem_root. We substitute our mem_root temporarily so that we + intercept those allocations into our own mem_root. + */ + + saved_mem_root= thd->mem_root; + thd->mem_root= &mem_root; - if (current) + if (current != NULL) { - if (keeping && (!current->entries.is_empty())) { - last= current; + if (keeping && + (current->query_source != NULL) && + (current->query_source[0] != '\0') && + (!current->entries.is_empty())) + { + current->profiling_query_id= next_profile_id(); /* assign an id */ + + last= current; /* never contains something that is not in the history. */ history.push_back(current); current= NULL; - } else { + } + else + { delete current; + current= NULL; } } - current= new PROFILE(this); - thd->mem_root= old_root; + DBUG_ASSERT(current == NULL); + current= new QUERY_PROFILE(this, thd->query, thd->query_length); + + /* Restore memory root */ + thd->mem_root= saved_mem_root; DBUG_VOID_RETURN; } @@ -364,8 +582,8 @@ void PROFILING::reset() store(); - current->reset(); - /*free_root(&root, MYF(0));*/ + if (current != NULL) + current->reset(); keep(); DBUG_VOID_RETURN; @@ -373,15 +591,15 @@ void PROFILING::reset() bool PROFILING::show_profiles() { - PROFILE *prof; + DBUG_ENTER("PROFILING::show_profiles"); + QUERY_PROFILE *prof; List field_list; - DBUG_ENTER("PROFILING::list_all"); field_list.push_back(new Item_return_int("Query_ID", 10, MYSQL_TYPE_LONG)); - field_list.push_back(new Item_return_int("Time", 20, - MYSQL_TYPE_LONGLONG)); - /* TODO: Add another field that lists the query. */ + field_list.push_back(new Item_return_int("Duration", TIME_FLOAT_DIGITS-1, + MYSQL_TYPE_DOUBLE)); + field_list.push_back(new Item_empty_string("Query", 40)); if (thd->protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) @@ -390,13 +608,15 @@ bool PROFILING::show_profiles() SELECT_LEX *sel= &thd->lex->select_lex; SELECT_LEX_UNIT *unit= &thd->lex->unit; ha_rows idx= 0; - Protocol *protocol=thd->protocol; + Protocol *protocol= thd->protocol; unit->set_limit(sel); - List_iterator it(history); - while ((prof= it++)) + List_iterator it(history); + while ((prof= it++) != NULL) { + String elapsed; + PROFILE_ENTRY *ps= &prof->profile_start; PROFILE_ENTRY *pe= prof->profile_end; @@ -406,8 +626,14 @@ bool PROFILING::show_profiles() break; protocol->prepare_for_resend(); - protocol->store((uint32)(prof->query_id)); - protocol->store((ulonglong)((pe->time - ps->time)/10)); + protocol->store((uint32)(prof->profiling_query_id)); + protocol->store((double)(pe->time_usecs - ps->time_usecs)/(1000.0*1000), + (uint32) TIME_FLOAT_DIGITS-1, &elapsed); + if (prof->query_source != NULL) + protocol->store(prof->query_source, strlen(prof->query_source), + system_charset_info); + else + protocol->store_null(); if (protocol->write()) DBUG_RETURN(TRUE); @@ -416,18 +642,37 @@ bool PROFILING::show_profiles() DBUG_RETURN(FALSE); } -bool PROFILING::show(uint options, uint query_id) +/* + This is an awful hack to let prepared statements tell us the query + that they're executing. +*/ +void PROFILING::set_query_source(char *query_source_arg, uint query_length_arg) +{ + DBUG_ENTER("PROFILING::set_query_source"); + + /* We can't get this query source through normal means. */ + DBUG_ASSERT((thd->query == NULL) || (thd->query_length == 0)); + + if (current != NULL) + current->set_query_source(query_source_arg, query_length_arg); + else + DBUG_PRINT("info", ("no current profile to send query source to")); + DBUG_VOID_RETURN; +} + +bool PROFILING::show(uint options, uint profiling_query_id) { DBUG_ENTER("PROFILING::show"); - PROFILE *prof; + QUERY_PROFILE *prof; - List_iterator it(history); - while ((prof= it++)) + List_iterator it(history); + while ((prof= it++) != NULL) { - if(prof->query_id == query_id) - prof->show(options); + if(prof->profiling_query_id == profiling_query_id) + DBUG_RETURN(prof->show(options)); } + my_error(ER_WRONG_ARGUMENTS, MYF(0), "SHOW PROFILE"); DBUG_RETURN(TRUE); } @@ -439,3 +684,130 @@ bool PROFILING::show_last(uint options) } DBUG_RETURN(TRUE); } + + +/** + Fill the information schema table, "query_profile", as defined in show.cc . +*/ +int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item *cond) +{ + DBUG_ENTER("PROFILING::fill_statistics_info"); + TABLE *table= tables->table; + ulonglong row_number= 0; + + List_iterator query_it(history); + QUERY_PROFILE *query; + /* Go through each query in this thread's stored history... */ + while ((query= query_it++) != NULL) + { + PROFILE_ENTRY *ps= &(query->profile_start); + double last_time= ps->time_usecs; +#ifdef HAVE_GETRUSAGE + struct rusage *last_rusage= &(ps->rusage); +#endif + + /* + Because we put all profiling info into a table that may be reordered, let + us also include a numbering of each state per query. The query_id and + the "seq" together are unique. + */ + ulonglong seq; + + List_iterator step_it(query->entries); + PROFILE_ENTRY *entry; + /* ...and for each query, go through all its state-change steps. */ + for (seq= 0, entry= step_it++; + entry != NULL; +#ifdef HAVE_GETRUSAGE + last_rusage= &(entry->rusage), +#endif + seq++, last_time= entry->time_usecs, entry= step_it++, row_number++) + { + /* Set default values for this row. */ + restore_record(table, s->default_values); + + /* + The order of these fields is set by the query_profile_statistics_info + array. + */ + table->field[0]->store((ulonglong) query->profiling_query_id); + table->field[1]->store((ulonglong) seq); /* the step in the sequence */ + table->field[2]->store(entry->status, strlen(entry->status), + system_charset_info); + table->field[3]->store((double)(entry->time_usecs - last_time)/(1000*1000)); + +#ifdef HAVE_GETRUSAGE + table->field[4]->store((double)RUSAGE_DIFF_USEC(entry->rusage.ru_utime, + last_rusage->ru_utime)/(1000.0*1000)); + table->field[4]->null_ptr= NULL; + table->field[5]->store((double)RUSAGE_DIFF_USEC(entry->rusage.ru_stime, + last_rusage->ru_stime)/(1000.0*1000)); + + table->field[5]->null_ptr= NULL; +#else + /* TODO: Add CPU-usage info for non-BSD systems */ +#endif + +#ifdef HAVE_GETRUSAGE + table->field[6]->store((uint32)(entry->rusage.ru_nvcsw - last_rusage->ru_nvcsw)); + table->field[6]->null_ptr= NULL; + table->field[7]->store((uint32)(entry->rusage.ru_nivcsw - last_rusage->ru_nivcsw)); + table->field[7]->null_ptr= NULL; +#else + /* TODO: Add context switch info for non-BSD systems */ +#endif + +#ifdef HAVE_GETRUSAGE + table->field[8]->store((uint32)(entry->rusage.ru_inblock - last_rusage->ru_inblock)); + table->field[8]->null_ptr= NULL; + table->field[9]->store((uint32)(entry->rusage.ru_oublock - last_rusage->ru_oublock)); + table->field[9]->null_ptr= NULL; +#else + /* TODO: Add block IO info for non-BSD systems */ +#endif + +#ifdef HAVE_GETRUSAGE + table->field[10]->store((uint32)(entry->rusage.ru_msgsnd - last_rusage->ru_msgsnd), true); + table->field[10]->null_ptr= NULL; + table->field[11]->store((uint32)(entry->rusage.ru_msgrcv - last_rusage->ru_msgrcv), true); + table->field[11]->null_ptr= NULL; +#else + /* TODO: Add message info for non-BSD systems */ +#endif + +#ifdef HAVE_GETRUSAGE + table->field[12]->store((uint32)(entry->rusage.ru_majflt - last_rusage->ru_majflt), true); + table->field[12]->null_ptr= NULL; + table->field[13]->store((uint32)(entry->rusage.ru_minflt - last_rusage->ru_minflt), true); + table->field[13]->null_ptr= NULL; +#else + /* TODO: Add page fault info for non-BSD systems */ +#endif + +#ifdef HAVE_GETRUSAGE + table->field[14]->store((uint32)(entry->rusage.ru_nswap - last_rusage->ru_nswap), true); + table->field[14]->null_ptr= NULL; +#else + /* TODO: Add swap info for non-BSD systems */ +#endif + + if ((entry->function != NULL) && (entry->file != NULL)) + { + table->field[15]->store(entry->function, strlen(entry->function), + system_charset_info); + table->field[15]->null_ptr= NULL; + table->field[16]->store(entry->file, strlen(entry->file), system_charset_info); + table->field[16]->null_ptr= NULL; + table->field[17]->store(entry->line, true); + table->field[17]->null_ptr= NULL; + } + + if (schema_table_store_record(thd, table)) + DBUG_RETURN(1); + + } + } + + DBUG_RETURN(0); +} +#endif /* ENABLED_PROFILING */ diff --git a/sql/sql_profile.h b/sql/sql_profile.h index 698a80f07e4..006760cab79 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2005 MySQL AB +/* Copyright (C) 2007 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,99 +14,135 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef SQL_PROFILE_H -#define SQL_PROFILE_H +#ifndef _SQL_PROFILE_H +#define _SQL_PROFILE_H -#include -#include - -#if 1 -#define THD_PROC_INFO(thd, msg) do { if(unlikely((thd)->profiling.enabled)) { (thd)->profiling.status((msg), __FUNCTION__, __FILE__, __LINE__); } else { (thd)->proc_info= (msg); } } while (0) +#if __STDC_VERSION__ < 199901L +# if __GNUC__ >= 2 +# define __func__ __FUNCTION__ +# else +# define __func__ _db_func_ +extern const char *_db_func_; +# endif +#elif defined(_MSC_VER) +# if _MSC_VER < 1300 +# define __func__ _db_func_ +extern const char *_db_func_; +# else +# define __func__ __FUNCTION__ +# endif +#elif defined(__BORLANDC__) +# define __func__ __FUNC__ #else -#define THD_PROC_INFO(thd, msg) do { (thd)->proc_info= (msg); } while (0) +# define __func__ _db_func_ +extern const char *_db_func_; #endif -#if 0 +extern ST_FIELD_INFO query_profile_statistics_info[]; +int fill_query_profile_statistics_info(THD *thd, struct st_table_list *tables, Item *cond); - struct rusage { - struct timeval ru_utime; /* user time used */ - struct timeval ru_stime; /* system time used */ - long ru_maxrss; /* integral max resident set size */ - long ru_ixrss; /* integral shared text memory size */ - long ru_idrss; /* integral unshared data size */ - long ru_isrss; /* integral unshared stack size */ - long ru_minflt; /* page reclaims */ - long ru_majflt; /* page faults */ - long ru_nswap; /* swaps */ - long ru_inblock; /* block input operations */ - long ru_oublock; /* block output operations */ - long ru_msgsnd; /* messages sent */ - long ru_msgrcv; /* messages received */ - long ru_nsignals; /* signals received */ - long ru_nvcsw; /* voluntary context switches */ - long ru_nivcsw; /* involuntary context switches */ - }; - -#endif #define PROFILE_NONE 0 -#define PROFILE_CPU 1 -#define PROFILE_MEMORY 2 -#define PROFILE_BLOCK_IO 4 -#define PROFILE_CONTEXT 8 -#define PROFILE_PAGE_FAULTS 16 -#define PROFILE_IPC 32 -#define PROFILE_SWAPS 64 -#define PROFILE_SOURCE 16384 -#define PROFILE_ALL 32767 +#define PROFILE_CPU (1<<0) +#define PROFILE_MEMORY (1<<1) +#define PROFILE_BLOCK_IO (1<<2) +#define PROFILE_CONTEXT (1<<3) +#define PROFILE_PAGE_FAULTS (1<<4) +#define PROFILE_IPC (1<<5) +#define PROFILE_SWAPS (1<<6) +#define PROFILE_SOURCE (1<<16) +#define PROFILE_ALL (~0) + + +#ifndef ENABLED_PROFILING + +# define thd_proc_info(thd, msg) do { (thd)->proc_info= (msg); } while (0) + +#else + +# define thd_proc_info(thd, msg) \ + do { \ + if (unlikely(((thd)->options & OPTION_PROFILING) != 0)) \ + { \ + (thd)->profiling.status_change((msg), __func__, __FILE__, __LINE__); \ + } \ + else \ + { \ + (thd)->proc_info= (msg); \ + } \ + } while (0) + +#include "mysql_priv.h" + +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif + class PROFILE_ENTRY; -class PROFILE; +class QUERY_PROFILE; class PROFILING; -/* + +/** A single entry in a single profile. */ - -class PROFILE_ENTRY: public Sql_alloc +class PROFILE_ENTRY { -public: - PROFILE *profile; - char *status; - ulonglong time; +private: + friend class QUERY_PROFILE; + friend class PROFILING; + + QUERY_PROFILE *profile; + char *status; +#ifdef HAVE_GETRUSAGE struct rusage rusage; +#endif char *function; char *file; unsigned int line; + + double time_usecs; + char *allocated_status_memory; + + void set_status(const char *status_arg, const char *function_arg, + const char *file_arg, unsigned int line_arg); + void clean_up(); PROFILE_ENTRY(); - PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg); - PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg, + PROFILE_ENTRY(QUERY_PROFILE *profile_arg, const char *status_arg); + PROFILE_ENTRY(QUERY_PROFILE *profile_arg, const char *status_arg, const char *function_arg, const char *file_arg, unsigned int line_arg); ~PROFILE_ENTRY(); - - void set_status(const char *status_arg); void collect(); }; -/* - The full profile for a single query. Includes multiple PROFILE_ENTRY + +/** + The full profile for a single query, and includes multiple PROFILE_ENTRY objects. */ - -class PROFILE: public Sql_alloc +class QUERY_PROFILE { -public: +private: + friend class PROFILING; + PROFILING *profiling; - query_id_t query_id; + + query_id_t server_query_id; /* Global id. */ + query_id_t profiling_query_id; /* Session-specific id. */ + char *query_source; PROFILE_ENTRY profile_start; PROFILE_ENTRY *profile_end; List entries; - PROFILE(PROFILING *profiling_arg); - ~PROFILE(); + + QUERY_PROFILE(PROFILING *profiling_arg, char *query_source_arg, uint query_length_arg); + ~QUERY_PROFILE(); + + void set_query_source(char *query_source_arg, uint query_length_arg); /* Add a profile status change to the current profile. */ void status(const char *status_arg, @@ -120,68 +156,86 @@ public: bool show(uint options); }; -/* - Profiling state for a single THD. Contains multiple PROFILE objects. -*/ -class PROFILING: public Sql_alloc +/** + Profiling state for a single THD; contains multiple QUERY_PROFILE objects. +*/ +class PROFILING { -public: - MEM_ROOT root; +private: + friend class PROFILE_ENTRY; + friend class QUERY_PROFILE; + + /* + Not the system query_id, but a counter unique to profiling. + */ + query_id_t profile_id_counter; + MEM_ROOT mem_root; THD *thd; - bool enabled; bool keeping; - PROFILE *current; - PROFILE *last; - List history; + QUERY_PROFILE *current; + QUERY_PROFILE *last; + List history; + + query_id_t next_profile_id() { return(profile_id_counter++); } +public: PROFILING(); ~PROFILING(); + void set_query_source(char *query_source_arg, uint query_length_arg); - inline void set_thd(THD *thd_arg) { thd= thd_arg; }; + /** Reset the current profile and state of profiling for the next query. */ + void reset(); - /* - Should we try to collect profiling information at all? - - If we disable profiling, we cannot later decide to turn it back - on for the same query. - */ - inline void enable() { enabled= 1; }; - inline void disable() { enabled= 0; }; - - /* + /** Do we intend to keep the currently collected profile? - We don't keep profiles for some commands, such as SHOW PROFILE, - SHOW PROFILES, and some SQLCOM commands which aren't useful to - profile. The keep() and discard() functions can be called many - times, only the final setting when the query finishes is used - to decide whether to discard the profile. + We don't keep profiles for some commands, such as SHOW PROFILE, SHOW + PROFILES, and some SQLCOM commands which aren't useful to profile. The + keep() and discard() functions can be called many times, only the final + setting when the query finishes is used to decide whether to discard the + profile. The default is to keep the profile for all queries. */ - inline void keep() { keeping= 1; }; - inline void discard() { keeping= 0; }; + inline void keep() { keeping= true; }; - void status(const char *status_arg, - const char *function_arg, - const char *file_arg, unsigned int line_arg); + /** + Do we intend to keep the currently collected profile? + @see keep() + */ + inline void discard() { keeping= false; }; - /* Stash this profile in the profile history. */ + /** + Stash this profile in the profile history and remove the oldest + profile if the history queue is full, as defined by the + profiling_history_size system variable. + */ void store(); - - /* Reset the current profile and state of profiling for the next query. */ - void reset(); + + /** + Called with every update of the status via thd_proc_info() , and is + therefore the main hook into the profiling code. + */ + void status_change(const char *status_arg, + const char *function_arg, + const char *file_arg, unsigned int line_arg); + + inline void set_thd(THD *thd_arg) { thd= thd_arg; }; /* SHOW PROFILES */ bool show_profiles(); /* SHOW PROFILE FOR QUERY query_id */ - bool show(uint options, uint query_id); + bool show(uint options, uint profiling_query_id); /* SHOW PROFILE */ bool show_last(uint options); + + /* ... from INFORMATION_SCHEMA.PROFILING ... */ + int fill_statistics_info(THD *thd, struct st_table_list *tables, Item *cond); }; -#endif /* SQL_PROFILE_H */ +# endif /* HAVE_PROFILING */ +#endif /* _SQL_PROFILE_H */ diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 07ae439cfb9..11c4d4464d8 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -645,7 +645,7 @@ impossible position"; if (read_packet) { - thd->proc_info = "Sending binlog event to slave"; + thd_proc_info(thd, "Sending binlog event to slave"); if (my_net_write(net, (char*)packet->ptr(), packet->length()) ) { errmsg = "Failed on my_net_write()"; @@ -683,7 +683,7 @@ impossible position"; bool loop_breaker = 0; /* need this to break out of the for loop from switch */ - thd->proc_info = "Finished reading one binlog; switching to next binlog"; + thd_proc_info(thd, "Finished reading one binlog; switching to next binlog"); switch (mysql_bin_log.find_next_log(&linfo, 1)) { case LOG_INFO_EOF: loop_breaker = (flags & BINLOG_DUMP_NON_BLOCK); @@ -729,14 +729,14 @@ end: (void)my_close(file, MYF(MY_WME)); send_eof(thd); - thd->proc_info = "Waiting to finalize termination"; + thd_proc_info(thd, "Waiting to finalize termination"); pthread_mutex_lock(&LOCK_thread_count); thd->current_linfo = 0; pthread_mutex_unlock(&LOCK_thread_count); DBUG_VOID_RETURN; err: - thd->proc_info = "Waiting to finalize termination"; + thd_proc_info(thd, "Waiting to finalize termination"); end_io_cache(&log); /* Exclude iteration through thread list @@ -888,7 +888,7 @@ int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report ) if (check_access(thd, SUPER_ACL, any_db,0,0,0,0)) return 1; - thd->proc_info = "Killing slave"; + thd_proc_info(thd, "Killing slave"); int thread_mask; lock_slave_threads(mi); // Get a mask of _running_ threads @@ -915,7 +915,7 @@ int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report ) ER(ER_SLAVE_WAS_NOT_RUNNING)); } unlock_slave_threads(mi); - thd->proc_info = 0; + thd_proc_info(thd, 0); if (slave_errno) { @@ -1071,7 +1071,7 @@ bool change_master(THD* thd, MASTER_INFO* mi) DBUG_RETURN(TRUE); } - thd->proc_info = "Changing master"; + thd_proc_info(thd, "Changing master"); LEX_MASTER_INFO* lex_mi= &thd->lex->mi; // TODO: see if needs re-write if (init_master_info(mi, master_info_file, relay_log_info_file, 0, @@ -1196,7 +1196,7 @@ bool change_master(THD* thd, MASTER_INFO* mi) if (need_relay_log_purge) { relay_log_purge= 1; - THD_PROC_INFO(thd, "Purging old relay logs"); + thd_proc_info(thd, "Purging old relay logs"); if (purge_relay_logs(&mi->rli, thd, 0 /* not only reset, but also reinit */, &errmsg)) @@ -1259,7 +1259,7 @@ bool change_master(THD* thd, MASTER_INFO* mi) pthread_mutex_unlock(&mi->rli.data_lock); unlock_slave_threads(mi); - thd->proc_info = 0; + thd_proc_info(thd, 0); send_ok(thd); DBUG_RETURN(FALSE); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ada440fbc2d..c9e334b7784 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -598,7 +598,7 @@ JOIN::optimize() if (thd->lex->orig_sql_command != SQLCOM_SHOW_STATUS) thd->status_var.last_query_cost= 0.0; - THD_PROC_INFO(thd, "optimizing"); + thd_proc_info(thd, "optimizing"); row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR : unit->select_limit_cnt); /* select_limit is used to decide if we are likely to scan the whole table */ @@ -745,7 +745,7 @@ JOIN::optimize() sort_by_table= get_sort_by_table(order, group_list, select_lex->leaf_tables); /* Calculate how to do the join */ - THD_PROC_INFO(thd, "statistics"); + thd_proc_info(thd, "statistics"); if (make_join_statistics(this, select_lex->leaf_tables, conds, &keyuse) || thd->is_fatal_error) { @@ -755,7 +755,7 @@ JOIN::optimize() /* Remove distinct if only const tables */ select_distinct= select_distinct && (const_tables != tables); - THD_PROC_INFO(thd, "preparing"); + thd_proc_info(thd, "preparing"); if (result->initialize_tables(this)) { DBUG_PRINT("error",("Error: initialize_tables() failed")); @@ -1162,7 +1162,7 @@ JOIN::optimize() if (need_tmp) { DBUG_PRINT("info",("Creating tmp table")); - THD_PROC_INFO(thd, "creating temporary table"); + thd_proc_info(thd, "Creating tmp table"); init_items_ref_array(); @@ -1213,7 +1213,7 @@ JOIN::optimize() if (group_list && simple_group) { DBUG_PRINT("info",("Sorting for group")); - THD_PROC_INFO(thd, "sorting for group"); + thd_proc_info(thd, "Sorting for group"); if (create_sort_index(thd, this, group_list, HA_POS_ERROR, HA_POS_ERROR) || alloc_group_fields(this, group_list) || @@ -1234,9 +1234,8 @@ JOIN::optimize() if (!group_list && ! exec_tmp_table1->distinct && order && simple_order) { - DBUG_PRINT("info",("Sorting for order")); - THD_PROC_INFO(thd, "Sorting for order"); - if (create_sort_index(thd, this, order, + thd_proc_info(thd, "Sorting for order"); + if (create_sort_index(thd, this, order, HA_POS_ERROR, HA_POS_ERROR)) { DBUG_RETURN(1); @@ -1364,7 +1363,7 @@ JOIN::exec() int tmp_error; DBUG_ENTER("JOIN::exec"); - THD_PROC_INFO(thd, "executing"); + thd_proc_info(thd, "executing"); error= 0; if (procedure) { @@ -1504,7 +1503,7 @@ JOIN::exec() curr_tmp_table= exec_tmp_table1; /* Copy data to the temporary table */ - THD_PROC_INFO(thd, "Copying to tmp table"); + thd_proc_info(thd, "Copying to tmp table"); DBUG_PRINT("info", ("%s", thd->proc_info)); if ((tmp_error= do_select(curr_join, (List *) 0, curr_tmp_table, 0))) { @@ -1627,7 +1626,7 @@ JOIN::exec() } if (curr_join->group_list) { - THD_PROC_INFO(thd, "Creating sort index"); + thd_proc_info(thd, "Creating sort index"); if (curr_join->join_tab == join_tab && save_join_tab()) { DBUG_VOID_RETURN; @@ -1641,7 +1640,7 @@ JOIN::exec() sortorder= curr_join->sortorder; } - THD_PROC_INFO(thd, "Copying to group table"); + thd_proc_info(thd, "Copying to group table"); DBUG_PRINT("info", ("%s", thd->proc_info)); tmp_error= -1; if (curr_join != this) @@ -1697,7 +1696,7 @@ JOIN::exec() curr_join->join_free(); /* Free quick selects */ if (curr_join->select_distinct && ! curr_join->group_list) { - THD_PROC_INFO(thd, "Removing duplicates"); + thd_proc_info(thd, "Removing duplicates"); if (curr_join->tmp_having) curr_join->tmp_having->update_used_tables(); if (remove_duplicates(curr_join, curr_tmp_table, @@ -1758,7 +1757,7 @@ JOIN::exec() if (curr_join->group_list || curr_join->order) { DBUG_PRINT("info",("Sorting for send_fields")); - THD_PROC_INFO(thd, "Sorting result"); + thd_proc_info(thd, "Sorting result"); /* If we have already done the group, add HAVING to sorted table */ if (curr_join->tmp_having && ! curr_join->group_list && ! curr_join->sort_and_group) @@ -1882,7 +1881,7 @@ JOIN::exec() } else { - THD_PROC_INFO(thd, "Sending data"); + thd_proc_info(thd, "Sending data"); DBUG_PRINT("info", ("%s", thd->proc_info)); result->send_fields((procedure ? curr_join->procedure_fields_list : *curr_fields_list), @@ -2030,7 +2029,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array, { if (!(join= new JOIN(thd, fields, select_options, result))) DBUG_RETURN(TRUE); - THD_PROC_INFO(thd, "init"); + thd_proc_info(thd, "init"); thd->used_tables=0; // Updated by setup_fields if (err= join->prepare(rref_pointer_array, tables, wild_num, conds, og_num, order, group, having, proc_param, @@ -2075,9 +2074,9 @@ mysql_select(THD *thd, Item ***rref_pointer_array, err: if (free_join) { - THD_PROC_INFO(thd, "cleaning up"); + thd_proc_info(thd, "end"); err|= select_lex->cleanup(); - THD_PROC_INFO(thd, "end"); + thd_proc_info(thd, "end"); DBUG_RETURN(err || thd->net.report_error); } DBUG_RETURN(join->error); @@ -9807,7 +9806,7 @@ free_tmp_table(THD *thd, TABLE *entry) DBUG_PRINT("enter",("table: %s",entry->alias)); save_proc_info=thd->proc_info; - THD_PROC_INFO(thd, "removing tmp table"); + thd_proc_info(thd, "removing tmp table"); if (entry->file) { @@ -9835,7 +9834,7 @@ free_tmp_table(THD *thd, TABLE *entry) bitmap_clear_bit(&temp_pool, entry->temp_pool_slot); free_root(&own_root, MYF(0)); /* the table is allocated in its own root */ - THD_PROC_INFO(thd, save_proc_info); + thd_proc_info(thd, save_proc_info); DBUG_VOID_RETURN; } @@ -9865,7 +9864,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, DBUG_RETURN(1); // End of memory save_proc_info=thd->proc_info; - THD_PROC_INFO(thd, "converting HEAP to MyISAM"); + thd_proc_info(thd, "converting HEAP to MyISAM"); if (create_myisam_tmp_table(&new_table,param, thd->lex->select_lex.options | thd->options)) @@ -9918,8 +9917,8 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, table->s= &table->share_not_to_be_used; table->file->change_table_ptr(table); if (save_proc_info) - THD_PROC_INFO(thd, (!strcmp(save_proc_info,"Copying to tmp table") ? - "Copying to tmp table on disk" : save_proc_info)); + thd_proc_info(thd, (!strcmp(save_proc_info,"Copying to tmp table") ? + "Copying to tmp table on disk" : save_proc_info)); DBUG_RETURN(0); err: @@ -9931,7 +9930,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, new_table.file->delete_table(new_table.s->table_name); delete new_table.file; err2: - THD_PROC_INFO(thd, save_proc_info); + thd_proc_info(thd, save_proc_info); DBUG_RETURN(1); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 0a39640aa4f..133bee1c481 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -44,7 +44,7 @@ static void append_algorithm(TABLE_LIST *table, String *buff); static int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff); -static bool schema_table_store_record(THD *thd, TABLE *table); +bool schema_table_store_record(THD *thd, TABLE *table); /*************************************************************************** @@ -1349,7 +1349,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) #if !defined(DONT_USE_THR_ALARM) && ! defined(SCO) if (pthread_kill(tmp->real_id,0)) - THD_PROC_INFO(tmp, "*** DEAD ***"); // This shouldn't happen + thd_proc_info(tmp, "*** DEAD ***"); // This shouldn't happen #endif #ifdef EXTRA_DEBUG thd_info->start_time= tmp->time_after_lock; @@ -1847,7 +1847,7 @@ typedef struct st_index_field_values 1 error */ -static bool schema_table_store_record(THD *thd, TABLE *table) +bool schema_table_store_record(THD *thd, TABLE *table) { int error; if ((error= table->file->write_row(table->record[0]))) @@ -4305,6 +4305,8 @@ ST_SCHEMA_TABLE schema_tables[]= get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0}, {"OPEN_TABLES", open_tables_fields_info, create_schema_table, fill_open_tables, make_old_format, 0, -1, -1, 1}, + {"PROFILING", query_profile_statistics_info, create_schema_table, + fill_query_profile_statistics_info, NULL, NULL, -1, -1, false}, {"ROUTINES", proc_fields_info, create_schema_table, fill_schema_proc, make_proc_old_format, 0, -1, -1, 0}, {"SCHEMATA", schema_fields_info, create_schema_table, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 43fdd693a4b..dc474c080b4 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1729,7 +1729,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, } } - THD_PROC_INFO(thd, "creating table"); + thd_proc_info(thd, "creating table"); create_info->table_existed= 0; // Mark that table is created if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) @@ -1760,7 +1760,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, end: VOID(pthread_mutex_unlock(&LOCK_open)); - THD_PROC_INFO(thd, "After create"); + thd_proc_info(thd, "After create"); DBUG_RETURN(error); warn: @@ -2879,7 +2879,7 @@ mysql_discard_or_import_tablespace(THD *thd, ALTER TABLE */ - THD_PROC_INFO(thd, "discard_or_import_tablespace"); + thd_proc_info(thd, "discard_or_import_tablespace"); discard= test(tablespace_op == DISCARD_TABLESPACE); @@ -2896,7 +2896,7 @@ mysql_discard_or_import_tablespace(THD *thd, error=table->file->discard_or_import_tablespace(discard); - THD_PROC_INFO(thd, "end"); + thd_proc_info(thd, "end"); if (error) goto err; @@ -3007,7 +3007,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, frm_type_enum frm_type; DBUG_ENTER("mysql_alter_table"); - THD_PROC_INFO(thd, "init"); + thd_proc_info(thd, "init"); table_name=table_list->table_name; alias= (lower_case_table_names == 2) ? table_list->alias : table_name; @@ -3142,7 +3142,7 @@ view_err: DBUG_RETURN(TRUE); } - THD_PROC_INFO(thd, "setup"); + thd_proc_info(thd, "setup"); if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) && !table->s->tmp_table) // no need to touch frm { @@ -3173,7 +3173,7 @@ view_err: if (!error && (new_name != table_name || new_db != db)) { - THD_PROC_INFO(thd, "rename"); + thd_proc_info(thd, "rename"); /* Then do a 'simple' rename of the table */ if (!access(new_name_buff,F_OK)) { @@ -3627,7 +3627,7 @@ view_err: /* We don't want update TIMESTAMP fields during ALTER TABLE. */ thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields thd->cuted_fields=0L; - THD_PROC_INFO(thd, "copy to tmp table"); + thd_proc_info(thd, "copy to tmp table"); next_insert_id=thd->next_insert_id; // Remember for logging copied=deleted=0; if (new_table && !new_table->s->is_view) @@ -3711,7 +3711,7 @@ view_err: from the cache, free all locks, close the old table and remove it. */ - THD_PROC_INFO(thd, "rename result table"); + thd_proc_info(thd, "rename result table"); my_snprintf(old_name, sizeof(old_name), "%s2-%lx-%lx", tmp_file_prefix, current_pid, thd->thread_id); if (lower_case_table_names) @@ -3822,7 +3822,7 @@ view_err: broadcast_refresh(); goto err; } - THD_PROC_INFO(thd, "end"); + thd_proc_info(thd, "end"); if (mysql_bin_log.is_open()) { thd->clear_error(); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 0fdadd9e0db..62be615d3f6 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -166,7 +166,7 @@ int mysql_update(THD *thd, mysql_handle_derived(thd->lex, &mysql_derived_filling))) DBUG_RETURN(1); - THD_PROC_INFO(thd, "init"); + thd_proc_info(thd, "init"); table= table_list->table; table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); @@ -358,7 +358,7 @@ int mysql_update(THD *thd, else init_read_record_idx(&info, thd, table, 1, used_index); - THD_PROC_INFO(thd, "Searching rows for update"); + thd_proc_info(thd, "Searching rows for update"); uint tmp_limit= limit; while (!(error=info.read_record(&info)) && !thd->killed) @@ -423,7 +423,7 @@ int mysql_update(THD *thd, updated= found= 0; thd->count_cuted_fields= CHECK_FIELD_WARN; /* calc cuted fields */ thd->cuted_fields=0L; - THD_PROC_INFO(thd, "Updating"); + thd_proc_info(thd, "Updating"); query_id=thd->query_id; transactional_table= table->file->has_transactions(); @@ -511,7 +511,7 @@ int mysql_update(THD *thd, end_read_record(&info); free_io_cache(table); // If ORDER BY delete select; - THD_PROC_INFO(thd, "end"); + thd_proc_info(thd, "end"); VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY)); /* @@ -959,7 +959,7 @@ int multi_update::prepare(List ¬_used_values, thd->count_cuted_fields= CHECK_FIELD_WARN; thd->cuted_fields=0L; - THD_PROC_INFO(thd, "updating main table"); + thd_proc_info(thd, "updating main table"); tables_to_update= get_table_map(fields); @@ -1511,11 +1511,11 @@ err2: bool multi_update::send_eof() { char buff[STRING_BUFFER_USUAL_SIZE]; - THD_PROC_INFO(thd, "updating reference tables"); + thd_proc_info(thd, "updating reference tables"); /* Does updates for the last n - 1 tables, returns 0 if ok */ int local_error = (table_count) ? do_updates(0) : 0; - THD_PROC_INFO(thd, "end"); + thd_proc_info(thd, "end"); /* We must invalidate the query cache before binlog writing and ha_autocommit_... */ diff --git a/sql/sql_view.cc b/sql/sql_view.cc index c03dd1f782e..c570c0e6570 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -588,7 +588,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, DBUG_RETURN(0); err: - THD_PROC_INFO(thd, "end"); + thd_proc_info(thd, "end"); lex->link_first_table_back(view, link_to_local); unit->cleanup(); DBUG_RETURN(res || thd->net.report_error); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 3372cfb3341..20c51360d51 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -928,7 +928,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); union_opt select_derived_init option_type2 %type - ulong_num raid_types merge_insert_types opt_profile_query_arg + ulong_num raid_types merge_insert_types %type ulonglong_num @@ -6678,36 +6678,52 @@ profile_defs: profile_def: CPU_SYM - { Lex->profile_options|= PROFILE_CPU; } + { + Lex->profile_options|= PROFILE_CPU; + } | MEMORY_SYM - { Lex->profile_options|= PROFILE_MEMORY; } + { + Lex->profile_options|= PROFILE_MEMORY; + } | BLOCK_SYM IO_SYM - { Lex->profile_options|= PROFILE_BLOCK_IO; } + { + Lex->profile_options|= PROFILE_BLOCK_IO; + } | CONTEXT_SYM SWITCHES_SYM - { Lex->profile_options|= PROFILE_CONTEXT; } + { + Lex->profile_options|= PROFILE_CONTEXT; + } | PAGE_SYM FAULTS_SYM - { Lex->profile_options|= PROFILE_PAGE_FAULTS; } + { + Lex->profile_options|= PROFILE_PAGE_FAULTS; + } | IPC_SYM - { Lex->profile_options|= PROFILE_IPC; } + { + Lex->profile_options|= PROFILE_IPC; + } | SWAPS_SYM - { Lex->profile_options|= PROFILE_SWAPS; } + { + Lex->profile_options|= PROFILE_SWAPS; + } | SOURCE_SYM - { Lex->profile_options|= PROFILE_SOURCE; } + { + Lex->profile_options|= PROFILE_SOURCE; + } | ALL - { Lex->profile_options|= PROFILE_ALL; } - ; - -opt_profile_query_arg: - /* empty */ - { $$= 0; } - | QUERY_SYM NUM - { $$= atoi($2.str); } + { + Lex->profile_options|= PROFILE_ALL; + } ; opt_profile_args: /* empty */ - | FOR_SYM opt_profile_query_arg - { Lex->profile_query_id = $2; } + { + Lex->profile_query_id= 0; + } + | FOR_SYM QUERY_SYM NUM + { + Lex->profile_query_id= atoi($3.str); + } ; /* Show things */ @@ -7940,7 +7956,7 @@ keyword_sp: | BERKELEY_DB_SYM {} | BINLOG_SYM {} | BIT_SYM {} - | BLOCK_SYM {} + | BLOCK_SYM {} | BOOL_SYM {} | BOOLEAN_SYM {} | BTREE_SYM {} @@ -7957,8 +7973,8 @@ keyword_sp: | COMPRESSED_SYM {} | CONCURRENT {} | CONSISTENT_SYM {} - | CONTEXT_SYM {} - | CPU_SYM {} + | CONTEXT_SYM {} + | CPU_SYM {} | CUBE_SYM {} | DATA_SYM {} | DATETIME {} @@ -7981,7 +7997,7 @@ keyword_sp: | EXPANSION_SYM {} | EXTENDED_SYM {} | FAST_SYM {} - | FAULTS_SYM {} + | FAULTS_SYM {} | FOUND_SYM {} | DISABLE_SYM {} | ENABLE_SYM {} @@ -8006,8 +8022,8 @@ keyword_sp: | ISSUER_SYM {} | INNOBASE_SYM {} | INSERT_METHOD {} - | IO_SYM {} - | IPC_SYM {} + | IO_SYM {} + | IPC_SYM {} | RELAY_THREAD {} | LAST_SYM {} | LEAVES {} @@ -8037,7 +8053,7 @@ keyword_sp: | MAX_UPDATES_PER_HOUR {} | MAX_USER_CONNECTIONS_SYM {} | MEDIUM_SYM {} - | MEMORY_SYM {} + | MEMORY_SYM {} | MERGE_SYM {} | MICROSECOND_SYM {} | MIGRATE_SYM {} @@ -8064,7 +8080,7 @@ keyword_sp: | ONE_SHOT_SYM {} | ONE_SYM {} | PACK_KEYS_SYM {} - | PAGE_SYM {} + | PAGE_SYM {} | PARTIAL {} | PASSWORD {} | PHASE_SYM {} @@ -8074,8 +8090,8 @@ keyword_sp: | PRIVILEGES {} | PROCESS {} | PROCESSLIST_SYM {} - | PROFILE_SYM {} - | PROFILES_SYM {} + | PROFILE_SYM {} + | PROFILES_SYM {} | QUARTER_SYM {} | QUERY_SYM {} | QUICK {} @@ -8109,7 +8125,7 @@ keyword_sp: | SHUTDOWN {} | SNAPSHOT_SYM {} | SOUNDS_SYM {} - | SOURCE_SYM {} + | SOURCE_SYM {} | SQL_CACHE_SYM {} | SQL_BUFFER_RESULT {} | SQL_NO_CACHE_SYM {} @@ -8121,8 +8137,8 @@ keyword_sp: | SUBJECT_SYM {} | SUPER_SYM {} | SUSPEND_SYM {} - | SWAPS_SYM {} - | SWITCHES_SYM {} + | SWAPS_SYM {} + | SWITCHES_SYM {} | TABLES {} | TABLESPACE {} | TEMPORARY {} diff --git a/sql/table.h b/sql/table.h index 70e64439af5..da0f2a48b10 100644 --- a/sql/table.h +++ b/sql/table.h @@ -308,6 +308,7 @@ enum enum_schema_tables SCH_COLUMN_PRIVILEGES, SCH_KEY_COLUMN_USAGE, SCH_OPEN_TABLES, + SCH_PROFILING, SCH_PROCEDURES, SCH_SCHEMATA, SCH_SCHEMA_PRIVILEGES, From cdacff2d95266965656a444adcbbfea241d70c60 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 22 Feb 2007 11:48:56 -0500 Subject: [PATCH 07/99] Enclose profiling in preprocessor conditions. include/config-win.h: Make profiling compiled-in by default on Windows too. --- BitKeeper/etc/collapsed | 2 ++ include/config-win.h | 3 +++ sql/sql_prepare.cc | 2 ++ 3 files changed, 7 insertions(+) diff --git a/BitKeeper/etc/collapsed b/BitKeeper/etc/collapsed index c79a4cf25cc..2b0df86d79c 100644 --- a/BitKeeper/etc/collapsed +++ b/BitKeeper/etc/collapsed @@ -43,3 +43,5 @@ 45db468b-DKE8kUTV42eYMYmk8_g9g 45dd21d1rVPnDfvZTNVHLalcjnbsZw 45ddaf15_Ld7IAEpUUP3FJjJ-oSEFg +45ddc763DodLG1BqH_wRBJXMbCSB5A +45ddc8282KnaNGuijqCTphlXV_eeog diff --git a/include/config-win.h b/include/config-win.h index a9977ec955a..8653c0a63f5 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -205,6 +205,9 @@ typedef uint rf_SetTimer; /* If LOAD DATA LOCAL INFILE should be enabled by default */ #define ENABLED_LOCAL_INFILE 1 +/* If query profiling should be enabled by default */ +#define ENABLED_PROFILING 1 + /* Convert some simple functions to Posix */ #define my_sigset(A,B) signal((A),(B)) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 83ddb9c9212..de08c43658c 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2222,7 +2222,9 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute"))) DBUG_VOID_RETURN; +#ifdef ENABLED_PROFILING thd->profiling.set_query_source(stmt->query, stmt->query_length); +#endif DBUG_PRINT("exec_query", ("%s", stmt->query)); DBUG_PRINT("info",("stmt: %p", stmt)); From f6d9570df16a863579704aeb9aa226c0a5ed9384 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 22 Feb 2007 12:27:15 -0500 Subject: [PATCH 08/99] Add profiling source file to cmake file. --- sql/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 7e26f62b5f7..b686288c4fe 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -73,6 +73,7 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc time.cc tztime.cc uniques.cc unireg.cc ../sql-common/my_user.c sql_locale.cc + sql_profiling.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h ${PROJECT_SOURCE_DIR}/include/mysqld_error.h From fe671b87041e95a1d90a86edfac6807661ac48f7 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 22 Feb 2007 13:17:02 -0500 Subject: [PATCH 09/99] Use correct filename for profiling code. --- sql/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index b686288c4fe..9058f9077d9 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -73,7 +73,7 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc time.cc tztime.cc uniques.cc unireg.cc ../sql-common/my_user.c sql_locale.cc - sql_profiling.cc + sql_profile.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h ${PROJECT_SOURCE_DIR}/include/mysqld_error.h From 633fb481c93ba6dc42d454060880753db149a007 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 22 Feb 2007 16:25:47 -0500 Subject: [PATCH 10/99] Disambiguate method call. (Windows compiler error.) --- sql/sql_profile.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index e9b6ef0b522..86f6854206d 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -453,7 +453,7 @@ bool QUERY_PROFILE::show(uint options) protocol->store(entry->function, strlen(entry->function), system_charset_info); protocol->store(entry->file, strlen(entry->file), system_charset_info); - protocol->store(entry->line); + protocol->store((uint32) entry->line); } else { protocol->store_null(); protocol->store_null(); From 9e2fd8caada234497a4f5c2c28aafeb66fe2b3b2 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 Feb 2007 13:11:36 -0500 Subject: [PATCH 11/99] Some changes suggested Serg, from message <20070223210659.GA24202@janus.mylan> configure.in: Use smarter autoconf help macro. sql/set_var.cc: Make a local variable static. sql/sql_lex.cc: Don't include CPP condition where it saves little time and decreases legibility. sql/sql_parse.cc: Use the name of the query in the error, instead of describing the feature. sql/sql_profile.cc: Update copyright. Make I_S schema table columns uppercase. sql/sql_profile.h: Update copyright. sql/sql_select.cc: Chagne tab indentation to spaces. --- configure.in | 2 +- sql/set_var.cc | 2 +- sql/sql_lex.cc | 2 -- sql/sql_parse.cc | 4 +-- sql/sql_profile.cc | 90 ++++++++++++++++++++-------------------------- sql/sql_profile.h | 3 +- sql/sql_select.cc | 4 +-- 7 files changed, 45 insertions(+), 62 deletions(-) diff --git a/configure.in b/configure.in index 3e0e6c9762b..f81e70f6173 100644 --- a/configure.in +++ b/configure.in @@ -669,7 +669,7 @@ fi # Add query profiler AC_ARG_ENABLE(profiling, - [ --disable-profiling Build a version without query profiling code ], + AS_HELP_STRING([--disable-profiling], [Build a version without query profiling code]), [ ENABLED_PROFILING=$enableval ], [ ENABLED_PROFILING=yes ]) diff --git a/sql/set_var.cc b/sql/set_var.cc index c02561261c0..dad6be06aa2 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -548,7 +548,7 @@ static sys_var_thd_bit sys_unique_checks("unique_checks", 0, #ifdef ENABLED_PROFILING static sys_var_thd_bit sys_profiling("profiling", NULL, set_option_bit, ulonglong(OPTION_PROFILING)); -sys_var_thd_ulong sys_profiling_history_size("profiling_history_size", +static sys_var_thd_ulong sys_profiling_history_size("profiling_history_size", &SV::profiling_history_size); #endif diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 47fe2e8ac0e..8742a9630b6 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -173,9 +173,7 @@ void lex_start(THD *thd, uchar *buf,uint length) lex->proc_list.first= 0; lex->escape_used= FALSE; lex->reset_query_tables_list(FALSE); -#ifdef ENABLED_PROFILING lex->profile_options= PROFILE_NONE; -#endif lex->nest_level=0 ; lex->allow_sum_func= 0; lex->in_sum_func= NULL; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 449d57c2b2d..370fa4a19c5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2707,7 +2707,7 @@ mysql_execute_command(THD *thd) if (res) goto error; #else - my_error(ER_FEATURE_DISABLED, MYF(0), "query profiling", "enable-profiling"); + my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROFILES", "enable-profiling"); goto error; #endif break; @@ -2724,7 +2724,7 @@ mysql_execute_command(THD *thd) if (res) goto error; #else - my_error(ER_FEATURE_DISABLED, MYF(0), "query profiling", "enable-profiling"); + my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROFILE", "enable-profiling"); goto error; #endif break; diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 86f6854206d..1d38b313bd3 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -1,9 +1,8 @@ -/* Copyright (C) 2005 MySQL AB +/* Copyright (C) 2007 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -12,7 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mysql_priv.h" @@ -42,24 +41,24 @@ int fill_query_profile_statistics_info(THD *thd, struct st_table_list *tables, ST_FIELD_INFO query_profile_statistics_info[]= { /* name, length, type, value, maybe_null, old_name */ - {"Query_id", 20, MYSQL_TYPE_LONG, 0, false, NULL}, - {"Seq", 20, MYSQL_TYPE_LONG, 0, false, NULL}, - {"State", 30, MYSQL_TYPE_STRING, 0, false, NULL}, - {"Duration", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, false, NULL}, - {"CPU_user", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, - {"CPU_system", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, - {"Context_voluntary", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Context_involuntary", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Block_ops_in", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Block_ops_out", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Messages_sent", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Messages_received", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Page_faults_major", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Page_faults_minor", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Swaps", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"Source_function", 30, MYSQL_TYPE_STRING, 0, true, NULL}, - {"Source_file", 20, MYSQL_TYPE_STRING, 0, true, NULL}, - {"Source_line", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"QUERY_ID", 20, MYSQL_TYPE_LONG, 0, false, NULL}, + {"SEQ", 20, MYSQL_TYPE_LONG, 0, false, NULL}, + {"STATE", 30, MYSQL_TYPE_STRING, 0, false, NULL}, + {"DURATION", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, false, NULL}, + {"CPU_USER", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, + {"CPU_SYSTEM", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, + {"CONTEXT_VOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"CONTEXT_INVOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"BLOCK_OPS_IN", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"BLOCK_OPS_OUT", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"MESSAGES_SENT", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"MESSAGES_RECEIVED", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"PAGE_FAULTS_MAJOR", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"PAGE_FAULTS_MINOR", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"SWAPS", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"SOURCE_FUNCTION", 30, MYSQL_TYPE_STRING, 0, true, NULL}, + {"SOURCE_FILE", 20, MYSQL_TYPE_STRING, 0, true, NULL}, + {"SOURCE_LINE", 20, MYSQL_TYPE_LONG, 0, true, NULL}, {NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL} }; @@ -107,20 +106,9 @@ void PROFILE_ENTRY::set_status(const char *status_arg, const char *function_arg, Compute all the space we'll need to allocate one block for everything we'll need, instead of N mallocs. */ - if (status_arg != NULL) - sizes[0]= strlen(status_arg) + 1; - else - sizes[0]= 0; - - if (function_arg != NULL) - sizes[1]= strlen(function_arg) + 1; - else - sizes[1]= 0; - - if (file_arg != NULL) - sizes[2]= strlen(file_arg) + 1; - else - sizes[2]= 0; + sizes[0]= (status_arg == NULL) ? 0 : strlen(status_arg) + 1; + sizes[1]= (function_arg == NULL) ? 0 : strlen(function_arg) + 1; + sizes[2]= (file_arg == NULL) ? 0 : strlen(file_arg) + 1; allocated_status_memory= (char *) my_malloc(sizes[0] + sizes[1] + sizes[2], MYF(0)); DBUG_ASSERT(allocated_status_memory != NULL); @@ -237,7 +225,6 @@ void QUERY_PROFILE::status(const char *status_arg, */ saved_mem_root= thd->mem_root; thd->mem_root= &profiling->mem_root; - //thd->mem_root= NULL; if (function_arg && file_arg) { @@ -375,7 +362,6 @@ bool QUERY_PROFILE::show(uint options) protocol->store(entry->status, strlen(entry->status), system_charset_info); protocol->store((double)(entry->time_usecs - last_time)/(1000.0*1000), (uint32) TIME_FLOAT_DIGITS-1, &elapsed); - //protocol->store((double)(entry->time - last_time)/(1000*1000*10)); if (options & PROFILE_CPU) { @@ -739,54 +725,54 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item #ifdef HAVE_GETRUSAGE table->field[4]->store((double)RUSAGE_DIFF_USEC(entry->rusage.ru_utime, last_rusage->ru_utime)/(1000.0*1000)); - table->field[4]->null_ptr= NULL; + table->field[4]->set_notnull(); table->field[5]->store((double)RUSAGE_DIFF_USEC(entry->rusage.ru_stime, last_rusage->ru_stime)/(1000.0*1000)); - table->field[5]->null_ptr= NULL; + table->field[5]->set_notnull(); #else /* TODO: Add CPU-usage info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE table->field[6]->store((uint32)(entry->rusage.ru_nvcsw - last_rusage->ru_nvcsw)); - table->field[6]->null_ptr= NULL; + table->field[6]->set_notnull(); table->field[7]->store((uint32)(entry->rusage.ru_nivcsw - last_rusage->ru_nivcsw)); - table->field[7]->null_ptr= NULL; + table->field[7]->set_notnull(); #else /* TODO: Add context switch info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE table->field[8]->store((uint32)(entry->rusage.ru_inblock - last_rusage->ru_inblock)); - table->field[8]->null_ptr= NULL; + table->field[8]->set_notnull(); table->field[9]->store((uint32)(entry->rusage.ru_oublock - last_rusage->ru_oublock)); - table->field[9]->null_ptr= NULL; + table->field[9]->set_notnull(); #else /* TODO: Add block IO info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE table->field[10]->store((uint32)(entry->rusage.ru_msgsnd - last_rusage->ru_msgsnd), true); - table->field[10]->null_ptr= NULL; + table->field[10]->set_notnull(); table->field[11]->store((uint32)(entry->rusage.ru_msgrcv - last_rusage->ru_msgrcv), true); - table->field[11]->null_ptr= NULL; + table->field[11]->set_notnull(); #else /* TODO: Add message info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE table->field[12]->store((uint32)(entry->rusage.ru_majflt - last_rusage->ru_majflt), true); - table->field[12]->null_ptr= NULL; + table->field[12]->set_notnull(); table->field[13]->store((uint32)(entry->rusage.ru_minflt - last_rusage->ru_minflt), true); - table->field[13]->null_ptr= NULL; + table->field[13]->set_notnull(); #else /* TODO: Add page fault info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE table->field[14]->store((uint32)(entry->rusage.ru_nswap - last_rusage->ru_nswap), true); - table->field[14]->null_ptr= NULL; + table->field[14]->set_notnull(); #else /* TODO: Add swap info for non-BSD systems */ #endif @@ -795,11 +781,11 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item { table->field[15]->store(entry->function, strlen(entry->function), system_charset_info); - table->field[15]->null_ptr= NULL; + table->field[15]->set_notnull(); table->field[16]->store(entry->file, strlen(entry->file), system_charset_info); - table->field[16]->null_ptr= NULL; + table->field[16]->set_notnull(); table->field[17]->store(entry->line, true); - table->field[17]->null_ptr= NULL; + table->field[17]->set_notnull(); } if (schema_table_store_record(thd, table)) diff --git a/sql/sql_profile.h b/sql/sql_profile.h index 006760cab79..944856a9f80 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c9e334b7784..1ee84ca9e3d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1234,8 +1234,8 @@ JOIN::optimize() if (!group_list && ! exec_tmp_table1->distinct && order && simple_order) { - thd_proc_info(thd, "Sorting for order"); - if (create_sort_index(thd, this, order, + thd_proc_info(thd, "Sorting for order"); + if (create_sort_index(thd, this, order, HA_POS_ERROR, HA_POS_ERROR)) { DBUG_RETURN(1); From 89fd0e9f9e2fa26a3e46c5b48f278d395feba245 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 27 Feb 2007 11:30:03 -0500 Subject: [PATCH 12/99] Updated column names of I_S table to conform to other I_S uppercase scheme. --- mysql-test/r/information_schema.result | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 742d35d4ce7..d89514c6060 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1193,7 +1193,7 @@ COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME COLUMNS TABLE_SCHEMA COLUMN_PRIVILEGES TABLE_SCHEMA KEY_COLUMN_USAGE CONSTRAINT_SCHEMA -PROFILING Query_id +PROFILING QUERY_ID ROUTINES ROUTINE_SCHEMA SCHEMATA SCHEMA_NAME SCHEMA_PRIVILEGES TABLE_SCHEMA @@ -1225,7 +1225,7 @@ COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME COLUMNS TABLE_SCHEMA COLUMN_PRIVILEGES TABLE_SCHEMA KEY_COLUMN_USAGE CONSTRAINT_SCHEMA -PROFILING Query_id +PROFILING QUERY_ID ROUTINES ROUTINE_SCHEMA SCHEMATA SCHEMA_NAME SCHEMA_PRIVILEGES TABLE_SCHEMA From 4cb4899fa203a2c483188251e70e67d3ef00f682 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 27 Feb 2007 20:04:58 -0500 Subject: [PATCH 13/99] Update to I_S result that now contains PROFILING entry. --- mysql-test/r/information_schema.result | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 0371652b081..b01ed152e33 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1308,6 +1308,7 @@ COLLATION_CHARACTER_SET_APPLICABILITY information_schema.COLLATION_CHARACTER_SET COLUMNS information_schema.COLUMNS 1 COLUMN_PRIVILEGES information_schema.COLUMN_PRIVILEGES 1 KEY_COLUMN_USAGE information_schema.KEY_COLUMN_USAGE 1 +PROFILING information_schema.PROFILING 1 ROUTINES information_schema.ROUTINES 1 SCHEMATA information_schema.SCHEMATA 1 SCHEMA_PRIVILEGES information_schema.SCHEMA_PRIVILEGES 1 From 7a916c2f03a0d09845d9346ab3194375e09c4a6a Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 1 Mar 2007 09:38:09 +0100 Subject: [PATCH 14/99] mysqld.cc: fix profiling_history_size type sql/mysqld.cc: fix profiling_history_size type --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 49546c2fb4b..3bf5aa42472 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5277,7 +5277,7 @@ Disable with --skip-ndbcluster (will save memory).", {"profiling_history_size", OPT_PROFILING, "Limit of query profiling memory", (gptr*) &global_system_variables.profiling_history_size, (gptr*) &max_system_variables.profiling_history_size, - 0, GET_UINT, REQUIRED_ARG, 15, 0, 100, 0, 0, 0}, + 0, GET_ULONG, REQUIRED_ARG, 15, 0, 100, 0, 0, 0}, #endif {"relay-log", OPT_RELAY_LOG, "The location and name to use for relay logs.", From 014cfd7e31db7a36243bb1c8bf34ecf502bcc950 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 1 Mar 2007 10:45:55 +0100 Subject: [PATCH 15/99] File.cpp: fileno is a macro on some platforms ndb/src/common/util/File.cpp: fileno is a macro on some platforms --- ndb/src/common/util/File.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ndb/src/common/util/File.cpp b/ndb/src/common/util/File.cpp index 23bf3415df9..b26ed26b3bd 100644 --- a/ndb/src/common/util/File.cpp +++ b/ndb/src/common/util/File.cpp @@ -50,7 +50,7 @@ File_class::size(FILE* f) MY_STAT s; // Note that my_fstat behaves *differently* than my_stat. ARGGGHH! - if(my_fstat(::fileno(f), &s, MYF(0))) + if(my_fstat(fileno(f), &s, MYF(0))) return 0; return s.st_size; From 0723eb457eb05ae6d7eeef1907ceef0d52dd8f42 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 1 Mar 2007 21:56:51 +0100 Subject: [PATCH 16/99] add missing file to vs project VC++Files/sql/mysqld.vcproj: add sql_profile.cpp to mysqld project --- VC++Files/sql/mysqld.vcproj | 75 +++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/VC++Files/sql/mysqld.vcproj b/VC++Files/sql/mysqld.vcproj index e18a6364c8b..cb0efb10b19 100644 --- a/VC++Files/sql/mysqld.vcproj +++ b/VC++Files/sql/mysqld.vcproj @@ -4744,6 +4744,81 @@ PreprocessorDefinitions=""/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Date: Fri, 2 Mar 2007 09:14:33 -0500 Subject: [PATCH 17/99] Patch to release clone. Fixes two post-pushbuild discovered failures. Expand float size to avoid assert()ion failures. "_db_func_" isn't a known linked object on some platforms, possibly because it is occasionaly shadowed by DBUG variables. Avoid that confusion. sql/sql_profile.cc: Expand float size to avoid assert()ion failures. "_db_func_" isn't a known linked object on some platforms, possibly because it is occasionaly shadowed by DBUG variables. Avoid that confusion. sql/sql_profile.h: "_db_func_" isn't a known linked object on some platforms, possibly because it is occasionaly shadowed by DBUG variables. Avoid that confusion. --- sql/sql_profile.cc | 4 ++-- sql/sql_profile.h | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 1d38b313bd3..028363f167e 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -17,13 +17,13 @@ #include "mysql_priv.h" #include "my_sys.h" -#define TIME_FLOAT_DIGITS 7 +#define TIME_FLOAT_DIGITS 9 #define MAX_QUERY_LENGTH 300 bool schema_table_store_record(THD *thd, TABLE *table); /* Reserved for systems that can't record the function name in source. */ -const char *_db_func_= ""; +const char * const _unknown_func_ = ""; /** Connects Information_Schema and Profiling. diff --git a/sql/sql_profile.h b/sql/sql_profile.h index 944856a9f80..0b387f2a7cb 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -20,21 +20,21 @@ # if __GNUC__ >= 2 # define __func__ __FUNCTION__ # else -# define __func__ _db_func_ -extern const char *_db_func_; +# define __func__ _unknown_func_ +extern const char * const _unknown_func_; # endif #elif defined(_MSC_VER) # if _MSC_VER < 1300 -# define __func__ _db_func_ -extern const char *_db_func_; +# define __func__ _unknown_func_ +extern const char * const _unknown_func_; # else # define __func__ __FUNCTION__ # endif #elif defined(__BORLANDC__) # define __func__ __FUNC__ #else -# define __func__ _db_func_ -extern const char *_db_func_; +# define __func__ _unknown_func_ +extern const char * const _unknown_func_; #endif extern ST_FIELD_INFO query_profile_statistics_info[]; From c161bf3e572da50c0fcc50fe385bfa6c69506120 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Mar 2007 16:10:42 +0100 Subject: [PATCH 18/99] add ad support-files/mysql.spec.sh: add ad at %post --- support-files/mysql.spec.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index f60664bdefd..39866872514 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -539,6 +539,11 @@ chmod -R og-rw $mysql_datadir/mysql # Allow safe_mysqld to start mysqld and print a message before we exit sleep 2 +echo "Thank you for installing the MySQL Community Server! For Production +systems, we recommend MySQL Enterprise, which contains enterprise-ready +software, intelligent advisory services, and full production support with +scheduled service packs and more. Visit www.mysql.com/enterprise for more +information." %post ndb-storage mysql_clusterdir=/var/lib/mysql-cluster From 6246edf728c71a1d6dfd89e85e338c733a8a4096 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Mar 2007 20:25:57 +0100 Subject: [PATCH 19/99] adjust version string in mysql-5.0-community commit trigger BitKeeper/triggers/post-commit: adjust version string in trigger --- BitKeeper/triggers/post-commit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BitKeeper/triggers/post-commit b/BitKeeper/triggers/post-commit index 8051cf98b7a..ce6d60fb933 100755 --- a/BitKeeper/triggers/post-commit +++ b/BitKeeper/triggers/post-commit @@ -5,7 +5,7 @@ FROM=$USER@mysql.com COMMITS=commits@lists.mysql.com DOCS=docs-commit@mysql.com LIMIT=10000 -VERSION="5.0" +VERSION="5.0-community" BKROOT=`bk root` if [ -x /usr/sbin/sendmail ]; then From 8c302fb15718e1745f5d3bcfb080b1d23ccdbb8b Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 13:26:19 -0400 Subject: [PATCH 20/99] Listing all columns of a particular type tells us nothing at all. The test fails, and it shouldn't. mysql-test/r/information_schema.result: The query to generate this list is pretty bogus in any case. Listing all columns of a particular type tells us nothing at all. --- mysql-test/r/information_schema.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index b01ed152e33..97bb5e4e446 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1096,7 +1096,7 @@ table_schema='information_schema' and group by column_type order by num; column_type group_concat(table_schema, '.', table_name) num varchar(20) information_schema.COLUMNS,information_schema.PROFILING 2 -varchar(7) information_schema.PROFILING,information_schema.PROFILING,information_schema.PROFILING,information_schema.ROUTINES,information_schema.VIEWS 5 +varchar(7) information_schema.ROUTINES,information_schema.VIEWS 2 create table t1(f1 char(1) not null, f2 char(9) not null) default character set utf8; select CHARACTER_MAXIMUM_LENGTH, CHARACTER_OCTET_LENGTH from From 892c54a05812ece5d169b9726fea19598dafeea6 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 14:05:00 -0400 Subject: [PATCH 21/99] The test suite erroneously removes backslashes. --- mysql-test/r/profiling.result | 2 +- mysql-test/t/profiling.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/profiling.result b/mysql-test/r/profiling.result index f8aa060eee4..a1e994220b9 100644 --- a/mysql-test/r/profiling.result +++ b/mysql-test/r/profiling.result @@ -198,7 +198,7 @@ Query_ID Duration Query 38 # insert into t2 values (1), (2), (3) 39 # insert into t3 values (1), (2), (3) 40 # select * from t1 -This ^^ should end in "select * from t1;\" +This ^^ should end in "select * from t1;" delete from t1; insert into t1 values (1), (2), (3); insert into t1 values (1), (2), (3); diff --git a/mysql-test/t/profiling.test b/mysql-test/t/profiling.test index ebde8eeffd8..fd7562f6f16 100644 --- a/mysql-test/t/profiling.test +++ b/mysql-test/t/profiling.test @@ -113,7 +113,7 @@ show profiles; select * from t1; --replace_column 2 # show profiles; ---echo This ^^ should end in \"select * from t1;\" +--echo This ^^ should end in "select * from t1;" delete from t1; insert into t1 values (1), (2), (3); From 992fc6b22c5718fde62eb0c93c296eaec45228ac Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 14:08:09 -0400 Subject: [PATCH 22/99] Backport of Igor's patch for Bug#27362, March 22 2007. Fixed bug #27362: crash at evaluation of IN predicate when one of its argument happened to be a decimal expression returning the NULL value. The crash was due to the fact the function in_decimal::set did not take into account that val_decimal() could return 0 if the decimal expression had been evaluated to NULL. mysql-test/r/func_in.result: Added a test case for bug #27362. mysql-test/t/func_in.test: Added a test case for bug #27362. sql/item_cmpfunc.cc: Fixed bug #27362: crash at evaluation of IN predicate when one of its argument happened to be a decimal expression returning the NULL value. The crash was due to the fact the function in_decimal::set did not take into account that val_decimal() could return 0 if the decimal expression had been evaluated to NULL. --- mysql-test/r/func_in.result | 5 +++++ mysql-test/t/func_in.test | 11 +++++++++++ sql/item_cmpfunc.cc | 3 ++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index fad9a7157e1..87855091699 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -470,4 +470,9 @@ a Warnings: Warning 1292 Incorrect date value: '19772-07-29' for column 'a' at row 1 DROP TABLE t1,t2,t3,t4; +CREATE TABLE t1 (id int not null); +INSERT INTO t1 VALUES (1),(2); +SELECT id FROM t1 WHERE id IN(4564, (SELECT IF(1=0,1,1/0)) ); +id +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test index f9749662ec1..77592d015eb 100644 --- a/mysql-test/t/func_in.test +++ b/mysql-test/t/func_in.test @@ -360,4 +360,15 @@ SELECT * FROM t4 WHERE a IN ('1972-02-06','19772-07-29'); DROP TABLE t1,t2,t3,t4; +# +# BUG#27362: IN with a decimal expression that may return NULL +# + +CREATE TABLE t1 (id int not null); +INSERT INTO t1 VALUES (1),(2); + +SELECT id FROM t1 WHERE id IN(4564, (SELECT IF(1=0,1,1/0)) ); + +DROP TABLE t1; + --echo End of 5.0 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 77d08f79033..d4534abdbcf 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2423,7 +2423,8 @@ void in_decimal::set(uint pos, Item *item) dec->len= DECIMAL_BUFF_LENGTH; dec->fix_buffer_pointer(); my_decimal *res= item->val_decimal(dec); - if (res != dec) + /* if item->val_decimal() is evaluated to NULL then res == 0 */ + if (!item->null_value && res != dec) my_decimal2decimal(res, dec); } From 698d98bea0522c913ba67159673b8290805b1f33 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 17:59:52 -0400 Subject: [PATCH 23/99] Backport: B-g#24795: SHOW PROFILE implementation Don't use memory roots to store profiling information, because memory roots make freeing the data a no-op, and thus long-running processes with profiling turned on the whole time could eventually use all available memory. Instead, use regular heap allocation and deallocation calls to manage profiling data. Replace the leaky List usage with a similar- behaving structure named "Queue". sql/sql_profile.cc: Don't use C++ iterators on our simple Queue implementation. They're not implemented and we don't really need them. Rip out idea of swapping out the thd's mem_root. sql/sql_profile.h: Rip out idea of needing a mem_root. Implement a Queue that looks and behaves very similarly to memroot- using List. --- sql/sql_profile.cc | 111 ++++++++++++++++----------------------------- sql/sql_profile.h | 111 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 147 insertions(+), 75 deletions(-) diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 028363f167e..8ed3df9cd2e 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -175,11 +175,8 @@ void QUERY_PROFILE::set_query_source(char *query_source_arg, QUERY_PROFILE::~QUERY_PROFILE() { - PROFILE_ENTRY *entry; - List_iterator it(entries); - while ((entry= it++) != NULL) - delete entry; - entries.empty(); + while (! entries.is_empty()) + delete entries.pop(); if (query_source != NULL) my_free(query_source, MYF(0)); @@ -191,7 +188,6 @@ void QUERY_PROFILE::status(const char *status_arg, { THD *thd= profiling->thd; PROFILE_ENTRY *prof; - MEM_ROOT *saved_mem_root; DBUG_ENTER("QUERY_PROFILE::status"); /* Blank status. Just return, and thd->proc_info will be set blank later. */ @@ -210,22 +206,6 @@ void QUERY_PROFILE::status(const char *status_arg, if (unlikely((thd->query_id != server_query_id) && !thd->spcont)) reset(); - /* - In order to keep the profile information between queries (i.e. from - SELECT to the following SHOW PROFILE command) the following code is - necessary to keep the profile from getting freed automatically when - mysqld cleans up after the query. - - The "entries" list allocates is memory from the current thd's mem_root. - We substitute our mem_root temporarily so that we intercept those - allocations into our own mem_root. - - The thd->mem_root structure is freed after each query is completed, - so temporarily override it. - */ - saved_mem_root= thd->mem_root; - thd->mem_root= &profiling->mem_root; - if (function_arg && file_arg) { if ((profile_end= prof= new PROFILE_ENTRY(this, status_arg, function_arg, @@ -238,9 +218,6 @@ void QUERY_PROFILE::status(const char *status_arg, entries.push_back(prof); } - /* Restore mem_root */ - thd->mem_root= saved_mem_root; - DBUG_VOID_RETURN; } @@ -252,11 +229,8 @@ void QUERY_PROFILE::reset() server_query_id= profiling->thd->query_id; /* despite name, is global */ profile_start.collect(); - PROFILE_ENTRY *entry; - List_iterator it(entries); - while ((entry= it++) != NULL) - delete entry; - entries.empty(); + while (! entries.is_empty()) + delete entries.pop(); } DBUG_VOID_RETURN; } @@ -344,10 +318,14 @@ bool QUERY_PROFILE::show(uint options) struct rusage *last_rusage= &(profile_start.rusage); #endif - List_iterator it(entries); PROFILE_ENTRY *entry; - while ((entry= it++) != NULL) + void *iterator; + for (iterator= entries.new_iterator(); + iterator != NULL; + iterator= entries.iterator_next(iterator)) { + entry= entries.iterator_value(iterator); + #ifdef HAVE_GETRUSAGE struct rusage *rusage= &(entry->rusage); #endif @@ -463,24 +441,15 @@ bool QUERY_PROFILE::show(uint options) PROFILING::PROFILING() :profile_id_counter(0), keeping(1), current(NULL), last(NULL) { - init_sql_alloc(&mem_root, - PROFILE_ALLOC_BLOCK_SIZE, - PROFILE_ALLOC_PREALLOC_SIZE); } PROFILING::~PROFILING() { - QUERY_PROFILE *prof; - - List_iterator it(history); - while ((prof= it++) != NULL) - delete prof; - history.empty(); + while (! history.is_empty()) + delete history.pop(); if (current != NULL) delete current; - - free_root(&mem_root, MYF(0)); } void PROFILING::status_change(const char *status_arg, @@ -505,7 +474,6 @@ void PROFILING::status_change(const char *status_arg, void PROFILING::store() { - MEM_ROOT *saved_mem_root; DBUG_ENTER("PROFILING::store"); /* Already stored */ @@ -517,22 +485,8 @@ void PROFILING::store() } while (history.elements > thd->variables.profiling_history_size) - { - QUERY_PROFILE *tmp= history.pop(); - delete tmp; - } + delete history.pop(); - /* - Switch out memory roots so that we're sure that we keep what we need - - The "history" list implementation allocates its memory in the current - thd's mem_root. We substitute our mem_root temporarily so that we - intercept those allocations into our own mem_root. - */ - - saved_mem_root= thd->mem_root; - thd->mem_root= &mem_root; - if (current != NULL) { if (keeping && @@ -556,9 +510,6 @@ void PROFILING::store() DBUG_ASSERT(current == NULL); current= new QUERY_PROFILE(this, thd->query, thd->query_length); - /* Restore memory root */ - thd->mem_root= saved_mem_root; - DBUG_VOID_RETURN; } @@ -598,9 +549,13 @@ bool PROFILING::show_profiles() unit->set_limit(sel); - List_iterator it(history); - while ((prof= it++) != NULL) + void *iterator; + for (iterator= history.new_iterator(); + iterator != NULL; + iterator= history.iterator_next(iterator)) { + prof= history.iterator_value(iterator); + String elapsed; PROFILE_ENTRY *ps= &prof->profile_start; @@ -651,9 +606,13 @@ bool PROFILING::show(uint options, uint profiling_query_id) DBUG_ENTER("PROFILING::show"); QUERY_PROFILE *prof; - List_iterator it(history); - while ((prof= it++) != NULL) + void *iterator; + for (iterator= history.new_iterator(); + iterator != NULL; + iterator= history.iterator_next(iterator)) { + prof= history.iterator_value(iterator); + if(prof->profiling_query_id == profiling_query_id) DBUG_RETURN(prof->show(options)); } @@ -681,11 +640,15 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item TABLE *table= tables->table; ulonglong row_number= 0; - List_iterator query_it(history); QUERY_PROFILE *query; /* Go through each query in this thread's stored history... */ - while ((query= query_it++) != NULL) + void *history_iterator; + for (history_iterator= history.new_iterator(); + history_iterator != NULL; + history_iterator= history.iterator_next(history_iterator)) { + query= history.iterator_value(history_iterator); + PROFILE_ENTRY *ps= &(query->profile_start); double last_time= ps->time_usecs; #ifdef HAVE_GETRUSAGE @@ -699,16 +662,20 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item */ ulonglong seq; - List_iterator step_it(query->entries); + void *entry_iterator; PROFILE_ENTRY *entry; /* ...and for each query, go through all its state-change steps. */ - for (seq= 0, entry= step_it++; - entry != NULL; + for (seq= 0, entry_iterator= query->entries.new_iterator(); + entry_iterator != NULL; + entry_iterator= query->entries.iterator_next(entry_iterator), #ifdef HAVE_GETRUSAGE last_rusage= &(entry->rusage), #endif - seq++, last_time= entry->time_usecs, entry= step_it++, row_number++) + seq++, last_time= entry->time_usecs, row_number++) { + entry= query->entries.iterator_value(entry_iterator); + + /* Set default values for this row. */ restore_record(table, s->default_values); diff --git a/sql/sql_profile.h b/sql/sql_profile.h index 0b387f2a7cb..7913d037551 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -83,6 +83,112 @@ class QUERY_PROFILE; class PROFILING; +/** + Implements a persistent FIFO using server List method names. Not + thread-safe. Intended to be used on thread-local data only. +*/ +template class Queue +{ +private: + + struct queue_item + { + T *payload; + struct queue_item *next, *previous; + }; + + struct queue_item *first, *last; + +public: + Queue() + { + elements= 0; + first= last= NULL; + } + + void empty() + { + struct queue_item *i, *after_i; + for (i= first; i != NULL; i= after_i) + { + after_i= i->next; + my_free((char *) i, MYF(0)); + } + elements= 0; + } + + ulong elements; /* The count of items in the Queue */ + + void push_back(T *payload) + { + struct queue_item *new_item; + + new_item= (struct queue_item *) my_malloc(sizeof(struct queue_item), MYF(0)); + + new_item->payload= payload; + + if (first == NULL) + first= new_item; + if (last != NULL) + { + DBUG_ASSERT(last->next == NULL); + last->next= new_item; + } + new_item->previous= last; + new_item->next= NULL; + last= new_item; + + elements++; + } + + T *pop() + { + struct queue_item *old_item= first; + T *ret= NULL; + + if (first == NULL) + { + DBUG_PRINT("warning", ("tried to pop nonexistent item from Queue")); + return NULL; + } + + ret= old_item->payload; + if (first->next != NULL) + first->next->previous= NULL; + else + last= NULL; + first= first->next; + + my_free((char *)old_item, MYF(0)); + elements--; + + return ret; + } + + bool is_empty() + { + DBUG_ASSERT(((elements > 0) && (first != NULL)) || ((elements == 0) || (first == NULL))); + return (elements == 0); + } + + void *new_iterator() + { + return first; + } + + void *iterator_next(void *current) + { + return ((struct queue_item *) current)->next; + } + + T *iterator_value(void *current) + { + return ((struct queue_item *) current)->payload; + } + +}; + + /** A single entry in a single profile. */ @@ -135,7 +241,7 @@ private: char *query_source; PROFILE_ENTRY profile_start; PROFILE_ENTRY *profile_end; - List entries; + Queue entries; QUERY_PROFILE(PROFILING *profiling_arg, char *query_source_arg, uint query_length_arg); @@ -169,13 +275,12 @@ private: Not the system query_id, but a counter unique to profiling. */ query_id_t profile_id_counter; - MEM_ROOT mem_root; THD *thd; bool keeping; QUERY_PROFILE *current; QUERY_PROFILE *last; - List history; + Queue history; query_id_t next_profile_id() { return(profile_id_counter++); } From 34a102d909f6bc0e0676e8bb6ff09da691dcbcb6 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 18:12:31 -0400 Subject: [PATCH 24/99] Backport: Patch contributed by Jocelyn Fournier. CLA received 2007-02-27. B-g#25347: mysqlcheck -A -r doesn't repair table marked as crashed mysqlcheck tests nullness of the engine type to know whether the "table" is a view or not. That also falsely catches tables that are severly damaged. Instead, use SHOW FULL TABLES to test whether a "table" is a view or not. (Don't add new function. Instead, get original data a smarter way.) Make it safe for use against databases before when views appeared. client/mysqlcheck.c: Use SHOW FULL TABLES to test better whether a name in the table list is one of a view. Checking that the engine is NULL is insufficient. Implemented suggestion from jimw that involved removing most of original patch and getting data a better way mysql-test/r/mysqlcheck.result: Verify that tables that have NULL/unreadable engine types are processed and not interpreted as views. mysql-test/t/mysqlcheck.test: Verify that tables that have NULL/unreadable engine types are processed and not interpreted as views. --- client/mysqlcheck.c | 27 +++++++++++++++------------ mysql-test/r/mysqlcheck.result | 10 ++++++++++ mysql-test/t/mysqlcheck.test | 16 ++++++++++++++++ 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index b69e9201a28..2c23a0bdd14 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -453,14 +453,17 @@ static int process_all_tables_in_db(char *database) { MYSQL_RES *res; MYSQL_ROW row; + uint num_columns; LINT_INIT(res); if (use_db(database)) return 1; - if (mysql_query(sock, "SHOW TABLE STATUS") || + if (mysql_query(sock, "SHOW /*!50002 FULL*/ TABLES") || !((res= mysql_store_result(sock)))) return 1; + num_columns= mysql_num_fields(res); + if (opt_all_in_1) { /* @@ -483,12 +486,11 @@ static int process_all_tables_in_db(char *database) } for (end = tables + 1; (row = mysql_fetch_row(res)) ;) { - /* Skip tables with an engine of NULL (probably a view). */ - if (row[1]) - { - end= fix_table_name(end, row[0]); - *end++= ','; - } + if ((num_columns == 2) && (strcmp(row[1], "VIEW") == 0)) + continue; + + end= fix_table_name(end, row[0]); + *end++= ','; } *--end = 0; if (tot_length) @@ -498,11 +500,12 @@ static int process_all_tables_in_db(char *database) else { while ((row = mysql_fetch_row(res))) - /* Skip tables with an engine of NULL (probably a view). */ - if (row[1]) - { - handle_request_for_tables(row[0], strlen(row[0])); - } + { + if ((num_columns == 2) && (strcmp(row[1], "VIEW") == 0)) + continue; + + handle_request_for_tables(row[0], strlen(row[0])); + } } mysql_free_result(res); return 0; diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result index b2820df8f4c..81a30267e04 100644 --- a/mysql-test/r/mysqlcheck.result +++ b/mysql-test/r/mysqlcheck.result @@ -41,4 +41,14 @@ test.t1 OK test.t1 OK drop view v1; drop table t1; +create database d_bug25347; +use d_bug25347; +create table t_bug25347 (a int); +create view v_bug25347 as select * from t_bug25347; +removing and creating +d_bug25347.t_bug25347 OK +drop view v_bug25347; +drop table t_bug25347; +drop database d_bug25347; +use test; End of 5.0 tests diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test index f4e18d4004f..eb732a05909 100644 --- a/mysql-test/t/mysqlcheck.test +++ b/mysql-test/t/mysqlcheck.test @@ -31,4 +31,20 @@ create view v1 as select * from t1; drop view v1; drop table t1; +# +# Bug#25347: mysqlcheck -A -r doesn't repair table marked as crashed +# +create database d_bug25347; +use d_bug25347; +create table t_bug25347 (a int); +create view v_bug25347 as select * from t_bug25347; +--echo removing and creating +--exec rm $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI; +--exec touch $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI; +--exec $MYSQL_CHECK --repair --databases d_bug25347 +drop view v_bug25347; +drop table t_bug25347; +drop database d_bug25347; +use test; + --echo End of 5.0 tests From 4eb0a55340353fa0545645bf4293f6e4dd92109e Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 19:45:28 -0400 Subject: [PATCH 25/99] Backport: B-g#27060: SQL Profile utility may not be reporting right duration \ for each step Whenever the profiler is reset at the beginning of a query, there's a "hidden" profiling entry that represents that point in time. It has no status description, as those are set by state changes and no such point has yet been encountered. That profiling entry is not in the list of entries generated when we change states. The profiling code had the problem that each step of printing profiling data subtracted the previous "step"'s data, but gave the label to that data of the current step, which is wrong. The label/ state refers to the period beginning with that profiling data, not ending with it. Now, give a label to the first profiling pseudo-entry, so that we have a name to assign to the period that ends with the first state change. Now also use the state name of the previous step in showing the delta values that end with this step. sql/sql_profile.cc: Store a status of "initializing" whenever we construct the first profile entry -- the one that gets reset whenever we're starting a new query, before the server sets a real status. Additionally, associate the previous status with the time period that ends with the current profile entry's stats. Since we need yet another piece of info from the previous profiling entry, take out the piecemeal ways we currently do it and make a general pointer to the whole thing. --- sql/sql_profile.cc | 107 ++++++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 46 deletions(-) diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 8ed3df9cd2e..4ee8d1ba9c8 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -72,6 +72,9 @@ PROFILE_ENTRY::PROFILE_ENTRY() time_usecs(0.0), allocated_status_memory(NULL) { collect(); + + /* The beginning of the query, before any state is set. */ + set_status("(initialization)", NULL, NULL, 0); } PROFILE_ENTRY::PROFILE_ENTRY(QUERY_PROFILE *profile_arg, const char *status_arg) @@ -313,10 +316,7 @@ bool QUERY_PROFILE::show(uint options) SELECT_LEX_UNIT *unit= &thd->lex->unit; ha_rows idx= 0; unit->set_limit(sel); - double last_time= profile_start.time_usecs; -#ifdef HAVE_GETRUSAGE - struct rusage *last_rusage= &(profile_start.rusage); -#endif + PROFILE_ENTRY *previous= &profile_start; PROFILE_ENTRY *entry; void *iterator; @@ -337,8 +337,18 @@ bool QUERY_PROFILE::show(uint options) break; protocol->prepare_for_resend(); - protocol->store(entry->status, strlen(entry->status), system_charset_info); - protocol->store((double)(entry->time_usecs - last_time)/(1000.0*1000), + + /* + This entry, n, has a point in time, T(n), and a status phrase, S(n). The + status phrase S(n) describes the period of time that begins at T(n). The + previous status phrase S(n-1) describes the period of time that starts at + T(n-1) and ends at T(n). Since we want to describe the time that a status + phrase took T(n)-T(n-1), this line must describe the previous status. + */ + protocol->store(previous->status, strlen(previous->status), + system_charset_info); + protocol->store((double)(entry->time_usecs - + previous->time_usecs)/(1000.0*1000), (uint32) TIME_FLOAT_DIGITS-1, &elapsed); if (options & PROFILE_CPU) @@ -346,10 +356,10 @@ bool QUERY_PROFILE::show(uint options) #ifdef HAVE_GETRUSAGE String cpu_utime, cpu_stime; protocol->store((double)(RUSAGE_DIFF_USEC(rusage->ru_utime, - last_rusage->ru_utime))/(1000.0*1000), + previous->rusage.ru_utime))/(1000.0*1000), (uint32) TIME_FLOAT_DIGITS-1, &cpu_utime); protocol->store((double)(RUSAGE_DIFF_USEC(rusage->ru_stime, - last_rusage->ru_stime))/(1000.0*1000), + previous->rusage.ru_stime))/(1000.0*1000), (uint32) TIME_FLOAT_DIGITS-1, &cpu_stime); #else protocol->store_null(); @@ -360,8 +370,8 @@ bool QUERY_PROFILE::show(uint options) if (options & PROFILE_CONTEXT) { #ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_nvcsw - last_rusage->ru_nvcsw)); - protocol->store((uint32)(rusage->ru_nivcsw - last_rusage->ru_nivcsw)); + protocol->store((uint32)(rusage->ru_nvcsw - previous->rusage.ru_nvcsw)); + protocol->store((uint32)(rusage->ru_nivcsw - previous->rusage.ru_nivcsw)); #else protocol->store_null(); protocol->store_null(); @@ -371,8 +381,8 @@ bool QUERY_PROFILE::show(uint options) if (options & PROFILE_BLOCK_IO) { #ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_inblock - last_rusage->ru_inblock)); - protocol->store((uint32)(rusage->ru_oublock - last_rusage->ru_oublock)); + protocol->store((uint32)(rusage->ru_inblock - previous->rusage.ru_inblock)); + protocol->store((uint32)(rusage->ru_oublock - previous->rusage.ru_oublock)); #else protocol->store_null(); protocol->store_null(); @@ -382,8 +392,8 @@ bool QUERY_PROFILE::show(uint options) if (options & PROFILE_IPC) { #ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_msgsnd - last_rusage->ru_msgsnd)); - protocol->store((uint32)(rusage->ru_msgrcv - last_rusage->ru_msgrcv)); + protocol->store((uint32)(rusage->ru_msgsnd - previous->rusage.ru_msgsnd)); + protocol->store((uint32)(rusage->ru_msgrcv - previous->rusage.ru_msgrcv)); #else protocol->store_null(); protocol->store_null(); @@ -393,8 +403,8 @@ bool QUERY_PROFILE::show(uint options) if (options & PROFILE_PAGE_FAULTS) { #ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_majflt - last_rusage->ru_majflt)); - protocol->store((uint32)(rusage->ru_minflt - last_rusage->ru_minflt)); + protocol->store((uint32)(rusage->ru_majflt - previous->rusage.ru_majflt)); + protocol->store((uint32)(rusage->ru_minflt - previous->rusage.ru_minflt)); #else protocol->store_null(); protocol->store_null(); @@ -404,7 +414,7 @@ bool QUERY_PROFILE::show(uint options) if (options & PROFILE_SWAPS) { #ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_nswap - last_rusage->ru_nswap)); + protocol->store((uint32)(rusage->ru_nswap - previous->rusage.ru_nswap)); #else protocol->store_null(); #endif @@ -428,11 +438,7 @@ bool QUERY_PROFILE::show(uint options) if (protocol->write()) DBUG_RETURN(TRUE); - last_time= entry->time_usecs; -#ifdef HAVE_GETRUSAGE - last_rusage= &(entry->rusage); -#endif - + previous= entry; } send_eof(thd); DBUG_RETURN(FALSE); @@ -648,12 +654,7 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item history_iterator= history.iterator_next(history_iterator)) { query= history.iterator_value(history_iterator); - - PROFILE_ENTRY *ps= &(query->profile_start); - double last_time= ps->time_usecs; -#ifdef HAVE_GETRUSAGE - struct rusage *last_rusage= &(ps->rusage); -#endif + PROFILE_ENTRY *previous= &(query->profile_start); /* Because we put all profiling info into a table that may be reordered, let @@ -668,14 +669,10 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item for (seq= 0, entry_iterator= query->entries.new_iterator(); entry_iterator != NULL; entry_iterator= query->entries.iterator_next(entry_iterator), -#ifdef HAVE_GETRUSAGE - last_rusage= &(entry->rusage), -#endif - seq++, last_time= entry->time_usecs, row_number++) + seq++, previous=entry, row_number++) { entry= query->entries.iterator_value(entry_iterator); - /* Set default values for this row. */ restore_record(table, s->default_values); @@ -685,16 +682,25 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item */ table->field[0]->store((ulonglong) query->profiling_query_id); table->field[1]->store((ulonglong) seq); /* the step in the sequence */ - table->field[2]->store(entry->status, strlen(entry->status), + /* + This entry, n, has a point in time, T(n), and a status phrase, S(n). + The status phrase S(n) describes the period of time that begins at + T(n). The previous status phrase S(n-1) describes the period of time + that starts at T(n-1) and ends at T(n). Since we want to describe the + time that a status phrase took T(n)-T(n-1), this line must describe the + previous status. + */ + table->field[2]->store(previous->status, strlen(previous->status), system_charset_info); - table->field[3]->store((double)(entry->time_usecs - last_time)/(1000*1000)); + table->field[3]->store((double)(entry->time_usecs - + previous->time_usecs)/(1000*1000)); #ifdef HAVE_GETRUSAGE table->field[4]->store((double)RUSAGE_DIFF_USEC(entry->rusage.ru_utime, - last_rusage->ru_utime)/(1000.0*1000)); + previous->rusage.ru_utime)/(1000.0*1000)); table->field[4]->set_notnull(); table->field[5]->store((double)RUSAGE_DIFF_USEC(entry->rusage.ru_stime, - last_rusage->ru_stime)/(1000.0*1000)); + previous->rusage.ru_stime)/(1000.0*1000)); table->field[5]->set_notnull(); #else @@ -702,43 +708,52 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item #endif #ifdef HAVE_GETRUSAGE - table->field[6]->store((uint32)(entry->rusage.ru_nvcsw - last_rusage->ru_nvcsw)); + table->field[6]->store((uint32)(entry->rusage.ru_nvcsw - + previous->rusage.ru_nvcsw)); table->field[6]->set_notnull(); - table->field[7]->store((uint32)(entry->rusage.ru_nivcsw - last_rusage->ru_nivcsw)); + table->field[7]->store((uint32)(entry->rusage.ru_nivcsw - + previous->rusage.ru_nivcsw)); table->field[7]->set_notnull(); #else /* TODO: Add context switch info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE - table->field[8]->store((uint32)(entry->rusage.ru_inblock - last_rusage->ru_inblock)); + table->field[8]->store((uint32)(entry->rusage.ru_inblock - + previous->rusage.ru_inblock)); table->field[8]->set_notnull(); - table->field[9]->store((uint32)(entry->rusage.ru_oublock - last_rusage->ru_oublock)); + table->field[9]->store((uint32)(entry->rusage.ru_oublock - + previous->rusage.ru_oublock)); table->field[9]->set_notnull(); #else /* TODO: Add block IO info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE - table->field[10]->store((uint32)(entry->rusage.ru_msgsnd - last_rusage->ru_msgsnd), true); + table->field[10]->store((uint32)(entry->rusage.ru_msgsnd - + previous->rusage.ru_msgsnd), true); table->field[10]->set_notnull(); - table->field[11]->store((uint32)(entry->rusage.ru_msgrcv - last_rusage->ru_msgrcv), true); + table->field[11]->store((uint32)(entry->rusage.ru_msgrcv - + previous->rusage.ru_msgrcv), true); table->field[11]->set_notnull(); #else /* TODO: Add message info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE - table->field[12]->store((uint32)(entry->rusage.ru_majflt - last_rusage->ru_majflt), true); + table->field[12]->store((uint32)(entry->rusage.ru_majflt - + previous->rusage.ru_majflt), true); table->field[12]->set_notnull(); - table->field[13]->store((uint32)(entry->rusage.ru_minflt - last_rusage->ru_minflt), true); + table->field[13]->store((uint32)(entry->rusage.ru_minflt - + previous->rusage.ru_minflt), true); table->field[13]->set_notnull(); #else /* TODO: Add page fault info for non-BSD systems */ #endif #ifdef HAVE_GETRUSAGE - table->field[14]->store((uint32)(entry->rusage.ru_nswap - last_rusage->ru_nswap), true); + table->field[14]->store((uint32)(entry->rusage.ru_nswap - + previous->rusage.ru_nswap), true); table->field[14]->set_notnull(); #else /* TODO: Add swap info for non-BSD systems */ From 8abb73142b2d2066ca945fba9d01d3d3aac83665 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 19:47:19 -0400 Subject: [PATCH 26/99] Backport: B-g#26600: table PROFILING in INFORMATION SCHEMA has wrong data type B-g#27047[partial]: INFORMATION_SCHEMA table cannot have BIGINT \ fields No Information_schema table has ever needed floating-point data before. Transforming all floating point to a string and back to a number causes a real data problem on Windows, where the libc may pad the exponent with more leading zeroes than we expect and the significant digits are truncated away. This also makes interpreting an unimplemented type as a string into a fatal error in debug builds. Thus, we will catch problems when we try to use those types in new I_S tables. sql/sql_show.cc: Add floating-point types to Information_schema output. --- sql/sql_show.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index cc3dd79d2ae..7da4ac55e92 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3605,7 +3605,16 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) DBUG_RETURN(0); } break; + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + if ((item= new Item_float(fields_info->field_name, 0.0, NOT_FIXED_DEC, + fields_info->field_length)) == NULL) + DBUG_RETURN(NULL); + break; default: + /* Don't let unimplemented types pass through. Could be a grave error. */ + DBUG_ASSERT(fields_info->field_type == MYSQL_TYPE_STRING); + /* this should be changed when Item_empty_string is fixed(in 4.1) */ if (!(item= new Item_empty_string("", 0, cs))) { From 46503d161ecc5756f0dd7130969e9ae9df303b31 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 19:50:55 -0400 Subject: [PATCH 27/99] Backport: B-g#27501: 5.0 significantly more sys ("kernel") time than 4.1 \ due to getrusage() calls Even if profiling is turned off, the parser makes calls to reset the state at the beginning of each query. That would eventually instantiate a PROFILE_ENTRY, which does indeed capture resource usage. Instead, now check that profiling is active before progressing far into the storage/expiration of old entries in the history. This has the pleasant side-effect that queries to toggle profiling are not recorded in the history. mysql-test/r/profiling.result: Now after we turn off profiling, the beginning of the next query refuses to enter the profiling code and it discards the info. sql/sql_profile.cc: Add the same condition twice: Once to abort storing previous query information and the other to abort initialization for this query that is starting. We do this symmetrically, before and after expiring old history entries, so that the counts are correct. --- mysql-test/r/profiling.result | 2 +- sql/sql_profile.cc | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/profiling.result b/mysql-test/r/profiling.result index a1e994220b9..75977f7f2e8 100644 --- a/mysql-test/r/profiling.result +++ b/mysql-test/r/profiling.result @@ -248,6 +248,7 @@ sum(id) 12 show profiles; Query_ID Duration Query +15 # select count(*) from t1 16 # insert into t1 select * from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 @@ -277,7 +278,6 @@ Query_ID Duration Query 42 # insert into t1 values (1), (2), (3) 43 # insert into t1 values (1), (2), (3) 44 # select * from t1 -45 # set session profiling = OFF set session profiling = ON; select @@profiling; @@profiling diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 4ee8d1ba9c8..b17bb6daa0d 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -493,6 +493,9 @@ void PROFILING::store() while (history.elements > thd->variables.profiling_history_size) delete history.pop(); + if (likely(((thd)->options & OPTION_PROFILING) == 0)) + DBUG_VOID_RETURN; + if (current != NULL) { if (keeping && @@ -519,12 +522,20 @@ void PROFILING::store() DBUG_VOID_RETURN; } +/** + Store and clean up the old information and get ready to hold info about this + new query. This is called very often so it must be very lightweight if + profiling is not active. +*/ void PROFILING::reset() { DBUG_ENTER("PROFILING::reset"); store(); + if (likely(((thd)->options & OPTION_PROFILING) == 0)) + DBUG_VOID_RETURN; + if (current != NULL) current->reset(); keep(); From 2879da7f847eeda8ebf7cdad769f665fe95f5259 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 19:52:24 -0400 Subject: [PATCH 28/99] Unreported minor bug: We start numbering query IDs at zero, which is a special case in "SHOW PROFILE FOR QUERY n". No one can get the zero item (which is always the statement that turns on profiling), because zero represents the final item, internally. Now, order the queries starting at one. mysql-test/r/profiling.result: Renumber the query IDs. sql/sql_profile.cc: Start the profile_id_counter at 1, to overstep the special-case value of zero. Unrelated, but looks similar: don't use -1 to initialize an unsigned integer field. That causes warnings in some environments. --- mysql-test/r/profiling.result | 254 +++++++++++++++++----------------- sql/sql_profile.cc | 4 +- 2 files changed, 129 insertions(+), 129 deletions(-) diff --git a/mysql-test/r/profiling.result b/mysql-test/r/profiling.result index 75977f7f2e8..50b6fff82b8 100644 --- a/mysql-test/r/profiling.result +++ b/mysql-test/r/profiling.result @@ -69,34 +69,34 @@ big_string 012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890 show profiles; Query_ID Duration Query -0 # set session profiling = ON -1 # set session profiling_history_size=30 -2 # show session variables like 'profil%' -3 # select @@profiling -4 # create table t1 ( +1 # set session profiling = ON +2 # set session profiling_history_size=30 +3 # show session variables like 'profil%' +4 # select @@profiling +5 # create table t1 ( a int, b int ) -5 # insert into t1 values (1,1), (2,null), (3, 4) -6 # insert into t1 values (5,1), (6,null), (7, 4) -7 # insert into t1 values (1,1), (2,null), (3, 4) -8 # insert into t1 values (5,1), (6,null), (7, 4) -9 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -10 # insert into t1 select * from t1 -11 # select count(*) from t1 -12 # insert into t1 select * from t1 +6 # insert into t1 values (1,1), (2,null), (3, 4) +7 # insert into t1 values (5,1), (6,null), (7, 4) +8 # insert into t1 values (1,1), (2,null), (3, 4) +9 # insert into t1 values (5,1), (6,null), (7, 4) +10 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +11 # insert into t1 select * from t1 +12 # select count(*) from t1 13 # insert into t1 select * from t1 14 # insert into t1 select * from t1 -15 # select count(*) from t1 -16 # insert into t1 select * from t1 +15 # insert into t1 select * from t1 +16 # select count(*) from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # select count(*) from t1 -20 # select sum(a) from t1 -21 # select sum(a) from t1 group by b -22 # select sum(a) + sum(b) from t1 group by b -23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +19 # insert into t1 select * from t1 +20 # select count(*) from t1 +21 # select sum(a) from t1 +22 # select sum(a) from t1 group by b +23 # select sum(a) + sum(b) from t1 group by b +24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 show profile for query 15; show profile cpu for query 15; show profile cpu, block io for query 15; @@ -131,36 +131,36 @@ insert into t2 values (1), (2), (3); insert into t3 values (1), (2), (3); show profiles; Query_ID Duration Query -10 # insert into t1 select * from t1 -11 # select count(*) from t1 -12 # insert into t1 select * from t1 +11 # insert into t1 select * from t1 +12 # select count(*) from t1 13 # insert into t1 select * from t1 14 # insert into t1 select * from t1 -15 # select count(*) from t1 -16 # insert into t1 select * from t1 +15 # insert into t1 select * from t1 +16 # select count(*) from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # select count(*) from t1 -20 # select sum(a) from t1 -21 # select sum(a) from t1 group by b -22 # select sum(a) + sum(b) from t1 group by b -23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 -25 # select * from information_schema.profiling -26 # select query_id, state, duration from information_schema.profiling -27 # select query_id, sum(duration) from information_schema.profiling group by query_id -28 # select query_id, count(*) from information_schema.profiling group by query_id -29 # select sum(duration) from information_schema.profiling -30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id -31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling -32 # drop table if exists t1, t2, t3 -33 # SHOW WARNINGS -34 # create table t1 (id int ) -35 # create table t2 (id int not null) -36 # create table t3 (id int not null primary key) -37 # insert into t1 values (1), (2), (3) -38 # insert into t2 values (1), (2), (3) -39 # insert into t3 values (1), (2), (3) +19 # insert into t1 select * from t1 +20 # select count(*) from t1 +21 # select sum(a) from t1 +22 # select sum(a) from t1 group by b +23 # select sum(a) + sum(b) from t1 group by b +24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +26 # select * from information_schema.profiling +27 # select query_id, state, duration from information_schema.profiling +28 # select query_id, sum(duration) from information_schema.profiling group by query_id +29 # select query_id, count(*) from information_schema.profiling group by query_id +30 # select sum(duration) from information_schema.profiling +31 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +32 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +33 # drop table if exists t1, t2, t3 +34 # SHOW WARNINGS +35 # create table t1 (id int ) +36 # create table t2 (id int not null) +37 # create table t3 (id int not null primary key) +38 # insert into t1 values (1), (2), (3) +39 # insert into t2 values (1), (2), (3) +40 # insert into t3 values (1), (2), (3) select * from t1; id 1 @@ -168,36 +168,36 @@ id 3 show profiles; Query_ID Duration Query -11 # select count(*) from t1 -12 # insert into t1 select * from t1 +12 # select count(*) from t1 13 # insert into t1 select * from t1 14 # insert into t1 select * from t1 -15 # select count(*) from t1 -16 # insert into t1 select * from t1 +15 # insert into t1 select * from t1 +16 # select count(*) from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # select count(*) from t1 -20 # select sum(a) from t1 -21 # select sum(a) from t1 group by b -22 # select sum(a) + sum(b) from t1 group by b -23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 -25 # select * from information_schema.profiling -26 # select query_id, state, duration from information_schema.profiling -27 # select query_id, sum(duration) from information_schema.profiling group by query_id -28 # select query_id, count(*) from information_schema.profiling group by query_id -29 # select sum(duration) from information_schema.profiling -30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id -31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling -32 # drop table if exists t1, t2, t3 -33 # SHOW WARNINGS -34 # create table t1 (id int ) -35 # create table t2 (id int not null) -36 # create table t3 (id int not null primary key) -37 # insert into t1 values (1), (2), (3) -38 # insert into t2 values (1), (2), (3) -39 # insert into t3 values (1), (2), (3) -40 # select * from t1 +19 # insert into t1 select * from t1 +20 # select count(*) from t1 +21 # select sum(a) from t1 +22 # select sum(a) from t1 group by b +23 # select sum(a) + sum(b) from t1 group by b +24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +26 # select * from information_schema.profiling +27 # select query_id, state, duration from information_schema.profiling +28 # select query_id, sum(duration) from information_schema.profiling group by query_id +29 # select query_id, count(*) from information_schema.profiling group by query_id +30 # select sum(duration) from information_schema.profiling +31 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +32 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +33 # drop table if exists t1, t2, t3 +34 # SHOW WARNINGS +35 # create table t1 (id int ) +36 # create table t2 (id int not null) +37 # create table t3 (id int not null primary key) +38 # insert into t1 values (1), (2), (3) +39 # insert into t2 values (1), (2), (3) +40 # insert into t3 values (1), (2), (3) +41 # select * from t1 This ^^ should end in "select * from t1;" delete from t1; insert into t1 values (1), (2), (3); @@ -212,72 +212,72 @@ id 3 show profiles; Query_ID Duration Query -15 # select count(*) from t1 -16 # insert into t1 select * from t1 +16 # select count(*) from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # select count(*) from t1 -20 # select sum(a) from t1 -21 # select sum(a) from t1 group by b -22 # select sum(a) + sum(b) from t1 group by b -23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 -25 # select * from information_schema.profiling -26 # select query_id, state, duration from information_schema.profiling -27 # select query_id, sum(duration) from information_schema.profiling group by query_id -28 # select query_id, count(*) from information_schema.profiling group by query_id -29 # select sum(duration) from information_schema.profiling -30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id -31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling -32 # drop table if exists t1, t2, t3 -33 # SHOW WARNINGS -34 # create table t1 (id int ) -35 # create table t2 (id int not null) -36 # create table t3 (id int not null primary key) -37 # insert into t1 values (1), (2), (3) -38 # insert into t2 values (1), (2), (3) -39 # insert into t3 values (1), (2), (3) -40 # select * from t1 -41 # delete from t1 -42 # insert into t1 values (1), (2), (3) +19 # insert into t1 select * from t1 +20 # select count(*) from t1 +21 # select sum(a) from t1 +22 # select sum(a) from t1 group by b +23 # select sum(a) + sum(b) from t1 group by b +24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +26 # select * from information_schema.profiling +27 # select query_id, state, duration from information_schema.profiling +28 # select query_id, sum(duration) from information_schema.profiling group by query_id +29 # select query_id, count(*) from information_schema.profiling group by query_id +30 # select sum(duration) from information_schema.profiling +31 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +32 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +33 # drop table if exists t1, t2, t3 +34 # SHOW WARNINGS +35 # create table t1 (id int ) +36 # create table t2 (id int not null) +37 # create table t3 (id int not null primary key) +38 # insert into t1 values (1), (2), (3) +39 # insert into t2 values (1), (2), (3) +40 # insert into t3 values (1), (2), (3) +41 # select * from t1 +42 # delete from t1 43 # insert into t1 values (1), (2), (3) -44 # select * from t1 +44 # insert into t1 values (1), (2), (3) +45 # select * from t1 set session profiling = OFF; select sum(id) from t1; sum(id) 12 show profiles; Query_ID Duration Query -15 # select count(*) from t1 -16 # insert into t1 select * from t1 +16 # select count(*) from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # select count(*) from t1 -20 # select sum(a) from t1 -21 # select sum(a) from t1 group by b -22 # select sum(a) + sum(b) from t1 group by b -23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 -25 # select * from information_schema.profiling -26 # select query_id, state, duration from information_schema.profiling -27 # select query_id, sum(duration) from information_schema.profiling group by query_id -28 # select query_id, count(*) from information_schema.profiling group by query_id -29 # select sum(duration) from information_schema.profiling -30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id -31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling -32 # drop table if exists t1, t2, t3 -33 # SHOW WARNINGS -34 # create table t1 (id int ) -35 # create table t2 (id int not null) -36 # create table t3 (id int not null primary key) -37 # insert into t1 values (1), (2), (3) -38 # insert into t2 values (1), (2), (3) -39 # insert into t3 values (1), (2), (3) -40 # select * from t1 -41 # delete from t1 -42 # insert into t1 values (1), (2), (3) +19 # insert into t1 select * from t1 +20 # select count(*) from t1 +21 # select sum(a) from t1 +22 # select sum(a) from t1 group by b +23 # select sum(a) + sum(b) from t1 group by b +24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +26 # select * from information_schema.profiling +27 # select query_id, state, duration from information_schema.profiling +28 # select query_id, sum(duration) from information_schema.profiling group by query_id +29 # select query_id, count(*) from information_schema.profiling group by query_id +30 # select sum(duration) from information_schema.profiling +31 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +32 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +33 # drop table if exists t1, t2, t3 +34 # SHOW WARNINGS +35 # create table t1 (id int ) +36 # create table t2 (id int not null) +37 # create table t3 (id int not null primary key) +38 # insert into t1 values (1), (2), (3) +39 # insert into t2 values (1), (2), (3) +40 # insert into t3 values (1), (2), (3) +41 # select * from t1 +42 # delete from t1 43 # insert into t1 values (1), (2), (3) -44 # select * from t1 +44 # insert into t1 values (1), (2), (3) +45 # select * from t1 set session profiling = ON; select @@profiling; @@profiling diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index b17bb6daa0d..5fd83ce70c6 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -158,7 +158,7 @@ void PROFILE_ENTRY::collect() QUERY_PROFILE::QUERY_PROFILE(PROFILING *profiling_arg, char *query_source_arg, uint query_length_arg) - :profiling(profiling_arg), server_query_id(-1), profiling_query_id(-1), + :profiling(profiling_arg), server_query_id(0), profiling_query_id(0), query_source(NULL) { profile_end= &profile_start; @@ -445,7 +445,7 @@ bool QUERY_PROFILE::show(uint options) } PROFILING::PROFILING() - :profile_id_counter(0), keeping(1), current(NULL), last(NULL) + :profile_id_counter(1), keeping(1), current(NULL), last(NULL) { } From c717287c22f2e18b31338d6ac7af5bf9c97e0b1f Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Apr 2007 07:44:12 -0400 Subject: [PATCH 29/99] Backport: B-g#27427: resolveip fails on hostnames with a leading digit We need inet_aton for the extra/resolveip tool. Some OSes put this in nonstandard libraries. configure.in: We need inet_aton for the extra/resolveip tool. --- configure.in | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.in b/configure.in index 13d2b50d7fa..f1a71d49359 100644 --- a/configure.in +++ b/configure.in @@ -791,6 +791,7 @@ AC_CHECK_FUNC(p2open, , AC_CHECK_LIB(gen, p2open)) AC_CHECK_FUNC(bind, , AC_CHECK_LIB(bind, bind)) # Check if crypt() exists in libc or libcrypt, sets LIBS if needed AC_SEARCH_LIBS(crypt, crypt, AC_DEFINE(HAVE_CRYPT, 1, [crypt])) +AC_SEARCH_LIBS(inet_aton, [socket nsl resolv]) # For the sched_yield() function on Solaris AC_CHECK_FUNC(sched_yield, , AC_CHECK_LIB(posix4, sched_yield)) From fcb52609e4727cdf6f246e7817c0fa625749c5c4 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 6 Apr 2007 09:15:18 -0400 Subject: [PATCH 30/99] Changing the state of whether we're recording profiling information halfway through a query (as happens in "SET SESSION PROFILING = ...") has a few side-effects, the worst of which is a memory leak for prepared statements, which poke directly from the parser into the profiling code (we don't have the query text when we need it) and that overwrites a pointer to heap-allocated memory when the previous statement turns on profiling. Instead, now set a flag when we begin a new statement that tracks whether profiling is on _at the start_ of the query. Use that to track whether we gather info. Additionally, use that AND use the state of the profiling variable after the end of a query to know whether to store information about the query that just finished. mysql-test/r/profiling.result: Testing whether profiling is on at the beginning of a query and at the end of a query makes "SET SESSION PROFILING = ..." statements disappear from the profiling. They were never reliable before. sql/sql_profile.cc: Check to see if profiling was enabled at the beginning of this query before trying to store query_source. This avoids a memory leak for prepared statements, which get here by direct means. If profiling was toggled in this query, then don't store this query profile. sql/sql_profile.h: Keep track of whether profiling is on. --- mysql-test/r/profiling.result | 253 +++++++++++++++++----------------- sql/sql_profile.cc | 18 ++- sql/sql_profile.h | 1 + 3 files changed, 142 insertions(+), 130 deletions(-) diff --git a/mysql-test/r/profiling.result b/mysql-test/r/profiling.result index 50b6fff82b8..9f478d68b8d 100644 --- a/mysql-test/r/profiling.result +++ b/mysql-test/r/profiling.result @@ -69,34 +69,33 @@ big_string 012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890 show profiles; Query_ID Duration Query -1 # set session profiling = ON -2 # set session profiling_history_size=30 -3 # show session variables like 'profil%' -4 # select @@profiling -5 # create table t1 ( +1 # set session profiling_history_size=30 +2 # show session variables like 'profil%' +3 # select @@profiling +4 # create table t1 ( a int, b int ) -6 # insert into t1 values (1,1), (2,null), (3, 4) -7 # insert into t1 values (5,1), (6,null), (7, 4) -8 # insert into t1 values (1,1), (2,null), (3, 4) -9 # insert into t1 values (5,1), (6,null), (7, 4) -10 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -11 # insert into t1 select * from t1 -12 # select count(*) from t1 +5 # insert into t1 values (1,1), (2,null), (3, 4) +6 # insert into t1 values (5,1), (6,null), (7, 4) +7 # insert into t1 values (1,1), (2,null), (3, 4) +8 # insert into t1 values (5,1), (6,null), (7, 4) +9 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +10 # insert into t1 select * from t1 +11 # select count(*) from t1 +12 # insert into t1 select * from t1 13 # insert into t1 select * from t1 14 # insert into t1 select * from t1 -15 # insert into t1 select * from t1 -16 # select count(*) from t1 +15 # select count(*) from t1 +16 # insert into t1 select * from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # insert into t1 select * from t1 -20 # select count(*) from t1 -21 # select sum(a) from t1 -22 # select sum(a) from t1 group by b -23 # select sum(a) + sum(b) from t1 group by b -24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 show profile for query 15; show profile cpu for query 15; show profile cpu, block io for query 15; @@ -131,36 +130,36 @@ insert into t2 values (1), (2), (3); insert into t3 values (1), (2), (3); show profiles; Query_ID Duration Query -11 # insert into t1 select * from t1 -12 # select count(*) from t1 +10 # insert into t1 select * from t1 +11 # select count(*) from t1 +12 # insert into t1 select * from t1 13 # insert into t1 select * from t1 14 # insert into t1 select * from t1 -15 # insert into t1 select * from t1 -16 # select count(*) from t1 +15 # select count(*) from t1 +16 # insert into t1 select * from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # insert into t1 select * from t1 -20 # select count(*) from t1 -21 # select sum(a) from t1 -22 # select sum(a) from t1 group by b -23 # select sum(a) + sum(b) from t1 group by b -24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 -26 # select * from information_schema.profiling -27 # select query_id, state, duration from information_schema.profiling -28 # select query_id, sum(duration) from information_schema.profiling group by query_id -29 # select query_id, count(*) from information_schema.profiling group by query_id -30 # select sum(duration) from information_schema.profiling -31 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id -32 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling -33 # drop table if exists t1, t2, t3 -34 # SHOW WARNINGS -35 # create table t1 (id int ) -36 # create table t2 (id int not null) -37 # create table t3 (id int not null primary key) -38 # insert into t1 values (1), (2), (3) -39 # insert into t2 values (1), (2), (3) -40 # insert into t3 values (1), (2), (3) +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +25 # select * from information_schema.profiling +26 # select query_id, state, duration from information_schema.profiling +27 # select query_id, sum(duration) from information_schema.profiling group by query_id +28 # select query_id, count(*) from information_schema.profiling group by query_id +29 # select sum(duration) from information_schema.profiling +30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +32 # drop table if exists t1, t2, t3 +33 # SHOW WARNINGS +34 # create table t1 (id int ) +35 # create table t2 (id int not null) +36 # create table t3 (id int not null primary key) +37 # insert into t1 values (1), (2), (3) +38 # insert into t2 values (1), (2), (3) +39 # insert into t3 values (1), (2), (3) select * from t1; id 1 @@ -168,36 +167,36 @@ id 3 show profiles; Query_ID Duration Query -12 # select count(*) from t1 +11 # select count(*) from t1 +12 # insert into t1 select * from t1 13 # insert into t1 select * from t1 14 # insert into t1 select * from t1 -15 # insert into t1 select * from t1 -16 # select count(*) from t1 +15 # select count(*) from t1 +16 # insert into t1 select * from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # insert into t1 select * from t1 -20 # select count(*) from t1 -21 # select sum(a) from t1 -22 # select sum(a) from t1 group by b -23 # select sum(a) + sum(b) from t1 group by b -24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 -26 # select * from information_schema.profiling -27 # select query_id, state, duration from information_schema.profiling -28 # select query_id, sum(duration) from information_schema.profiling group by query_id -29 # select query_id, count(*) from information_schema.profiling group by query_id -30 # select sum(duration) from information_schema.profiling -31 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id -32 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling -33 # drop table if exists t1, t2, t3 -34 # SHOW WARNINGS -35 # create table t1 (id int ) -36 # create table t2 (id int not null) -37 # create table t3 (id int not null primary key) -38 # insert into t1 values (1), (2), (3) -39 # insert into t2 values (1), (2), (3) -40 # insert into t3 values (1), (2), (3) -41 # select * from t1 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +25 # select * from information_schema.profiling +26 # select query_id, state, duration from information_schema.profiling +27 # select query_id, sum(duration) from information_schema.profiling group by query_id +28 # select query_id, count(*) from information_schema.profiling group by query_id +29 # select sum(duration) from information_schema.profiling +30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +32 # drop table if exists t1, t2, t3 +33 # SHOW WARNINGS +34 # create table t1 (id int ) +35 # create table t2 (id int not null) +36 # create table t3 (id int not null primary key) +37 # insert into t1 values (1), (2), (3) +38 # insert into t2 values (1), (2), (3) +39 # insert into t3 values (1), (2), (3) +40 # select * from t1 This ^^ should end in "select * from t1;" delete from t1; insert into t1 values (1), (2), (3); @@ -212,72 +211,72 @@ id 3 show profiles; Query_ID Duration Query -16 # select count(*) from t1 +15 # select count(*) from t1 +16 # insert into t1 select * from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # insert into t1 select * from t1 -20 # select count(*) from t1 -21 # select sum(a) from t1 -22 # select sum(a) from t1 group by b -23 # select sum(a) + sum(b) from t1 group by b -24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 -26 # select * from information_schema.profiling -27 # select query_id, state, duration from information_schema.profiling -28 # select query_id, sum(duration) from information_schema.profiling group by query_id -29 # select query_id, count(*) from information_schema.profiling group by query_id -30 # select sum(duration) from information_schema.profiling -31 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id -32 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling -33 # drop table if exists t1, t2, t3 -34 # SHOW WARNINGS -35 # create table t1 (id int ) -36 # create table t2 (id int not null) -37 # create table t3 (id int not null primary key) -38 # insert into t1 values (1), (2), (3) -39 # insert into t2 values (1), (2), (3) -40 # insert into t3 values (1), (2), (3) -41 # select * from t1 -42 # delete from t1 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +25 # select * from information_schema.profiling +26 # select query_id, state, duration from information_schema.profiling +27 # select query_id, sum(duration) from information_schema.profiling group by query_id +28 # select query_id, count(*) from information_schema.profiling group by query_id +29 # select sum(duration) from information_schema.profiling +30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +32 # drop table if exists t1, t2, t3 +33 # SHOW WARNINGS +34 # create table t1 (id int ) +35 # create table t2 (id int not null) +36 # create table t3 (id int not null primary key) +37 # insert into t1 values (1), (2), (3) +38 # insert into t2 values (1), (2), (3) +39 # insert into t3 values (1), (2), (3) +40 # select * from t1 +41 # delete from t1 +42 # insert into t1 values (1), (2), (3) 43 # insert into t1 values (1), (2), (3) -44 # insert into t1 values (1), (2), (3) -45 # select * from t1 +44 # select * from t1 set session profiling = OFF; select sum(id) from t1; sum(id) 12 show profiles; Query_ID Duration Query -16 # select count(*) from t1 +15 # select count(*) from t1 +16 # insert into t1 select * from t1 17 # insert into t1 select * from t1 18 # insert into t1 select * from t1 -19 # insert into t1 select * from t1 -20 # select count(*) from t1 -21 # select sum(a) from t1 -22 # select sum(a) from t1 group by b -23 # select sum(a) + sum(b) from t1 group by b -24 # select max(x) from (select sum(a) as x from t1 group by b) as teeone -25 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 -26 # select * from information_schema.profiling -27 # select query_id, state, duration from information_schema.profiling -28 # select query_id, sum(duration) from information_schema.profiling group by query_id -29 # select query_id, count(*) from information_schema.profiling group by query_id -30 # select sum(duration) from information_schema.profiling -31 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id -32 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling -33 # drop table if exists t1, t2, t3 -34 # SHOW WARNINGS -35 # create table t1 (id int ) -36 # create table t2 (id int not null) -37 # create table t3 (id int not null primary key) -38 # insert into t1 values (1), (2), (3) -39 # insert into t2 values (1), (2), (3) -40 # insert into t3 values (1), (2), (3) -41 # select * from t1 -42 # delete from t1 +19 # select count(*) from t1 +20 # select sum(a) from t1 +21 # select sum(a) from t1 group by b +22 # select sum(a) + sum(b) from t1 group by b +23 # select max(x) from (select sum(a) as x from t1 group by b) as teeone +24 # select '0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345 +25 # select * from information_schema.profiling +26 # select query_id, state, duration from information_schema.profiling +27 # select query_id, sum(duration) from information_schema.profiling group by query_id +28 # select query_id, count(*) from information_schema.profiling group by query_id +29 # select sum(duration) from information_schema.profiling +30 # select query_id, count(*), sum(duration) from information_schema.profiling group by query_id +31 # select CPU_user, CPU_system, Context_voluntary, Context_involuntary, Block_ops_in, Block_ops_out, Messages_sent, Messages_received, Page_faults_major, Page_faults_minor, Swaps, Source_function, Source_file, Source_line from information_schema.profiling +32 # drop table if exists t1, t2, t3 +33 # SHOW WARNINGS +34 # create table t1 (id int ) +35 # create table t2 (id int not null) +36 # create table t3 (id int not null primary key) +37 # insert into t1 values (1), (2), (3) +38 # insert into t2 values (1), (2), (3) +39 # insert into t3 values (1), (2), (3) +40 # select * from t1 +41 # delete from t1 +42 # insert into t1 values (1), (2), (3) 43 # insert into t1 values (1), (2), (3) -44 # insert into t1 values (1), (2), (3) -45 # select * from t1 +44 # select * from t1 set session profiling = ON; select @@profiling; @@profiling diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 5fd83ce70c6..91b0b062e4f 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -168,10 +168,14 @@ QUERY_PROFILE::QUERY_PROFILE(PROFILING *profiling_arg, char *query_source_arg, void QUERY_PROFILE::set_query_source(char *query_source_arg, uint query_length_arg) { + if (! profiling->enabled) + return; + /* Truncate to avoid DoS attacks. */ uint length= min(MAX_QUERY_LENGTH, query_length_arg); /* TODO?: Provide a way to include the full text, as in SHOW PROCESSLIST. */ + DBUG_ASSERT(query_source == NULL); if (query_source_arg != NULL) query_source= my_strdup_with_length(query_source_arg, length, MYF(0)); } @@ -445,7 +449,7 @@ bool QUERY_PROFILE::show(uint options) } PROFILING::PROFILING() - :profile_id_counter(1), keeping(1), current(NULL), last(NULL) + :profile_id_counter(1), keeping(TRUE), enabled(FALSE), current(NULL), last(NULL) { } @@ -464,7 +468,7 @@ void PROFILING::status_change(const char *status_arg, { DBUG_ENTER("PROFILING::status_change"); - if (unlikely((thd->options & OPTION_PROFILING) != 0)) + if (unlikely(enabled)) { if (unlikely(current == NULL)) reset(); @@ -499,6 +503,8 @@ void PROFILING::store() if (current != NULL) { if (keeping && + (enabled) && /* ON at start? */ + (((thd)->options & OPTION_PROFILING) != 0) && /* and ON at end? */ (current->query_source != NULL) && (current->query_source[0] != '\0') && (!current->entries.is_empty())) @@ -517,7 +523,8 @@ void PROFILING::store() } DBUG_ASSERT(current == NULL); - current= new QUERY_PROFILE(this, thd->query, thd->query_length); + if (enabled) + current= new QUERY_PROFILE(this, thd->query, thd->query_length); DBUG_VOID_RETURN; } @@ -534,7 +541,12 @@ void PROFILING::reset() store(); if (likely(((thd)->options & OPTION_PROFILING) == 0)) + { + enabled= FALSE; DBUG_VOID_RETURN; + } + else + enabled= TRUE; if (current != NULL) current->reset(); diff --git a/sql/sql_profile.h b/sql/sql_profile.h index 7913d037551..b82b5ce090c 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -277,6 +277,7 @@ private: query_id_t profile_id_counter; THD *thd; bool keeping; + bool enabled; QUERY_PROFILE *current; QUERY_PROFILE *last; From d1c5f54ba5420f5b0c286c1ca74abd8989c7cbf9 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 10 Apr 2007 16:47:07 -0400 Subject: [PATCH 31/99] Use platform-independent mysqltest language. --- mysql-test/t/mysqlcheck.test | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test index eb732a05909..5efe6ade6bb 100644 --- a/mysql-test/t/mysqlcheck.test +++ b/mysql-test/t/mysqlcheck.test @@ -39,8 +39,9 @@ use d_bug25347; create table t_bug25347 (a int); create view v_bug25347 as select * from t_bug25347; --echo removing and creating ---exec rm $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI; ---exec touch $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI; +--remove_file $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI +--write_file $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI EOF +EOF --exec $MYSQL_CHECK --repair --databases d_bug25347 drop view v_bug25347; drop table t_bug25347; From a318c75af76c8676cfe45dc154685a6e0e283cfa Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 16 Apr 2007 15:00:16 -0400 Subject: [PATCH 32/99] Bug#25347: mysqlcheck -A -r doesn't repair table marked as crashed Additional changes to test: "flush tables" so that Windows releases the files. mysql-test/r/mysqlcheck.result: Add "flush tables" to get windows to release the files, so that we can test truncation properly. mysql-test/t/mysqlcheck.test: Add "flush tables" to get windows to release the files, so that we can test truncation properly. --- mysql-test/r/mysqlcheck.result | 27 ++++++++++++++++++++++++++- mysql-test/t/mysqlcheck.test | 8 ++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result index 81a30267e04..1c42b0060f7 100644 --- a/mysql-test/r/mysqlcheck.result +++ b/mysql-test/r/mysqlcheck.result @@ -45,8 +45,33 @@ create database d_bug25347; use d_bug25347; create table t_bug25347 (a int); create view v_bug25347 as select * from t_bug25347; +insert into t_bug25347 values (1),(2),(3); +flush tables; removing and creating -d_bug25347.t_bug25347 OK +d_bug25347.t_bug25347 +error : Incorrect file format 't_bug25347' +insert into t_bug25347 values (4),(5),(6); +ERROR HY000: Incorrect file format 't_bug25347' +d_bug25347.t_bug25347 +warning : Number of rows changed from 0 to 3 +status : OK +insert into t_bug25347 values (7),(8),(9); +select * from t_bug25347; +a +1 +2 +3 +7 +8 +9 +select * from v_bug25347; +a +1 +2 +3 +7 +8 +9 drop view v_bug25347; drop table t_bug25347; drop database d_bug25347; diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test index 5efe6ade6bb..655ff39001c 100644 --- a/mysql-test/t/mysqlcheck.test +++ b/mysql-test/t/mysqlcheck.test @@ -38,11 +38,19 @@ create database d_bug25347; use d_bug25347; create table t_bug25347 (a int); create view v_bug25347 as select * from t_bug25347; +insert into t_bug25347 values (1),(2),(3); +flush tables; --echo removing and creating --remove_file $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI --write_file $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI EOF EOF --exec $MYSQL_CHECK --repair --databases d_bug25347 +--error 130 +insert into t_bug25347 values (4),(5),(6); +--exec $MYSQL_CHECK --repair --use-frm --databases d_bug25347 +insert into t_bug25347 values (7),(8),(9); +select * from t_bug25347; +select * from v_bug25347; drop view v_bug25347; drop table t_bug25347; drop database d_bug25347; From 84ddade7538e0de1fed9adc5b505fbdbfb146354 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 20 Apr 2007 14:01:49 +0200 Subject: [PATCH 33/99] win32 build fix --- VC++Files/sql/mysqld.vcproj | 78 ++----------------------------------- 1 file changed, 3 insertions(+), 75 deletions(-) diff --git a/VC++Files/sql/mysqld.vcproj b/VC++Files/sql/mysqld.vcproj index 1caa66c7519..802ca638c90 100644 --- a/VC++Files/sql/mysqld.vcproj +++ b/VC++Files/sql/mysqld.vcproj @@ -908,81 +908,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1091,6 +1016,9 @@ + + From be16a11fbbf3af859ad1bbc2e0096087f8c2f30a Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 30 Apr 2007 11:41:19 +0200 Subject: [PATCH 34/99] backport vista manifest patch --- CMakeLists.txt | 27 ++++++++++++++++++++ client/CMakeLists.txt | 14 ++++++++++ extra/CMakeLists.txt | 7 +++++ libmysql/CMakeLists.txt | 5 ++++ myisam/CMakeLists.txt | 8 ++++++ server-tools/instance-manager/CMakeLists.txt | 5 ++++ sql/CMakeLists.txt | 5 ++++ win/Makefile.am | 3 ++- win/README | 2 ++ win/configure.js | 1 + 10 files changed, 76 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a286071bb0..ec2a875ee92 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,6 +128,33 @@ ENDIF(CMAKE_GENERATOR MATCHES "Visual Studio 7" OR ADD_DEFINITIONS("-D_WINDOWS -D__WIN__ -D _CRT_SECURE_NO_DEPRECATE") +IF(EMBED_MANIFESTS) + # Search for the Manifest tool. CMake will first search it's defaults + # (CMAKE_FRAMEWORK_PATH, CMAKE_APPBUNDLE_PATH, CMAKE_PROGRAM_PATH and + # the system PATH) followed by the listed paths which are the current + # possible defaults and should be updated when necessary. The custom + # manifests are designed to be compatible with all mt versions. + FIND_PROGRAM(HAVE_MANIFEST_TOOL NAMES mt + PATHS + "$ENV{PROGRAMFILES}/Microsoft Visual Studio 8/VC/bin" + "$ENV{PROGRAMFILES}/Microsoft Visual Studio 8/Common7/Tools/Bin" + "$ENV{PROGRAMFILES}/Microsoft Visual Studio 8/SDK/v2.0/Bin") + IF(HAVE_MANIFEST_TOOL) + MESSAGE(STATUS "Found Mainfest Tool. Embedding custom manifests.") + ELSE(HAVE_MANIFEST_TOOL) + MESSAGE(FATAL_ERROR "Manifest tool, mt.exe, can't be found.") + ENDIF(HAVE_MANIFEST_TOOL) + # Disable automatic manifest generation. + STRING(REPLACE "/MANIFEST" "/MANIFEST:NO" CMAKE_EXE_LINKER_FLAGS + ${CMAKE_EXE_LINKER_FLAGS}) + # Set the processor architecture. + IF(CMAKE_GENERATOR MATCHES "Visual Studio 8 2005 Win64") + SET(PROCESSOR_ARCH "X64") + ELSE(CMAKE_GENERATOR MATCHES "Visual Studio 8 2005 Win64") + SET(PROCESSOR_ARCH "X86") + ENDIF(CMAKE_GENERATOR MATCHES "Visual Studio 8 2005 Win64") +ENDIF(EMBED_MANIFESTS) + ADD_SUBDIRECTORY(vio) ADD_SUBDIRECTORY(dbug) ADD_SUBDIRECTORY(strings) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 785bba738bf..8fd56cb92b5 100755 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -12,6 +12,7 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake") SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") @@ -97,3 +98,16 @@ TARGET_LINK_LIBRARIES(mysqladmin mysqlclient mysys dbug yassl taocrypt zlib wsoc ADD_EXECUTABLE(echo echo.c) +IF(EMBED_MANIFESTS) + MYSQL_EMBED_MANIFEST("mysql" "asInvoker") + MYSQL_EMBED_MANIFEST("mysqltest" "asInvoker") + MYSQL_EMBED_MANIFEST("mysqlcheck" "asInvoker") + MYSQL_EMBED_MANIFEST("mysqldump" "asInvoker") + MYSQL_EMBED_MANIFEST("mysqlimport" "asInvoker") + MYSQL_EMBED_MANIFEST("mysql_upgrade" "asInvoker") + MYSQL_EMBED_MANIFEST("mysqlshow" "asInvoker") + MYSQL_EMBED_MANIFEST("mysqlbinlog" "asInvoker") + MYSQL_EMBED_MANIFEST("mysqladmin" "asInvoker") + MYSQL_EMBED_MANIFEST("echo" "asInvoker") +ENDIF(EMBED_MANIFESTS) + diff --git a/extra/CMakeLists.txt b/extra/CMakeLists.txt index a7a5e3e7b66..8608e72127b 100755 --- a/extra/CMakeLists.txt +++ b/extra/CMakeLists.txt @@ -12,6 +12,7 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake") SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") @@ -45,3 +46,9 @@ TARGET_LINK_LIBRARIES(perror strings mysys dbug wsock32) ADD_EXECUTABLE(replace replace.c) TARGET_LINK_LIBRARIES(replace strings mysys dbug wsock32) + +IF(EMBED_MANIFESTS) + MYSQL_EMBED_MANIFEST("my_print_defaults" "asInvoker") + MYSQL_EMBED_MANIFEST("perror" "asInvoker") + MYSQL_EMBED_MANIFEST("replace" "asInvoker") +ENDIF(EMBED_MANIFESTS) diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt index db4368a3534..647f6bd5e33 100755 --- a/libmysql/CMakeLists.txt +++ b/libmysql/CMakeLists.txt @@ -12,6 +12,7 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake") # Need to set USE_TLS, since __declspec(thread) approach to thread local # storage does not work properly in DLLs. @@ -67,3 +68,7 @@ TARGET_LINK_LIBRARIES(libmysql mysys strings wsock32) ADD_EXECUTABLE(myTest mytest.c) TARGET_LINK_LIBRARIES(myTest libmysql) + +IF(EMBED_MANIFESTS) + MYSQL_EMBED_MANIFEST("myTest" "asInvoker") +ENDIF(EMBED_MANIFESTS) diff --git a/myisam/CMakeLists.txt b/myisam/CMakeLists.txt index 28d06254e8a..94a7ffc9952 100755 --- a/myisam/CMakeLists.txt +++ b/myisam/CMakeLists.txt @@ -12,6 +12,7 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake") SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") @@ -39,3 +40,10 @@ TARGET_LINK_LIBRARIES(myisamlog myisam mysys dbug strings zlib wsock32) ADD_EXECUTABLE(myisampack myisampack.c) TARGET_LINK_LIBRARIES(myisampack myisam mysys dbug strings zlib wsock32) + +IF(EMBED_MANIFESTS) + MYSQL_EMBED_MANIFEST("myisam_ftdump" "asInvoker") + MYSQL_EMBED_MANIFEST("myisamchk" "asInvoker") + MYSQL_EMBED_MANIFEST("myisamlog" "asInvoker") + MYSQL_EMBED_MANIFEST("myisampack" "asInvoker") +ENDIF(EMBED_MANIFESTS) diff --git a/server-tools/instance-manager/CMakeLists.txt b/server-tools/instance-manager/CMakeLists.txt index 861c44e9f71..b7e2f08ff6e 100755 --- a/server-tools/instance-manager/CMakeLists.txt +++ b/server-tools/instance-manager/CMakeLists.txt @@ -12,6 +12,7 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake") SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") @@ -30,3 +31,7 @@ ADD_EXECUTABLE(mysqlmanager buffer.cc command.cc commands.cc guardian.cc instanc ADD_DEPENDENCIES(mysqlmanager GenError) TARGET_LINK_LIBRARIES(mysqlmanager dbug mysys strings taocrypt vio yassl zlib wsock32) + +IF(EMBED_MANIFESTS) + MYSQL_EMBED_MANIFEST("mysqlmanager" "asInvoker") +ENDIF(EMBED_MANIFESTS) diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 9058f9077d9..537a441925c 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -12,6 +12,7 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake") SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX -DUSE_SYMDIR /Zi") @@ -85,6 +86,10 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc TARGET_LINK_LIBRARIES(mysqld heap myisam myisammrg mysys yassl zlib dbug yassl taocrypt strings vio regex wsock32) +IF(EMBED_MANIFESTS) + MYSQL_EMBED_MANIFEST("mysqld" "requireAdministrator") +ENDIF(EMBED_MANIFESTS) + IF(WITH_EXAMPLE_STORAGE_ENGINE) TARGET_LINK_LIBRARIES(mysqld example) ENDIF(WITH_EXAMPLE_STORAGE_ENGINE) diff --git a/win/Makefile.am b/win/Makefile.am index b087675793b..c6632737d7b 100755 --- a/win/Makefile.am +++ b/win/Makefile.am @@ -14,7 +14,8 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## Process this file with automake to create Makefile.in -EXTRA_DIST = build-vs71.bat build-vs8.bat build-vs8_x64.bat configure.js README +EXTRA_DIST = build-vs71.bat build-vs8.bat build-vs8_x64.bat configure.js README \ + mysql_manifest.cmake create_manifest.js # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/win/README b/win/README index 871ae4efee7..118d619226a 100644 --- a/win/README +++ b/win/README @@ -50,6 +50,8 @@ The options right now are MYSQL_TCP_PORT= Server port, default 3306 DISABLE_GRANT_OPTIONS Disables the use of --init-file and --skip-grant-tables options of mysqld.exe + EMBED_MANIFESTS Embed custom manifests into final exes, otherwise VS + default will be used. So the command line could look like: diff --git a/win/configure.js b/win/configure.js index 3488efacba3..a2502d96b80 100755 --- a/win/configure.js +++ b/win/configure.js @@ -47,6 +47,7 @@ try case "WITH_PARTITION_STORAGE_ENGINE": case "__NT__": case "DISABLE_GRANT_OPTIONS": + case "EMBED_MANIFESTS": configfile.WriteLine("SET (" + args.Item(i) + " TRUE)"); break; case "MYSQL_SERVER_SUFFIX": From 7d4f14cbace270e9803870cb45249fbcba3cf1a0 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 30 Apr 2007 13:30:58 +0200 Subject: [PATCH 35/99] Makefile.am: fix typo win/Makefile.am: fix typo --- win/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/Makefile.am b/win/Makefile.am index c6632737d7b..89f0d65b528 100755 --- a/win/Makefile.am +++ b/win/Makefile.am @@ -14,7 +14,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## Process this file with automake to create Makefile.in -EXTRA_DIST = build-vs71.bat build-vs8.bat build-vs8_x64.bat configure.js README \ +EXTRA_DIST = build-vs71.bat build-vs8.bat build-vs8_x64.bat configure.js README \ mysql_manifest.cmake create_manifest.js # Don't update the files from bitkeeper From 297bb5d8b6e155757de53796eb6cecec995cbf97 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 30 Apr 2007 14:22:38 +0200 Subject: [PATCH 36/99] create_manifest.js, mysql_manifest.cmake: add files for patch win/create_manifest.js: add files for patch win/mysql_manifest.cmake: add files for patch --- win/create_manifest.js | 85 ++++++++++++++++++++++++++++++++++++++++ win/mysql_manifest.cmake | 20 ++++++++++ 2 files changed, 105 insertions(+) create mode 100644 win/create_manifest.js create mode 100644 win/mysql_manifest.cmake diff --git a/win/create_manifest.js b/win/create_manifest.js new file mode 100644 index 00000000000..5605f57ef74 --- /dev/null +++ b/win/create_manifest.js @@ -0,0 +1,85 @@ +/* + manifest.js - Writes a custom XML manifest for each executable/library + 6 command line options must be supplied: + name - Name of the executable/library into which the mainfest will be + embedded. + version - Version of the executable + arch - Architecture intended. + type - Application type. + exe_level - Application execution level. + [asInvoker|highestAvailable|requireAdministrator] + outfile - Final destination where mainfest will be written. + + Example: + cscript manifest.js name=mysql version=5.0.32 arch=X86 type=win32 + exe_level=asInvoker outfile=out.xml +*/ + +try +{ + var args = WScript.Arguments + for (i=0; i < args.Count(); i++) + { + var parts = args.Item(i).split('='); + switch (parts[0]) + { + case "name": + var app_name= parts[1]; + break; + case "version": + var app_version= parts[1]; + break; + case "arch": + var app_arch= parts[1]; + break; + case "type": + var app_type= parts[1]; + break; + case "exe_level": + var app_exe_level= parts[1]; + break; + case "outfile": + var manifest_file= parts[1]; + break; + default: + WScript.echo("Invalid argument supplied."); + } + } + if (i != 6) + throw new Error(1, "Incorrect number of arguments."); + + var manifest_xml= "\r\n"; + manifest_xml+= "\r\n"; + // Identify the application security requirements. + manifest_xml+= "\t\r\n"; + manifest_xml+= "\t\t\r\n\t\t\t\r\n\t\t\t\t"; + manifest_xml+= " Date: Fri, 4 May 2007 09:46:33 +0200 Subject: [PATCH 37/99] backport a manifest fix CMakeLists.txt: backported fix --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9cde3e222ec..11f9100b7ad 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,6 +150,11 @@ IF(EMBED_MANIFESTS) # Disable automatic manifest generation. STRING(REPLACE "/MANIFEST" "/MANIFEST:NO" CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS}) + # Explicitly disable it since it is the default for newer versions of VS + STRING(REGEX MATCH "MANIFEST:NO" tmp_manifest ${CMAKE_EXE_LINKER_FLAGS}) + IF(NOT tmp_manifest) + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO") + ENDIF(tmp_manifest) # Set the processor architecture. IF(CMAKE_GENERATOR MATCHES "Visual Studio 8 2005 Win64") SET(PROCESSOR_ARCH "X64") From 7f2881c9f248e4e9814359d9ab8a07de45aa3c95 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 7 May 2007 08:25:47 +0200 Subject: [PATCH 38/99] specfile fixes --- support-files/mysql.spec.sh | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index accf0f1d201..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 @@ -540,7 +545,7 @@ fi %doc %attr(644, root, man) %{_mandir}/man1/mysqld_multi.1* %doc %attr(644, root, man) %{_mandir}/man1/mysqld_safe.1* %doc %attr(644, root, man) %{_mandir}/man1/mysql_fix_privilege_tables.1* -%doc %attr(644, root, man) %{_mandir}/man1/mysql_install_db.1 +%doc %attr(644, root, man) %{_mandir}/man1/mysql_install_db.1* %doc %attr(644, root, man) %{_mandir}/man1/mysql_upgrade.1* %doc %attr(644, root, man) %{_mandir}/man1/mysqlhotcopy.1* %doc %attr(644, root, man) %{_mandir}/man1/mysqlman.1* From d29f4da4fcbd1284c1fec7722f651331c7606ef9 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 7 May 2007 19:48:11 +0200 Subject: [PATCH 39/99] raise version number --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 260c9a9f0fd..5184587f453 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.41) +AM_INIT_AUTOMAKE(mysql, 5.0.43) 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=41 +NDB_VERSION_BUILD=43 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From 358b942b20bf04a2393487b4dded9b60ac5a2ef7 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 2 Jul 2007 07:27:39 -0400 Subject: [PATCH 40/99] Unify profiling SHOW code and INFORMATION_SCHEMA code for profiling. Also, Bug#26938: profiling client hang if used before enabled In the SHOW command, not sending header data because we had no rows to send was a protocol violation. Porting the SHOW PROFILE command to use the Information Schema table avoids that problem. mysql-test/r/profiling.result: Add headers of pre-profile SHOW test. mysql-test/t/profiling.test: Verify that the protocol isn't violated if we ask for profiling info before profiling has recorded anything. sql/sql_parse.cc: Remove SQLCOM_SHOW_PROFILE and add a I_S schema table entry. sql/sql_profile.cc: Add SHOW column-names and a new function that takes profile options set in the parser and packs a list of selected fields from the I_S table implementation. sql/sql_profile.h: Remove unused functions and add a new function. sql/sql_show.cc: Add a pointer to the function that selects fields from I_S table for SHOW command. sql/sql_yacc.yy: Prepare an I_S table for SHOW PROFILE. sql/table.h: Rename to match the intention. --- mysql-test/r/profiling.result | 4 + mysql-test/t/profiling.test | 5 + sql/sql_parse.cc | 26 +-- sql/sql_profile.cc | 348 ++++++++++------------------------ sql/sql_profile.h | 7 +- sql/sql_show.cc | 3 +- sql/sql_yacc.yy | 8 +- sql/table.h | 2 +- 8 files changed, 124 insertions(+), 279 deletions(-) diff --git a/mysql-test/r/profiling.result b/mysql-test/r/profiling.result index 9f478d68b8d..b99870e3564 100644 --- a/mysql-test/r/profiling.result +++ b/mysql-test/r/profiling.result @@ -1,3 +1,7 @@ +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 diff --git a/mysql-test/t/profiling.test b/mysql-test/t/profiling.test index fd7562f6f16..960aa496731 100644 --- a/mysql-test/t/profiling.test +++ b/mysql-test/t/profiling.test @@ -1,3 +1,8 @@ +# 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; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 34702dce957..8c1d627c5f5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2315,6 +2315,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: @@ -2755,23 +2764,6 @@ mysql_execute_command(THD *thd) #else my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROFILES", "enable-profiling"); goto error; -#endif - break; - } - case SQLCOM_SHOW_PROFILE: - { -#ifdef ENABLED_PROFILING - thd->profiling.store(); - thd->profiling.discard(); // will get re-enabled by reset() - if (lex->profile_query_id != 0) - res= thd->profiling.show(lex->profile_options, lex->profile_query_id); - else - res= thd->profiling.show_last(lex->profile_options); - if (res) - goto error; -#else - my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROFILE", "enable-profiling"); - goto error; #endif break; } diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 91b0b062e4f..fbb05a988c5 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -41,27 +41,77 @@ int fill_query_profile_statistics_info(THD *thd, struct st_table_list *tables, ST_FIELD_INFO query_profile_statistics_info[]= { /* name, length, type, value, maybe_null, old_name */ - {"QUERY_ID", 20, MYSQL_TYPE_LONG, 0, false, NULL}, - {"SEQ", 20, MYSQL_TYPE_LONG, 0, false, NULL}, - {"STATE", 30, MYSQL_TYPE_STRING, 0, false, NULL}, - {"DURATION", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, false, NULL}, - {"CPU_USER", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, - {"CPU_SYSTEM", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, - {"CONTEXT_VOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"CONTEXT_INVOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"BLOCK_OPS_IN", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"BLOCK_OPS_OUT", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"MESSAGES_SENT", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"MESSAGES_RECEIVED", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"PAGE_FAULTS_MAJOR", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"PAGE_FAULTS_MINOR", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"SWAPS", 20, MYSQL_TYPE_LONG, 0, true, NULL}, - {"SOURCE_FUNCTION", 30, MYSQL_TYPE_STRING, 0, true, NULL}, - {"SOURCE_FILE", 20, MYSQL_TYPE_STRING, 0, true, NULL}, - {"SOURCE_LINE", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"QUERY_ID", 20, MYSQL_TYPE_LONG, 0, false, "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) @@ -242,212 +292,6 @@ void QUERY_PROFILE::reset() DBUG_VOID_RETURN; } -bool QUERY_PROFILE::show(uint options) -{ - THD *thd= profiling->thd; - List field_list; - DBUG_ENTER("QUERY_PROFILE::show"); - - field_list.push_back(new Item_empty_string("Status", MYSQL_ERRMSG_SIZE)); - field_list.push_back(new Item_return_int("Duration", TIME_FLOAT_DIGITS, - MYSQL_TYPE_DOUBLE)); - - if (options & PROFILE_CPU) - { - field_list.push_back(new Item_return_int("CPU_user", TIME_FLOAT_DIGITS, - MYSQL_TYPE_DOUBLE)); - field_list.push_back(new Item_return_int("CPU_system", TIME_FLOAT_DIGITS, - MYSQL_TYPE_DOUBLE)); - } - - if (options & PROFILE_MEMORY) - { - } - - if (options & PROFILE_CONTEXT) - { - field_list.push_back(new Item_return_int("Context_voluntary", 10, - MYSQL_TYPE_LONG)); - field_list.push_back(new Item_return_int("Context_involuntary", 10, - MYSQL_TYPE_LONG)); - } - - if (options & PROFILE_BLOCK_IO) - { - field_list.push_back(new Item_return_int("Block_ops_in", 10, - MYSQL_TYPE_LONG)); - field_list.push_back(new Item_return_int("Block_ops_out", 10, - MYSQL_TYPE_LONG)); - } - - if (options & PROFILE_IPC) - { - field_list.push_back(new Item_return_int("Messages_sent", 10, - MYSQL_TYPE_LONG)); - field_list.push_back(new Item_return_int("Messages_received", 10, - MYSQL_TYPE_LONG)); - } - - if (options & PROFILE_PAGE_FAULTS) - { - field_list.push_back(new Item_return_int("Page_faults_major", 10, - MYSQL_TYPE_LONG)); - field_list.push_back(new Item_return_int("Page_faults_minor", 10, - MYSQL_TYPE_LONG)); - } - - if (options & PROFILE_SWAPS) - { - field_list.push_back(new Item_return_int("Swaps", 10, MYSQL_TYPE_LONG)); - } - - if (options & PROFILE_SOURCE) - { - field_list.push_back(new Item_empty_string("Source_function", - MYSQL_ERRMSG_SIZE)); - field_list.push_back(new Item_empty_string("Source_file", - MYSQL_ERRMSG_SIZE)); - field_list.push_back(new Item_return_int("Source_line", 10, - MYSQL_TYPE_LONG)); - } - - if (thd->protocol->send_fields(&field_list, - Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) - DBUG_RETURN(TRUE); - - Protocol *protocol= thd->protocol; - SELECT_LEX *sel= &thd->lex->select_lex; - SELECT_LEX_UNIT *unit= &thd->lex->unit; - ha_rows idx= 0; - unit->set_limit(sel); - PROFILE_ENTRY *previous= &profile_start; - - PROFILE_ENTRY *entry; - void *iterator; - for (iterator= entries.new_iterator(); - iterator != NULL; - iterator= entries.iterator_next(iterator)) - { - entry= entries.iterator_value(iterator); - -#ifdef HAVE_GETRUSAGE - struct rusage *rusage= &(entry->rusage); -#endif - String elapsed; - - if (++idx <= unit->offset_limit_cnt) - continue; - if (idx > unit->select_limit_cnt) - break; - - protocol->prepare_for_resend(); - - /* - This entry, n, has a point in time, T(n), and a status phrase, S(n). The - status phrase S(n) describes the period of time that begins at T(n). The - previous status phrase S(n-1) describes the period of time that starts at - T(n-1) and ends at T(n). Since we want to describe the time that a status - phrase took T(n)-T(n-1), this line must describe the previous status. - */ - protocol->store(previous->status, strlen(previous->status), - system_charset_info); - protocol->store((double)(entry->time_usecs - - previous->time_usecs)/(1000.0*1000), - (uint32) TIME_FLOAT_DIGITS-1, &elapsed); - - if (options & PROFILE_CPU) - { -#ifdef HAVE_GETRUSAGE - String cpu_utime, cpu_stime; - protocol->store((double)(RUSAGE_DIFF_USEC(rusage->ru_utime, - previous->rusage.ru_utime))/(1000.0*1000), - (uint32) TIME_FLOAT_DIGITS-1, &cpu_utime); - protocol->store((double)(RUSAGE_DIFF_USEC(rusage->ru_stime, - previous->rusage.ru_stime))/(1000.0*1000), - (uint32) TIME_FLOAT_DIGITS-1, &cpu_stime); -#else - protocol->store_null(); - protocol->store_null(); -#endif - } - - if (options & PROFILE_CONTEXT) - { -#ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_nvcsw - previous->rusage.ru_nvcsw)); - protocol->store((uint32)(rusage->ru_nivcsw - previous->rusage.ru_nivcsw)); -#else - protocol->store_null(); - protocol->store_null(); -#endif - } - - if (options & PROFILE_BLOCK_IO) - { -#ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_inblock - previous->rusage.ru_inblock)); - protocol->store((uint32)(rusage->ru_oublock - previous->rusage.ru_oublock)); -#else - protocol->store_null(); - protocol->store_null(); -#endif - } - - if (options & PROFILE_IPC) - { -#ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_msgsnd - previous->rusage.ru_msgsnd)); - protocol->store((uint32)(rusage->ru_msgrcv - previous->rusage.ru_msgrcv)); -#else - protocol->store_null(); - protocol->store_null(); -#endif - } - - if (options & PROFILE_PAGE_FAULTS) - { -#ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_majflt - previous->rusage.ru_majflt)); - protocol->store((uint32)(rusage->ru_minflt - previous->rusage.ru_minflt)); -#else - protocol->store_null(); - protocol->store_null(); -#endif - } - - if (options & PROFILE_SWAPS) - { -#ifdef HAVE_GETRUSAGE - protocol->store((uint32)(rusage->ru_nswap - previous->rusage.ru_nswap)); -#else - protocol->store_null(); -#endif - } - - if (options & PROFILE_SOURCE) - { - if ((entry->function != NULL) && (entry->file != NULL)) - { - protocol->store(entry->function, strlen(entry->function), - system_charset_info); - protocol->store(entry->file, strlen(entry->file), system_charset_info); - protocol->store((uint32) entry->line); - } else { - protocol->store_null(); - protocol->store_null(); - protocol->store_null(); - } - } - - if (protocol->write()) - DBUG_RETURN(TRUE); - - previous= entry; - } - send_eof(thd); - DBUG_RETURN(FALSE); -} - PROFILING::PROFILING() :profile_id_counter(1), keeping(TRUE), enabled(FALSE), current(NULL), last(NULL) { @@ -630,38 +474,11 @@ void PROFILING::set_query_source(char *query_source_arg, uint query_length_arg) DBUG_VOID_RETURN; } -bool PROFILING::show(uint options, uint profiling_query_id) -{ - DBUG_ENTER("PROFILING::show"); - QUERY_PROFILE *prof; - - void *iterator; - for (iterator= history.new_iterator(); - iterator != NULL; - iterator= history.iterator_next(iterator)) - { - prof= history.iterator_value(iterator); - - if(prof->profiling_query_id == profiling_query_id) - DBUG_RETURN(prof->show(options)); - } - - my_error(ER_WRONG_ARGUMENTS, MYF(0), "SHOW PROFILE"); - DBUG_RETURN(TRUE); -} - -bool PROFILING::show_last(uint options) -{ - DBUG_ENTER("PROFILING::show_last"); - if (!history.is_empty()) { - DBUG_RETURN(last->show(options)); - } - DBUG_RETURN(TRUE); -} - /** 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) { @@ -696,6 +513,31 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item { 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); diff --git a/sql/sql_profile.h b/sql/sql_profile.h index b82b5ce090c..56022de0dcc 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -39,6 +39,7 @@ extern const char * const _unknown_func_; 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 @@ -332,12 +333,6 @@ public: /* SHOW PROFILES */ bool show_profiles(); - /* SHOW PROFILE FOR QUERY query_id */ - bool show(uint options, uint profiling_query_id); - - /* SHOW PROFILE */ - bool show_last(uint options); - /* ... from INFORMATION_SCHEMA.PROFILING ... */ int fill_statistics_info(THD *thd, struct st_table_list *tables, Item *cond); }; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index c59e2845c14..a26c3b41fcb 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4344,7 +4344,8 @@ ST_SCHEMA_TABLE schema_tables[]= {"OPEN_TABLES", open_tables_fields_info, create_schema_table, fill_open_tables, make_old_format, 0, -1, -1, 1}, {"PROFILING", query_profile_statistics_info, create_schema_table, - fill_query_profile_statistics_info, NULL, NULL, -1, -1, false}, + 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_yacc.yy b/sql/sql_yacc.yy index 54a6a6dc462..6cff3090da3 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7044,7 +7044,13 @@ show_param: | PROFILES_SYM { Lex->sql_command = SQLCOM_SHOW_PROFILES; } | PROFILE_SYM opt_profile_defs opt_profile_args opt_limit_clause_init - { Lex->sql_command = SQLCOM_SHOW_PROFILE; } + { + 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; diff --git a/sql/table.h b/sql/table.h index 9dbdbeb7264..c982eb90cd5 100644 --- a/sql/table.h +++ b/sql/table.h @@ -320,7 +320,7 @@ enum enum_schema_tables SCH_COLUMN_PRIVILEGES, SCH_KEY_COLUMN_USAGE, SCH_OPEN_TABLES, - SCH_PROFILING, + SCH_PROFILES, SCH_PROCEDURES, SCH_SCHEMATA, SCH_SCHEMA_PRIVILEGES, From ae5c3bf81703bc98ca2c6463c7a85e25f8626360 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 2 Jul 2007 12:29:07 -0400 Subject: [PATCH 41/99] Merge fix-up. BitKeeper/deleted/.del-create_manifest.js: Delete: win/create_manifest.js BitKeeper/deleted/.del-mysql_manifest.cmake: Delete: win/mysql_manifest.cmake mysql-test/r/information_schema.result: Move the test down. --- mysql-test/r/information_schema.result | 14 +++++++------- win/mysql_manifest.cmake | 0 2 files changed, 7 insertions(+), 7 deletions(-) mode change 100644 => 100755 win/mysql_manifest.cmake diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index aff0ba94f13..62b81ea260c 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1319,6 +1319,13 @@ TABLE_PRIVILEGES information_schema.TABLE_PRIVILEGES 1 TRIGGERS information_schema.TRIGGERS 1 USER_PRIVILEGES information_schema.USER_PRIVILEGES 1 VIEWS information_schema.VIEWS 1 +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 # create table t1(f1 int); create view v1 as select f1+1 as a from t1; create table t2 (f1 int, f2 int); @@ -1330,10 +1337,3 @@ 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/win/mysql_manifest.cmake b/win/mysql_manifest.cmake old mode 100644 new mode 100755 From 83e4f46e4bb0f304878f4a87bf20d5f595bc30e3 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Jul 2007 11:25:32 -0400 Subject: [PATCH 42/99] Avoid a warning on windows about a missing case enum. sql/sql_parse.cc: Avoid a warning on windows. --- sql/sql_parse.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 9b0fce13678..17ae8fee0ea 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5502,6 +5502,7 @@ static bool check_show_access(THD *thd, TABLE_LIST *table) case SCH_COLUMN_PRIVILEGES: case SCH_TABLE_CONSTRAINTS: case SCH_KEY_COLUMN_USAGE: + case SCH_PROFILES: break; } From fd70537309701acc51a0f92ac46e495363221e07 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Jul 2007 12:20:19 -0400 Subject: [PATCH 43/99] In 5.0, Field_double::val_str uses "%g" to render floating point numbers, which uses "X.YeZ" notation when the exponent Z would be less than -4. That behavior at -4 is not exactly what we want, and our Decimal type offers smarter number representation. By changing profiling to use Decimal types, we get more readable output. sql/sql_profile.cc: Change the DOUBLE I_S types to DECIMAL, so we get a smarter floating-point number renderer. sql/sql_show.cc: Add MYSQL_TYPE_DECIMAL as a string-ish type that INFORMATION_SCHEMA tables may use. --- sql/sql_profile.cc | 35 +++++++++++++++++++++++++---------- sql/sql_show.cc | 11 +++++++++-- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index fbb05a988c5..d4e3568f592 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -44,9 +44,9 @@ ST_FIELD_INFO query_profile_statistics_info[]= {"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"}, + {"DURATION", TIME_FLOAT_DIGITS, MYSQL_TYPE_DECIMAL, 0, false, "Duration"}, + {"CPU_USER", TIME_FLOAT_DIGITS, MYSQL_TYPE_DECIMAL, 0, true, "CPU_user"}, + {"CPU_SYSTEM", TIME_FLOAT_DIGITS, MYSQL_TYPE_DECIMAL, 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"}, @@ -557,16 +557,31 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item */ 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)); + + my_decimal duration; + double2my_decimal(E_DEC_FATAL_ERROR, + (entry->time_usecs-previous->time_usecs)/(1000.0*1000), + &duration); + table->field[3]->store_decimal(&duration); #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)); + my_decimal cpu_utime, cpu_stime; + double2my_decimal(E_DEC_FATAL_ERROR, + RUSAGE_DIFF_USEC(entry->rusage.ru_utime, + previous->rusage.ru_utime) / + (1000.0*1000), + &cpu_utime); + + double2my_decimal(E_DEC_FATAL_ERROR, + RUSAGE_DIFF_USEC(entry->rusage.ru_stime, + previous->rusage.ru_stime) / + (1000.0*1000), + &cpu_stime); + + table->field[4]->store_decimal(&cpu_utime); + table->field[5]->store_decimal(&cpu_stime); + table->field[4]->set_notnull(); table->field[5]->set_notnull(); #else /* TODO: Add CPU-usage info for non-BSD systems */ diff --git a/sql/sql_show.cc b/sql/sql_show.cc index d37fb3fb6a9..e1e332ff03d 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3657,11 +3657,18 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) fields_info->field_length)) == NULL) DBUG_RETURN(NULL); break; + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_STRING: default: /* Don't let unimplemented types pass through. Could be a grave error. */ - DBUG_ASSERT(fields_info->field_type == MYSQL_TYPE_STRING); + DBUG_ASSERT(fields_info->field_type == MYSQL_TYPE_STRING || + fields_info->field_type == MYSQL_TYPE_DECIMAL); - /* this should be changed when Item_empty_string is fixed(in 4.1) */ + /** + @todo Change when Item_empty_string is fixed (in 4.1). [Presumably, + this means removing the first of two steps: setting a useless, bogus + value; and then setting the attributes.] + */ if (!(item= new Item_empty_string("", 0, cs))) { DBUG_RETURN(0); From 5008a4e720a9ccd6ae82e9ce5f97f71727c463eb Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 4 Oct 2007 10:35:09 -0400 Subject: [PATCH 44/99] Track typedef'd struct. Name changed in Enterprise tree, but community-exclusive file also referred to struct. sql/sql_profile.cc: Track typedef'd struct. sql/sql_profile.h: Track typedef'd struct. --- sql/sql_profile.cc | 4 ++-- sql/sql_profile.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index d4e3568f592..30bedcfc813 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -28,7 +28,7 @@ const char * const _unknown_func_ = ""; /** Connects Information_Schema and Profiling. */ -int fill_query_profile_statistics_info(THD *thd, struct st_table_list *tables, +int fill_query_profile_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) { #ifdef ENABLED_PROFILING @@ -480,7 +480,7 @@ void PROFILING::set_query_source(char *query_source_arg, uint query_length_arg) 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) +int PROFILING::fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) { DBUG_ENTER("PROFILING::fill_statistics_info"); TABLE *table= tables->table; diff --git a/sql/sql_profile.h b/sql/sql_profile.h index 56022de0dcc..5a28bc32442 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -38,7 +38,7 @@ 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 fill_query_profile_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond); int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table); @@ -334,7 +334,7 @@ public: bool show_profiles(); /* ... from INFORMATION_SCHEMA.PROFILING ... */ - int fill_statistics_info(THD *thd, struct st_table_list *tables, Item *cond); + int fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond); }; # endif /* HAVE_PROFILING */ From e9f437dbcd39ca7f6bd5e50153577f998e25a7b2 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 10 Oct 2007 08:19:01 -0400 Subject: [PATCH 45/99] Bug#27433: Parser error for MySQL 5.0.37 with Bison 1.75 for \ sql_yacc.yy Yacc rules lacked semicolons to terminate rules, which is illegal in old versions of bison. Added semicolons. sql/sql_yacc.yy: Add semicolons to terminate rules. --- sql/sql_yacc.yy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 21eb7cbc14c..9952cc7e659 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6900,11 +6900,11 @@ opt_table_sym: opt_profile_defs: /* empty */ - | profile_defs + | profile_defs; profile_defs: profile_def - | profile_defs ',' profile_def + | profile_defs ',' profile_def; profile_def: CPU_SYM From c1a36d80ef50b7cd23da893a08e7610d9e9dd02e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 14 Nov 2007 15:11:58 -0500 Subject: [PATCH 46/99] Push history-limiting code until after the code that adds new history entries. Lazy deletion isn't smart or useful here. Backport from 5.1 . include/my_sys.h: Prepare for rename in 5.1. mysql-test/r/profiling.result: Backport tests from 5.1. mysql-test/t/profiling.test: Backport tests from 5.1. sql/mysql_priv.h: Backport changes from 5.1 . sql/sp_head.cc: Backport changes from 5.1 . sql/sql_class.cc: Backport changes from 5.1 . sql/sql_parse.cc: Backport changes from 5.1 . sql/sql_profile.cc: Push history-limiting code until after the code that adds new history entries. Lazy deletion isn't smart or useful here. Correct for 5.0 member existance and execution. sql/sql_profile.h: Backport changes from 5.1 . sql/sql_show.cc: Backport changes from 5.1 . --- include/my_sys.h | 1 + mysql-test/r/profiling.result | 47 ++++ mysql-test/t/profiling.test | 66 +++++- sql/mysql_priv.h | 14 ++ sql/sp_head.cc | 29 +++ sql/sql_class.cc | 14 ++ sql/sql_parse.cc | 44 +++- sql/sql_profile.cc | 429 +++++++++++++++++----------------- sql/sql_profile.h | 82 ++----- sql/sql_show.cc | 21 ++ 10 files changed, 464 insertions(+), 283 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index 7df2718c7b1..5bfd43d41ef 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -162,6 +162,7 @@ extern char *my_strdup_with_length(const char *from, uint length, #define ORIG_CALLER_INFO /* nothing */ #define TRASH(A,B) /* nothing */ #endif +#define my_strndup(A,B,C) my_strdup_with_length((A), (B), (C)) #ifdef HAVE_LARGE_PAGES extern uint my_get_large_page_size(void); diff --git a/mysql-test/r/profiling.result b/mysql-test/r/profiling.result index b99870e3564..a9ada576b4b 100644 --- a/mysql-test/r/profiling.result +++ b/mysql-test/r/profiling.result @@ -300,6 +300,53 @@ id select @@profiling; @@profiling 1 +set session profiling = OFF; +drop table if exists profile_log; +Warnings: +Note 1051 Unknown table 'profile_log' +create table profile_log (how_many int); +drop procedure if exists p1; +drop procedure if exists p2; +drop procedure if exists p3; +create procedure p1 () +modifies sql data +begin +set profiling = ON; +select 'This p1 should show up in profiling'; +insert into profile_log select count(*) from information_schema.profiling; +end// +create procedure p2() +deterministic +begin +set profiling = ON; +call p1(); +select 'This p2 should show up in profiling'; +end// +create procedure p3 () +reads sql data +begin +set profiling = ON; +select 'This p3 should show up in profiling'; +show profile; +end// +first call to p1 +call p1; +select * from profile_log; +second call to p1 +call p1; +select * from profile_log; +third call to p1 +call p1; +select * from profile_log; +set session profiling = OFF; +call p2; +set session profiling = OFF; +call p3; +show profiles; +drop procedure if exists p1; +drop procedure if exists p2; +drop procedure if exists p3; +drop table if exists profile_log; set session profiling = ON; drop table if exists t2; create table t2 (id int not null); diff --git a/mysql-test/t/profiling.test b/mysql-test/t/profiling.test index 960aa496731..ffd38caf781 100644 --- a/mysql-test/t/profiling.test +++ b/mysql-test/t/profiling.test @@ -136,7 +136,7 @@ show profiles; ## Verify that the various juggling of THD contexts doesn't affect profiling. -## Functions +## Functions and procedures set session profiling = ON; select @@profiling; create function f1() returns varchar(50) return 'hello'; @@ -144,6 +144,64 @@ select @@profiling; select * from t1 where id <> f1(); select @@profiling; +set session profiling = OFF; +drop table if exists profile_log; +create table profile_log (how_many int); + +--disable_warnings +drop procedure if exists p1; +drop procedure if exists p2; +drop procedure if exists p3; +--enable_warnings + +delimiter //; +create procedure p1 () + modifies sql data +begin + set profiling = ON; + select 'This p1 should show up in profiling'; + insert into profile_log select count(*) from information_schema.profiling; +end// +create procedure p2() + deterministic +begin + set profiling = ON; + call p1(); + select 'This p2 should show up in profiling'; +end// +create procedure p3 () + reads sql data +begin + set profiling = ON; + select 'This p3 should show up in profiling'; + show profile; +end// +delimiter ;// + +--disable_result_log +--echo first call to p1 +call p1; +select * from profile_log; +--echo second call to p1 +call p1; +select * from profile_log; +--echo third call to p1 +call p1; +select * from profile_log; +set session profiling = OFF; +call p2; +set session profiling = OFF; +call p3; + +--replace_column 1 # 2 # +show profiles; +--enable_result_log + +drop procedure if exists p1; +drop procedure if exists p2; +drop procedure if exists p3; +drop table if exists profile_log; + ## Triggers set session profiling = ON; drop table if exists t2; @@ -193,6 +251,12 @@ drop table if exists t1, t2, t3; drop view if exists v1; drop function if exists f1; +## Multiple queries in one packet. Combo statements don't work with ps-proto. +#--eval select 1; select 2; select 3; +## two continuations, one starting +#select state from information_schema.profiling where seq=1 order by query_id desc limit 3; + + ## last thing in the file set session profiling = OFF; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 3482cfe9a70..20e4dacaded 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -495,6 +495,8 @@ enum enum_parsing_place struct st_table; class THD; +#define thd_proc_info(thd, msg) set_thd_proc_info(thd, msg, __func__, __FILE__, __LINE__) + /* Struct to handle simple linked lists */ typedef struct st_sql_list { @@ -580,6 +582,16 @@ typedef Comp_creator* (*chooser_compare_func_creator)(bool invert); #include "item.h" extern my_decimal decimal_zero; +/** + The meat of thd_proc_info(THD*, char*), a macro that packs the last + three calling-info parameters. +*/ +extern "C" +const char *set_thd_proc_info(THD *thd, const char *info, + const char *calling_func, + const char *calling_file, + const unsigned int calling_line); + /* sql_parse.cc */ void free_items(Item *item); void cleanup_items(Item *item); @@ -978,6 +990,8 @@ bool get_schema_tables_result(JOIN *join, enum enum_schema_table_state executed_place); enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table); +bool schema_table_store_record(THD *thd, TABLE *table); + #define is_schema_db(X) \ !my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.str, (X)) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index c659b222628..2c02b07206f 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1057,15 +1057,36 @@ sp_head::execute(THD *thd) */ thd->spcont->callers_arena= &backup_arena; +#if defined(ENABLED_PROFILING) + /* Discard the initial part of executing routines. */ + thd->profiling.discard_current_query(); +#endif do { sp_instr *i; uint hip; // Handler ip +#if defined(ENABLED_PROFILING) + /* + Treat each "instr" of a routine as discrete unit that could be profiled. + Profiling only records information for segments of code that set the + source of the query, and almost all kinds of instructions in s-p do not. + */ + thd->profiling.finish_current_query(); + thd->profiling.start_new_query("continuing inside routine"); +#endif + i = get_instr(ip); // Returns NULL when we're done. if (i == NULL) + { +#if defined(ENABLED_PROFILING) + thd->profiling.discard_current_query(); +#endif break; + } + DBUG_PRINT("execute", ("Instruction %u", ip)); + /* Don't change NOW() in FUNCTION or TRIGGER */ if (!thd->in_sub_stmt) thd->set_time(); // Make current_time() et al work @@ -1142,6 +1163,10 @@ sp_head::execute(THD *thd) } } while (!err_status && !thd->killed); +#if defined(ENABLED_PROFILING) + thd->profiling.finish_current_query(); + thd->profiling.start_new_query("tail end of routine"); +#endif thd->restore_active_arena(&execute_arena, &backup_arena); thd->spcont->pop_all_cursors(); // To avoid memory leaks after an error @@ -2539,6 +2564,10 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) query= thd->query; query_length= thd->query_length; +#if defined(ENABLED_PROFILING) + /* This s-p instr is profilable and will be captured. */ + thd->profiling.set_query_source(m_query.str, m_query.length); +#endif if (!(res= alloc_query(thd, m_query.str, m_query.length+1)) && !(res=subst_spvars(thd, this, &m_query))) { diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ebce723d577..a8725923624 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -165,6 +165,20 @@ Open_tables_state::Open_tables_state(ulong version_arg) reset_open_tables_state(); } +extern "C" +const char *set_thd_proc_info(THD *thd, const char *info, + const char *calling_function, + const char *calling_file, + const unsigned int calling_line) +{ + const char *old_info= thd->proc_info; + DBUG_PRINT("proc_info", ("%s:%d %s", calling_file, calling_line, info)); +#if defined(ENABLED_PROFILING) + thd->profiling.status_change(info, calling_function, calling_file, calling_line); +#endif + thd->proc_info= info; + return old_info; +} THD::THD() diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7e105689d22..e3166c07cbd 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1313,6 +1313,10 @@ pthread_handler_t handle_bootstrap(void *arg) thd->db_length+1+QUERY_CACHE_FLAGS_SIZE); thd->query[length] = '\0'; DBUG_PRINT("query",("%-.4096s",thd->query)); +#if defined(ENABLED_PROFILING) + thd->profiling.set_query_source(thd->query, length); +#endif + /* We don't need to obtain LOCK_thread_count here because in bootstrap mode we have only one thread. @@ -1522,6 +1526,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) bool do_command(THD *thd) { + bool return_value; char *packet= 0; ulong packet_length; NET *net= &thd->net; @@ -1545,7 +1550,12 @@ bool do_command(THD *thd) thd->clear_error(); // Clear error message net_new_transaction(net); - if ((packet_length=my_net_read(net)) == packet_error) + + packet_length= my_net_read(net); +#if defined(ENABLED_PROFILING) + thd->profiling.start_new_query(); +#endif + if (packet_length == packet_error) { DBUG_PRINT("info",("Got error %d reading command from socket %s", net->error, @@ -1554,11 +1564,13 @@ bool do_command(THD *thd) if (net->error != 3) { statistic_increment(aborted_threads,&LOCK_status); - DBUG_RETURN(TRUE); // We have to close it. + return_value= TRUE; // We have to close it. + goto out; } net_send_error(thd, net->last_errno, NullS); net->error= 0; - DBUG_RETURN(FALSE); + return_value= FALSE; + goto out; } else { @@ -1583,7 +1595,13 @@ bool do_command(THD *thd) command == packet[0] == COM_SLEEP). In dispatch_command packet[packet_length] points beyond the end of packet. */ - DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length)); + return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length)); + +out: +#if defined(ENABLED_PROFILING) + thd->profiling.finish_current_query(); +#endif + DBUG_RETURN(return_value); } #endif /* EMBEDDED_LIBRARY */ @@ -1805,6 +1823,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, mysql_log.write(thd,command, format, thd->query_length, thd->query); DBUG_PRINT("query",("%-.4096s",thd->query)); +#if defined(ENABLED_PROFILING) + thd->profiling.set_query_source(thd->query, thd->query_length); +#endif if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),QUERY_PRIOR); @@ -1831,6 +1852,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd, next_packet++; length--; } + +#if defined(ENABLED_PROFILING) + thd->profiling.finish_current_query(); + thd->profiling.start_new_query("continuing"); + thd->profiling.set_query_source(next_packet, length); +#endif + VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query_length= length; thd->query= next_packet; @@ -2325,7 +2353,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, wish to have SHOW commands show up in profiling. */ #ifdef ENABLED_PROFILING - thd->profiling.discard(); + thd->profiling.discard_current_query(); #endif break; case SCH_OPEN_TABLES: @@ -2762,8 +2790,7 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_PROFILES: { #ifdef ENABLED_PROFILING - thd->profiling.store(); - thd->profiling.discard(); + thd->profiling.discard_current_query(); res= thd->profiling.show_profiles(); if (res) goto error; @@ -5887,9 +5914,6 @@ 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; } diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 30bedcfc813..6ae70ab1d13 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -14,13 +14,29 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/** + @file + + Implement query profiling as as list of metaphorical fences, with one fence + per query, and each fencepost a change of thd->proc_info state (with a + snapshot of system statistics). When asked, we can then iterate over the + fenceposts and calculate the distance between them, to inform the user what + happened during a particular query or thd->proc_info state. + + User variables that inform profiling behavior: + - "profiling", boolean, session only, "Are queries profiled?" + - "profiling_history_size", integer, session + global, "Num queries stored?" +*/ + + #include "mysql_priv.h" #include "my_sys.h" #define TIME_FLOAT_DIGITS 9 -#define MAX_QUERY_LENGTH 300 +/** two vals encoded: (dec*100)+len */ +#define TIME_I_S_DECIMAL_SIZE (TIME_FLOAT_DIGITS*100)+(TIME_FLOAT_DIGITS-3) -bool schema_table_store_record(THD *thd, TABLE *table); +#define MAX_QUERY_LENGTH 300 /* Reserved for systems that can't record the function name in source. */ const char * const _unknown_func_ = ""; @@ -28,25 +44,26 @@ const char * const _unknown_func_ = ""; /** Connects Information_Schema and Profiling. */ -int fill_query_profile_statistics_info(THD *thd, TABLE_LIST *tables, +int fill_query_profile_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) { -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) return(thd->profiling.fill_statistics_info(thd, tables, cond)); #else + my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROFILE", "enable-profiling"); return(1); #endif } ST_FIELD_INFO query_profile_statistics_info[]= { - /* name, length, type, value, maybe_null, old_name */ + /* name, length, type, value, maybe_null, old_name, open_method */ {"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_DECIMAL, 0, false, "Duration"}, - {"CPU_USER", TIME_FLOAT_DIGITS, MYSQL_TYPE_DECIMAL, 0, true, "CPU_user"}, - {"CPU_SYSTEM", TIME_FLOAT_DIGITS, MYSQL_TYPE_DECIMAL, 0, true, "CPU_system"}, + {"DURATION", TIME_I_S_DECIMAL_SIZE, MYSQL_TYPE_DECIMAL, 0, false, "Duration"}, + {"CPU_USER", TIME_I_S_DECIMAL_SIZE, MYSQL_TYPE_DECIMAL, 0, true, "CPU_user"}, + {"CPU_SYSTEM", TIME_I_S_DECIMAL_SIZE, MYSQL_TYPE_DECIMAL, 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"}, @@ -59,7 +76,7 @@ ST_FIELD_INFO query_profile_statistics_info[]= {"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} + {NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL} }; @@ -112,45 +129,41 @@ int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table) } -#ifdef ENABLED_PROFILING +#if defined(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) +PROF_MEASUREMENT::PROF_MEASUREMENT(QUERY_PROFILE *profile_arg, const char + *status_arg) :profile(profile_arg) { collect(); - set_status(status_arg, NULL, NULL, 0); + set_label(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) +PROF_MEASUREMENT::PROF_MEASUREMENT(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); + set_label(status_arg, function_arg, file_arg, line_arg); } -PROFILE_ENTRY::~PROFILE_ENTRY() +PROF_MEASUREMENT::~PROF_MEASUREMENT() { 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) + +void PROF_MEASUREMENT::set_label(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; @@ -162,7 +175,7 @@ void PROFILE_ENTRY::set_status(const char *status_arg, const char *function_arg, 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); @@ -198,7 +211,15 @@ void PROFILE_ENTRY::set_status(const char *status_arg, const char *function_arg, line= line_arg; } -void PROFILE_ENTRY::collect() +/** + This updates the statistics for this moment of time. It captures the state + of the running system, so later we can compare points in time and infer what + happened in the mean time. It should only be called immediately upon + instantiation of this PROF_MEASUREMENT. + + @todo Implement resource capture for OSes not like BSD. +*/ +void PROF_MEASUREMENT::collect() { time_usecs= (double) my_getsystime() / 10.0; /* 1 sec was 1e7, now is 1e6 */ #ifdef HAVE_GETRUSAGE @@ -206,28 +227,13 @@ void PROFILE_ENTRY::collect() #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) + +QUERY_PROFILE::QUERY_PROFILE(PROFILING *profiling_arg, const char *status_arg) + :profiling(profiling_arg), 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)); + profile_start= new PROF_MEASUREMENT(this, status_arg); + entries.push_back(profile_start); + profile_end= profile_start; } QUERY_PROFILE::~QUERY_PROFILE() @@ -239,61 +245,44 @@ QUERY_PROFILE::~QUERY_PROFILE() 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) +/** + @todo Provide a way to include the full text, as in SHOW PROCESSLIST. +*/ +void QUERY_PROFILE::set_query_source(char *query_source_arg, + uint query_length_arg) { - THD *thd= profiling->thd; - PROFILE_ENTRY *prof; + /* Truncate to avoid DoS attacks. */ + uint length= min(MAX_QUERY_LENGTH, query_length_arg); + + DBUG_ASSERT(query_source == NULL); /* we don't leak memory */ + if (query_source_arg != NULL) + query_source= my_strndup(query_source_arg, length, MYF(0)); +} + +void QUERY_PROFILE::new_status(const char *status_arg, + const char *function_arg, const char *file_arg, + unsigned int line_arg) +{ + PROF_MEASUREMENT *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; + DBUG_ASSERT(status_arg != NULL); - /* 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; - } + if ((function_arg != NULL) && (file_arg != NULL)) + prof= new PROF_MEASUREMENT(this, status_arg, function_arg, file_arg, line_arg); + else + prof= new PROF_MEASUREMENT(this, status_arg); - /* 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); - } + profile_end= prof; + 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) + :profile_id_counter(1), current(NULL), last(NULL) { } @@ -306,95 +295,110 @@ PROFILING::~PROFILING() delete current; } +/** + A new state is given, and that signals the profiler to start a new + timed step for the current query's profile. + + @param status_arg name of this step + @param function_arg calling function (usually supplied from compiler) + @param function_arg calling file (usually supplied from compiler) + @param function_arg calling line number (usually supplied from compiler) +*/ 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 (status_arg == NULL) /* We don't know how to handle that */ + DBUG_VOID_RETURN; + + if (current == NULL) /* This profile was already discarded. */ + DBUG_VOID_RETURN; + if (unlikely(enabled)) - { - if (unlikely(current == NULL)) - reset(); + current->new_status(status_arg, function_arg, file_arg, line_arg); - 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"); +/** + Prepare to start processing a new query. It is an error to do this + if there's a query already in process; nesting is not supported. - /* Already stored */ - if (unlikely((last != NULL) && - (current != NULL) && - (last->server_query_id == current->server_query_id))) + @param initial_state (optional) name of period before first state change +*/ +void PROFILING::start_new_query(const char *initial_state) +{ + DBUG_ENTER("PROFILING::start_new_query"); + + /* This should never happen unless the server is radically altered. */ + if (unlikely(current != NULL)) { - DBUG_VOID_RETURN; + DBUG_PRINT("warning", ("profiling code was asked to start a new query " + "before the old query was finished. This is " + "probably a bug.")); + finish_current_query(); } - while (history.elements > thd->variables.profiling_history_size) - delete history.pop(); + enabled= (((thd)->options & OPTION_PROFILING) != 0); - if (likely(((thd)->options & OPTION_PROFILING) == 0)) - DBUG_VOID_RETURN; + if (! enabled) DBUG_VOID_RETURN; + DBUG_ASSERT(current == NULL); + current= new QUERY_PROFILE(this, initial_state); + + DBUG_VOID_RETURN; +} + +/** + Throw away the current profile, because it's useless or unwanted + or corrupted. +*/ +void PROFILING::discard_current_query() +{ + DBUG_ENTER("PROFILING::discard_current_profile"); + + delete current; + current= NULL; + + DBUG_VOID_RETURN; +} + +/** + Try to save the current profile entry, clean up the data if it shouldn't be + saved, and maintain the profile history size. Naturally, this may not + succeed if the profile was previously discarded, and that's expected. +*/ +void PROFILING::finish_current_query() +{ + DBUG_ENTER("PROFILING::finish_current_profile"); 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())) + /* The last fence-post, so we can support the span before this. */ + status_change("ending", NULL, NULL, 0); + + if ((enabled) && /* ON at start? */ + ((thd->options & OPTION_PROFILING) != 0) && /* and ON at end? */ + (current->query_source != NULL) && + (! 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); + last= current; /* never contains something that is not in the history. */ 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(); + /* Maintain the history size. */ + while (history.elements > thd->variables.profiling_history_size) + delete history.pop(); DBUG_VOID_RETURN; } @@ -410,29 +414,29 @@ bool PROFILING::show_profiles() 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; + 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; + PROF_MEASUREMENT *ps= prof->profile_start; + PROF_MEASUREMENT *pe= prof->profile_end; if (++idx <= unit->offset_limit_cnt) continue; @@ -441,14 +445,14 @@ bool PROFILING::show_profiles() protocol->prepare_for_resend(); protocol->store((uint32)(prof->profiling_query_id)); - protocol->store((double)(pe->time_usecs - ps->time_usecs)/(1000.0*1000), + 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), + protocol->store(prof->query_source, strlen(prof->query_source), system_charset_info); else protocol->store_null(); - + if (protocol->write()) DBUG_RETURN(TRUE); } @@ -456,16 +460,18 @@ bool PROFILING::show_profiles() DBUG_RETURN(FALSE); } -/* - This is an awful hack to let prepared statements tell us the query - that they're executing. +/** + At a point in execution where we know the query source, save the text + of it in the query profile. + + This must be called exactly once per descrete statement. */ 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 (! enabled) + DBUG_VOID_RETURN; if (current != NULL) current->set_query_source(query_source_arg, query_length_arg); @@ -474,11 +480,10 @@ void PROFILING::set_query_source(char *query_source_arg, uint query_length_arg) 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. + schema, and a SHOW command. */ int PROFILING::fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) { @@ -489,12 +494,11 @@ int PROFILING::fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) 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; + 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 @@ -504,18 +508,21 @@ int PROFILING::fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) ulonglong seq; void *entry_iterator; - PROFILE_ENTRY *entry; + PROF_MEASUREMENT *entry, *previous= NULL; /* ...and for each query, go through all its state-change steps. */ - for (seq= 0, entry_iterator= query->entries.new_iterator(); - entry_iterator != NULL; + 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); + /* Skip the first. We count spans of fence, not fence-posts. */ + if (previous == NULL) continue; + 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 @@ -555,43 +562,46 @@ int PROFILING::fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) 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), + table->field[2]->store(previous->status, strlen(previous->status), system_charset_info); - my_decimal duration; - double2my_decimal(E_DEC_FATAL_ERROR, + my_decimal duration_decimal; + double2my_decimal(E_DEC_FATAL_ERROR, (entry->time_usecs-previous->time_usecs)/(1000.0*1000), - &duration); - table->field[3]->store_decimal(&duration); + &duration_decimal); + + table->field[3]->store_decimal(&duration_decimal); + #ifdef HAVE_GETRUSAGE - my_decimal cpu_utime, cpu_stime; - double2my_decimal(E_DEC_FATAL_ERROR, - RUSAGE_DIFF_USEC(entry->rusage.ru_utime, + my_decimal cpu_utime_decimal, cpu_stime_decimal; + + double2my_decimal(E_DEC_FATAL_ERROR, + RUSAGE_DIFF_USEC(entry->rusage.ru_utime, previous->rusage.ru_utime) / (1000.0*1000), - &cpu_utime); + &cpu_utime_decimal); - double2my_decimal(E_DEC_FATAL_ERROR, + double2my_decimal(E_DEC_FATAL_ERROR, RUSAGE_DIFF_USEC(entry->rusage.ru_stime, - previous->rusage.ru_stime) / + previous->rusage.ru_stime) / (1000.0*1000), - &cpu_stime); + &cpu_stime_decimal); - table->field[4]->store_decimal(&cpu_utime); - table->field[5]->store_decimal(&cpu_stime); + table->field[4]->store_decimal(&cpu_utime_decimal); + table->field[5]->store_decimal(&cpu_stime_decimal); table->field[4]->set_notnull(); 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 - + 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 - + table->field[7]->store((uint32)(entry->rusage.ru_nivcsw - previous->rusage.ru_nivcsw)); table->field[7]->set_notnull(); #else @@ -599,32 +609,32 @@ int PROFILING::fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) #endif #ifdef HAVE_GETRUSAGE - table->field[8]->store((uint32)(entry->rusage.ru_inblock - + table->field[8]->store((uint32)(entry->rusage.ru_inblock - previous->rusage.ru_inblock)); table->field[8]->set_notnull(); - table->field[9]->store((uint32)(entry->rusage.ru_oublock - + 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 - + 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 - + 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 - + 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 - + table->field[13]->store((uint32)(entry->rusage.ru_minflt - previous->rusage.ru_minflt), true); table->field[13]->set_notnull(); #else @@ -632,21 +642,22 @@ int PROFILING::fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) #endif #ifdef HAVE_GETRUSAGE - table->field[14]->store((uint32)(entry->rusage.ru_nswap - + 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)) + + /* Emit the location that started this step, not that ended it. */ + if ((previous->function != NULL) && (previous->file != NULL)) { - table->field[15]->store(entry->function, strlen(entry->function), - system_charset_info); + table->field[15]->store(previous->function, strlen(previous->function), + system_charset_info); table->field[15]->set_notnull(); - table->field[16]->store(entry->file, strlen(entry->file), system_charset_info); + table->field[16]->store(previous->file, strlen(previous->file), system_charset_info); table->field[16]->set_notnull(); - table->field[17]->store(entry->line, true); + table->field[17]->store(previous->line, true); table->field[17]->set_notnull(); } diff --git a/sql/sql_profile.h b/sql/sql_profile.h index 5a28bc32442..022422fbb81 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -54,24 +54,7 @@ int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table); #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) - +#if defined(ENABLED_PROFILING) #include "mysql_priv.h" #ifdef HAVE_SYS_RESOURCE_H @@ -79,7 +62,7 @@ int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table); #endif -class PROFILE_ENTRY; +class PROF_MEASUREMENT; class QUERY_PROFILE; class PROFILING; @@ -193,7 +176,7 @@ public: /** A single entry in a single profile. */ -class PROFILE_ENTRY +class PROF_MEASUREMENT { private: friend class QUERY_PROFILE; @@ -212,22 +195,22 @@ private: double time_usecs; char *allocated_status_memory; - void set_status(const char *status_arg, const char *function_arg, + void set_label(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, + PROF_MEASUREMENT(); + PROF_MEASUREMENT(QUERY_PROFILE *profile_arg, const char *status_arg); + PROF_MEASUREMENT(QUERY_PROFILE *profile_arg, const char *status_arg, const char *function_arg, const char *file_arg, unsigned int line_arg); - ~PROFILE_ENTRY(); + ~PROF_MEASUREMENT(); void collect(); }; /** - The full profile for a single query, and includes multiple PROFILE_ENTRY + The full profile for a single query, and includes multiple PROF_MEASUREMENT objects. */ class QUERY_PROFILE @@ -237,21 +220,21 @@ private: 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 entries; + + PROF_MEASUREMENT *profile_start; + PROF_MEASUREMENT *profile_end; + Queue entries; - QUERY_PROFILE(PROFILING *profiling_arg, char *query_source_arg, uint query_length_arg); + QUERY_PROFILE(PROFILING *profiling_arg, const char *status_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, + void new_status(const char *status_arg, const char *function_arg, const char *file_arg, unsigned int line_arg); @@ -269,7 +252,7 @@ private: class PROFILING { private: - friend class PROFILE_ENTRY; + friend class PROF_MEASUREMENT; friend class QUERY_PROFILE; /* @@ -291,39 +274,12 @@ public: ~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(); + void start_new_query(const char *initial_state= "starting"); - /** - 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; }; + void discard_current_query(); - /** - Do we intend to keep the currently collected profile? - @see keep() - */ - inline void discard() { keeping= false; }; + void finish_current_query(); - /** - 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); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index cd5b537996d..1eb6838d98e 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3622,6 +3622,14 @@ ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx) /* Create information_schema table using schema_table data + @note + For MYSQL_TYPE_DECIMAL fields only, the field_length member has encoded + into it two numbers, based on modulus of base-10 numbers. In the ones + position is the number of decimals. Tens position is unused. In the + hundreds and thousands position is a two-digit decimal number representing + length. Encode this value with (decimals*100)+length , where + 0value, false))) + { + DBUG_RETURN(0); + } + item->decimals= fields_info->field_length%10; + item->max_length= (fields_info->field_length/100)%100; + if (item->unsigned_flag == 0) + item->max_length+= 1; + if (item->decimals > 0) + item->max_length+= 1; + item->set_name(fields_info->field_name, + strlen(fields_info->field_name), cs); + break; case MYSQL_TYPE_STRING: default: /* Don't let unimplemented types pass through. Could be a grave error. */ From f48c09e96faf73b032500b11385f25a780e22fa9 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 15 Nov 2007 10:00:39 +0100 Subject: [PATCH 47/99] Revert a premature version upgrade - this is 5.0.51 still. --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 64d02dd95d6..05a6620965b 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.53) +AM_INIT_AUTOMAKE(mysql, 5.0.51) AM_CONFIG_HEADER([include/config.h:config.h.in]) 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=53 +NDB_VERSION_BUILD=51 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From 0679860358d42f2e6bb4c018c982549b9a09586f Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 15 Nov 2007 10:55:47 +0100 Subject: [PATCH 48/99] BUG#32111 - Security Breach via DATA/INDEX DIRECORY and RENAME TABLE RENAME TABLE against a table with DATA/INDEX DIRECTORY overwrites the file to which the symlink points. This is security issue, because it is possible to create a table with some name in some non-system database and set DATA/INDEX DIRECTORY to mysql system database. Renaming this table to one of mysql system tables (e.g. user, host) would overwrite the system table. Return an error when the file to which the symlink points exist. (This is a copy of changeset 2007/11/06 18:09:33+04:00 svoj@mysql.com and its merge changesets on the way from 4.0 up to 5.0) mysql-test/r/symlink.result: A test case for BUG#32111, with after merge fix, and using proper variable. mysql-test/t/symlink.test: A test case for BUG#32111, with after merge fix, and using proper variable. mysys/my_symlink2.c: Return an error when the file to which the symlink points exist. --- mysql-test/r/symlink.result | 6 ++++++ mysql-test/t/symlink.test | 12 ++++++++++++ mysys/my_symlink2.c | 11 ++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/symlink.result b/mysql-test/r/symlink.result index 18299bf4298..833adbeb851 100644 --- a/mysql-test/r/symlink.result +++ b/mysql-test/r/symlink.result @@ -99,6 +99,12 @@ t1 CREATE TABLE `t1` ( `b` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +CREATE TABLE t1(a INT) +DATA DIRECTORY='TEST_DIR/master-data/mysql' +INDEX DIRECTORY='TEST_DIR/master-data/mysql'; +RENAME TABLE t1 TO user; +ERROR HY000: Can't create/write to file 'TEST_DIR/master-data/mysql/user.MYI' (Errcode: 17) +DROP TABLE t1; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/mysql-test/t/symlink.test b/mysql-test/t/symlink.test index 8c67a4c1048..7eaeaa00c0a 100644 --- a/mysql-test/t/symlink.test +++ b/mysql-test/t/symlink.test @@ -124,6 +124,18 @@ enable_query_log; show create table t1; drop table t1; +# +# BUG#32111 - Security Breach via DATA/INDEX DIRECORY and RENAME TABLE +# +--replace_result $MYSQLTEST_VARDIR TEST_DIR +eval CREATE TABLE t1(a INT) +DATA DIRECTORY='$MYSQLTEST_VARDIR/master-data/mysql' +INDEX DIRECTORY='$MYSQLTEST_VARDIR/master-data/mysql'; +--replace_result $MYSQLTEST_VARDIR TEST_DIR +--error 1 +RENAME TABLE t1 TO user; +DROP TABLE t1; + # # Test specifying DATA DIRECTORY that is the same as what would normally # have been chosen. (Bug #8707) diff --git a/mysys/my_symlink2.c b/mysys/my_symlink2.c index e2493874097..ee0a45cf93b 100644 --- a/mysys/my_symlink2.c +++ b/mysys/my_symlink2.c @@ -126,6 +126,7 @@ int my_rename_with_symlink(const char *from, const char *to, myf MyFlags) int was_symlink= (!my_disable_symlinks && !my_readlink(link_name, from, MYF(0))); int result=0; + int name_is_different; DBUG_ENTER("my_rename_with_symlink"); if (!was_symlink) @@ -134,6 +135,14 @@ int my_rename_with_symlink(const char *from, const char *to, myf MyFlags) /* Change filename that symlink pointed to */ strmov(tmp_name, to); fn_same(tmp_name,link_name,1); /* Copy dir */ + name_is_different= strcmp(link_name, tmp_name); + if (name_is_different && !access(tmp_name, F_OK)) + { + my_errno= EEXIST; + if (MyFlags & MY_WME) + my_error(EE_CANTCREATEFILE, MYF(0), tmp_name, EEXIST); + DBUG_RETURN(1); + } /* Create new symlink */ if (my_symlink(tmp_name, to, MyFlags)) @@ -145,7 +154,7 @@ int my_rename_with_symlink(const char *from, const char *to, myf MyFlags) the same basename and different directories. */ - if (strcmp(link_name, tmp_name) && my_rename(link_name, tmp_name, MyFlags)) + if (name_is_different && my_rename(link_name, tmp_name, MyFlags)) { int save_errno=my_errno; my_delete(to, MyFlags); /* Remove created symlink */ From f2a9ad42a83816aff0f536f8453f67d841798d27 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 15 Nov 2007 14:59:40 +0100 Subject: [PATCH 49/99] Prevent a sytax error in the top-level "Makefile". Makefile.am: Prevent a sytax error in the commercial package: Removing "debian" would have produced an empty continuation line, the autotools cannot deal with that. --- Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 66daff4bd68..3e706fee80c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,8 +33,7 @@ DIST_SUBDIRS = . include @docs_dirs@ zlib \ @thread_dirs@ pstack \ @sql_union_dirs@ scripts @man_dirs@ tests SSL\ BUILD netware os2 @libmysqld_dirs@ \ - @bench_dirs@ support-files @tools_dirs@ win \ - debian + @bench_dirs@ support-files @tools_dirs@ win debian # Run these targets before any others, also make part of clean target, # to make sure we create new links after a clean. From 18f49fdf3d0d3890e8b97923bbe257da959dcaa4 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 22 Nov 2007 14:10:18 +0400 Subject: [PATCH 50/99] Bug#32458 Test "mysqlcheck" fails, because "mysqlcheck --repair" changed output format update result file because of Bug#26976 changes mysql-test/r/mysqlcheck.result: update result file --- mysql-test/r/mysqlcheck.result | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result index 1c42b0060f7..207b6ec88df 100644 --- a/mysql-test/r/mysqlcheck.result +++ b/mysql-test/r/mysqlcheck.result @@ -49,7 +49,8 @@ insert into t_bug25347 values (1),(2),(3); flush tables; removing and creating d_bug25347.t_bug25347 -error : Incorrect file format 't_bug25347' +Error : Incorrect file format 't_bug25347' +error : Corrupt insert into t_bug25347 values (4),(5),(6); ERROR HY000: Incorrect file format 't_bug25347' d_bug25347.t_bug25347 From 7952ac489b22175c9fcd1448b4b6eda23792d858 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 6 Dec 2007 10:23:58 +0100 Subject: [PATCH 51/99] configure.in: Merged missing change in the 5.0 community repository, --without-server was not working if thread safe client was enabled (Bug#32898) configure.in: Merged missing change in the 5.0 community repository, --without-server was not working if thread safe client was enabled (Bug#32898) --- configure.in | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 05a6620965b..000bc69a967 100644 --- a/configure.in +++ b/configure.in @@ -2675,13 +2675,17 @@ 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" = "yes" -o "$THREAD_SAFE_CLIENT" != "no" +if test "$with_server" != "no" -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" From 6fd4c4042f1525fd7bdafb3a404b051b3ce1c87c Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Jan 2008 13:47:43 +0100 Subject: [PATCH 52/99] configure.in: adjust version number configure.in: adjust version number --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 05a6620965b..9eb20b3fa7d 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.51) +AM_INIT_AUTOMAKE(mysql, 5.0.51a) AM_CONFIG_HEADER([include/config.h:config.h.in]) PROTOCOL_VERSION=10 From 2a3ed87d545d7d126db394e40472adf7bd3d209c Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Jan 2008 15:15:11 +0100 Subject: [PATCH 53/99] template_instnt.cpp, yassl_imp.cpp, handshake.cpp: apply patch for bug#33814 extra/yassl/src/handshake.cpp: apply patch for bug#33814 extra/yassl/src/template_instnt.cpp: apply patch for bug#33814 extra/yassl/src/yassl_imp.cpp: apply patch for bug#33814 --- extra/yassl/src/handshake.cpp | 5 +++++ extra/yassl/src/template_instnt.cpp | 1 + extra/yassl/src/yassl_imp.cpp | 11 ++++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/extra/yassl/src/handshake.cpp b/extra/yassl/src/handshake.cpp index 1d5a95820bb..262b5cb3b8b 100644 --- a/extra/yassl/src/handshake.cpp +++ b/extra/yassl/src/handshake.cpp @@ -527,6 +527,11 @@ void ProcessOldClientHello(input_buffer& input, SSL& ssl) input.read(len, sizeof(len)); uint16 randomLen; ato16(len, randomLen); + if (ch.suite_len_ > MAX_SUITE_SZ || sessionLen > ID_LEN || + randomLen > RAN_LEN) { + ssl.SetError(bad_input); + return; + } int j = 0; for (uint16 i = 0; i < ch.suite_len_; i += 3) { diff --git a/extra/yassl/src/template_instnt.cpp b/extra/yassl/src/template_instnt.cpp index f82f7924359..fe3a251b865 100644 --- a/extra/yassl/src/template_instnt.cpp +++ b/extra/yassl/src/template_instnt.cpp @@ -101,6 +101,7 @@ template void ysArrayDelete(unsigned char*); template void ysArrayDelete(char*); template int min(int, int); +template uint16 min(uint16, uint16); template unsigned int min(unsigned int, unsigned int); template unsigned long min(unsigned long, unsigned long); } diff --git a/extra/yassl/src/yassl_imp.cpp b/extra/yassl/src/yassl_imp.cpp index 0bc95f64abc..b43d9c27355 100644 --- a/extra/yassl/src/yassl_imp.cpp +++ b/extra/yassl/src/yassl_imp.cpp @@ -621,6 +621,10 @@ void HandShakeHeader::Process(input_buffer& input, SSL& ssl) } uint len = c24to32(length_); + if (len > input.get_remaining()) { + ssl.SetError(bad_input); + return; + } hashHandShake(ssl, input, len); hs->set_length(len); @@ -1391,10 +1395,15 @@ input_buffer& operator>>(input_buffer& input, ClientHello& hello) // Suites byte tmp[2]; + uint16 len; tmp[0] = input[AUTO]; tmp[1] = input[AUTO]; - ato16(tmp, hello.suite_len_); + ato16(tmp, len); + + hello.suite_len_ = min(len, static_cast(MAX_SUITE_SZ)); input.read(hello.cipher_suites_, hello.suite_len_); + if (len > hello.suite_len_) // ignore extra suites + input.set_current(input.get_current() + len - hello.suite_len_); // Compression hello.comp_len_ = input[AUTO]; From fd8471363a704fbd4c76c836ede58c649de83818 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Jan 2008 15:19:32 +0100 Subject: [PATCH 54/99] mysqlcheck.result: fix test case - bug#32458 mysql-test/r/mysqlcheck.result: fix test case - bug#32458 --- mysql-test/r/mysqlcheck.result | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result index 1c42b0060f7..207b6ec88df 100644 --- a/mysql-test/r/mysqlcheck.result +++ b/mysql-test/r/mysqlcheck.result @@ -49,7 +49,8 @@ insert into t_bug25347 values (1),(2),(3); flush tables; removing and creating d_bug25347.t_bug25347 -error : Incorrect file format 't_bug25347' +Error : Incorrect file format 't_bug25347' +error : Corrupt insert into t_bug25347 values (4),(5),(6); ERROR HY000: Incorrect file format 't_bug25347' d_bug25347.t_bug25347 From 333447eb999c539a1d179ad3ddf02dbd91b03bbc Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Jan 2008 15:27:18 +0100 Subject: [PATCH 55/99] ha_federated.cc: patch for bug#29801 sql/ha_federated.cc: patch for bug#29801 --- sql/ha_federated.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index d8ffd6c55f8..4c15b13a5c9 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -2528,7 +2528,12 @@ int ha_federated::info(uint flag) status_query_string.length(0); result= mysql_store_result(mysql); - if (!result) + + /* + We're going to use fields num. 4, 12 and 13 of the resultset, + so make sure we have these fields. + */ + if (!result || (mysql_num_fields(result) < 14)) goto error; if (!mysql_num_rows(result)) From f1c8a588436d627911dc22363ad2523108795946 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Jan 2008 15:37:18 +0100 Subject: [PATCH 56/99] view_grant.result, view_grant.test, sql_view.cc: apply patch for bug#29908 mysql-test/r/view_grant.result: apply patch for bug#29908 mysql-test/t/view_grant.test: apply patch for bug#29908 sql/sql_view.cc: apply patch for bug#29908 --- mysql-test/r/view_grant.result | 51 ++++++++++++++++++++++++++++++++-- mysql-test/t/view_grant.test | 50 +++++++++++++++++++++++++++++++-- sql/sql_view.cc | 5 +--- 3 files changed, 97 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result index 0f9ce47dec6..eef61c65fb8 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -776,15 +776,60 @@ GRANT CREATE VIEW ON db26813.v2 TO u26813@localhost; GRANT DROP, CREATE VIEW ON db26813.v3 TO u26813@localhost; GRANT SELECT ON db26813.t1 TO u26813@localhost; ALTER VIEW v1 AS SELECT f2 FROM t1; -ERROR 42000: CREATE VIEW command denied to user 'u26813'@'localhost' for table 'v1' +ERROR 42000: Access denied; you need the SUPER privilege for this operation ALTER VIEW v2 AS SELECT f2 FROM t1; -ERROR 42000: DROP command denied to user 'u26813'@'localhost' for table 'v2' +ERROR 42000: Access denied; you need the SUPER privilege for this operation ALTER VIEW v3 AS SELECT f2 FROM t1; +ERROR 42000: Access denied; you need the SUPER privilege for this operation SHOW CREATE VIEW v3; View Create View -v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select `t1`.`f2` AS `f2` from `t1` +v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select `t1`.`f1` AS `f1` from `t1` DROP USER u26813@localhost; DROP DATABASE db26813; +# +# Bug#29908: A user can gain additional access through the ALTER VIEW. +# +CREATE DATABASE mysqltest_29908; +USE mysqltest_29908; +CREATE TABLE t1(f1 INT, f2 INT); +CREATE USER u29908_1@localhost; +CREATE DEFINER = u29908_1@localhost VIEW v1 AS SELECT f1 FROM t1; +CREATE DEFINER = u29908_1@localhost SQL SECURITY INVOKER VIEW v2 AS +SELECT f1 FROM t1; +GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v1 TO u29908_1@localhost; +GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v2 TO u29908_1@localhost; +GRANT SELECT ON mysqltest_29908.t1 TO u29908_1@localhost; +CREATE USER u29908_2@localhost; +GRANT DROP, CREATE VIEW ON mysqltest_29908.v1 TO u29908_2@localhost; +GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v2 TO u29908_2@localhost; +GRANT SELECT ON mysqltest_29908.t1 TO u29908_2@localhost; +ALTER VIEW v1 AS SELECT f2 FROM t1; +ERROR 42000: Access denied; you need the SUPER privilege for this operation +ALTER VIEW v2 AS SELECT f2 FROM t1; +ERROR 42000: Access denied; you need the SUPER privilege for this operation +SHOW CREATE VIEW v2; +View Create View +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select `t1`.`f1` AS `f1` from `t1` +ALTER VIEW v1 AS SELECT f2 FROM t1; +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f2` AS `f2` from `t1` +ALTER VIEW v2 AS SELECT f2 FROM t1; +SHOW CREATE VIEW v2; +View Create View +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select `t1`.`f2` AS `f2` from `t1` +ALTER VIEW v1 AS SELECT f1 FROM t1; +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` +ALTER VIEW v2 AS SELECT f1 FROM t1; +SHOW CREATE VIEW v2; +View Create View +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select `t1`.`f1` AS `f1` from `t1` +DROP USER u29908_1@localhost; +DROP USER u29908_2@localhost; +DROP DATABASE mysqltest_29908; +####################################################################### DROP DATABASE IF EXISTS mysqltest1; DROP DATABASE IF EXISTS mysqltest2; CREATE DATABASE mysqltest1; diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test index a102f87c4e8..7f9eb4e1cff 100644 --- a/mysql-test/t/view_grant.test +++ b/mysql-test/t/view_grant.test @@ -1034,10 +1034,11 @@ GRANT SELECT ON db26813.t1 TO u26813@localhost; connect (u1,localhost,u26813,,db26813); connection u1; ---error 1142 +--error ER_SPECIFIC_ACCESS_DENIED_ERROR ALTER VIEW v1 AS SELECT f2 FROM t1; ---error 1142 +--error ER_SPECIFIC_ACCESS_DENIED_ERROR ALTER VIEW v2 AS SELECT f2 FROM t1; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR ALTER VIEW v3 AS SELECT f2 FROM t1; connection root; @@ -1047,6 +1048,51 @@ DROP USER u26813@localhost; DROP DATABASE db26813; disconnect u1; +--echo # +--echo # Bug#29908: A user can gain additional access through the ALTER VIEW. +--echo # +connection root; +CREATE DATABASE mysqltest_29908; +USE mysqltest_29908; +CREATE TABLE t1(f1 INT, f2 INT); +CREATE USER u29908_1@localhost; +CREATE DEFINER = u29908_1@localhost VIEW v1 AS SELECT f1 FROM t1; +CREATE DEFINER = u29908_1@localhost SQL SECURITY INVOKER VIEW v2 AS + SELECT f1 FROM t1; +GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v1 TO u29908_1@localhost; +GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v2 TO u29908_1@localhost; +GRANT SELECT ON mysqltest_29908.t1 TO u29908_1@localhost; +CREATE USER u29908_2@localhost; +GRANT DROP, CREATE VIEW ON mysqltest_29908.v1 TO u29908_2@localhost; +GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v2 TO u29908_2@localhost; +GRANT SELECT ON mysqltest_29908.t1 TO u29908_2@localhost; + +connect (u2,localhost,u29908_2,,mysqltest_29908); +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +ALTER VIEW v1 AS SELECT f2 FROM t1; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +ALTER VIEW v2 AS SELECT f2 FROM t1; +SHOW CREATE VIEW v2; + +connect (u1,localhost,u29908_1,,mysqltest_29908); +ALTER VIEW v1 AS SELECT f2 FROM t1; +SHOW CREATE VIEW v1; +ALTER VIEW v2 AS SELECT f2 FROM t1; +SHOW CREATE VIEW v2; + +connection root; +ALTER VIEW v1 AS SELECT f1 FROM t1; +SHOW CREATE VIEW v1; +ALTER VIEW v2 AS SELECT f1 FROM t1; +SHOW CREATE VIEW v2; + +DROP USER u29908_1@localhost; +DROP USER u29908_2@localhost; +DROP DATABASE mysqltest_29908; +disconnect u1; +disconnect u2; +--echo ####################################################################### + # # BUG#24040: Create View don't succed with "all privileges" on a database. # diff --git a/sql/sql_view.cc b/sql/sql_view.cc index fd05d97a94a..ea956031395 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -223,9 +223,6 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, { LEX *lex= thd->lex; bool link_to_local; -#ifndef NO_EMBEDDED_ACCESS_CHECKS - bool definer_check_is_needed= mode != VIEW_ALTER || lex->definer; -#endif /* first table in list is target VIEW name => cut off it */ TABLE_LIST *view= lex->unlink_first_table(&link_to_local); TABLE_LIST *tables= lex->query_tables; @@ -280,7 +277,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, - same as current user - current user has SUPER_ACL */ - if (definer_check_is_needed && + if (lex->definer && (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) != 0 || my_strcasecmp(system_charset_info, lex->definer->host.str, From a8cbbef15c089027cecd7f80b54b8992b49d7a36 Mon Sep 17 00:00:00 2001 From: Chad MILLER Date: Tue, 15 Jul 2008 12:51:05 -0400 Subject: [PATCH 57/99] Fixed packet-test bug caused by if block that didn't have curly braces. --- sql/sql_parse.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ccd131e5f90..ab2099d932c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1559,8 +1559,10 @@ static bool do_command(THD *thd) /* Check if we can continue without closing the connection */ if (net->error != 3) + { return_value= TRUE; // We have to close it. goto out; + } net_send_error(thd, net->last_errno, NullS); net->error= 0; From f81792945a215a842894a0bc131c7ee7661f3442 Mon Sep 17 00:00:00 2001 From: Jonathan Perkin Date: Wed, 16 Jul 2008 17:47:30 +0200 Subject: [PATCH 58/99] Put version number back to 5.0.67 --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 8ac0ee407d8..7c90f0fc310 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.68) +AM_INIT_AUTOMAKE(mysql, 5.0.67) AM_CONFIG_HEADER([include/config.h:config.h.in]) 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=68 +NDB_VERSION_BUILD=67 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From 9ee2262c9d815c266fc9d9bb69ab144dcc593a82 Mon Sep 17 00:00:00 2001 From: Jonathan Perkin Date: Wed, 16 Jul 2008 18:07:16 +0200 Subject: [PATCH 59/99] Raise version number after cloning 5.0.67 --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 7c90f0fc310..48d6515903f 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.67) +AM_INIT_AUTOMAKE(mysql, 5.0.69) AM_CONFIG_HEADER([include/config.h:config.h.in]) 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=67 +NDB_VERSION_BUILD=69 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From 6256bf17b88da0b0e04f5223d67714e687e3738d Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Thu, 17 Jul 2008 20:19:13 -0300 Subject: [PATCH 60/99] Bug#33812: mysql client incorrectly parsing DELIMITER Revert fix for this bug as it introduced a regression reported in Bug#38158. client/mysql.cc: Revert fix for Bug#33812 mysql-test/r/mysql.result: Revert fix for Bug#33812 mysql-test/t/mysql_delimiter.sql: Revert fix for Bug#33812 --- client/mysql.cc | 31 +++++++++++++++++++++++++++++++ mysql-test/r/mysql.result | 2 -- mysql-test/t/mysql_delimiter.sql | 6 ------ 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index c8d5522628d..9b14f9fb3ef 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -2081,6 +2081,37 @@ static bool add_line(String &buffer,char *line,char *in_string, continue; } } + else if (!*ml_comment && !*in_string && + (end_of_line - pos) >= 10 && + !my_strnncoll(charset_info, (uchar*) pos, 10, + (const uchar*) "delimiter ", 10)) + { + // Flush previously accepted characters + if (out != line) + { + buffer.append(line, (uint32) (out - line)); + out= line; + } + + // Flush possible comments in the buffer + if (!buffer.is_empty()) + { + if (com_go(&buffer, 0) > 0) // < 0 is not fatal + DBUG_RETURN(1); + buffer.length(0); + } + + /* + Delimiter wants the get rest of the given line as argument to + allow one to change ';' to ';;' and back + */ + buffer.append(pos); + if (com_delimiter(&buffer, pos) > 0) + DBUG_RETURN(1); + + buffer.length(0); + break; + } else if (!*ml_comment && !*in_string && is_prefix(pos, delimiter)) { // Found a statement. Continue parsing after the delimiter diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index bc50c686ac6..eded1a3fc3b 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -38,8 +38,6 @@ t2 t3 Tables_in_test t1 -delimiter -1 _ Test delimiter : from command line a diff --git a/mysql-test/t/mysql_delimiter.sql b/mysql-test/t/mysql_delimiter.sql index 917401275a2..533ac2ce093 100644 --- a/mysql-test/t/mysql_delimiter.sql +++ b/mysql-test/t/mysql_delimiter.sql @@ -60,12 +60,6 @@ use test// show tables// delimiter ; # Reset delimiter -# -# Bug #33812: mysql client incorrectly parsing DELIMITER -# -select a as delimiter from t1 -delimiter ; # Reset delimiter - # # Bug #36244: MySQL CLI doesn't recognize standalone -- as comment # before DELIMITER statement From 2d590c28257cefaa8d25a2bbdab189e362e1470c Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Mon, 28 Jul 2008 19:22:12 +0500 Subject: [PATCH 61/99] Bug#37428 Potential security issue with UDFs - linux shellcode execution. plugin_dir option backported from 5.1 per-file messages: sql/mysql_priv.h Bug#37428 Potential security issue with UDFs - linux shellcode execution. opt_plugin_dir and opt_plugin_dir_ptr declared. sql/mysqld.cc Bug#37428 Potential security issue with UDFs - linux shellcode execution. 'plugin_dir' option added sql/set_var.cc Bug#37428 Potential security issue with UDFs - linux shellcode execution. 'plugin_dir' option added. sql/sql_udf.cc Bug#37428 Potential security issue with UDFs - linux shellcode execution. opt_plugin_dir added to the udf->dl path. Warn if it's not specified. sql/unireg.h Bug#37428 Potential security issue with UDFs - linux shellcode execution. PLUGINDIR defined. --- sql/mysql_priv.h | 3 +++ sql/mysqld.cc | 11 +++++++++++ sql/set_var.cc | 1 + sql/sql_udf.cc | 26 +++++++++++++++++++++++--- sql/unireg.h | 3 +++ 5 files changed, 41 insertions(+), 3 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index f3bda4e5819..c1694cbbbe4 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1362,6 +1362,9 @@ extern char *default_tz_name; extern my_bool opt_large_pages; extern uint opt_large_page_size; +extern char *opt_plugin_dir_ptr; +extern char opt_plugin_dir[FN_REFLEN]; + extern MYSQL_LOG mysql_log,mysql_slow_log,mysql_bin_log; extern FILE *bootstrap_file; extern int bootstrap_error; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7edc3b91752..d591ce46af7 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -324,6 +324,9 @@ arg_cmp_func Arg_comparator::comparator_matrix[5][2] = /* static variables */ +char opt_plugin_dir[FN_REFLEN]; +char *opt_plugin_dir_ptr; + static bool lower_case_table_names_used= 0; static bool volatile select_thread_in_use, signal_thread_in_use; static bool volatile ready_to_exit; @@ -4984,6 +4987,7 @@ enum options_mysqld OPT_OLD_STYLE_USER_LIMITS, OPT_LOG_SLOW_ADMIN_STATEMENTS, OPT_TABLE_LOCK_WAIT_TIMEOUT, + OPT_PLUGIN_DIR, OPT_PORT_OPEN_TIMEOUT, OPT_MERGE, OPT_PROFILING, @@ -6223,6 +6227,10 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.optimizer_search_depth, (gptr*) &max_system_variables.optimizer_search_depth, 0, GET_ULONG, OPT_ARG, MAX_TABLES+1, 0, MAX_TABLES+2, 0, 1, 0}, + {"plugin_dir", OPT_PLUGIN_DIR, + "Directory for plugins.", + (gptr*) &opt_plugin_dir_ptr, (gptr*) &opt_plugin_dir_ptr, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"preload_buffer_size", OPT_PRELOAD_BUFFER_SIZE, "The size of the buffer that is allocated when preloading indexes", (gptr*) &global_system_variables.preload_buff_size, @@ -7761,6 +7769,9 @@ static void fix_paths(void) (void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir (void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home); (void) my_load_path(pidfile_name,pidfile_name,mysql_real_data_home); + (void) my_load_path(opt_plugin_dir, opt_plugin_dir_ptr ? opt_plugin_dir_ptr : + "", ""); + opt_plugin_dir_ptr= opt_plugin_dir; char *sharedir=get_relative_path(SHAREDIR); if (test_if_hard_path(sharedir)) diff --git a/sql/set_var.cc b/sql/set_var.cc index eb381bfecf4..a0ddef0b386 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1036,6 +1036,7 @@ struct show_var_st init_vars[]= { {sys_optimizer_search_depth.name,(char*) &sys_optimizer_search_depth, SHOW_SYS}, {"pid_file", (char*) pidfile_name, SHOW_CHAR}, + {"plugin_dir", (char*) opt_plugin_dir, SHOW_CHAR}, {"port", (char*) &mysqld_port, SHOW_INT}, {sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS}, #ifdef ENABLED_PROFILING diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 34ca18d5c39..e3a0230d2fb 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -214,7 +214,17 @@ void udf_init() void *dl = find_udf_dl(tmp->dl); if (dl == NULL) { - if (!(dl = dlopen(tmp->dl, RTLD_NOW))) + char dlpath[FN_REFLEN]; + if (*opt_plugin_dir) + strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", tmp->dl, + NullS); + else + { + strxnmov(dlpath, sizeof(dlpath)-1, tmp->dl, NullS); + push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, + "plugin_dir was not specified"); + } + if (!(dl = dlopen(dlpath, RTLD_NOW))) { /* Print warning to log */ sql_print_error(ER(ER_CANT_OPEN_LIBRARY), tmp->dl,errno,dlerror()); @@ -443,8 +453,18 @@ int mysql_create_function(THD *thd,udf_func *udf) } if (!(dl = find_udf_dl(udf->dl))) { - DBUG_PRINT("info", ("Calling dlopen, udf->dl: %s", udf->dl)); - if (!(dl = dlopen(udf->dl, RTLD_NOW))) + char dlpath[FN_REFLEN]; + if (*opt_plugin_dir) + strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", udf->dl, + NullS); + else + { + strxnmov(dlpath, sizeof(dlpath)-1, udf->dl, NullS); + push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, + "plugin_dir was not specified"); + } + DBUG_PRINT("info", ("Calling dlopen, udf->dl: %s", dlpath)); + if (!(dl = dlopen(dlpath, RTLD_NOW))) { DBUG_PRINT("error",("dlopen of %s failed, error: %d (%s)", udf->dl,errno,dlerror())); diff --git a/sql/unireg.h b/sql/unireg.h index 1326b22c8c9..8e01e6222e6 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -35,6 +35,9 @@ #ifndef SHAREDIR #define SHAREDIR "share/" #endif +#ifndef PLUGINDIR +#define PLUGINDIR "lib/plugin" +#endif #define ER(X) errmesg[(X) - ER_ERROR_FIRST] #define ER_SAFE(X) (((X) >= ER_ERROR_FIRST && (X) <= ER_ERROR_LAST) ? ER(X) : "Invalid error code") From 94de2319e7d9eacc8a092ebb42c7300d568ea7cf Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 31 Jul 2008 12:41:30 +0300 Subject: [PATCH 62/99] Bug#34159: mysql_install_db fails with sql_mode=TRADITIONAL Reset session sql_mode before creating system tables as it is done in the mysql_fix_privilege_tables.sql script. scripts/mysql_system_tables.sql: reset sql_mode --- scripts/mysql_system_tables.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/mysql_system_tables.sql b/scripts/mysql_system_tables.sql index d9c870f1d73..31eb205eed0 100644 --- a/scripts/mysql_system_tables.sql +++ b/scripts/mysql_system_tables.sql @@ -2,6 +2,7 @@ -- The system tables of MySQL Server -- +set sql_mode=''; set storage_engine=myisam; CREATE TABLE IF NOT EXISTS db ( Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, PRIMARY KEY Host (Host,Db,User), KEY User (User) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Database privileges'; From 1cbc2f7e3a1df747dd2aab1140e904e81a44cc8c Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 31 Jul 2008 14:42:44 +0500 Subject: [PATCH 63/99] Buq#32167 another privilege bypass with DATA/INDEX DIRECTORY. test_if_data_home_dir fixed to look into real path. Checks added to mi_open for symlinks into data home directory. per-file messages: include/my_sys.h Bug#32167 another privilege bypass with DATA/INDEX DIRECTORY. my_is_symlink interface added mysql-test/r/udf.result test result fixed (not related to #32167) mysys/my_symlink.c my_is_symlink() implementsd my_realpath() now returns the 'realpath' even if a file isn't a symlink --- include/my_sys.h | 1 + mysql-test/r/udf.result | 6 +++++ mysys/my_symlink.c | 50 +++++++++++++++++++++-------------------- 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index a2b705a0c59..359d3453cf5 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -575,6 +575,7 @@ extern int my_close(File Filedes,myf MyFlags); extern File my_dup(File file, myf MyFlags); extern int my_mkdir(const char *dir, int Flags, myf MyFlags); extern int my_readlink(char *to, const char *filename, myf MyFlags); +extern int my_is_symlink(const char *filename); extern int my_realpath(char *to, const char *filename, myf MyFlags); extern File my_create_with_symlink(const char *linkname, const char *filename, int createflags, int access_flags, diff --git a/mysql-test/r/udf.result b/mysql-test/r/udf.result index a79be1c3189..92185962d1f 100644 --- a/mysql-test/r/udf.result +++ b/mysql-test/r/udf.result @@ -1,5 +1,7 @@ drop table if exists t1; CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; +Warnings: +Warning 1105 plugin_dir was not specified CREATE FUNCTION myfunc_double RETURNS REAL SONAME "UDF_EXAMPLE_LIB"; CREATE FUNCTION myfunc_nonexist RETURNS INTEGER SONAME "UDF_EXAMPLE_LIB"; ERROR HY000: Can't find function 'myfunc_nonexist' in library @@ -197,6 +199,8 @@ DROP FUNCTION avgcost; select * from mysql.func; name ret dl type CREATE FUNCTION is_const RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; +Warnings: +Warning 1105 plugin_dir was not specified select IS_const(3); IS_const(3) const @@ -206,6 +210,8 @@ name ret dl type select is_const(3); ERROR 42000: FUNCTION test.is_const does not exist CREATE FUNCTION is_const RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; +Warnings: +Warning 1105 plugin_dir was not specified select is_const(3) as const, is_const(3.14) as const, diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c index 810c0c72632..4391d1fd009 100644 --- a/mysys/my_symlink.c +++ b/mysys/my_symlink.c @@ -2,7 +2,8 @@ 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. + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -106,38 +107,38 @@ int my_symlink(const char *content, const char *linkname, myf MyFlags) #define BUFF_LEN FN_LEN #endif +int my_is_symlink(const char *filename __attribute__((unused))) +{ + struct stat stat_buff; + return !lstat(filename, &stat_buff) && S_ISLNK(stat_buff.st_mode); +} + + int my_realpath(char *to, const char *filename, myf MyFlags __attribute__((unused))) { #if defined(HAVE_REALPATH) && !defined(HAVE_purify) && !defined(HAVE_BROKEN_REALPATH) int result=0; char buff[BUFF_LEN]; - struct stat stat_buff; + char *ptr; DBUG_ENTER("my_realpath"); - if (!(MyFlags & MY_RESOLVE_LINK) || - (!lstat(filename,&stat_buff) && S_ISLNK(stat_buff.st_mode))) + DBUG_PRINT("info",("executing realpath")); + if ((ptr=realpath(filename,buff))) + strmake(to,ptr,FN_REFLEN-1); + else { - char *ptr; - DBUG_PRINT("info",("executing realpath")); - if ((ptr=realpath(filename,buff))) - { - strmake(to,ptr,FN_REFLEN-1); - } - else - { - /* - Realpath didn't work; Use my_load_path() which is a poor substitute - original name but will at least be able to resolve paths that starts - with '.'. - */ - DBUG_PRINT("error",("realpath failed with errno: %d", errno)); - my_errno=errno; - if (MyFlags & MY_WME) - my_error(EE_REALPATH, MYF(0), filename, my_errno); - my_load_path(to, filename, NullS); - result= -1; - } + /* + Realpath didn't work; Use my_load_path() which is a poor substitute + original name but will at least be able to resolve paths that starts + with '.'. + */ + DBUG_PRINT("error",("realpath failed with errno: %d", errno)); + my_errno=errno; + if (MyFlags & MY_WME) + my_error(EE_REALPATH, MYF(0), filename, my_errno); + my_load_path(to, filename, NullS); + result= -1; } DBUG_RETURN(result); #else @@ -145,3 +146,4 @@ int my_realpath(char *to, const char *filename, return 0; #endif } + From befef397b42d62c22bad858cb16fafcbfc675fff Mon Sep 17 00:00:00 2001 From: Jonathan Perkin Date: Mon, 4 Aug 2008 11:39:05 +0200 Subject: [PATCH 64/99] Use autoconf glue around new my_is_symlink to avoid stat(2) and friends being used on systems which don't support that interface. --- mysys/my_symlink.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c index 4391d1fd009..f7a31b92f05 100644 --- a/mysys/my_symlink.c +++ b/mysys/my_symlink.c @@ -109,8 +109,12 @@ int my_symlink(const char *content, const char *linkname, myf MyFlags) int my_is_symlink(const char *filename __attribute__((unused))) { +#if defined(HAVE_REALPATH) && !defined(HAVE_purify) && !defined(HAVE_BROKEN_REALPATH) struct stat stat_buff; return !lstat(filename, &stat_buff) && S_ISLNK(stat_buff.st_mode); +#else + return 0; +#endif } From 8348a92853471d14028defb441979743bcdde79f Mon Sep 17 00:00:00 2001 From: Jonathan Perkin Date: Mon, 4 Aug 2008 12:05:21 +0200 Subject: [PATCH 65/99] Change preprocessor tests to match what we will be using. --- mysys/my_symlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c index f7a31b92f05..f797d75c27b 100644 --- a/mysys/my_symlink.c +++ b/mysys/my_symlink.c @@ -109,7 +109,7 @@ int my_symlink(const char *content, const char *linkname, myf MyFlags) int my_is_symlink(const char *filename __attribute__((unused))) { -#if defined(HAVE_REALPATH) && !defined(HAVE_purify) && !defined(HAVE_BROKEN_REALPATH) +#if defined(HAVE_LSTAT) && defined(S_ISLNK) struct stat stat_buff; return !lstat(filename, &stat_buff) && S_ISLNK(stat_buff.st_mode); #else From cc97ca3513a0bd70b11299e292f3646d52b3a980 Mon Sep 17 00:00:00 2001 From: Jonathan Perkin Date: Mon, 4 Aug 2008 13:45:50 +0200 Subject: [PATCH 66/99] Revert previous unintentional license change. --- mysys/my_symlink.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c index f797d75c27b..49c63fc3948 100644 --- a/mysys/my_symlink.c +++ b/mysys/my_symlink.c @@ -2,8 +2,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of From d445b215d10d1239d097d9fb362f232ec9bdb2f4 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 21 Nov 2008 17:38:42 +0400 Subject: [PATCH 67/99] Bug#25058 ignored return codes in memory allocation functions memory allocation error checks added for functions calling insert_dynamic() per-file messages: myisam/mi_delete.c Bug#25058 ignored return codes in memory allocation functions out-of-memory errors handled myisam/mi_write.c Bug#25058 ignored return codes in memory allocation functions out-of-memory errors handled server-tools/instance-manager/instance_options.cc Bug#25058 ignored return codes in memory allocation functions out-of-memory errors handled sql/slave.cc Bug#25058 ignored return codes in memory allocation functions out-of-memory errors handled sql/sp_head.cc Bug#25058 ignored return codes in memory allocation functions out-of-memory errors handled sql/sp_head.h Bug#25058 ignored return codes in memory allocation functions out-of-memory errors handled sql/sp_pcontext.cc Bug#25058 ignored return codes in memory allocation functions out-of-memory errors handled sql/sp_pcontext.h Bug#25058 ignored return codes in memory allocation functions out-of-memory errors handled sql/sql_select.cc Bug#25058 ignored return codes in memory allocation functions out-of-memory errors handled sql/sql_yacc.yy Bug#25058 ignored return codes in memory allocation functions out-of-memory errors handled --- myisam/mi_delete.c | 6 +- myisam/mi_write.c | 9 +- .../instance-manager/instance_options.cc | 3 +- sql/slave.cc | 3 +- sql/sp_head.cc | 27 +-- sql/sp_head.h | 8 +- sql/sp_pcontext.cc | 22 +-- sql/sp_pcontext.h | 4 +- sql/sql_select.cc | 46 +++-- sql/sql_yacc.yy | 172 +++++++++--------- 10 files changed, 167 insertions(+), 133 deletions(-) diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c index ca8a537b322..e08e5097e33 100644 --- a/myisam/mi_delete.c +++ b/myisam/mi_delete.c @@ -250,7 +250,11 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, if (info->ft1_to_ft2) { /* we're in ft1->ft2 conversion mode. Saving key data */ - insert_dynamic(info->ft1_to_ft2, (char*) (lastkey+off)); + if (insert_dynamic(info->ft1_to_ft2, (char*) (lastkey+off))) + { + DBUG_PRINT("error",("Out of memory")); + DBUG_RETURN(-1); + } } else { diff --git a/myisam/mi_write.c b/myisam/mi_write.c index 4f11fc78ccf..b4843a748dd 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -550,7 +550,14 @@ int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo, we cannot easily dispatch an empty page here */ b+=blen+ft2len+2; for (a=anc_buff+a_length ; b < a ; b+=ft2len+2) - insert_dynamic(info->ft1_to_ft2, (char*) b); + { + if (insert_dynamic(info->ft1_to_ft2, (char*) b)) + { + mi_print_error(info->s, HA_ERR_OUT_OF_MEM); + my_errno= HA_ERR_OUT_OF_MEM; + DBUG_RETURN(-1); + } + } /* fixing the page's length - it contains only one key now */ mi_putint(anc_buff,2+blen+ft2len+2,0); diff --git a/server-tools/instance-manager/instance_options.cc b/server-tools/instance-manager/instance_options.cc index d4ca2ad570f..c01b09de2b2 100644 --- a/server-tools/instance-manager/instance_options.cc +++ b/server-tools/instance-manager/instance_options.cc @@ -522,8 +522,7 @@ int Instance_options::add_option(const char* option) switch (selected_options->type) { case SAVE_WHOLE_AND_ADD: *(selected_options->value)= tmp; - insert_dynamic(&options_array,(gptr) &tmp); - return 0; + return insert_dynamic(&options_array,(gptr) &tmp); case SAVE_VALUE: *(selected_options->value)= strchr(tmp, '=') + 1; return 0; diff --git a/sql/slave.cc b/sql/slave.cc index b4e74f8e68d..c15c395cdb8 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1053,8 +1053,7 @@ int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec) e->tbl_name = e->db + (dot - table_spec) + 1; e->key_len = len; memcpy(e->db, table_spec, len); - insert_dynamic(a, (gptr)&e); - return 0; + return insert_dynamic(a, (gptr)&e); } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 3ec6dd5cf06..57502f240d9 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1924,17 +1924,16 @@ sp_head::restore_lex(THD *thd) DBUG_VOID_RETURN; } -void +int sp_head::push_backpatch(sp_instr *i, sp_label_t *lab) { bp_t *bp= (bp_t *)sql_alloc(sizeof(bp_t)); - if (bp) - { - bp->lab= lab; - bp->instr= i; - (void)m_backpatch.push_front(bp); - } + if (!bp) + return 1; + bp->lab= lab; + bp->instr= i; + return m_backpatch.push_front(bp); } void @@ -2009,7 +2008,7 @@ sp_head::fill_field_definition(THD *thd, LEX *lex, } -void +int sp_head::new_cont_backpatch(sp_instr_opt_meta *i) { m_cont_level+= 1; @@ -2017,15 +2016,17 @@ sp_head::new_cont_backpatch(sp_instr_opt_meta *i) { /* Use the cont. destination slot to store the level */ i->m_cont_dest= m_cont_level; - (void)m_cont_backpatch.push_front(i); + if (m_cont_backpatch.push_front(i)) + return 1; } + return 0; } -void +int sp_head::add_cont_backpatch(sp_instr_opt_meta *i) { i->m_cont_dest= m_cont_level; - (void)m_cont_backpatch.push_front(i); + return m_cont_backpatch.push_front(i); } void @@ -2207,7 +2208,7 @@ sp_head::show_create_procedure(THD *thd) instr Instruction */ -void sp_head::add_instr(sp_instr *instr) +int sp_head::add_instr(sp_instr *instr) { instr->free_list= m_thd->free_list; m_thd->free_list= 0; @@ -2218,7 +2219,7 @@ void sp_head::add_instr(sp_instr *instr) entire stored procedure, as their life span is equal. */ instr->mem_root= &main_mem_root; - insert_dynamic(&m_instr, (gptr)&instr); + return insert_dynamic(&m_instr, (gptr)&instr); } diff --git a/sql/sp_head.h b/sql/sp_head.h index 91f465a4e2a..c54dc7401c4 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -226,7 +226,7 @@ public: int show_create_function(THD *thd); - void + int add_instr(sp_instr *instr); inline uint @@ -254,7 +254,7 @@ public: restore_lex(THD *thd); // Put the instruction on the backpatch list, associated with the label. - void + int push_backpatch(sp_instr *, struct sp_label *); // Update all instruction with this label in the backpatch list to @@ -263,11 +263,11 @@ public: backpatch(struct sp_label *); // Start a new cont. backpatch level. If 'i' is NULL, the level is just incr. - void + int new_cont_backpatch(sp_instr_opt_meta *i); // Add an instruction to the current level - void + int add_cont_backpatch(sp_instr_opt_meta *i); // Backpatch (and pop) the current level to the current position. diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index 780243cc79f..265964d3d45 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -263,7 +263,8 @@ sp_pcontext::push_variable(LEX_STRING *name, enum enum_field_types type, p->mode= mode; p->offset= current_var_count(); p->dflt= NULL; - insert_dynamic(&m_vars, (gptr)&p); + if (insert_dynamic(&m_vars, (gptr)&p)) + return NULL; return p; } @@ -308,18 +309,17 @@ sp_pcontext::find_label(char *name) return NULL; } -void +int sp_pcontext::push_cond(LEX_STRING *name, sp_cond_type_t *val) { sp_cond_t *p= (sp_cond_t *)sql_alloc(sizeof(sp_cond_t)); - if (p) - { - p->name.str= name->str; - p->name.length= name->length; - p->val= val; - insert_dynamic(&m_conds, (gptr)&p); - } + if (p == NULL) + return 1; + p->name.str= name->str; + p->name.length= name->length; + p->val= val; + return insert_dynamic(&m_conds, (gptr)&p); } /* @@ -382,7 +382,7 @@ sp_pcontext::find_handler(sp_cond_type_t *cond) return FALSE; } -void +int sp_pcontext::push_cursor(LEX_STRING *name) { LEX_STRING n; @@ -391,7 +391,7 @@ sp_pcontext::push_cursor(LEX_STRING *name) m_max_cursor_index+= 1; n.str= name->str; n.length= name->length; - insert_dynamic(&m_cursors, (gptr)&n); + return insert_dynamic(&m_cursors, (gptr)&n); } /* diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index 5bffda79f98..db8bed349f2 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -323,7 +323,7 @@ public: // Conditions // - void + int push_cond(LEX_STRING *name, sp_cond_type_t *val); inline void @@ -365,7 +365,7 @@ public: // Cursors // - void + int push_cursor(LEX_STRING *name); my_bool diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 428d1709f94..4883e9e4196 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3342,10 +3342,6 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, } } -/* - Add all keys with uses 'field' for some keypart - If field->and_level != and_level then only mark key_part as const_part -*/ static uint max_part_bit(key_part_map bits) @@ -3355,7 +3351,16 @@ max_part_bit(key_part_map bits) return found; } -static void +/* + Add all keys with uses 'field' for some keypart + If field->and_level != and_level then only mark key_part as const_part + + RETURN + 0 - OK + 1 - Out of memory. +*/ + +static bool add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field) { Field *field=key_field->field; @@ -3385,24 +3390,26 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field) keyuse.optimize= key_field->optimize & KEY_OPTIMIZE_REF_OR_NULL; keyuse.null_rejecting= key_field->null_rejecting; keyuse.cond_guard= key_field->cond_guard; - VOID(insert_dynamic(keyuse_array,(gptr) &keyuse)); + if (insert_dynamic(keyuse_array,(gptr) &keyuse)) + return TRUE; } } } } + return FALSE; } #define FT_KEYPART (MAX_REF_PARTS+10) -static void +static bool add_ft_keys(DYNAMIC_ARRAY *keyuse_array, JOIN_TAB *stat,COND *cond,table_map usable_tables) { Item_func_match *cond_func=NULL; if (!cond) - return; + return FALSE; if (cond->type() == Item::FUNC_ITEM) { @@ -3436,13 +3443,16 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array, { Item *item; while ((item=li++)) - add_ft_keys(keyuse_array,stat,item,usable_tables); + { + if (add_ft_keys(keyuse_array,stat,item,usable_tables)) + return TRUE; + } } } if (!cond_func || cond_func->key == NO_SUCH_KEY || !(usable_tables & cond_func->table->map)) - return; + return FALSE; KEYUSE keyuse; keyuse.table= cond_func->table; @@ -3452,7 +3462,7 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array, keyuse.used_tables=cond_func->key_item()->used_tables(); keyuse.optimize= 0; keyuse.keypart_map= 0; - VOID(insert_dynamic(keyuse_array,(gptr) &keyuse)); + return insert_dynamic(keyuse_array,(gptr) &keyuse); } @@ -3602,7 +3612,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, sargables); for (; field != end ; field++) { - add_key_part(keyuse,field); + if (add_key_part(keyuse,field)) + return TRUE; /* Mark that we can optimize LEFT JOIN */ if (field->val->type() == Item::NULL_ITEM && !field->field->real_maybe_null()) @@ -3640,11 +3651,15 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, /* fill keyuse with found key parts */ for ( ; field != end ; field++) - add_key_part(keyuse,field); + { + if (add_key_part(keyuse,field)) + return TRUE; + } if (select_lex->ftfunc_list->elements) { - add_ft_keys(keyuse,join_tab,cond,normal_tables); + if (add_ft_keys(keyuse,join_tab,cond,normal_tables)) + return TRUE; } /* @@ -3665,7 +3680,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, (qsort_cmp) sort_keyuse); bzero((char*) &key_end,sizeof(key_end)); /* Add for easy testing */ - VOID(insert_dynamic(keyuse,(gptr) &key_end)); + if (insert_dynamic(keyuse,(gptr) &key_end)) + return TRUE; use=save_pos=dynamic_element(keyuse,0,KEYUSE*); prev= &key_end; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0eefe782354..c149e12d567 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -234,9 +234,7 @@ int case_stmt_action_expr(LEX *lex, Item* expr) parsing_ctx, case_expr_id, expr, lex); sp->add_cont_backpatch(i); - sp->add_instr(i); - - return 0; + return sp->add_instr(i); } /** @@ -247,7 +245,7 @@ int case_stmt_action_expr(LEX *lex, Item* expr) @param simple true for simple cases, false for searched cases */ -void case_stmt_action_when(LEX *lex, Item *when, bool simple) +int case_stmt_action_when(LEX *lex, Item *when, bool simple) { sp_head *sp= lex->sphead; sp_pcontext *ctx= lex->spcont; @@ -279,9 +277,10 @@ void case_stmt_action_when(LEX *lex, Item *when, bool simple) (jump_if_not from instruction 2 to 5, 5 to 8 ... in the example) */ - sp->push_backpatch(i, ctx->push_label((char *)"", 0)); - sp->add_cont_backpatch(i); - sp->add_instr(i); + return !test(i) || + sp->push_backpatch(i, ctx->push_label((char *)"", 0)) || + sp->add_cont_backpatch(i) || + sp->add_instr(i); } /** @@ -290,13 +289,14 @@ void case_stmt_action_when(LEX *lex, Item *when, bool simple) @param lex the parser lex context */ -void case_stmt_action_then(LEX *lex) +int case_stmt_action_then(LEX *lex) { sp_head *sp= lex->sphead; sp_pcontext *ctx= lex->spcont; uint ip= sp->instructions(); sp_instr_jump *i = new sp_instr_jump(ip, ctx); - sp->add_instr(i); + if (!test(i) || sp->add_instr(i)) + return 1; /* BACKPATCH: Resolving forward jump from @@ -312,7 +312,7 @@ void case_stmt_action_then(LEX *lex) (jump from instruction 4 to 12, 7 to 12 ... in the example) */ - sp->push_backpatch(i, ctx->last_label()); + return sp->push_backpatch(i, ctx->last_label()); } /** @@ -1905,10 +1905,9 @@ sp_decl: var_type, lex, (i == num_vars - 1)); - if (is == NULL) + if (is == NULL || + lex->sphead->add_instr(is)) MYSQL_YYABORT; - - lex->sphead->add_instr(is); } pctx->declare_var_boundary(0); @@ -1927,7 +1926,8 @@ sp_decl: my_error(ER_SP_DUP_COND, MYF(0), $2.str); MYSQL_YYABORT; } - YYTHD->lex->spcont->push_cond(&$2, $5); + if(YYTHD->lex->spcont->push_cond(&$2, $5)) + MYSQL_YYABORT; $$.vars= $$.hndlrs= $$.curs= 0; $$.conds= 1; } @@ -1942,10 +1942,10 @@ sp_decl: sp_instr_hpush_jump *i= new sp_instr_hpush_jump(sp->instructions(), ctx, $2, ctx->current_var_count()); - if (i == NULL) + if (i == NULL || + sp->add_instr(i)) MYSQL_YYABORT; - sp->add_instr(i); sp->push_backpatch(i, ctx->push_label((char *)"", 0)); } sp_hcond_list sp_proc_stmt @@ -1960,17 +1960,17 @@ sp_decl: { i= new sp_instr_hreturn(sp->instructions(), ctx, ctx->current_var_count()); - if (i == NULL ) + if (i == NULL || + sp->add_instr(i)) MYSQL_YYABORT; - sp->add_instr(i); } else { /* EXIT or UNDO handler, just jump to the end of the block */ i= new sp_instr_hreturn(sp->instructions(), ctx, 0); - if (i == NULL) + if (i == NULL || + sp->add_instr(i) || + sp->push_backpatch(i, lex->spcont->last_label())) /* Block end */ MYSQL_YYABORT; - sp->add_instr(i); - sp->push_backpatch(i, lex->spcont->last_label()); /* Block end */ } lex->sphead->backpatch(hlab); @@ -1996,10 +1996,10 @@ sp_decl: } i= new sp_instr_cpush(sp->instructions(), ctx, $5, ctx->current_cursor_count()); - if (i == NULL) + if (i == NULL || + sp->add_instr(i) || + ctx->push_cursor(&$2)) MYSQL_YYABORT; - sp->add_instr(i); - ctx->push_cursor(&$2); $$.vars= $$.conds= $$.hndlrs= 0; $$.curs= 1; } @@ -2223,10 +2223,11 @@ sp_proc_stmt: i->m_query.length= lip->ptr - sp->m_tmp_query; else i->m_query.length= lip->tok_end - sp->m_tmp_query; - i->m_query.str= strmake_root(thd->mem_root, - sp->m_tmp_query, - i->m_query.length); - sp->add_instr(i); + if (!(i->m_query.str= strmake_root(thd->mem_root, + sp->m_tmp_query, + i->m_query.length)) || + sp->add_instr(i)) + MYSQL_YYABORT; } sp->restore_lex(thd); } @@ -2251,9 +2252,9 @@ sp_proc_stmt: i= new sp_instr_freturn(sp->instructions(), lex->spcont, $3, sp->m_return_field_def.sql_type, lex); - if (i == NULL) + if (i == NULL || + sp->add_instr(i)) MYSQL_YYABORT; - sp->add_instr(i); sp->m_flags|= sp_head::HAS_RETURN; } sp->restore_lex(YYTHD); @@ -2311,23 +2312,23 @@ sp_proc_stmt: if (n) { sp_instr_hpop *hpop= new sp_instr_hpop(ip++, ctx, n); - if (hpop == NULL) + if (hpop == NULL || + sp->add_instr(hpop)) MYSQL_YYABORT; - sp->add_instr(hpop); } n= ctx->diff_cursors(lab->ctx, exclusive); if (n) { sp_instr_cpop *cpop= new sp_instr_cpop(ip++, ctx, n); - if (cpop == NULL) + if (cpop == NULL || + sp->add_instr(cpop)) MYSQL_YYABORT; - sp->add_instr(cpop); } i= new sp_instr_jump(ip, ctx); - if (i == NULL) + if (i == NULL || + sp->push_backpatch(i, lab) || /* Jumping forward */ + sp->add_instr(i)) MYSQL_YYABORT; - sp->push_backpatch(i, lab); /* Jumping forward */ - sp->add_instr(i); } } | ITERATE_SYM label_ident @@ -2352,22 +2353,22 @@ sp_proc_stmt: if (n) { sp_instr_hpop *hpop= new sp_instr_hpop(ip++, ctx, n); - if (hpop == NULL) + if (hpop == NULL || + sp->add_instr(hpop)) MYSQL_YYABORT; - sp->add_instr(hpop); } n= ctx->diff_cursors(lab->ctx, FALSE); /* Inclusive the dest. */ if (n) { sp_instr_cpop *cpop= new sp_instr_cpop(ip++, ctx, n); - if (cpop == NULL) + if (cpop == NULL || + sp->add_instr(cpop)) MYSQL_YYABORT; - sp->add_instr(cpop); } i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */ - if (i == NULL) + if (i == NULL || + sp->add_instr(i)) MYSQL_YYABORT; - sp->add_instr(i); } } | OPEN_SYM ident @@ -2383,9 +2384,9 @@ sp_proc_stmt: MYSQL_YYABORT; } i= new sp_instr_copen(sp->instructions(), lex->spcont, offset); - if (i == NULL) + if (i == NULL || + sp->add_instr(i)) MYSQL_YYABORT; - sp->add_instr(i); } | FETCH_SYM sp_opt_fetch_noise ident INTO { @@ -2400,9 +2401,9 @@ sp_proc_stmt: MYSQL_YYABORT; } i= new sp_instr_cfetch(sp->instructions(), lex->spcont, offset); - if (i == NULL) + if (i == NULL || + sp->add_instr(i)) MYSQL_YYABORT; - sp->add_instr(i); } sp_fetch_list { } @@ -2419,9 +2420,9 @@ sp_proc_stmt: MYSQL_YYABORT; } i= new sp_instr_cclose(sp->instructions(), lex->spcont, offset); - if (i == NULL) + if (i == NULL || + sp->add_instr(i)) MYSQL_YYABORT; - sp->add_instr(i); } ; @@ -2488,11 +2489,11 @@ sp_if: uint ip= sp->instructions(); sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, ctx, $2, lex); - if (i == NULL) + if (i == NULL || + sp->push_backpatch(i, ctx->push_label((char *)"", 0)) || + sp->add_cont_backpatch(i) || + sp->add_instr(i)) MYSQL_YYABORT; - sp->push_backpatch(i, ctx->push_label((char *)"", 0)); - sp->add_cont_backpatch(i); - sp->add_instr(i); sp->restore_lex(YYTHD); } sp_proc_stmts1 @@ -2501,9 +2502,9 @@ sp_if: sp_pcontext *ctx= Lex->spcont; uint ip= sp->instructions(); sp_instr_jump *i = new sp_instr_jump(ip, ctx); - if (i == NULL) + if (i == NULL || + sp->add_instr(i)) MYSQL_YYABORT; - sp->add_instr(i); sp->backpatch(ctx->pop_label()); sp->push_backpatch(i, ctx->push_label((char *)"", 0)); } @@ -2589,14 +2590,16 @@ simple_when_clause: /* Simple case: = */ LEX *lex= Lex; - case_stmt_action_when(lex, $3, true); + if (case_stmt_action_when(lex, $3, true)) + MYSQL_YYABORT; lex->sphead->restore_lex(YYTHD); /* For expr $3 */ } THEN_SYM sp_proc_stmts1 { LEX *lex= Lex; - case_stmt_action_then(lex); + if (case_stmt_action_then(lex)) + MYSQL_YYABORT; } ; @@ -2609,14 +2612,16 @@ searched_when_clause: expr { LEX *lex= Lex; - case_stmt_action_when(lex, $3, false); + if (case_stmt_action_when(lex, $3, false)) + MYSQL_YYABORT; lex->sphead->restore_lex(YYTHD); /* For expr $3 */ } THEN_SYM sp_proc_stmts1 { LEX *lex= Lex; - case_stmt_action_then(lex); + if (case_stmt_action_then(lex)) + MYSQL_YYABORT; } ; @@ -2628,9 +2633,9 @@ else_clause_opt: uint ip= sp->instructions(); sp_instr_error *i= new sp_instr_error(ip, lex->spcont, ER_SP_CASE_NOT_FOUND); - if (i == NULL) + if (i == NULL || + sp->add_instr(i)) MYSQL_YYABORT; - sp->add_instr(i); } | ELSE sp_proc_stmts1 ; @@ -2744,17 +2749,17 @@ sp_block_content: { sp_instr_hpop *hpop= new sp_instr_hpop(sp->instructions(), ctx, $3.hndlrs); - if (hpop == NULL) + if (hpop == NULL || + sp->add_instr(hpop)) MYSQL_YYABORT; - sp->add_instr(hpop); } if ($3.curs) { sp_instr_cpop *cpop= new sp_instr_cpop(sp->instructions(), ctx, $3.curs); - if (cpop == NULL) + if (cpop == NULL || + sp->add_instr(cpop)) MYSQL_YYABORT; - sp->add_instr(cpop); } lex->spcont= ctx->pop_context(); } @@ -2768,9 +2773,9 @@ sp_unlabeled_control: uint ip= lex->sphead->instructions(); sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */ sp_instr_jump *i = new sp_instr_jump(ip, lex->spcont, lab->ip); - if (i == NULL) + if (i == NULL || + lex->sphead->add_instr(i)) MYSQL_YYABORT; - lex->sphead->add_instr(i); } | WHILE_SYM { @@ -2784,12 +2789,12 @@ sp_unlabeled_control: uint ip= sp->instructions(); sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont, $3, lex); - if (i == NULL) - MYSQL_YYABORT; + if (i == NULL || /* Jumping forward */ - sp->push_backpatch(i, lex->spcont->last_label()); - sp->new_cont_backpatch(i); - sp->add_instr(i); + sp->push_backpatch(i, lex->spcont->last_label()) || + sp->new_cont_backpatch(i) || + sp->add_instr(i)) + MYSQL_YYABORT; sp->restore_lex(YYTHD); } sp_proc_stmts1 END WHILE_SYM @@ -2798,9 +2803,9 @@ sp_unlabeled_control: uint ip= lex->sphead->instructions(); sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */ sp_instr_jump *i = new sp_instr_jump(ip, lex->spcont, lab->ip); - if (i == NULL) + if (i == NULL || + lex->sphead->add_instr(i)) MYSQL_YYABORT; - lex->sphead->add_instr(i); lex->sphead->do_cont_backpatch(); } | REPEAT_SYM sp_proc_stmts1 UNTIL_SYM @@ -2816,9 +2821,9 @@ sp_unlabeled_control: sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont, $5, lab->ip, lex); - if (i == NULL) + if (i == NULL || + lex->sphead->add_instr(i)) MYSQL_YYABORT; - lex->sphead->add_instr(i); lex->sphead->restore_lex(YYTHD); /* We can shortcut the cont_backpatch here */ i->m_cont_dest= ip+1; @@ -9643,7 +9648,8 @@ option_type_value: qbuff.length); qbuff.length+= 4; i->m_query= qbuff; - sp->add_instr(i); + if (sp->add_instr(i)) + MYSQL_YYABORT; } lex->sphead->restore_lex(thd); } @@ -9725,7 +9731,8 @@ sys_option_value: lex->trg_table_fields.link_in_list((byte *)trg_fld, (byte **)&trg_fld->next_trg_field); - lex->sphead->add_instr(sp_fld); + if (lex->sphead->add_instr(sp_fld)) + MYSQL_YYABORT; } else if ($2.var) { /* System variable */ @@ -9755,11 +9762,12 @@ sys_option_value: it= spv->dflt; else it= new Item_null(); - if (it == NULL) + if (it == NULL || + (sp_set= new sp_instr_set(lex->sphead->instructions(), ctx, + spv->offset, it, spv->type, lex, + TRUE)) == NULL || + lex->sphead->add_instr(sp_set)) MYSQL_YYABORT; - sp_set= new sp_instr_set(lex->sphead->instructions(), ctx, - spv->offset, it, spv->type, lex, TRUE); - lex->sphead->add_instr(sp_set); } } | option_type TRANSACTION_SYM ISOLATION LEVEL_SYM isolation_types From c5738c0051cfd903804afd06353f3dc431ec2726 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 18 Dec 2008 17:53:47 +0100 Subject: [PATCH 68/99] Raise version number after cloning 5.0.75 --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 0dd71851315..48ac64d86c2 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.75) +AM_INIT_AUTOMAKE(mysql, 5.0.77) AM_CONFIG_HEADER([include/config.h:config.h.in]) 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=75 +NDB_VERSION_BUILD=77 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From 295e876718d03d8c19fae2427421571b5c935f7f Mon Sep 17 00:00:00 2001 From: Satya B Date: Fri, 20 Mar 2009 14:48:14 +0530 Subject: [PATCH 69/99] Fix for BUG#41330 -Myisam table open count set to zero before index blocks are written. When we have a myisam table with DELAY_KEY_WRITE option, index updates are not applied until the flush tables command is issued or until the server is shutdown. If server gets killed before the index updates are written to disk, the index file is corrupted as expected but the table is not marked as crashed. So when we start server with myisam-recover, table is not repaired leaving the table unusable. The problem is when we try to write the index updates to index file, we decrement the open_count even before the flushing the keys to index file. Fixed by moving the decrement operation after flushing the keys to the index file. So we always have non zero open count if the flush table operation is killed and when the server is started with mysiam-recover option, it marks the table as crashed and repairs it. Note: No testcase for added as we need to kill the server and start the server with different set of options and other non trivial operations involved. myisam/mi_close.c: Decrement open count after flushing the key blocks to the key file. If the server(with DELAY_KEY_WRITE option) is killed before flush_key_blocks operation, we will have non zero open count and the table can be repaired when server is started with --myisam-recover option. --- myisam/mi_close.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/myisam/mi_close.c b/myisam/mi_close.c index 81d32be468a..43eebed520b 100644 --- a/myisam/mi_close.c +++ b/myisam/mi_close.c @@ -35,8 +35,6 @@ int mi_close(register MI_INFO *info) if (info->lock_type == F_EXTRA_LCK) info->lock_type=F_UNLCK; /* HA_EXTRA_NO_USER_CHANGE */ - if (share->reopen == 1 && share->kfile >= 0) - _mi_decrement_open_count(info); if (info->lock_type != F_UNLCK) { @@ -78,6 +76,8 @@ int mi_close(register MI_INFO *info) */ if (share->mode != O_RDONLY && mi_is_crashed(info)) mi_state_info_write(share->kfile, &share->state, 1); + /* Decrement open count must be last I/O on this file. */ + _mi_decrement_open_count(info); if (my_close(share->kfile,MYF(0))) error = my_errno; } From 51a91166387760546d563ebf72bfa037fcff24a8 Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Fri, 27 Mar 2009 13:19:50 +0800 Subject: [PATCH 70/99] BUG#37145 Killing a statement doing DDL may log binlog event with error code 1053 When the thread executing a DDL was killed after finished its execution but before writing the binlog event, the error code in the binlog event could be set wrongly to ER_SERVER_SHUTDOWN or ER_QUERY_INTERRUPTED. This patch fixed the problem by ignoring the kill status when constructing the event for DDL statements. This patch also included the following changes in order to provide the test case. 1) modified mysqltest to support variable for connection command 2) modified mysql-test-run.pl, add new variable MYSQL_SLAVE to run mysql client against the slave mysqld. --- client/mysqltest.c | 21 +- mysql-test/include/diff_master_slave.inc | 21 ++ mysql-test/include/kill_query.inc | 68 +++++ .../kill_query_and_diff_master_slave.inc | 43 +++ mysql-test/mysql-test-run.pl | 14 +- mysql-test/r/rpl_killed_ddl.result | 146 ++++++++++ mysql-test/t/rpl_killed_ddl-master.opt | 1 + mysql-test/t/rpl_killed_ddl.test | 271 ++++++++++++++++++ sql/item_func.cc | 4 + sql/log.cc | 15 +- sql/log_event.cc | 3 + sql/log_event.h | 6 +- sql/mysql_priv.h | 7 + sql/sp.cc | 8 +- sql/sp_head.cc | 3 +- sql/sql_acl.cc | 24 +- sql/sql_base.cc | 16 +- sql/sql_db.cc | 8 +- sql/sql_delete.cc | 4 +- sql/sql_insert.cc | 5 +- sql/sql_parse.cc | 12 +- sql/sql_rename.cc | 3 +- sql/sql_table.cc | 24 +- sql/sql_trigger.cc | 2 +- sql/sql_update.cc | 2 +- sql/sql_view.cc | 6 +- 26 files changed, 674 insertions(+), 63 deletions(-) create mode 100644 mysql-test/include/diff_master_slave.inc create mode 100644 mysql-test/include/kill_query.inc create mode 100644 mysql-test/include/kill_query_and_diff_master_slave.inc create mode 100644 mysql-test/r/rpl_killed_ddl.result create mode 100644 mysql-test/t/rpl_killed_ddl-master.opt create mode 100644 mysql-test/t/rpl_killed_ddl.test diff --git a/client/mysqltest.c b/client/mysqltest.c index 312012d7b8d..865c1d9a717 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -4093,13 +4093,20 @@ int select_connection(struct st_command *command) if (!*p) die("Missing connection name in connect"); - name= p; - while (*p && !my_isspace(charset_info,*p)) - p++; - if (*p) - *p++= 0; - command->last_argument= p; - return select_connection_name(name); + + static DYNAMIC_STRING ds_connection; + const struct command_arg connection_args[] = { + { "connection_name", ARG_STRING, TRUE, &ds_connection, "Name of the connection that we switch to." } + }; + check_command_args(command, command->first_argument, connection_args, + sizeof(connection_args)/sizeof(struct command_arg), + ','); + + DBUG_PRINT("info", ("changing connection: %s", ds_connection.str)); + + int ret= select_connection_name(ds_connection.str); + dynstr_free(&ds_connection); + return ret; } diff --git a/mysql-test/include/diff_master_slave.inc b/mysql-test/include/diff_master_slave.inc new file mode 100644 index 00000000000..b6d79190671 --- /dev/null +++ b/mysql-test/include/diff_master_slave.inc @@ -0,0 +1,21 @@ +# ==== Purpose ==== +# +# Diff the output of a statement on master and slave +# +# ==== Usage ===== +# +# let $diff_statement= SELECT * FROM t1 WHERE a < 100; +# source include/diff_master_slave.inc; + +--echo source include/diff_master_slave.inc; +disable_query_log; +disable_result_log; + +exec $MYSQL test -e "$diff_statement" > $MYSQLTEST_VARDIR/tmp/diff_master.out; +sync_slave_with_master; +exec $MYSQL_SLAVE test -e "$diff_statement" > $MYSQLTEST_VARDIR/tmp/diff_slave.out; + +diff_files $MYSQLTEST_VARDIR/tmp/diff_master.out $MYSQLTEST_VARDIR/tmp/diff_slave.out; + +enable_result_log; +enable_query_log; diff --git a/mysql-test/include/kill_query.inc b/mysql-test/include/kill_query.inc new file mode 100644 index 00000000000..341c3b93535 --- /dev/null +++ b/mysql-test/include/kill_query.inc @@ -0,0 +1,68 @@ +# ==== Purpose ==== +# +# Kill a query in the master connection, and then try to reap the +# result of the killed query. +# +# ==== Usage ==== +# +# The following variables should be set before sourcing this file. +# +# $debug_lock: name of the debug user lock, if set, will release/lock +# the specified debug lock accordingly, and before +# sourcing this, connection 'master' should get the user +# lock and run a query in another thread, which will +# block before creating statement event. +# +# $connection_name: name of the connection that is waiting for the +# lock, this can not be 'master' +# +# $connection_id: id of the connection that is waiting for the lock +# +# Example: +# let $debug_lock=; +# connection master1; +# let $connection_name= master1; +# let $connection_id= `SELECT CONNECTION_ID()`; +# send CREATE TABLE t1; +# source kill_query.inc; +# +# let $debug_lock= "debug_lock.before_query_log_event"; +# connection master; +# eval SELECT GET_LOCK($debug_lock, 10); +# connection master1; +# let $connection_name= master1; +# let $connection_id= `SELECT CONNECTION_ID()`; +# send CREATE TABLE t1; +# source kill_query.inc; + + +--echo source include/kill_query.inc; +disable_query_log; +disable_result_log; +connection master; + +# kill the query that is waiting +eval kill query $connection_id; + +if (`SELECT '$debug_lock' != ''`) +{ + # release the lock to allow binlog continue + eval SELECT RELEASE_LOCK($debug_lock); +} + +# reap the result of the waiting query +connection $connection_name; +error 0, 1317, 1307, 1306, 1334, 1305; +reap; + +connection master; + +if (`SELECT '$debug_lock' != ''`) +{ + # get lock again to make the next query wait + eval SELECT GET_LOCK($debug_lock, 10); +} + +connection $connection_name; +enable_query_log; +enable_result_log; diff --git a/mysql-test/include/kill_query_and_diff_master_slave.inc b/mysql-test/include/kill_query_and_diff_master_slave.inc new file mode 100644 index 00000000000..611d6929c99 --- /dev/null +++ b/mysql-test/include/kill_query_and_diff_master_slave.inc @@ -0,0 +1,43 @@ +# ==== Purpose ==== +# +# Kill a query, sync master with slave, and diff the output of a +# statement on master and slave to check if statement is correctly +# replicated. +# +# ==== Usage ==== +# +# connection ; +# let $connection_name= +# let $connection_id=`SELECT CONNECTION_ID()`; +# let $diff_statement=; +# send ; +# source include/kill_query_and_diff_master_slave.inc; +# +# Note: must not be 'master'. +# +# See also kill_query.inc and diff_master_slave.inc for more +# information + +source include/kill_query.inc; + +# Release the debug lock if used, so that the statements in +# diff_master_slave.inc will not be blocked. +connection master; +disable_query_log; +disable_result_log; +if (`SELECT '$debug_lock' != ''`) +{ + eval SELECT RELEASE_LOCK($debug_lock); +} +enable_result_log; +enable_query_log; + +source include/diff_master_slave.inc; + +# Acquire the debug lock again if used +connection master; +disable_query_log; disable_result_log; if (`SELECT '$debug_lock' != +''`) { eval SELECT GET_LOCK($debug_lock, 10); } enable_result_log; +enable_query_log; + +connection $connection_name; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 0948c973e9b..ffa9b4cb1d3 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2063,7 +2063,7 @@ sub environment_setup () { $ENV{'MYSQL_BINLOG'}= $cmdline_mysqlbinlog; # ---------------------------------------------------- - # Setup env so childs can execute mysql + # Setup env so childs can execute mysql against master # ---------------------------------------------------- my $cmdline_mysql= mtr_native_path($exe_mysql) . @@ -2074,6 +2074,18 @@ sub environment_setup () { $ENV{'MYSQL'}= $cmdline_mysql; + # ---------------------------------------------------- + # Setup env so childs can execute mysql against slave + # ---------------------------------------------------- + my $cmdline_mysql_slave= + mtr_native_path($exe_mysql) . + " --no-defaults --host=localhost --user=root --password= " . + "--port=$slave->[0]->{'port'} " . + "--socket=$slave->[0]->{'path_sock'} ". + "--character-sets-dir=$path_charsetsdir"; + + $ENV{'MYSQL_SLAVE'}= $cmdline_mysql_slave; + # ---------------------------------------------------- # Setup env so childs can execute bug25714 # ---------------------------------------------------- diff --git a/mysql-test/r/rpl_killed_ddl.result b/mysql-test/r/rpl_killed_ddl.result new file mode 100644 index 00000000000..aa419a8556e --- /dev/null +++ b/mysql-test/r/rpl_killed_ddl.result @@ -0,0 +1,146 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +DROP DATABASE IF EXISTS d1; +DROP DATABASE IF EXISTS d2; +DROP DATABASE IF EXISTS d3; +DROP DATABASE IF EXISTS d4; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP FUNCTION IF EXISTS f3; +DROP FUNCTION IF EXISTS f4; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t3; +DROP TABLE IF EXISTS t4; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP PROCEDURE IF EXISTS p3; +DROP PROCEDURE IF EXISTS p4; +DROP TRIGGER IF EXISTS tr1; +DROP TRIGGER IF EXISTS tr2; +DROP TRIGGER IF EXISTS tr3; +DROP TRIGGER IF EXISTS tr4; +CREATE DATABASE d1; +CREATE FUNCTION f1 () RETURNS INT DETERMINISTIC +RETURN 1; +CREATE PROCEDURE p1 (OUT rows INT) +BEGIN +SELECT COUNT(*) INTO rows FROM t1; +END; +// +CREATE TABLE t1 (a int); +CREATE TABLE t3 (a int); +CREATE TRIGGER tr1 BEFORE INSERT ON t1 +FOR EACH ROW BEGIN +DELETE FROM t4 WHERE a=NEW.a; +END; +// +CREATE INDEX i1 ON t1 (a); +CREATE VIEW v1 AS SELECT a FROM t1 WHERE a < 100; +[on master] +[on master1] +CREATE DATABASE d2; +source include/kill_query.inc; +source include/diff_master_slave.inc; +ALTER DATABASE d1 +DEFAULT CHARACTER SET = 'utf8'; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP DATABASE d1; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP DATABASE d2; +source include/kill_query.inc; +source include/diff_master_slave.inc; +CREATE FUNCTION f2 () RETURNS INT DETERMINISTIC +RETURN 1; +source include/kill_query.inc; +source include/diff_master_slave.inc; +ALTER FUNCTION f1 SQL SECURITY INVOKER; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP FUNCTION IF EXISTS f1; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP FUNCTION IF EXISTS f2; +source include/kill_query.inc; +source include/diff_master_slave.inc; +CREATE PROCEDURE p2 (OUT rows INT) +BEGIN +SELECT COUNT(*) INTO rows FROM t2; +END; +// +source include/kill_query.inc; +source include/diff_master_slave.inc; +ALTER PROCEDURE p1 SQL SECURITY INVOKER COMMENT 'return rows of table t1'; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP PROCEDURE IF EXISTS p1; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP PROCEDURE IF EXISTS p2; +source include/kill_query.inc; +source include/diff_master_slave.inc; +CREATE TABLE t2 (b int); +source include/kill_query.inc; +source include/diff_master_slave.inc; +ALTER TABLE t1 ADD (d int); +source include/kill_query.inc; +source include/diff_master_slave.inc; +RENAME TABLE t3 TO t4; +source include/kill_query.inc; +source include/diff_master_slave.inc; +CREATE INDEX i2 on t1 (a); +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP INDEX i1 on t1; +source include/kill_query.inc; +source include/diff_master_slave.inc; +CREATE TRIGGER tr2 BEFORE INSERT ON t4 +FOR EACH ROW BEGIN +DELETE FROM t1 WHERE a=NEW.a; +END; +// +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP TRIGGER tr1; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP TRIGGER IF EXISTS tr2; +source include/kill_query.inc; +source include/diff_master_slave.inc; +CREATE VIEW v2 AS SELECT a FROM t1 WHERE a > 100; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP VIEW v1; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP VIEW IF EXISTS v2; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP TABLE t1; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP TABLE IF EXISTS t2; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP DATABASE IF EXISTS d1; +DROP DATABASE IF EXISTS d2; +DROP DATABASE IF EXISTS d3; +DROP DATABASE IF EXISTS d4; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP FUNCTION IF EXISTS f3; +DROP FUNCTION IF EXISTS f4; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t3; +DROP TABLE IF EXISTS t4; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP PROCEDURE IF EXISTS p3; +DROP PROCEDURE IF EXISTS p4; diff --git a/mysql-test/t/rpl_killed_ddl-master.opt b/mysql-test/t/rpl_killed_ddl-master.opt new file mode 100644 index 00000000000..aaf2d8a4251 --- /dev/null +++ b/mysql-test/t/rpl_killed_ddl-master.opt @@ -0,0 +1 @@ +--debug=d,debug_lock_before_query_log_event diff --git a/mysql-test/t/rpl_killed_ddl.test b/mysql-test/t/rpl_killed_ddl.test new file mode 100644 index 00000000000..f4f2f6ac320 --- /dev/null +++ b/mysql-test/t/rpl_killed_ddl.test @@ -0,0 +1,271 @@ +# ==== Purpose ==== +# +# This test check if DDL statements are correctly binlogged when the +# thread is killed +# +# ==== Method ==== +# +# Start a DDL query and kill it, check if the error code of the binlog +# event is correct. +# +# DDL statements tested: +# CREATE/ALTER/RENAME/DROP DATABASE +# CREATE/ALTER/DROP FUNCTION +# CREATE/ALTER/DROP PROCEDURE +# CREATE/ALTER/RENAME/DROP TABLE +# CREATE/DROP TRIGGER +# CREATE/ALTER/DROP VIEW +# +# ==== Bugs ===== +# + +source include/have_debug.inc; +source include/master-slave.inc; + +# Use the DBUG_SYNC_POINT to make sure the thread running the DDL is +# waiting before creating the query log event + +let $debug_lock= "debug_lock.before_query_log_event"; + +######## INITIALIZATION ######## + +disable_warnings; +DROP DATABASE IF EXISTS d1; +DROP DATABASE IF EXISTS d2; +DROP DATABASE IF EXISTS d3; +DROP DATABASE IF EXISTS d4; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP FUNCTION IF EXISTS f3; +DROP FUNCTION IF EXISTS f4; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t3; +DROP TABLE IF EXISTS t4; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP PROCEDURE IF EXISTS p3; +DROP PROCEDURE IF EXISTS p4; +DROP TRIGGER IF EXISTS tr1; +DROP TRIGGER IF EXISTS tr2; +DROP TRIGGER IF EXISTS tr3; +DROP TRIGGER IF EXISTS tr4; +enable_warnings; + +CREATE DATABASE d1; + +CREATE FUNCTION f1 () RETURNS INT DETERMINISTIC + RETURN 1; + +DELIMITER //; +CREATE PROCEDURE p1 (OUT rows INT) + BEGIN + SELECT COUNT(*) INTO rows FROM t1; + END; + // +DELIMITER ;// + +CREATE TABLE t1 (a int); +CREATE TABLE t3 (a int); + +DELIMITER //; +CREATE TRIGGER tr1 BEFORE INSERT ON t1 + FOR EACH ROW BEGIN + DELETE FROM t4 WHERE a=NEW.a; + END; + // +DELIMITER ;// + +CREATE INDEX i1 ON t1 (a); + +CREATE VIEW v1 AS SELECT a FROM t1 WHERE a < 100; + +sync_slave_with_master; + +connection master1; +let $connection_name= master1; +let $connection_id= `SELECT CONNECTION_ID()`; + +connection master; +echo [on master]; + +# This will block the execution of a statement at the DBUG_SYNC_POINT +# with given lock name +if (`SELECT '$debug_lock' != ''`) +{ + disable_query_log; + disable_result_log; + eval SELECT IS_FREE_LOCK($debug_lock); + eval SELECT GET_LOCK($debug_lock, 10); + eval SELECT IS_FREE_LOCK($debug_lock); + enable_query_log; + enable_result_log; +} + +######## START TEST ######## + +connection master1; +echo [on master1]; + +disable_warnings; + +######## DATABASE ######## + +let $diff_statement= SHOW DATABASES LIKE 'd%'; + +send CREATE DATABASE d2; +source include/kill_query_and_diff_master_slave.inc; + +send ALTER DATABASE d1 + DEFAULT CHARACTER SET = 'utf8'; +source include/kill_query_and_diff_master_slave.inc; + +send DROP DATABASE d1; +source include/kill_query_and_diff_master_slave.inc; + +send DROP DATABASE d2; +source include/kill_query_and_diff_master_slave.inc; + +######## FUNCTION ######## + +let $diff_statement= SHOW FUNCTION STATUS LIKE 'f%'; + +send CREATE FUNCTION f2 () RETURNS INT DETERMINISTIC + RETURN 1; +source include/kill_query_and_diff_master_slave.inc; + +send ALTER FUNCTION f1 SQL SECURITY INVOKER; +source include/kill_query_and_diff_master_slave.inc; + +# function f1 probably does not exist because the ALTER query was +# killed +send DROP FUNCTION IF EXISTS f1; +source include/kill_query_and_diff_master_slave.inc; + +# function f2 probably does not exist because the CREATE query was +# killed +send DROP FUNCTION IF EXISTS f2; +source include/kill_query_and_diff_master_slave.inc; + +######## PROCEDURE ######## + +let $diff_statement= SHOW PROCEDURE STATUS LIKE 'p%'; + +DELIMITER //; +send CREATE PROCEDURE p2 (OUT rows INT) + BEGIN + SELECT COUNT(*) INTO rows FROM t2; + END; + // +DELIMITER ;// +source include/kill_query_and_diff_master_slave.inc; + +send ALTER PROCEDURE p1 SQL SECURITY INVOKER COMMENT 'return rows of table t1'; +source include/kill_query_and_diff_master_slave.inc; + +send DROP PROCEDURE IF EXISTS p1; +source include/kill_query_and_diff_master_slave.inc; + +send DROP PROCEDURE IF EXISTS p2; +source include/kill_query_and_diff_master_slave.inc; + +######## TABLE ######## + +let $diff_statement= SHOW TABLES LIKE 't%'; + +send CREATE TABLE t2 (b int); +source include/kill_query_and_diff_master_slave.inc; + +send ALTER TABLE t1 ADD (d int); +source include/kill_query_and_diff_master_slave.inc; + +send RENAME TABLE t3 TO t4; +source include/kill_query_and_diff_master_slave.inc; + +######## INDEX ######## + +let $diff_statement= SHOW INDEX FROM t1; + +send CREATE INDEX i2 on t1 (a); +source include/kill_query_and_diff_master_slave.inc; + +send DROP INDEX i1 on t1; +source include/kill_query_and_diff_master_slave.inc; + +######## TRIGGER ######## + +let $diff_statement= SHOW TRIGGERS LIKE 'v%'; + +DELIMITER //; +send CREATE TRIGGER tr2 BEFORE INSERT ON t4 + FOR EACH ROW BEGIN + DELETE FROM t1 WHERE a=NEW.a; + END; + // +DELIMITER ;// +source include/kill_query_and_diff_master_slave.inc; + +send DROP TRIGGER tr1; +source include/kill_query_and_diff_master_slave.inc; + +send DROP TRIGGER IF EXISTS tr2; +source include/kill_query_and_diff_master_slave.inc; + +######## VIEW ######## + +let $diff_statement= SHOW TABLES LIKE 'v%'; + +send CREATE VIEW v2 AS SELECT a FROM t1 WHERE a > 100; +source include/kill_query_and_diff_master_slave.inc; + +send DROP VIEW v1; +source include/kill_query_and_diff_master_slave.inc; + +send DROP VIEW IF EXISTS v2; +source include/kill_query_and_diff_master_slave.inc; + +######## DROP TABLE ######## + +# Because of BUG#43529, we cannot use the DBUG_SYNC_POINT for DROP +# TABLE statements on 5.0 +connection master; +disable_query_log; +disable_result_log; +eval SELECT RELEASE_LOCK($debug_lock); +enable_result_log; +enable_query_log; +let $debug_lock=; + +connection master1; + +let $diff_statement= SHOW TABLES LIKE 't%'; + +send DROP TABLE t1; +source include/kill_query_and_diff_master_slave.inc; + +send DROP TABLE IF EXISTS t2; +source include/kill_query_and_diff_master_slave.inc; + +######## CLEAN UP ######## + +# The DROP statements above are killed during the process, so they +# does not make sure the objects are dropped. + +disable_warnings; +DROP DATABASE IF EXISTS d1; +DROP DATABASE IF EXISTS d2; +DROP DATABASE IF EXISTS d3; +DROP DATABASE IF EXISTS d4; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP FUNCTION IF EXISTS f3; +DROP FUNCTION IF EXISTS f4; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t3; +DROP TABLE IF EXISTS t4; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP PROCEDURE IF EXISTS p3; +DROP PROCEDURE IF EXISTS p4; +enable_warnings; diff --git a/sql/item_func.cc b/sql/item_func.cc index 47e16a1bcc3..e7e75ecd020 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3377,6 +3377,10 @@ longlong Item_master_pos_wait::val_int() } #ifdef EXTRA_DEBUG +/** + This will release the user lock that the thread currently locked, + please see also the comment of DEBUG_SYNC_POINT. +*/ void debug_sync_point(const char* lock_name, uint lock_timeout) { THD* thd=current_thd; diff --git a/sql/log.cc b/sql/log.cc index d979dd101e0..b16303ee232 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -158,7 +158,8 @@ static int binlog_commit(THD *thd, bool all) */ if (all || !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { - Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE); + Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), + TRUE, FALSE, THD::KILLED_NO_VALUE); qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE) DBUG_RETURN(binlog_end_trans(thd, trans_log, &qev)); } @@ -202,7 +203,8 @@ static int binlog_rollback(THD *thd, bool all) */ if (unlikely(thd->transaction.all.modified_non_trans_table)) { - Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE); + Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), + TRUE, FALSE, THD::KILLED_NO_VALUE); qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE) error= binlog_end_trans(thd, trans_log, &qev); } @@ -240,7 +242,8 @@ static int binlog_savepoint_set(THD *thd, void *sv) *(my_off_t *)sv= my_b_tell(trans_log); /* Write it to the binary log */ - Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + TRUE, FALSE, THD::KILLED_NO_VALUE); DBUG_RETURN(mysql_bin_log.write(&qinfo)); } @@ -257,7 +260,8 @@ static int binlog_savepoint_rollback(THD *thd, void *sv) */ if (unlikely(thd->transaction.all.modified_non_trans_table)) { - Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + TRUE, FALSE, THD::KILLED_NO_VALUE); DBUG_RETURN(mysql_bin_log.write(&qinfo)); } reinit_io_cache(trans_log, WRITE_CACHE, *(my_off_t *)sv, 0, 0); @@ -2089,7 +2093,8 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) transaction is either a BEGIN..COMMIT block or a single statement in autocommit mode. */ - Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, FALSE); + Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), + TRUE, FALSE, THD::KILLED_NO_VALUE); /* Imagine this is rollback due to net timeout, after all statements of the transaction succeeded. Then we want a diff --git a/sql/log_event.cc b/sql/log_event.cc index c4cdfc27fa0..7856e1458ef 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1358,6 +1358,9 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, { time_t end_time; + DBUG_EXECUTE_IF("debug_lock_before_query_log_event", + DBUG_SYNC_POINT("debug_lock.before_query_log_event", 10);); + if (killed_status_arg == THD::KILLED_NO_VALUE) killed_status_arg= thd_arg->killed; error_code= diff --git a/sql/log_event.h b/sql/log_event.h index 6ccbf8e4d5c..45e3d11b48c 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -813,9 +813,13 @@ public: #ifndef MYSQL_CLIENT + /* + for argument killed_err_arg, use ` THD::NOT_KILLED ' if the killed + status should be ignored, otherwise use `THD::KILLED_NO_VALUE' + */ Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length, bool using_trans, bool suppress_use, - THD::killed_state killed_err_arg= THD::KILLED_NO_VALUE); + THD::killed_state killed_err_arg); const char* get_db() { return db; } #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b855af9a8d3..37ba0611ee0 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -451,6 +451,13 @@ MY_LOCALE *my_locale_by_number(uint number); The client tells the server to block with SELECT GET_LOCK() and unblocks it with SELECT RELEASE_LOCK(). Used for debugging difficult concurrency problems + + NOTE: This will release the user lock that the thread currently + locked, which can cause problem if users want to use user locks for + other purposes. In order to overcome this problem, it's adviced to + wrap the call to DBUG_SYNC_POINT() within the DBUG_EXECUTE_IF(), so + that it will only be activated if the given keyword is included in + the 'debug' option, and will not fiddle user locks otherwise. */ #define DBUG_SYNC_POINT(lock_name,lock_timeout) \ debug_sync_point(lock_name,lock_timeout) diff --git a/sql/sp.cc b/sql/sp.cc index 3af51b82521..2450e9564d0 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -646,7 +646,7 @@ db_create_routine(THD *thd, int type, sp_head *sp) /* Such a statement can always go directly to binlog, no trans cache */ Query_log_event qinfo(thd, log_query.c_ptr(), log_query.length(), 0, - FALSE); + FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } @@ -680,7 +680,8 @@ db_drop_routine(THD *thd, int type, sp_name *name) if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } @@ -725,7 +726,8 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index b51d97e66c5..7da52458f26 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1601,7 +1601,8 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, if (need_binlog_call && thd->binlog_evt_union.unioned_events) { Query_log_event qinfo(thd, binlog_buf.ptr(), binlog_buf.length(), - thd->binlog_evt_union.unioned_events_trans, FALSE); + thd->binlog_evt_union.unioned_events_trans, + FALSE, THD::KILLED_NO_VALUE); if (mysql_bin_log.write(&qinfo) && thd->binlog_evt_union.unioned_events_trans) { diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index b2d0304f007..f61304a1e26 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1506,7 +1506,8 @@ bool change_password(THD *thd, const char *host, const char *user, acl_user->host.hostname ? acl_user->host.hostname : "", new_password)); thd->clear_error(); - Query_log_event qinfo(thd, buff, query_length, 0, FALSE); + Query_log_event qinfo(thd, buff, query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } end: @@ -3014,7 +3015,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } @@ -3181,7 +3183,8 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } @@ -3294,7 +3297,8 @@ bool mysql_grant(THD *thd, const char *db, List &list, if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } @@ -5404,7 +5408,8 @@ bool mysql_create_user(THD *thd, List &list) if (some_users_created && mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } @@ -5473,7 +5478,8 @@ bool mysql_drop_user(THD *thd, List &list) if (some_users_deleted && mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } @@ -5553,7 +5559,8 @@ bool mysql_rename_user(THD *thd, List &list) if (some_users_renamed && mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } @@ -5731,7 +5738,8 @@ bool mysql_revoke_all(THD *thd, List &list) if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 0cf3e023be9..8f60c02a08c 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -793,18 +793,9 @@ void close_temporary_tables(THD *thd) thd->variables.character_set_client= system_charset_info; Query_log_event qinfo(thd, s_query.ptr(), s_query.length() - 1 /* to remove trailing ',' */, - 0, FALSE); + 0, FALSE, THD::NOT_KILLED); thd->variables.character_set_client= cs_save; - /* - Imagine the thread had created a temp table, then was doing a SELECT, and - the SELECT was killed. Then it's not clever to mark the statement above as - "killed", because it's not really a statement updating data, and there - are 99.99% chances it will succeed on slave. - If a real update (one updating a persistent table) was killed on the - master, then this real update will be logged with error_code=killed, - rightfully causing the slave to stop. - */ - qinfo.error_code= 0; + DBUG_ASSERT(qinfo.error_code == 0); mysql_bin_log.write(&qinfo); } else @@ -2578,7 +2569,8 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, { end = strxmov(strmov(query, "DELETE FROM `"), db,"`.`",name,"`", NullS); - Query_log_event qinfo(thd, query, (ulong)(end-query), 0, FALSE); + Query_log_event qinfo(thd, query, (ulong)(end-query), + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); my_free(query, MYF(0)); } diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 80fea3ef1b1..be538783458 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -70,7 +70,7 @@ static byte* dboptions_get_key(my_dbopt_t *opt, uint *length, static inline void write_to_binlog(THD *thd, char *query, uint q_len, char *db, uint db_len) { - Query_log_event qinfo(thd, query, q_len, 0, 0); + Query_log_event qinfo(thd, query, q_len, 0, 0, THD::NOT_KILLED); qinfo.error_code= 0; qinfo.db= db; qinfo.db_len= db_len; @@ -562,7 +562,7 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, if (mysql_bin_log.is_open()) { Query_log_event qinfo(thd, query, query_length, 0, - /* suppress_use */ TRUE); + /* suppress_use */ TRUE, THD::NOT_KILLED); /* Write should use the database being created as the "current @@ -645,7 +645,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) if (mysql_bin_log.is_open()) { Query_log_event qinfo(thd, thd->query, thd->query_length, 0, - /* suppress_use */ TRUE); + /* suppress_use */ TRUE, THD::NOT_KILLED); /* Write should use the database being created as the "current @@ -770,7 +770,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) if (mysql_bin_log.is_open()) { Query_log_event qinfo(thd, query, query_length, 0, - /* suppress_use */ TRUE); + /* suppress_use */ TRUE, THD::NOT_KILLED); /* Write should use the database being created as the "current database" and not the threads current database, which is the diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 38f89683065..a757b7c28a5 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -730,7 +730,7 @@ void multi_delete::send_error(uint errcode,const char *err) if (mysql_bin_log.is_open()) { Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); + transactional_tables, FALSE, THD::KILLED_NO_VALUE); mysql_bin_log.write(&qinfo); } thd->transaction.all.modified_non_trans_table= true; @@ -958,7 +958,7 @@ end: { thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, - 0, FALSE); + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } send_ok(thd); // This should return record count diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index b79f979df05..dcee47f6518 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2537,7 +2537,8 @@ bool Delayed_insert::handle_inserts(void) thd.variables.time_zone = row->time_zone; } - Query_log_event qinfo(&thd, row->query, row->query_length, 0, FALSE); + Query_log_event qinfo(&thd, row->query, row->query_length, + 0, FALSE, THD::KILLED_NO_VALUE); mysql_bin_log.write(&qinfo); thd.time_zone_used = backup_time_zone_used; @@ -3099,7 +3100,7 @@ void select_insert::abort() if (mysql_bin_log.is_open()) { Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE); + transactional_table, FALSE, THD::KILLED_NO_VALUE); mysql_bin_log.write(&qinfo); } if (thd->transaction.stmt.modified_non_trans_table) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 2297283c92d..a946a6afb35 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3551,7 +3551,8 @@ end_with_restore_list: if (mysql_bin_log.is_open()) { thd->clear_error(); // No binlog error generated - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } @@ -3586,7 +3587,8 @@ end_with_restore_list: if (mysql_bin_log.is_open()) { thd->clear_error(); // No binlog error generated - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } @@ -3612,7 +3614,8 @@ end_with_restore_list: if (mysql_bin_log.is_open()) { thd->clear_error(); // No binlog error generated - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } @@ -4394,7 +4397,8 @@ end_with_restore_list: { if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index f6766aec285..cec9e4c39de 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -84,7 +84,8 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list) if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } send_ok(thd); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 963a98cfb59..eec6ad626f0 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -333,7 +333,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, { if (!error) thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + FALSE, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } @@ -1814,7 +1815,8 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, if (!internal_tmp_table && mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + FALSE, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } error= FALSE; @@ -2903,7 +2905,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST *src_table, if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + FALSE, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } res= FALSE; @@ -3012,7 +3015,8 @@ mysql_discard_or_import_tablespace(THD *thd, goto err; if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + FALSE, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } err: @@ -3168,7 +3172,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } send_ok(thd); @@ -3360,7 +3365,8 @@ view_err: if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + FALSE, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } send_ok(thd); @@ -3872,7 +3878,8 @@ view_err: if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + FALSE, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } goto end_temporary; @@ -4007,7 +4014,8 @@ view_err: if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + FALSE, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } broadcast_refresh(); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 930e3601699..d2ae494d4eb 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -304,7 +304,7 @@ end: /* Such a statement can always go directly to binlog, no trans cache. */ Query_log_event qinfo(thd, stmt_query.ptr(), stmt_query.length(), 0, - FALSE); + FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 8a3f5bcdc26..0da0b6e6635 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1575,7 +1575,7 @@ void multi_update::send_error(uint errcode,const char *err) into repl event. */ Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); + transactional_tables, FALSE, THD::KILLED_NO_VALUE); mysql_bin_log.write(&qinfo); } thd->transaction.all.modified_non_trans_table= TRUE; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 9e0fa87d5f5..9e1e2a20dc6 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -655,7 +655,8 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, else if (views->with_check == VIEW_CHECK_CASCADED) buff.append(STRING_WITH_LEN(" WITH CASCADED CHECK OPTION")); - Query_log_event qinfo(thd, buff.ptr(), buff.length(), 0, FALSE); + Query_log_event qinfo(thd, buff.ptr(), buff.length(), + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } @@ -1544,7 +1545,8 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) { if (!something_wrong) thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } From 02f8ec4d762a9ffdb8810387ab0ebd1416d3e87d Mon Sep 17 00:00:00 2001 From: Chad MILLER Date: Thu, 2 Apr 2009 11:29:28 -0400 Subject: [PATCH 71/99] Bug#43876: mysqld_multi introduces --no-defaults which screws up my system Bug#32136: mysqld_multi --defaults-file not respected while using \ --mysqld=mysqld_safe Revert change that adds "--no-defaults" to mysqld_multi. This closes Bug#43508 and re-opens Bug#32136. --- scripts/mysqld_multi.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh index 631e1e38cc7..3cb4665eb1c 100644 --- a/scripts/mysqld_multi.sh +++ b/scripts/mysqld_multi.sh @@ -293,12 +293,7 @@ sub start_mysqlds() @groups = &find_groups($groupids); for ($i = 0; defined($groups[$i]); $i++) { - # Defaults are made explicit parameters to server execution... @options = defaults_for_group($groups[$i]); - # ...so server MUST NOT try to read again from some config file, especially - # as the "right" file may be unknown to the server if we are using - # --defaults-file=... params in here. - unshift(@options,"--no-defaults"); $mysqld_found= 1; # The default $mysqld_found= 0 if (!length($mysqld)); From 72e978828edb6b6cc045e6c728747dafd46b8732 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Fri, 3 Apr 2009 16:11:54 -0300 Subject: [PATCH 72/99] Bug#43230: SELECT ... FOR UPDATE can hang with FLUSH TABLES WITH READ LOCK indefinitely The problem is that a SELECT .. FOR UPDATE statement might open a table and later wait for a impeding global read lock without noticing whether it is holding a table that is being waited upon the the flush phase of the process that took the global read lock. The same problem also affected the following statements: LOCK TABLES .. WRITE UPDATE .. SET (update and multi-table update) TRUNCATE TABLE .. LOAD DATA .. The solution is to make the above statements wait for a impending global read lock before opening the tables. If there is no impending global read lock, the statement raises a temporary protection against global read locks and progresses smoothly towards completion. Important notice: the patch does not try to address all possible cases, only those which are common and can be fixed unintrusively enough for 5.0. mysql-test/r/lock_multi.result: Add test case result for Bug#43230 mysql-test/t/lock_multi.test: Add test case for Bug#43230 sql/sql_lex.cc: Initialize flag. sql/sql_lex.h: Add a flag to the lexer. sql/sql_parse.cc: Wait for the global read lock is a write lock is going to be taken. The wait is done before opening tables. sql/sql_yacc.yy: Protect against the GRL if its a SELECT .. FOR UPDATE or LOCK TABLES .. WRITE statement. --- mysql-test/r/lock_multi.result | 55 ++++++++++++++ mysql-test/t/lock_multi.test | 128 +++++++++++++++++++++++++++++++++ sql/sql_lex.cc | 1 + sql/sql_lex.h | 16 +++++ sql/sql_parse.cc | 26 ++++++- sql/sql_yacc.yy | 7 +- 6 files changed, 231 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/lock_multi.result b/mysql-test/r/lock_multi.result index d1b50a0080c..037b375fe0b 100644 --- a/mysql-test/r/lock_multi.result +++ b/mysql-test/r/lock_multi.result @@ -133,3 +133,58 @@ ALTER TABLE t1 ADD COLUMN a INT; # 2.2.1. normal mode # 2.2.2. PS mode DROP TABLE t1; +create table t1 (a int); +create table t2 like t1; +# con1 +lock tables t1 write; +# con2 +flush tables with read lock; +# con5 +# global read lock is taken +# con3 +select * from t2 for update; +# waiting for release of read lock +# con4 +# would hang and later cause a deadlock +flush tables t2; +# clean up +unlock tables; +unlock tables; +a +drop table t1,t2; +# +# Lightweight version: +# Ensure that the wait for a GRL is done before opening tables. +# +create table t1 (a int); +create table t2 like t1; +# +# UPDATE +# +# default +flush tables with read lock; +# con1 +update t2 set a = 1; +# default +# statement is waiting for release of read lock +# con2 +flush table t2; +# default +unlock tables; +# con1 +# +# LOCK TABLES .. WRITE +# +# default +flush tables with read lock; +# con1 +lock tables t2 write; +# default +# statement is waiting for release of read lock +# con2 +flush table t2; +# default +unlock tables; +# con1 +unlock tables; +drop table t1,t2; diff --git a/mysql-test/t/lock_multi.test b/mysql-test/t/lock_multi.test index 6c3c942b046..fa6af85f29c 100644 --- a/mysql-test/t/lock_multi.test +++ b/mysql-test/t/lock_multi.test @@ -683,6 +683,134 @@ DROP TABLE t1; --disconnect locker --disconnect writer +# +# Bug#43230: SELECT ... FOR UPDATE can hang with FLUSH TABLES WITH READ LOCK indefinitely +# + +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); +connect (con3,localhost,root,,); +connect (con4,localhost,root,,); +connect (con5,localhost,root,,); + +create table t1 (a int); +create table t2 like t1; + +connection con1; +--echo # con1 +lock tables t1 write; +connection con2; +--echo # con2 +send flush tables with read lock; +connection con5; +--echo # con5 +let $show_statement= SHOW PROCESSLIST; +let $field= State; +let $condition= = 'Flushing tables'; +--source include/wait_show_condition.inc +--echo # global read lock is taken +connection con3; +--echo # con3 +send select * from t2 for update; +connection con5; +let $show_statement= SHOW PROCESSLIST; +let $field= State; +let $condition= = 'Waiting for release of readlock'; +--source include/wait_show_condition.inc +--echo # waiting for release of read lock +connection con4; +--echo # con4 +--echo # would hang and later cause a deadlock +flush tables t2; +connection con1; +--echo # clean up +unlock tables; +connection con2; +--reap +unlock tables; +connection con3; +--reap +connection default; +disconnect con5; +disconnect con4; +disconnect con3; +disconnect con2; +disconnect con1; + +drop table t1,t2; + +--echo # +--echo # Lightweight version: +--echo # Ensure that the wait for a GRL is done before opening tables. +--echo # + +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); + +create table t1 (a int); +create table t2 like t1; + +--echo # +--echo # UPDATE +--echo # + +connection default; +--echo # default +flush tables with read lock; +connection con1; +--echo # con1 +send update t2 set a = 1; +connection default; +--echo # default +let $show_statement= SHOW PROCESSLIST; +let $field= State; +let $condition= = 'Waiting for release of readlock'; +--source include/wait_show_condition.inc +--echo # statement is waiting for release of read lock +connection con2; +--echo # con2 +flush table t2; +connection default; +--echo # default +unlock tables; +connection con1; +--echo # con1 +--reap + +--echo # +--echo # LOCK TABLES .. WRITE +--echo # + +connection default; +--echo # default +flush tables with read lock; +connection con1; +--echo # con1 +send lock tables t2 write; +connection default; +--echo # default +let $show_statement= SHOW PROCESSLIST; +let $field= State; +let $condition= = 'Waiting for release of readlock'; +--source include/wait_show_condition.inc +--echo # statement is waiting for release of read lock +connection con2; +--echo # con2 +flush table t2; +connection default; +--echo # default +unlock tables; +connection con1; +--echo # con1 +--reap +unlock tables; + +connection default; +disconnect con2; +disconnect con1; + +drop table t1,t2; + # End of 5.0 tests # Wait till all disconnects are completed diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 4c53772bc25..da31106648a 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -204,6 +204,7 @@ void lex_start(THD *thd) lex->nest_level=0 ; lex->allow_sum_func= 0; lex->in_sum_func= NULL; + lex->protect_against_global_read_lock= FALSE; DBUG_VOID_RETURN; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 9f020f4adc5..3e762581e04 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1176,6 +1176,22 @@ typedef struct st_lex : public Query_tables_list bool escape_used; + /* + Special case for SELECT .. FOR UPDATE and LOCK TABLES .. WRITE. + + Protect from a impending GRL as otherwise the thread might deadlock + if it starts waiting for the GRL in mysql_lock_tables. + + The protection is needed because there is a race between setting + the global read lock and waiting for all open tables to be closed. + The problem is a circular wait where a thread holding "old" open + tables will wait for the global read lock to be released while the + thread holding the global read lock will wait for all "old" open + tables to be closed -- the flush part of flush tables with read + lock. + */ + bool protect_against_global_read_lock; + st_lex(); virtual ~st_lex() diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ba887486aa1..02030ac2e19 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2800,6 +2800,10 @@ mysql_execute_command(THD *thd) if (res) goto error; + if (!thd->locked_tables && lex->protect_against_global_read_lock && + !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1))) + goto error; + if (!(res= open_and_lock_tables(thd, all_tables))) { if (lex->describe) @@ -3660,6 +3664,9 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); if (update_precheck(thd, all_tables)) break; + if (!thd->locked_tables && + !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1))) + goto error; DBUG_ASSERT(select_lex->offset_limit == 0); unit->set_limit(select_lex); res= (up_result= mysql_update(thd, all_tables, @@ -3686,6 +3693,15 @@ end_with_restore_list: else res= 0; + /* + Protection might have already been risen if its a fall through + from the SQLCOM_UPDATE case above. + */ + if (!thd->locked_tables && + lex->sql_command == SQLCOM_UPDATE_MULTI && + !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1))) + goto error; + res= mysql_multi_update_prepare(thd); #ifdef HAVE_REPLICATION @@ -3853,7 +3869,8 @@ end_with_restore_list: ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); goto error; } - + if (!(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1))) + goto error; res= mysql_truncate(thd, first_table, 0); break; case SQLCOM_DELETE: @@ -4027,6 +4044,10 @@ end_with_restore_list: if (check_one_table_access(thd, privilege, all_tables)) goto error; + if (!thd->locked_tables && + !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1))) + goto error; + res= mysql_load(thd, lex->exchange, first_table, lex->field_list, lex->update_list, lex->value_list, lex->duplicates, lex->ignore, (bool) lex->local_file); @@ -4082,6 +4103,9 @@ end_with_restore_list: goto error; if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0)) goto error; + if (lex->protect_against_global_read_lock && + !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1))) + goto error; thd->in_lock_tables=1; thd->options|= OPTION_TABLE_LOCK; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 51fb5dbdfe4..b36c65854d7 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4522,6 +4522,7 @@ select_lock_type: LEX *lex=Lex; lex->current_select->set_lock_for_tables(TL_WRITE); lex->safe_to_cache_query=0; + lex->protect_against_global_read_lock= TRUE; } | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM { @@ -10058,8 +10059,12 @@ table_lock_list: table_lock: table_ident opt_table_alias lock_option { - if (!Select->add_table_to_list(YYTHD, $1, $2, 0, (thr_lock_type) $3)) + thr_lock_type lock_type= (thr_lock_type) $3; + if (!Select->add_table_to_list(YYTHD, $1, $2, 0, lock_type)) MYSQL_YYABORT; + /* If table is to be write locked, protect from a impending GRL. */ + if (lock_type >= TL_WRITE_ALLOW_WRITE) + Lex->protect_against_global_read_lock= TRUE; } ; From 10350e2097393cb7410eedfcf6ba533faba20a56 Mon Sep 17 00:00:00 2001 From: Satya B Date: Tue, 7 Apr 2009 16:54:32 +0530 Subject: [PATCH 73/99] Fix for Bug #43973 - backup_myisam.test fails on 6.0-bugteam The test started failing following the push for BUG#41541. Some of the algorithms access bytes beyond the input data and this can affect up to one byte less than "word size" which is BITS_SAVED / 8. Fixed by adding (BITS_SAVED / 8) -1 bytes to buffer size (i.e. Memory Segment #2) to avoid accessing un-allocated data. myisam/mi_packrec.c: Fixed _mi_read_pack_info() method to allocate (BITS_SAVED/8) - 1 bytes to the Memory Segment #2 mysql-test/r/myisampack.result: Result file for BUG#43973 mysql-test/t/myisampack.test: Testcase for BUG#43973 --- myisam/mi_packrec.c | 36 +++++++++------------------------- mysql-test/r/myisampack.result | 22 +++++++++++++++++++++ mysql-test/t/myisampack.test | 25 +++++++++++++++++++++++ 3 files changed, 56 insertions(+), 27 deletions(-) diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c index df9a4d18a6c..68911d7f129 100644 --- a/myisam/mi_packrec.c +++ b/myisam/mi_packrec.c @@ -208,10 +208,17 @@ my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys) This segment will be reallocated after construction of the tables. */ length=(uint) (elements*2+trees*(1 << myisam_quick_table_bits)); + /* + To keep some algorithms simpler, we accept that they access + bytes beyond the end of the input data. This can affect up to + one byte less than the "word size" size used in this file, + which is BITS_SAVED / 8. To avoid accessing non-allocated + data, we add (BITS_SAVED / 8) - 1 bytes to the buffer size. + */ if (!(share->decode_tables=(uint16*) my_malloc((length + OFFSET_TABLE_SIZE) * sizeof(uint16) + - (uint) (share->pack.header_length - sizeof(header)), - MYF(MY_WME | MY_ZEROFILL)))) + (uint) (share->pack.header_length - sizeof(header) + + (BITS_SAVED / 8) - 1), MYF(MY_WME | MY_ZEROFILL)))) goto err1; tmp_buff=share->decode_tables+length; disk_cache=(byte*) (tmp_buff+OFFSET_TABLE_SIZE); @@ -1430,31 +1437,6 @@ static void fill_buffer(MI_BIT_BUFF *bit_buff) bit_buff->current_byte=0; return; } - else - { - uint len= 0; - uint i= 0; - /* - Check if the remaining buffer/record to read is less than the word size. - If so read byte by byte - - Note: if this branch becomes a bottleneck it can be removed, assuming - that the second memory segment allocates 7 extra bytes (see - _mi_read_pack_info()). - */ - len= bit_buff->end - bit_buff->pos; - if (len < (BITS_SAVED / 8)) - { - bit_buff->current_byte= 0; - for (i=0 ; i < len ; i++) - { - bit_buff->current_byte+= (((uint) ((uchar) bit_buff->pos[len - i - 1])) - << (8 * i)); - } - bit_buff->pos= bit_buff->end; - return; - } - } #if BITS_SAVED == 64 bit_buff->current_byte= ((((uint) ((uchar) bit_buff->pos[7]))) + diff --git a/mysql-test/r/myisampack.result b/mysql-test/r/myisampack.result index b4b200549a5..736a550e32b 100644 --- a/mysql-test/r/myisampack.result +++ b/mysql-test/r/myisampack.result @@ -38,3 +38,25 @@ SELECT COUNT(*) FROM t1; COUNT(*) 1024 DROP TABLE t1; +# +# Bug #43973 - backup_myisam.test fails on 6.0-bugteam +# +CREATE DATABASE mysql_db1; +CREATE TABLE mysql_db1.t1 (c1 VARCHAR(5), c2 int); +CREATE INDEX i1 ON mysql_db1.t1 (c1, c2); +INSERT INTO mysql_db1.t1 VALUES ('A',1); +INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1; +INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1; +INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1; +INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1; +INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1; +INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1; +INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1; +FLUSH TABLE mysql_db1.t1; +# Compress the table using MYISAMPACK tool +# Run MYISAMCHK tool on the compressed table +SELECT COUNT(*) FROM mysql_db1.t1 WHERE c2 < 5; +COUNT(*) +128 +DROP TABLE mysql_db1.t1; +DROP DATABASE mysql_db1; diff --git a/mysql-test/t/myisampack.test b/mysql-test/t/myisampack.test index ace7afce88a..ce27071bcf8 100644 --- a/mysql-test/t/myisampack.test +++ b/mysql-test/t/myisampack.test @@ -50,3 +50,28 @@ FLUSH TABLE t1; --exec $MYISAMPACK $MYSQLTEST_VARDIR/master-data/test/t1 SELECT COUNT(*) FROM t1; DROP TABLE t1; + +--echo # +--echo # Bug #43973 - backup_myisam.test fails on 6.0-bugteam +--echo # +CREATE DATABASE mysql_db1; +CREATE TABLE mysql_db1.t1 (c1 VARCHAR(5), c2 int); +CREATE INDEX i1 ON mysql_db1.t1 (c1, c2); +INSERT INTO mysql_db1.t1 VALUES ('A',1); +INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1; +INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1; +INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1; +INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1; +INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1; +INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1; +INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1; +FLUSH TABLE mysql_db1.t1; +# +--echo # Compress the table using MYISAMPACK tool +--exec $MYISAMPACK -s $MYSQLTEST_VARDIR/master-data/mysql_db1/t1 +--echo # Run MYISAMCHK tool on the compressed table +--exec $MYISAMCHK -srq $MYSQLTEST_VARDIR/master-data/mysql_db1/t1 +SELECT COUNT(*) FROM mysql_db1.t1 WHERE c2 < 5; +# +DROP TABLE mysql_db1.t1; +DROP DATABASE mysql_db1; From dd0a6eb230686de05429770464c68a9337dadec0 Mon Sep 17 00:00:00 2001 From: Anurag Shekhar Date: Wed, 8 Apr 2009 16:45:43 +0530 Subject: [PATCH 74/99] Bug #43950 myisamchk shows negative value for 'Max keyfile length' While printing the Max keyfile length 'llstr' call was used which was treating the max_key_file_length as negative. Changing this to ullstr fixes the problem. myisamchk output will differ in 32 bit and 64 bit Operating systems so its not possible to have test case for this bug. myisam/myisamchk.c: Replaced llstr by ullstr, while converting share->base.max_key_file_length-1 to string. --- myisam/myisamchk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index 29fb2ea1a60..b1a61f2f373 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -1311,7 +1311,7 @@ static void descript(MI_CHECK *param, register MI_INFO *info, my_string name) share->base.max_key_file_length != HA_OFFSET_ERROR) printf("Max datafile length: %13s Max keyfile length: %13s\n", llstr(share->base.max_data_file_length-1,llbuff), - llstr(share->base.max_key_file_length-1,llbuff2)); + ullstr(share->base.max_key_file_length - 1, llbuff2)); } } From 3308a7f2fd33508b6dc98e4faabb3be6b40e29dc Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Thu, 9 Apr 2009 15:42:59 +0800 Subject: [PATCH 75/99] post fix compiling problem after push BUG#37145 to 5.0-bugteam --- client/mysqltest.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 865c1d9a717..799609a7d27 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -4087,17 +4087,16 @@ int select_connection_name(const char *name) int select_connection(struct st_command *command) { - char *name; char *p= command->first_argument; + static DYNAMIC_STRING ds_connection; + const struct command_arg connection_args[] = { + { "connection_name", ARG_STRING, TRUE, &ds_connection, "Name of the connection that we switch to." } + }; DBUG_ENTER("select_connection"); if (!*p) die("Missing connection name in connect"); - static DYNAMIC_STRING ds_connection; - const struct command_arg connection_args[] = { - { "connection_name", ARG_STRING, TRUE, &ds_connection, "Name of the connection that we switch to." } - }; check_command_args(command, command->first_argument, connection_args, sizeof(connection_args)/sizeof(struct command_arg), ','); From 3b4ec32d45988dc8ccfbea1a6fb7e4f427fb3a08 Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Thu, 9 Apr 2009 16:58:18 +0800 Subject: [PATCH 76/99] Fix compile error on windows for BUG#37145 on 5.0-bugteam --- client/mysqltest.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 799609a7d27..2f19fad9ea9 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -4087,6 +4087,7 @@ int select_connection_name(const char *name) int select_connection(struct st_command *command) { + int ret; char *p= command->first_argument; static DYNAMIC_STRING ds_connection; const struct command_arg connection_args[] = { @@ -4103,7 +4104,7 @@ int select_connection(struct st_command *command) DBUG_PRINT("info", ("changing connection: %s", ds_connection.str)); - int ret= select_connection_name(ds_connection.str); + ret= select_connection_name(ds_connection.str); dynstr_free(&ds_connection); return ret; } From 920abd58b2172ff39275e852924fa2dc41775f1c Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Thu, 9 Apr 2009 14:19:31 +0500 Subject: [PATCH 77/99] Bug#43833 Simple INSERT crashes the server The crash happens due to wrong 'digits' variable value(0), 'digits' can not be 0, so the fix is use 1 as min allowed value. mysql-test/r/insert.result: test result mysql-test/t/insert.test: test case sql/field.cc: The crash happens due to wrong 'digits' variable value(0), 'digits' can not be 0, so the fix is use 1 as min allowed value. --- mysql-test/r/insert.result | 5 +++++ mysql-test/t/insert.test | 9 +++++++++ sql/field.cc | 6 +++--- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result index 2e49bd373d6..c98ed104a69 100644 --- a/mysql-test/r/insert.result +++ b/mysql-test/r/insert.result @@ -595,4 +595,9 @@ SELECT * FROM t2; c1 15449237462 DROP TABLE t1, t2; +CREATE TABLE t1(f1 FLOAT); +INSERT INTO t1 VALUES (1.23); +CREATE TABLE t2(f1 CHAR(1)); +INSERT INTO t2 SELECT f1 FROM t1; +DROP TABLE t1, t2; End of 5.0 tests. diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index 0b5a12fa523..a1735c1a91f 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -454,5 +454,14 @@ SELECT * FROM t2; DROP TABLE t1, t2; +# +# Bug#43833 Simple INSERT crashes the server +# +CREATE TABLE t1(f1 FLOAT); +INSERT INTO t1 VALUES (1.23); +CREATE TABLE t2(f1 CHAR(1)); +INSERT INTO t2 SELECT f1 FROM t1; +DROP TABLE t1, t2; + --echo End of 5.0 tests. diff --git a/sql/field.cc b/sql/field.cc index 36cc4681dec..99e9d7803e1 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5987,13 +5987,13 @@ int Field_str::store(double nr) calculate the maximum number of significant digits if the 'f'-format would be used (+1 for decimal point if the number has a fractional part). */ - digits= max(0, (int) max_length - fractional); + digits= max(1, (int) max_length - fractional); /* If the exponent is negative, decrease digits by the number of leading zeros after the decimal point that do not count as significant digits. */ if (exp < 0) - digits= max(0, (int) digits + exp); + digits= max(1, (int) digits + exp); /* 'e'-format is used only if the exponent is less than -4 or greater than or equal to the precision. In this case we need to adjust the number of @@ -6001,7 +6001,7 @@ int Field_str::store(double nr) We also have to reserve one additional character if abs(exp) >= 100. */ if (exp >= (int) digits || exp < -4) - digits= max(0, (int) (max_length - 5 - (exp >= 100 || exp <= -100))); + digits= max(1, (int) (max_length - 5 - (exp >= 100 || exp <= -100))); /* Limit precision to DBL_DIG to avoid garbage past significant digits */ set_if_smaller(digits, DBL_DIG); From 84ae9ecab0f3761d8086bce4c2f8dfbcfd43f31e Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Thu, 9 Apr 2009 11:40:22 +0100 Subject: [PATCH 78/99] BUG#13684: SP: DROP PROCEDURE|FUNCTION IF EXISTS not binlogged if routine does not exist There is an inconsistency with DROP DATABASE IF EXISTS, DROP TABLE IF EXISTS and DROP VIEW IF EXISTS: those are binlogged even if the DB or TABLE does not exist, whereas DROP PROCEDURE IF EXISTS does not. It would be nice or at least consistent if DROP PROCEDURE/STATEMENT worked the same too. Fixed DROP PROCEDURE|FUNCTION IF EXISTS by adding a call to mysql_bin_log.write in mysql_execute_command. Checked also if all documented "DROP (...) IF EXISTS" get binlogged. NOTE: This is a 5.0 backport patch as requested by support. mysql-test/r/rpl_drop_if_exists.result: Result file for test case added. mysql-test/r/rpl_sp.result: Updated result file for existing test case that has now extra events in binary log (the ones from drop if exists procedure/function). mysql-test/t/rpl_drop_if_exists.test: Added test case for asserting validity of proposed patch. sql/sql_parse.cc: Added call mysql_bin_log.write when lex has drop_if_exists enabled for stored procedures. --- mysql-test/r/rpl_drop_if_exists.result | 80 ++++++++++++++++++++++++++ mysql-test/r/rpl_sp.result | 16 ++++++ mysql-test/t/rpl_drop_if_exists.test | 77 +++++++++++++++++++++++++ sql/sql_parse.cc | 8 +++ 4 files changed, 181 insertions(+) create mode 100644 mysql-test/r/rpl_drop_if_exists.result create mode 100644 mysql-test/t/rpl_drop_if_exists.test diff --git a/mysql-test/r/rpl_drop_if_exists.result b/mysql-test/r/rpl_drop_if_exists.result new file mode 100644 index 00000000000..f711a873122 --- /dev/null +++ b/mysql-test/r/rpl_drop_if_exists.result @@ -0,0 +1,80 @@ +RESET MASTER; +DROP PROCEDURE IF EXISTS db_bug_13684.p; +DROP FUNCTION IF EXISTS db_bug_13684.f; +DROP TRIGGER IF EXISTS db_bug_13684.tr; +DROP VIEW IF EXISTS db_bug_13684.v; +DROP TABLE IF EXISTS db_bug_13684.t; +DROP DATABASE IF EXISTS db_bug_13684; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP PROCEDURE IF EXISTS db_bug_13684.p +master-bin.000001 # Query # # use `test`; DROP FUNCTION IF EXISTS db_bug_13684.f +master-bin.000001 # Query # # use `test`; DROP TRIGGER IF EXISTS db_bug_13684.tr +master-bin.000001 # Query # # use `test`; DROP VIEW IF EXISTS db_bug_13684.v +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS db_bug_13684.t +master-bin.000001 # Query # # DROP DATABASE IF EXISTS db_bug_13684 +CREATE DATABASE db_bug_13684; +CREATE TABLE db_bug_13684.t (a int); +CREATE VIEW db_bug_13684.v +AS SELECT * FROM db_bug_13684.t; +CREATE TRIGGER db_bug_13684.tr BEFORE INSERT ON db_bug_13684.t +FOR EACH ROW BEGIN +END; +CREATE PROCEDURE db_bug_13684.p (OUT p1 INT) +BEGIN +END; +CREATE FUNCTION db_bug_13684.f (s CHAR(20)) +RETURNS CHAR(50) DETERMINISTIC +RETURN s; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP PROCEDURE IF EXISTS db_bug_13684.p +master-bin.000001 # Query # # use `test`; DROP FUNCTION IF EXISTS db_bug_13684.f +master-bin.000001 # Query # # use `test`; DROP TRIGGER IF EXISTS db_bug_13684.tr +master-bin.000001 # Query # # use `test`; DROP VIEW IF EXISTS db_bug_13684.v +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS db_bug_13684.t +master-bin.000001 # Query # # DROP DATABASE IF EXISTS db_bug_13684 +master-bin.000001 # Query # # CREATE DATABASE db_bug_13684 +master-bin.000001 # Query # # use `test`; CREATE TABLE db_bug_13684.t (a int) +master-bin.000001 # Query # # use `test`; CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `db_bug_13684`.`v` AS select `db_bug_13684`.`t`.`a` AS `a` from `db_bug_13684`.`t` +master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` TRIGGER db_bug_13684.tr BEFORE INSERT ON db_bug_13684.t +FOR EACH ROW BEGIN +END +master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `db_bug_13684`.`p`(OUT p1 INT) +BEGIN +END +master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` FUNCTION `db_bug_13684`.`f`(s CHAR(20)) RETURNS char(50) CHARSET latin1 + DETERMINISTIC +RETURN s +DROP PROCEDURE IF EXISTS db_bug_13684.p; +DROP FUNCTION IF EXISTS db_bug_13684.f; +DROP TRIGGER IF EXISTS db_bug_13684.tr; +DROP VIEW IF EXISTS db_bug_13684.v; +DROP TABLE IF EXISTS db_bug_13684.t; +DROP DATABASE IF EXISTS db_bug_13684; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; DROP PROCEDURE IF EXISTS db_bug_13684.p +master-bin.000001 # Query # # use `test`; DROP FUNCTION IF EXISTS db_bug_13684.f +master-bin.000001 # Query # # use `test`; DROP TRIGGER IF EXISTS db_bug_13684.tr +master-bin.000001 # Query # # use `test`; DROP VIEW IF EXISTS db_bug_13684.v +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS db_bug_13684.t +master-bin.000001 # Query # # DROP DATABASE IF EXISTS db_bug_13684 +master-bin.000001 # Query # # CREATE DATABASE db_bug_13684 +master-bin.000001 # Query # # use `test`; CREATE TABLE db_bug_13684.t (a int) +master-bin.000001 # Query # # use `test`; CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `db_bug_13684`.`v` AS select `db_bug_13684`.`t`.`a` AS `a` from `db_bug_13684`.`t` +master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` TRIGGER db_bug_13684.tr BEFORE INSERT ON db_bug_13684.t +FOR EACH ROW BEGIN +END +master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `db_bug_13684`.`p`(OUT p1 INT) +BEGIN +END +master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` FUNCTION `db_bug_13684`.`f`(s CHAR(20)) RETURNS char(50) CHARSET latin1 + DETERMINISTIC +RETURN s +master-bin.000001 # Query # # use `test`; DROP PROCEDURE IF EXISTS db_bug_13684.p +master-bin.000001 # Query # # use `test`; DROP FUNCTION IF EXISTS db_bug_13684.f +master-bin.000001 # Query # # use `test`; DROP TRIGGER IF EXISTS db_bug_13684.tr +master-bin.000001 # Query # # use `test`; DROP VIEW IF EXISTS db_bug_13684.v +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS db_bug_13684.t +master-bin.000001 # Query # # DROP DATABASE IF EXISTS db_bug_13684 diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result index ebe5f8b0be9..0f4d0fa8dad 100644 --- a/mysql-test/r/rpl_sp.result +++ b/mysql-test/r/rpl_sp.result @@ -483,6 +483,7 @@ master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1 master-bin.000001 # Query 1 # drop database mysqltest1 master-bin.000001 # Query 1 # drop user "zedjzlcsjhd"@127.0.0.1 +master-bin.000001 # Query 1 # use `test`; drop function if exists f1 master-bin.000001 # Query 1 # use `test`; CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11) READS SQL DATA begin @@ -498,12 +499,15 @@ master-bin.000001 # Query 1 # use `test`; create table t1 (a int) master-bin.000001 # Query 1 # use `test`; insert into t1 (a) values (f1()) master-bin.000001 # Query 1 # use `test`; drop view v1 master-bin.000001 # Query 1 # use `test`; drop function f1 +master-bin.000001 # Query 1 # use `test`; DROP PROCEDURE IF EXISTS p1 master-bin.000001 # Query 1 # use `test`; DROP TABLE IF EXISTS t1 master-bin.000001 # Query 1 # use `test`; CREATE TABLE t1(col VARCHAR(10)) master-bin.000001 # Query 1 # use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`(arg VARCHAR(10)) INSERT INTO t1 VALUES(arg) master-bin.000001 # Query 1 # use `test`; INSERT INTO t1 VALUES( NAME_CONST('arg',_latin1'test' COLLATE 'latin1_swedish_ci')) master-bin.000001 # Query 1 # use `test`; DROP PROCEDURE p1 +master-bin.000001 # Query 1 # use `test`; DROP PROCEDURE IF EXISTS p1 +master-bin.000001 # Query 1 # use `test`; DROP FUNCTION IF EXISTS f1 master-bin.000001 # Query 1 # use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`() SET @a = 1 master-bin.000001 # Query 1 # use `test`; CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11) @@ -804,6 +808,9 @@ drop user "zedjzlcsjhd"@127.0.0.1 /*!*/; use test/*!*/; SET TIMESTAMP=t/*!*/; +drop function if exists f1 +/*!*/; +SET TIMESTAMP=t/*!*/; CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11) READS SQL DATA begin @@ -831,6 +838,9 @@ SET TIMESTAMP=t/*!*/; drop function f1 /*!*/; SET TIMESTAMP=t/*!*/; +DROP PROCEDURE IF EXISTS p1 +/*!*/; +SET TIMESTAMP=t/*!*/; DROP TABLE IF EXISTS t1 /*!*/; SET TIMESTAMP=t/*!*/; @@ -847,6 +857,12 @@ SET TIMESTAMP=t/*!*/; DROP PROCEDURE p1 /*!*/; SET TIMESTAMP=t/*!*/; +DROP PROCEDURE IF EXISTS p1 +/*!*/; +SET TIMESTAMP=t/*!*/; +DROP FUNCTION IF EXISTS f1 +/*!*/; +SET TIMESTAMP=t/*!*/; CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`() SET @a = 1 /*!*/; diff --git a/mysql-test/t/rpl_drop_if_exists.test b/mysql-test/t/rpl_drop_if_exists.test new file mode 100644 index 00000000000..a042fa8caff --- /dev/null +++ b/mysql-test/t/rpl_drop_if_exists.test @@ -0,0 +1,77 @@ +# BUG#13684: +# SP: DROP PROCEDURE|FUNCTION IF EXISTS not binlogged if routine +# does not exist +# +# There is an inconsistency with DROP DATABASE IF EXISTS, DROP +# TABLE IF EXISTS and DROP VIEW IF EXISTS: those are binlogged even +# if the DB or TABLE does not exist, whereas DROP PROCEDURE IF +# EXISTS does not. It would be nice or at least consistent if DROP +# PROCEDURE/STATEMENT worked the same too. +# +# Description: +# DROP PROCEDURE|FUNCTION IF EXISTS does not get binlogged whereas DROP +# DATABASE|TABLE|TRIGGER|... IF EXISTS do. +# +# Fixed DROP PROCEDURE|FUNCTION IF EXISTS by adding a call to +# mysql_bin_log.write in mysql_execute_command. Checked also if all +# documented "DROP (...) IF EXISTS" get binlogged. +# +# Test is implemented as follows: +# +# i) test each "drop if exists" (DDL) +# ii) show binlog events; +# iii) create an object for each drop if exists statement; +# iv) issue "drop if exists" in existent objects. +# v) show binlog events; +# + +--source include/have_log_bin.inc +RESET MASTER; + +disable_warnings; + +# test all "drop if exists" in manual with inexistent objects +DROP PROCEDURE IF EXISTS db_bug_13684.p; +DROP FUNCTION IF EXISTS db_bug_13684.f; +DROP TRIGGER IF EXISTS db_bug_13684.tr; +DROP VIEW IF EXISTS db_bug_13684.v; +DROP TABLE IF EXISTS db_bug_13684.t; +DROP DATABASE IF EXISTS db_bug_13684; + +--source include/show_binlog_events.inc + +# test drop with existing values + +# create +CREATE DATABASE db_bug_13684; + +CREATE TABLE db_bug_13684.t (a int); + +CREATE VIEW db_bug_13684.v + AS SELECT * FROM db_bug_13684.t; + +CREATE TRIGGER db_bug_13684.tr BEFORE INSERT ON db_bug_13684.t + FOR EACH ROW BEGIN + END; + +CREATE PROCEDURE db_bug_13684.p (OUT p1 INT) + BEGIN + END; + +CREATE FUNCTION db_bug_13684.f (s CHAR(20)) + RETURNS CHAR(50) DETERMINISTIC + RETURN s; + +--source include/show_binlog_events.inc + +# drop existing +DROP PROCEDURE IF EXISTS db_bug_13684.p; +DROP FUNCTION IF EXISTS db_bug_13684.f; +DROP TRIGGER IF EXISTS db_bug_13684.tr; +DROP VIEW IF EXISTS db_bug_13684.v; +DROP TABLE IF EXISTS db_bug_13684.t; +DROP DATABASE IF EXISTS db_bug_13684; + +--source include/show_binlog_events.inc + +enable_warnings; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e4618874fb9..7fbe6b86fbd 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5067,6 +5067,14 @@ create_sp_error: case SP_KEY_NOT_FOUND: if (lex->drop_if_exists) { + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query, thd->query_length, + /* using_trans */ 0, + /* suppress use */ FALSE, + THD::NOT_KILLED); + mysql_bin_log.write(&qinfo); + } push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), SP_COM_STRING(lex), lex->spname->m_name.str); From 3819daf0640c298774581aeb9ec7b7aa11b2c6d2 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Tue, 14 Apr 2009 19:16:30 +0500 Subject: [PATCH 79/99] Bug#41268 Help Text for \c is misleading in client command line interface(addon) fixed message for 'help' command client/mysql.cc: fixed message for 'help' command --- client/mysql.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysql.cc b/client/mysql.cc index 983d7719c3c..93aab390e5a 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -241,7 +241,7 @@ typedef struct { static COMMANDS commands[] = { { "?", '?', com_help, 1, "Synonym for `help'." }, - { "clear", 'c', com_clear, 0, "Clear command."}, + { "clear", 'c', com_clear, 0, "Clear the current input statement."}, { "connect",'r', com_connect,1, "Reconnect to the server. Optional arguments are db and host." }, { "delimiter", 'd', com_delimiter, 1, From 9301da563fa9643648413aedc2eadce72097d317 Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Thu, 16 Apr 2009 11:40:51 +0200 Subject: [PATCH 80/99] Bug#42430 Final commit to 5.0-bugteam --- cmd-line-utils/libedit/term.c | 2 +- ndb/tools/restore/consumer_restore.cpp | 4 ++-- ndb/tools/restore/consumer_restorem.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd-line-utils/libedit/term.c b/cmd-line-utils/libedit/term.c index 488c760da14..2f1aefa7117 100644 --- a/cmd-line-utils/libedit/term.c +++ b/cmd-line-utils/libedit/term.c @@ -61,7 +61,7 @@ static char sccsid[] = "@(#)term.c 8.2 (Berkeley) 4/30/95"; #ifdef HAVE_NCURSES_H #include #endif -/* Solaris's term.h does horrid things. */ +/* Don't use Solaris's term.h. */ #if (defined(HAVE_TERM_H) && !defined(__SunOS)) #include #endif diff --git a/ndb/tools/restore/consumer_restore.cpp b/ndb/tools/restore/consumer_restore.cpp index 811868f3e77..869dd0e9d8b 100644 --- a/ndb/tools/restore/consumer_restore.cpp +++ b/ndb/tools/restore/consumer_restore.cpp @@ -556,7 +556,7 @@ BackupRestore::logEntry(const LogEntry & tup) NdbTransaction * trans = m_ndb->startTransaction(); if (trans == NULL) { - // Deep shit, TODO: handle the error + // TODO: handle the error err << "Cannot start transaction" << endl; exitHandler(); } // if @@ -693,7 +693,7 @@ BackupRestore::tuple(const TupleS & tup) NdbTransaction * trans = m_ndb->startTransaction(); if (trans == NULL) { - // Deep shit, TODO: handle the error + // TODO: handle the error ndbout << "Cannot start transaction" << endl; exitHandler(); } // if diff --git a/ndb/tools/restore/consumer_restorem.cpp b/ndb/tools/restore/consumer_restorem.cpp index 2dc0476b5a6..642c9e4acb4 100644 --- a/ndb/tools/restore/consumer_restorem.cpp +++ b/ndb/tools/restore/consumer_restorem.cpp @@ -373,7 +373,7 @@ BackupRestore::tuple(const TupleS & tup) NdbTransaction * trans = m_ndb->startTransaction(); if (trans == NULL) { - // Deep shit, TODO: handle the error + // TODO: handle the error ndbout << "Cannot start transaction" << endl; exit(-1); } // if @@ -462,7 +462,7 @@ BackupRestore::logEntry(const LogEntry & tup) NdbTransaction * trans = m_ndb->startTransaction(); if (trans == NULL) { - // Deep shit, TODO: handle the error + // TODO: handle the error ndbout << "Cannot start transaction" << endl; exit(-1); } // if From 60083f4895b3c21cf24f311ea5d483a06e75b1f8 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 16 Apr 2009 16:47:02 +0300 Subject: [PATCH 81/99] bumped the version to 5.0.82 (5.0.81-community to be released) --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 1fbb5bf9b7a..9267e5d3189 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.81) +AM_INIT_AUTOMAKE(mysql, 5.0.82) AM_CONFIG_HEADER([include/config.h:config.h.in]) 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=81 +NDB_VERSION_BUILD=82 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From 5b05d360b0003de4aaa8b0e88d7a70d5c70dfb72 Mon Sep 17 00:00:00 2001 From: Patrick Crews Date: Thu, 16 Apr 2009 13:47:44 -0400 Subject: [PATCH 82/99] Bug#26887 - main.count_distinct3 fails randomly Streamlined how we increase the size of our test table. The new method shows run time decreased by ~60%. This is not a guarantee that we will not see test timeouts (the random failures noted in the bug), but it should significantly reduce the chances of this occurring. --- mysql-test/r/count_distinct3.result | 5 ++-- mysql-test/t/count_distinct3.test | 39 +++++++++++------------------ 2 files changed, 17 insertions(+), 27 deletions(-) diff --git a/mysql-test/r/count_distinct3.result b/mysql-test/r/count_distinct3.result index 086e1360b0c..840c26669a1 100644 --- a/mysql-test/r/count_distinct3.result +++ b/mysql-test/r/count_distinct3.result @@ -2,7 +2,8 @@ DROP TABLE IF EXISTS t1, t2; CREATE TABLE t1 (id INTEGER, grp TINYINT, id_rev INTEGER); SELECT COUNT(*) FROM t1; COUNT(*) -4181000 +4201000 SELECT COUNT(DISTINCT id) FROM t1 GROUP BY grp; +# Begin cleanup +SET session myisam_sort_buffer_size = @orig_myisam_sort_buffer_size; DROP TABLE t1; -set @@read_buffer_size=default; diff --git a/mysql-test/t/count_distinct3.test b/mysql-test/t/count_distinct3.test index f817b2c635d..2f7cf7e5260 100644 --- a/mysql-test/t/count_distinct3.test +++ b/mysql-test/t/count_distinct3.test @@ -1,4 +1,4 @@ -# +# Bug #958 a big table without indices and select with group by doesnt work # this is a test for error 1032 in count(distinct) + group by, introduced in # mysql-4.1 # @@ -21,27 +21,16 @@ while ($1) INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev); dec $1; } -set @@read_buffer_size=2*1024*1024; -CREATE TABLE t2 SELECT * FROM t1; -INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; -INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; -INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; -INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; -INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; -INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; -INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; -INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; -INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; -INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; -INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; -INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; -INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; -INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; -INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; -INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; -INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; -INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; -DROP TABLE t2; + +# We increase the size of t1 here. +SET @orig_myisam_sort_buffer_size = @@session.myisam_sort_buffer_size; +SET session myisam_sort_buffer_size=20000000; +INSERT INTO t1 +SELECT A.id, A.grp, A.id_rev +FROM + t1 A, + (SELECT * FROM t1 B LIMIT 100) B, + (SELECT * FROM t1 Z LIMIT 42) Z; --enable_query_log SELECT COUNT(*) FROM t1; @@ -49,12 +38,12 @@ SELECT COUNT(*) FROM t1; # As t1 contains random numbers, results are different from test to test. # That's okay, because we test only that select doesn't yield an # error. Note, that --disable_result_log doesn't suppress error output. - --disable_result_log SELECT COUNT(DISTINCT id) FROM t1 GROUP BY grp; --enable_result_log + +--echo # Begin cleanup +SET session myisam_sort_buffer_size = @orig_myisam_sort_buffer_size; DROP TABLE t1; -set @@read_buffer_size=default; - # End of 4.1 tests From ff923cc82d23f9806834a2411150e32d30b9f4d9 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 17 Apr 2009 12:41:15 +0500 Subject: [PATCH 83/99] Bug#44151 using handler commands on information_schema tables crashes server information schema tables are based on internal tmp tables which are removed after each statement execution. So HANDLER comands can not be used with information schema. mysql-test/r/handler.result: test result mysql-test/t/handler.test: test case sql/sql_handler.cc: information schema tables are based on internal tmp tables which are removed after each statement execution. So HANDLER comands can not be used with information schema. --- mysql-test/r/handler.result | 4 ++++ mysql-test/t/handler.test | 8 ++++++++ sql/sql_handler.cc | 8 ++++++++ 3 files changed, 20 insertions(+) diff --git a/mysql-test/r/handler.result b/mysql-test/r/handler.result index dc3750e16ea..4906111982f 100644 --- a/mysql-test/r/handler.result +++ b/mysql-test/r/handler.result @@ -502,3 +502,7 @@ handler t1_alias READ a next where inexistent > 0; ERROR 42S22: Unknown column 'inexistent' in 'field list' handler t1_alias close; drop table t1; +USE information_schema; +HANDLER COLUMNS OPEN; +ERROR HY000: Incorrect usage of HANDLER OPEN and information_schema +USE test; diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test index 6ef216f6ed2..70d4157a272 100644 --- a/mysql-test/t/handler.test +++ b/mysql-test/t/handler.test @@ -460,3 +460,11 @@ handler t1_alias read a next; handler t1_alias READ a next where inexistent > 0; handler t1_alias close; drop table t1; + +# +# Bug#44151 using handler commands on information_schema tables crashes server +# +USE information_schema; +--error ER_WRONG_USAGE +HANDLER COLUMNS OPEN; +USE test; diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index c376f1b3d1d..721b365a7b9 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -190,6 +190,14 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) tables->db, tables->table_name, tables->alias, (int) reopen)); + if (tables->schema_table) + { + my_error(ER_WRONG_USAGE, MYF(0), "HANDLER OPEN", + INFORMATION_SCHEMA_NAME.str); + DBUG_PRINT("exit",("ERROR")); + DBUG_RETURN(TRUE); + } + if (! hash_inited(&thd->handler_tables_hash)) { /* From 08044795697dfd588841f9bacf589a4eeeff2431 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 17 Apr 2009 18:52:57 +0300 Subject: [PATCH 84/99] Bug #35087: Inserting duplicate values at one time with DES_ENCRYPT leads to wrong results 3 problems found with DES_ENCRYPT/DES_DECRYPT : 1. The max length was not calculated properly. Fixed in fix_length_and_dec() 2. DES_ENCRYPT had a side effect of sometimes reallocating and changing the value of its argument. Fixed by explicitly pre-allocating the necessary space to pad the argument with trailing '*' (stars) when calculating the DES digest. 3. in DES_ENCRYPT the string buffer for the result value was not reallocated to the correct size and only string length was assigned to it. Fixed by making sure there's enough space to hold the result. --- mysql-test/r/func_des_encrypt.result | 34 ++++++++++++++++++++++++++++ mysql-test/t/func_des_encrypt.test | 28 +++++++++++++++++++++++ sql/item_strfunc.cc | 12 ++++++---- sql/item_strfunc.h | 15 +++++++++--- 4 files changed, 82 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/func_des_encrypt.result b/mysql-test/r/func_des_encrypt.result index 46b30bdab58..b81f96f6ef7 100644 --- a/mysql-test/r/func_des_encrypt.result +++ b/mysql-test/r/func_des_encrypt.result @@ -1,3 +1,37 @@ select des_encrypt('hello'); des_encrypt('hello') €Ö2nV“Ø} +# +# Bug #11643: des_encrypt() causes server to die +# +CREATE TABLE t1 (des VARBINARY(200) NOT NULL DEFAULT '') ENGINE=MyISAM; +INSERT INTO t1 VALUES ('1234'), ('12345'), ('123456'), ('1234567'); +UPDATE t1 SET des=DES_ENCRYPT('1234'); +SELECT LENGTH(des) FROM t1; +LENGTH(des) +9 +9 +9 +9 +SELECT DES_DECRYPT(des) FROM t1; +DES_DECRYPT(des) +1234 +1234 +1234 +1234 +SELECT +LENGTH(DES_ENCRYPT('1234')), +LENGTH(DES_ENCRYPT('12345')), +LENGTH(DES_ENCRYPT('123456')), +LENGTH(DES_ENCRYPT('1234567')); +LENGTH(DES_ENCRYPT('1234')) LENGTH(DES_ENCRYPT('12345')) LENGTH(DES_ENCRYPT('123456')) LENGTH(DES_ENCRYPT('1234567')) +9 9 9 9 +SELECT +DES_DECRYPT(DES_ENCRYPT('1234')), +DES_DECRYPT(DES_ENCRYPT('12345')), +DES_DECRYPT(DES_ENCRYPT('123456')), +DES_DECRYPT(DES_ENCRYPT('1234567')); +DES_DECRYPT(DES_ENCRYPT('1234')) DES_DECRYPT(DES_ENCRYPT('12345')) DES_DECRYPT(DES_ENCRYPT('123456')) DES_DECRYPT(DES_ENCRYPT('1234567')) +1234 12345 123456 1234567 +DROP TABLE t1; +End of 5.0 tests diff --git a/mysql-test/t/func_des_encrypt.test b/mysql-test/t/func_des_encrypt.test index b757a632adf..2c364a40090 100644 --- a/mysql-test/t/func_des_encrypt.test +++ b/mysql-test/t/func_des_encrypt.test @@ -9,3 +9,31 @@ select des_encrypt('hello'); # End of 4.1 tests + +--echo # +--echo # Bug #11643: des_encrypt() causes server to die +--echo # + +CREATE TABLE t1 (des VARBINARY(200) NOT NULL DEFAULT '') ENGINE=MyISAM; + +INSERT INTO t1 VALUES ('1234'), ('12345'), ('123456'), ('1234567'); + +UPDATE t1 SET des=DES_ENCRYPT('1234'); + +SELECT LENGTH(des) FROM t1; +SELECT DES_DECRYPT(des) FROM t1; + +SELECT + LENGTH(DES_ENCRYPT('1234')), + LENGTH(DES_ENCRYPT('12345')), + LENGTH(DES_ENCRYPT('123456')), + LENGTH(DES_ENCRYPT('1234567')); +SELECT + DES_DECRYPT(DES_ENCRYPT('1234')), + DES_DECRYPT(DES_ENCRYPT('12345')), + DES_DECRYPT(DES_ENCRYPT('123456')), + DES_DECRYPT(DES_ENCRYPT('1234567')); + +DROP TABLE t1; + +--Echo End of 5.0 tests diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 7edc1a62307..4640929b2bf 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -473,17 +473,21 @@ String *Item_func_des_encrypt::val_str(String *str) string marking change of string length. */ - tail= (8-(res_length) % 8); // 1..8 marking extra length + tail= 8 - (res_length % 8); // 1..8 marking extra length res_length+=tail; + tmp_arg.realloc(res_length); + tmp_arg.length(0); + tmp_arg.append(res->ptr(), res->length()); code= ER_OUT_OF_RESOURCES; - if (tail && res->append(append_str, tail) || tmp_value.alloc(res_length+1)) + if (tmp_arg.append(append_str, tail) || tmp_value.alloc(res_length+1)) goto error; - (*res)[res_length-1]=tail; // save extra length + tmp_arg[res_length-1]=tail; // save extra length + tmp_value.realloc(res_length+1); tmp_value.length(res_length+1); tmp_value[0]=(char) (128 | key_number); // Real encryption bzero((char*) &ivec,sizeof(ivec)); - DES_ede3_cbc_encrypt((const uchar*) (res->ptr()), + DES_ede3_cbc_encrypt((const uchar*) (tmp_arg.ptr()), (uchar*) (tmp_value.ptr()+1), res_length, &keyschedule.ks1, diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 9794a092648..1c5346ab074 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -306,13 +306,17 @@ public: class Item_func_des_encrypt :public Item_str_func { - String tmp_value; + String tmp_value,tmp_arg; public: Item_func_des_encrypt(Item *a) :Item_str_func(a) {} Item_func_des_encrypt(Item *a, Item *b): Item_str_func(a,b) {} String *val_str(String *); void fix_length_and_dec() - { maybe_null=1; max_length = args[0]->max_length+8; } + { + maybe_null=1; + /* 9 = MAX ((8- (arg_len % 8)) + 1) */ + max_length = args[0]->max_length + 9; + } const char *func_name() const { return "des_encrypt"; } }; @@ -323,7 +327,12 @@ public: Item_func_des_decrypt(Item *a) :Item_str_func(a) {} Item_func_des_decrypt(Item *a, Item *b): Item_str_func(a,b) {} String *val_str(String *); - void fix_length_and_dec() { maybe_null=1; max_length = args[0]->max_length; } + void fix_length_and_dec() + { + maybe_null=1; + /* 9 = MAX ((8- (arg_len % 8)) + 1) */ + max_length = args[0]->max_length - 9; + } const char *func_name() const { return "des_decrypt"; } }; From f8b219ee296f58358d66c443dc89adfa6b718bda Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Tue, 21 Apr 2009 14:01:13 +0500 Subject: [PATCH 85/99] BUG#36966 - mysqldump.test fails in pushbuild mysqldump.test is designed to run with concurrent inserts disabled. It is disabling concurrent inserts at the very beginning of the test case, and re-enables them at the bottom of the test. But for some reason (likely incorrect merge) we enable concurrent inserts in the middle of the test. The problem is fixed by enabling concurrent inserts only at the bottom of the test case. --- mysql-test/r/mysqldump.result | 2 +- mysql-test/t/mysqldump.test | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 1897a7df799..ce24922db28 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -3557,7 +3557,6 @@ DROP TABLE t1,t2; -- Dump completed on DATE -SET @@GLOBAL.CONCURRENT_INSERT = @OLD_CONCURRENT_INSERT; # # Bug #42635: mysqldump includes views that were excluded using # the --ignore-table option @@ -3693,6 +3692,7 @@ UNLOCK TABLES; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE `כדשגכחךלדגכחשךדגחכךלדגכ`; SET NAMES latin1; +SET @@GLOBAL.CONCURRENT_INSERT = @OLD_CONCURRENT_INSERT; # # End of 5.0 tests # diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 52eecc62931..1e9090fdd01 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -1646,9 +1646,6 @@ DROP TABLE t1,t2; --replace_regex /-- [^D][^u][^m][^p].*// /\/\*!.*// / on [0-9 :-]+/ on DATE/ --exec $MYSQL_DUMP test -# We reset concurrent_inserts value to whatever it was at the start of the test -SET @@GLOBAL.CONCURRENT_INSERT = @OLD_CONCURRENT_INSERT; - --echo # --echo # Bug #42635: mysqldump includes views that were excluded using --echo # the --ignore-table option @@ -1681,6 +1678,9 @@ CREATE TABLE `כדשגכחךלדגכחשךדגחכךלדגכ` ( f1 INT ); DROP TABLE `כדשגכחךלדגכחשךדגחכךלדגכ`; SET NAMES latin1; +# We reset concurrent_inserts value to whatever it was at the start of the test +# This line must be executed _after_ all test cases. +SET @@GLOBAL.CONCURRENT_INSERT = @OLD_CONCURRENT_INSERT; --echo # --echo # End of 5.0 tests From e1b22ab9a1f0acfaec4cf3077b94e49fbadf2684 Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Thu, 23 Apr 2009 19:52:39 +0200 Subject: [PATCH 86/99] Bug#33146 CHECKSUM TABLE is not interruptable by KILL QUERY statement Commit 55629 applied to 5.0-bugteam and 5.1-bugteam: Check for thd->killed in CHECKSUM loop. --- sql/sql_table.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index eec6ad626f0..08ea093f2c8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4376,6 +4376,16 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt) { for (;;) { + if (thd->killed) + { + /* + we've been killed; let handler clean up, and remove the + partial current row from the recordset (embedded lib) + */ + t->file->ha_rnd_end(); + thd->protocol->remove_last_row(); + goto err; + } ha_checksum row_crc= 0; int error= t->file->rnd_next(t->record[0]); if (unlikely(error)) From 4610c13a2477e88bc055febb886e90a562bc2f76 Mon Sep 17 00:00:00 2001 From: Satya B Date: Fri, 24 Apr 2009 16:33:50 +0530 Subject: [PATCH 87/99] Fix for BUG#43660- SHOW INDEXES/ANALYZE does NOT update cardinality for indexes of InnoDB table Fixes by replacing the PRNG that is used to pick random pages with a better one. Also adds a configuration option "innodb_use_legacy_cardinality_algorithm" to enable the fix only when the option is set. This patch is from http://bugs.mysql.com/file.php?id=11789 --- innobase/include/srv0srv.h | 6 +++ innobase/page/page0cur.c | 75 +++++++++++++++++++++++++++++++++++++- innobase/srv/srv0srv.c | 6 +++ sql/ha_innodb.h | 5 +++ sql/mysqld.cc | 11 +++++- sql/set_var.cc | 6 +++ 6 files changed, 106 insertions(+), 3 deletions(-) diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h index 97e9136040d..ece6b1d763f 100644 --- a/innobase/include/srv0srv.h +++ b/innobase/include/srv0srv.h @@ -253,6 +253,12 @@ extern ulint srv_read_ahead_seq; /* variable to count the number of random read-aheads were done */ extern ulint srv_read_ahead_rnd; +/* An option to enable the fix for "Bug#43660 SHOW INDEXES/ANALYZE does +NOT update cardinality for indexes of InnoDB table". By default we are +running with the fix disabled because MySQL 5.1 is frozen for such +behavioral changes. */ +extern char srv_use_legacy_cardinality_algorithm; + /* In this structure we store status variables to be passed to MySQL */ typedef struct export_var_struct export_struc; diff --git a/innobase/page/page0cur.c b/innobase/page/page0cur.c index d0b89e81787..93082560001 100644 --- a/innobase/page/page0cur.c +++ b/innobase/page/page0cur.c @@ -15,6 +15,8 @@ Created 10/4/1994 Heikki Tuuri #include "mtr0log.h" #include "log0recv.h" #include "rem0cmp.h" +#include "srv0srv.h" +#include "ut0ut.h" static ulint page_rnd = 976722341; @@ -23,6 +25,44 @@ static ulint page_rnd = 976722341; ulint page_cur_short_succ = 0; # endif /* UNIV_SEARCH_PERF_STAT */ +/*********************************************************************** +This is a linear congruential generator PRNG. Returns a pseudo random +number between 0 and 2^64-1 inclusive. The formula and the constants +being used are: +X[n+1] = (a * X[n] + c) mod m +where: +X[0] = ut_usectime() +a = 1103515245 (3^5 * 5 * 7 * 129749) +c = 12345 (3 * 5 * 823) +m = 18446744073709551616 (2^64) +*/ +#define LCG_a 1103515245 +#define LCG_c 12345 +static +unsigned long long +page_cur_lcg_prng() +/*===============*/ + /* out: number between 0 and 2^64-1 */ +{ + static unsigned long long lcg_current = 0; + static ibool initialized = FALSE; + ulint time_sec; + ulint time_ms; + + if (!initialized) { + ut_usectime(&time_sec, &time_ms); + lcg_current = (unsigned long long) (time_sec * 1000000 + + time_ms); + initialized = TRUE; + } + + /* no need to "% 2^64" explicitly because lcg_current is + 64 bit and this will be done anyway */ + lcg_current = LCG_a * lcg_current + LCG_c; + + return(lcg_current); +} + /******************************************************************** Tries a search shortcut based on the last insert. */ UNIV_INLINE @@ -489,9 +529,13 @@ page_cur_open_on_rnd_user_rec( return; } - page_rnd += 87584577; + if (srv_use_legacy_cardinality_algorithm) { + page_rnd += 87584577; - rnd = page_rnd % page_get_n_recs(page); + rnd = page_rnd % page_get_n_recs(page); + } else { + rnd = (ulint) page_cur_lcg_prng() % page_get_n_recs(page); + } rec = page_get_infimum_rec(page); @@ -1419,3 +1463,30 @@ page_cur_delete_rec( page_dir_balance_slot(page, cur_slot_no); } } + +#ifdef UNIV_COMPILE_TEST_FUNCS + +/*********************************************************************** +Print the first n numbers, generated by page_cur_lcg_prng() to make sure +(visually) that it works properly. */ +void +test_page_cur_lcg_prng( +/*===================*/ + int n) /* in: print first n numbers */ +{ + int i; + unsigned long long rnd; + + for (i = 0; i < n; i++) { + rnd = page_cur_lcg_prng(); + printf("%llu\t%%2=%llu %%3=%llu %%5=%llu %%7=%llu %%11=%llu\n", + rnd, + rnd % 2, + rnd % 3, + rnd % 5, + rnd % 7, + rnd % 11); + } +} + +#endif /* UNIV_COMPILE_TEST_FUNCS */ diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index 6b755ae9816..0974c616db3 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -239,6 +239,12 @@ ulint srv_read_ahead_seq = 0; /* variable to count the number of random read-aheads */ ulint srv_read_ahead_rnd = 0; +/* An option to enable the fix for "Bug#43660 SHOW INDEXES/ANALYZE does +NOT update cardinality for indexes of InnoDB table". By default we are +running with the fix disabled because MySQL 5.1 is frozen for such +behavioral changes. */ +char srv_use_legacy_cardinality_algorithm = TRUE; + /* structure to pass status variables to MySQL */ export_struc export_vars; diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 3db983901b3..e27fb89d014 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -234,6 +234,11 @@ extern ulong srv_thread_sleep_delay; extern ulong srv_thread_concurrency; extern ulong srv_commit_concurrency; extern ulong srv_flush_log_at_trx_commit; +/* An option to enable the fix for "Bug#43660 SHOW INDEXES/ANALYZE does +NOT update cardinality for indexes of InnoDB table". By default we are +running with the fix disabled because MySQL 5.1 is frozen for such +behavioral changes. */ +extern char srv_use_legacy_cardinality_algorithm; } bool innobase_init(void); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index ad3521e5dde..0583e3fa57f 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5044,7 +5044,8 @@ enum options_mysqld OPT_SECURE_FILE_PRIV, OPT_KEEP_FILES_ON_CREATE, OPT_INNODB_ADAPTIVE_HASH_INDEX, - OPT_FEDERATED + OPT_FEDERATED, + OPT_INNODB_USE_LEGACY_CARDINALITY_ALGORITHM }; @@ -5351,6 +5352,14 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite, (gptr*) &global_system_variables.innodb_table_locks, (gptr*) &global_system_variables.innodb_table_locks, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, + {"innodb_use_legacy_cardinality_algorithm", + OPT_INNODB_USE_LEGACY_CARDINALITY_ALGORITHM, + "Use legacy algorithm for picking random pages during index cardinality " + "estimation. Disable this to use a better algorithm, but note that your " + "query plans may change (enabled by default).", + (gptr*) &srv_use_legacy_cardinality_algorithm, + (gptr*) &srv_use_legacy_cardinality_algorithm, + 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, #endif /* End HAVE_INNOBASE_DB */ {"isam", OPT_ISAM, "Obsolete. ISAM storage engine is no longer supported.", (gptr*) &opt_isam, (gptr*) &opt_isam, 0, GET_BOOL, NO_ARG, 0, 0, 0, diff --git a/sql/set_var.cc b/sql/set_var.cc index 735bb5279bd..14ec2e57aab 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -450,6 +450,9 @@ sys_var_thd_bool sys_innodb_table_locks("innodb_table_locks", &SV::innodb_table_locks); sys_var_thd_bool sys_innodb_support_xa("innodb_support_xa", &SV::innodb_support_xa); +sys_var_bool_ptr sys_innodb_use_legacy_cardinality_algorithm( + "innodb_use_legacy_cardinality_algorithm", + &srv_use_legacy_cardinality_algorithm); sys_var_long_ptr sys_innodb_autoextend_increment("innodb_autoextend_increment", &srv_auto_extend_increment); sys_var_long_ptr sys_innodb_sync_spin_loops("innodb_sync_spin_loops", @@ -804,6 +807,7 @@ sys_var *sys_variables[]= &sys_innodb_max_purge_lag, &sys_innodb_table_locks, &sys_innodb_support_xa, + &sys_innodb_use_legacy_cardinality_algorithm, &sys_innodb_autoextend_increment, &sys_innodb_sync_spin_loops, &sys_innodb_concurrency_tickets, @@ -946,6 +950,8 @@ struct show_var_st init_vars[]= { {sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS}, {sys_innodb_thread_concurrency.name, (char*) &sys_innodb_thread_concurrency, SHOW_SYS}, {sys_innodb_thread_sleep_delay.name, (char*) &sys_innodb_thread_sleep_delay, SHOW_SYS}, + {sys_innodb_use_legacy_cardinality_algorithm.name, + (char*) &sys_innodb_use_legacy_cardinality_algorithm, SHOW_SYS}, #endif {sys_interactive_timeout.name,(char*) &sys_interactive_timeout, SHOW_SYS}, {sys_join_buffer_size.name, (char*) &sys_join_buffer_size, SHOW_SYS}, From 0e4caf39fe792168c1032ad4097a3991a12a1cc0 Mon Sep 17 00:00:00 2001 From: Satya B Date: Fri, 24 Apr 2009 17:18:20 +0530 Subject: [PATCH 88/99] Applying InnoDB snashot 5.0-ss4900 part 1, Fixes BUG#42279 1) BUG#42279 - Race condition in btr_search_drop_page_hash_when_freed() Detailed revision comments: r4031 | marko | 2009-01-23 15:33:46 +0200 (Fri, 23 Jan 2009) | 8 lines branches/5.0: btr_search_drop_page_hash_when_freed(): Check if buf_page_get_gen() returns NULL. The page may have been evicted from the buffer pool between buf_page_peek_if_search_hashed() and buf_page_get_gen(), because the buffer pool mutex will be released between these two calls. (Bug #42279) rb://82 approved by Heikki Tuuri --- innobase/btr/btr0sea.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/innobase/btr/btr0sea.c b/innobase/btr/btr0sea.c index 3c202c5a3bf..e8f294e9305 100644 --- a/innobase/btr/btr0sea.c +++ b/innobase/btr/btr0sea.c @@ -1101,12 +1101,20 @@ btr_search_drop_page_hash_when_freed( page = buf_page_get_gen(space, page_no, RW_S_LATCH, NULL, BUF_GET_IF_IN_POOL, __FILE__, __LINE__, &mtr); + /* Because the buffer pool mutex was released by + buf_page_peek_if_search_hashed(), it is possible that the + block was removed from the buffer pool by another thread + before buf_page_get_gen() got a chance to acquire the buffer + pool mutex again. Thus, we must check for a NULL return. */ + + if (UNIV_LIKELY(page != NULL)) { #ifdef UNIV_SYNC_DEBUG - buf_page_dbg_add_level(page, SYNC_TREE_NODE_FROM_HASH); + buf_page_dbg_add_level(page, SYNC_TREE_NODE_FROM_HASH); #endif /* UNIV_SYNC_DEBUG */ - btr_search_drop_page_hash_index(page); + btr_search_drop_page_hash_index(page); + } mtr_commit(&mtr); } From d5065d14265fd2fa6efc8d566a8f542f30ced36e Mon Sep 17 00:00:00 2001 From: Satya B Date: Fri, 24 Apr 2009 17:27:53 +0530 Subject: [PATCH 89/99] Applying InnoDB snashot 5.0-ss4900, part 2. Fixes BUG#43309 1) BUG#43309 - Test main.innodb can't be run twice Detailed revision comments: r4701 | vasil | 2009-04-13 17:03:46 +0300 (Mon, 13 Apr 2009) | 6 lines branches/5.0: Fix Bug#43309 Test main.innodb can't be run twice by making the innodb.test reentrant. --- mysql-test/r/innodb.result | 15 ++++++--------- mysql-test/t/innodb.test | 29 ++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 854712fdb1d..415fbe87f53 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1803,15 +1803,12 @@ Innodb_buffer_pool_pages_total 512 show status like "Innodb_page_size"; Variable_name Value Innodb_page_size 16384 -show status like "Innodb_rows_deleted"; -Variable_name Value -Innodb_rows_deleted 73 -show status like "Innodb_rows_inserted"; -Variable_name Value -Innodb_rows_inserted 29734 -show status like "Innodb_rows_updated"; -Variable_name Value -Innodb_rows_updated 29532 +innodb_rows_deleted +73 +innodb_rows_inserted +29734 +innodb_rows_updated +29532 show status like "Innodb_row_lock_waits"; Variable_name Value Innodb_row_lock_waits 0 diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index d045bad39f7..f09901d1112 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -13,6 +13,18 @@ -- source include/have_innodb.inc +# Save the original values of some variables in order to be able to +# estimate how much they have changed during the tests. Previously this +# test assumed that e.g. rows_deleted is 0 here and after deleting 23 +# rows it expected that rows_deleted will be 23. Now we do not make +# assumptions about the values of the variables at the beginning, e.g. +# rows_deleted should be 23 + "rows_deleted before the test". This allows +# the test to be run multiple times without restarting the mysqld server. +# See Bug#43309 Test main.innodb can't be run twice +-- let $innodb_rows_deleted_orig = query_get_value(SHOW STATUS WHERE variable_name = 'innodb_rows_deleted', Value, 1) +-- let $innodb_rows_inserted_orig = query_get_value(SHOW STATUS WHERE variable_name = 'innodb_rows_inserted', Value, 1) +-- let $innodb_rows_updated_orig = query_get_value(SHOW STATUS WHERE variable_name = 'innodb_rows_updated', Value, 1) + # # Small basic test with ignore # @@ -1344,9 +1356,14 @@ drop table t1; # uses previous ones(pages_created, rows_deleted, ...). show status like "Innodb_buffer_pool_pages_total"; show status like "Innodb_page_size"; -show status like "Innodb_rows_deleted"; -show status like "Innodb_rows_inserted"; -show status like "Innodb_rows_updated"; +-- let $innodb_rows_deleted = query_get_value(SHOW STATUS WHERE variable_name = 'innodb_rows_deleted', Value, 1) +-- let $innodb_rows_inserted = query_get_value(SHOW STATUS WHERE variable_name = 'innodb_rows_inserted', Value, 1) +-- let $innodb_rows_updated = query_get_value(SHOW STATUS WHERE variable_name = 'innodb_rows_updated', Value, 1) +-- disable_query_log +-- eval SELECT $innodb_rows_deleted - $innodb_rows_deleted_orig AS innodb_rows_deleted +-- eval SELECT $innodb_rows_inserted - $innodb_rows_inserted_orig AS innodb_rows_inserted +-- eval SELECT $innodb_rows_updated - $innodb_rows_updated_orig AS innodb_rows_updated +-- enable_query_log # Test for row locks InnoDB status variables. show status like "Innodb_row_lock_waits"; @@ -1365,6 +1382,8 @@ set global innodb_sync_spin_loops=20; show variables like "innodb_sync_spin_loops"; # Test for innodb_thread_concurrency variable +# save the original value so we can restore it at the end +-- let $innodb_thread_concurrency_orig = query_get_value(SHOW VARIABLES WHERE variable_name = 'innodb_thread_concurrency', Value, 1) show variables like "innodb_thread_concurrency"; set global innodb_thread_concurrency=1001; show variables like "innodb_thread_concurrency"; @@ -1372,6 +1391,10 @@ set global innodb_thread_concurrency=0; show variables like "innodb_thread_concurrency"; set global innodb_thread_concurrency=16; show variables like "innodb_thread_concurrency"; +# restore the orginal value, this way the test can be run multiple times +-- disable_query_log +-- eval set global innodb_thread_concurrency = $innodb_thread_concurrency_orig +-- enable_query_log # Test for innodb_concurrency_tickets variable show variables like "innodb_concurrency_tickets"; From b7a70c8b3d30db6007b5e731ae2790e9c963d8c9 Mon Sep 17 00:00:00 2001 From: Patrick Crews Date: Fri, 24 Apr 2009 12:58:23 -0400 Subject: [PATCH 90/99] Bug#32784: Timeout in test "innodb_charset": InnoDB much slower than other handlers Turned off autocommit at the start of this test per Innobase recommendation. Noted significant reduction in run time for this test w/ a minor increase in other tests' run-times. --- mysql-test/suite/funcs_2/charset/charset_master.test | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mysql-test/suite/funcs_2/charset/charset_master.test b/mysql-test/suite/funcs_2/charset/charset_master.test index 09e24e2c246..99ca4564a0b 100644 --- a/mysql-test/suite/funcs_2/charset/charset_master.test +++ b/mysql-test/suite/funcs_2/charset/charset_master.test @@ -86,6 +86,15 @@ let $check_std_csets= 1; let $check_ucs2_csets= 1; let $check_utf8_csets= 1; +# Bug#32784: Timeout in test "innodb_charset": InnoDB much slower +# than other handlers +# NOTE: We turn autocommit off to improve the performance of the innodb variant +# of this test. Per Innobase's recommendation. + +--disable_query_log +SET autocommit=0; +--enable_query_log + # # Check all charsets/collation combinations # From def04705986a9abad6927c0b52aaf63c136b546b Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Tue, 28 Apr 2009 05:19:13 +0500 Subject: [PATCH 91/99] backport from 6.0: Bug #40925: Equality propagation takes non indexed attribute Query execution plans and execution time of queries like select a, b, c from t1 where a > '2008-11-21' and b = a limit 10 depended on the order of equality operator parameters: "b = a" and "a = b" are not same. An equality propagation algorithm has been fixed: the substitute_for_best_equal_field function should not substitute a field for an equal field if both fields belong to the same table. mysql-test/r/select.result: Added test case for bug #40925. mysql-test/t/select.test: Added test case for bug #40925. sql/item.cc: Bug #40925: Equality propagation takes non indexed attribute An equality propagation algorithm has been fixed: the substitute_for_best_equal_field function should not substitute a field for an equal field if both fields belong to the same table. --- mysql-test/r/select.result | 13 +++++++++++++ mysql-test/t/select.test | 14 ++++++++++++++ sql/item.cc | 2 +- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 9558b0533ad..c9dd65108da 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4388,4 +4388,17 @@ f3 f4 count 1 abc 1 1 def 2 drop table t1, t2, t3; +CREATE TABLE t1 (a INT KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4); +EXPLAIN EXTENDED SELECT a, b FROM t1 WHERE a > 1 AND a = b LIMIT 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where ((`test`.`t1`.`b` = `test`.`t1`.`a`) and (`test`.`t1`.`a` > 1)) limit 2 +EXPLAIN EXTENDED SELECT a, b FROM t1 WHERE a > 1 AND b = a LIMIT 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where ((`test`.`t1`.`a` = `test`.`t1`.`b`) and (`test`.`t1`.`a` > 1)) limit 2 +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 1e8dc7ac2f6..60f2f191e0b 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -3737,4 +3737,18 @@ cr.f4 = cr2.f4 GROUP BY a.f3, cr.f4; drop table t1, t2, t3; + + +# +# Bug #40925: Equality propagation takes non indexed attribute +# + +CREATE TABLE t1 (a INT KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4); + +EXPLAIN EXTENDED SELECT a, b FROM t1 WHERE a > 1 AND a = b LIMIT 2; +EXPLAIN EXTENDED SELECT a, b FROM t1 WHERE a > 1 AND b = a LIMIT 2; + +DROP TABLE t1; + --echo End of 5.0 tests diff --git a/sql/item.cc b/sql/item.cc index c284e8b3bf4..13f09914ec6 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4341,7 +4341,7 @@ Item *Item_field::replace_equal_field(byte *arg) return const_item; } Item_field *subst= item_equal->get_first(); - if (subst && !field->eq(subst->field)) + if (subst && field->table != subst->field->table && !field->eq(subst->field)) return subst; } return this; From 620fb880d7b45f67abc3edd20aed2aca11b039cd Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 28 Apr 2009 14:47:26 +0500 Subject: [PATCH 92/99] Bug#38990 Arbitrary data input plus GIS functions causes mysql server crash the Point() and Linestring() functions create WKB representation of an object instead of an real geometry object. That produced bugs when these were inserted into tables. GIS tests fixed accordingly. per-file messages: mysql-test/r/gis-rtree.result Bug#38990 Arbitrary data input plus GIS functions causes mysql server crash test result mysql-test/r/gis.result Bug#38990 Arbitrary data input plus GIS functions causes mysql server crash test result mysql-test/t/gis-rtree.test Bug#38990 Arbitrary data input plus GIS functions causes mysql server crash test fixed - GeomFromWKB invocations removed mysql-test/t/gis.test Bug#38990 Arbitrary data input plus GIS functions causes mysql server crash test fixed - AsWKB invocations added sql/item_geofunc.cc Bug#38990 Arbitrary data input plus GIS functions causes mysql server crash Point() and similar functions to create a proper object --- mysql-test/r/gis-rtree.result | 668 +++++++++++++++++----------------- mysql-test/r/gis.result | 12 +- mysql-test/t/gis-rtree.test | 72 ++-- mysql-test/t/gis.test | 12 +- sql/item_geofunc.cc | 27 +- 5 files changed, 401 insertions(+), 390 deletions(-) diff --git a/mysql-test/r/gis-rtree.result b/mysql-test/r/gis-rtree.result index 99bfede3ee0..a4fa929c32e 100644 --- a/mysql-test/r/gis-rtree.result +++ b/mysql-test/r/gis-rtree.result @@ -186,106 +186,106 @@ CREATE TABLE t2 ( fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY, g GEOMETRY NOT NULL ) ENGINE=MyISAM; -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 10 * 10 - 9), Point(10 * 10, 10 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 9 * 10 - 9), Point(10 * 10, 9 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 8 * 10 - 9), Point(10 * 10, 8 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 7 * 10 - 9), Point(10 * 10, 7 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 6 * 10 - 9), Point(10 * 10, 6 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 5 * 10 - 9), Point(10 * 10, 5 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 4 * 10 - 9), Point(10 * 10, 4 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 3 * 10 - 9), Point(10 * 10, 3 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 2 * 10 - 9), Point(10 * 10, 2 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 1 * 10 - 9), Point(10 * 10, 1 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 10 * 10 - 9), Point(9 * 10, 10 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 9 * 10 - 9), Point(9 * 10, 9 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 8 * 10 - 9), Point(9 * 10, 8 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 7 * 10 - 9), Point(9 * 10, 7 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 6 * 10 - 9), Point(9 * 10, 6 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 5 * 10 - 9), Point(9 * 10, 5 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 4 * 10 - 9), Point(9 * 10, 4 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 3 * 10 - 9), Point(9 * 10, 3 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 2 * 10 - 9), Point(9 * 10, 2 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 1 * 10 - 9), Point(9 * 10, 1 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 10 * 10 - 9), Point(8 * 10, 10 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 9 * 10 - 9), Point(8 * 10, 9 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 8 * 10 - 9), Point(8 * 10, 8 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 7 * 10 - 9), Point(8 * 10, 7 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 6 * 10 - 9), Point(8 * 10, 6 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 5 * 10 - 9), Point(8 * 10, 5 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 4 * 10 - 9), Point(8 * 10, 4 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 3 * 10 - 9), Point(8 * 10, 3 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 2 * 10 - 9), Point(8 * 10, 2 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 1 * 10 - 9), Point(8 * 10, 1 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 10 * 10 - 9), Point(7 * 10, 10 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 9 * 10 - 9), Point(7 * 10, 9 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 8 * 10 - 9), Point(7 * 10, 8 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 7 * 10 - 9), Point(7 * 10, 7 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 6 * 10 - 9), Point(7 * 10, 6 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 5 * 10 - 9), Point(7 * 10, 5 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 4 * 10 - 9), Point(7 * 10, 4 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 3 * 10 - 9), Point(7 * 10, 3 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 2 * 10 - 9), Point(7 * 10, 2 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 1 * 10 - 9), Point(7 * 10, 1 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 10 * 10 - 9), Point(6 * 10, 10 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 9 * 10 - 9), Point(6 * 10, 9 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 8 * 10 - 9), Point(6 * 10, 8 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 7 * 10 - 9), Point(6 * 10, 7 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 6 * 10 - 9), Point(6 * 10, 6 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 5 * 10 - 9), Point(6 * 10, 5 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 4 * 10 - 9), Point(6 * 10, 4 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 3 * 10 - 9), Point(6 * 10, 3 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 2 * 10 - 9), Point(6 * 10, 2 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 1 * 10 - 9), Point(6 * 10, 1 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 10 * 10 - 9), Point(5 * 10, 10 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 9 * 10 - 9), Point(5 * 10, 9 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 8 * 10 - 9), Point(5 * 10, 8 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 7 * 10 - 9), Point(5 * 10, 7 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 6 * 10 - 9), Point(5 * 10, 6 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 5 * 10 - 9), Point(5 * 10, 5 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 4 * 10 - 9), Point(5 * 10, 4 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 3 * 10 - 9), Point(5 * 10, 3 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 2 * 10 - 9), Point(5 * 10, 2 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 1 * 10 - 9), Point(5 * 10, 1 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 10 * 10 - 9), Point(4 * 10, 10 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 9 * 10 - 9), Point(4 * 10, 9 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 8 * 10 - 9), Point(4 * 10, 8 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 7 * 10 - 9), Point(4 * 10, 7 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 6 * 10 - 9), Point(4 * 10, 6 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 5 * 10 - 9), Point(4 * 10, 5 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 4 * 10 - 9), Point(4 * 10, 4 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 3 * 10 - 9), Point(4 * 10, 3 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 2 * 10 - 9), Point(4 * 10, 2 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 1 * 10 - 9), Point(4 * 10, 1 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 10 * 10 - 9), Point(3 * 10, 10 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 9 * 10 - 9), Point(3 * 10, 9 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 8 * 10 - 9), Point(3 * 10, 8 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 7 * 10 - 9), Point(3 * 10, 7 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 6 * 10 - 9), Point(3 * 10, 6 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 5 * 10 - 9), Point(3 * 10, 5 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 4 * 10 - 9), Point(3 * 10, 4 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 3 * 10 - 9), Point(3 * 10, 3 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 2 * 10 - 9), Point(3 * 10, 2 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 1 * 10 - 9), Point(3 * 10, 1 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 10 * 10 - 9), Point(2 * 10, 10 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 9 * 10 - 9), Point(2 * 10, 9 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 8 * 10 - 9), Point(2 * 10, 8 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 7 * 10 - 9), Point(2 * 10, 7 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 6 * 10 - 9), Point(2 * 10, 6 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 5 * 10 - 9), Point(2 * 10, 5 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 4 * 10 - 9), Point(2 * 10, 4 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 3 * 10 - 9), Point(2 * 10, 3 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 2 * 10 - 9), Point(2 * 10, 2 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 1 * 10 - 9), Point(2 * 10, 1 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 10 * 10 - 9), Point(1 * 10, 10 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 9 * 10 - 9), Point(1 * 10, 9 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 8 * 10 - 9), Point(1 * 10, 8 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 7 * 10 - 9), Point(1 * 10, 7 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 6 * 10 - 9), Point(1 * 10, 6 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 5 * 10 - 9), Point(1 * 10, 5 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 4 * 10 - 9), Point(1 * 10, 4 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 3 * 10 - 9), Point(1 * 10, 3 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 2 * 10 - 9), Point(1 * 10, 2 * 10)))); -INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 1 * 10 - 9), Point(1 * 10, 1 * 10)))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 10 * 10 - 9), Point(10 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 9 * 10 - 9), Point(10 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 8 * 10 - 9), Point(10 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 7 * 10 - 9), Point(10 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 6 * 10 - 9), Point(10 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 5 * 10 - 9), Point(10 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 4 * 10 - 9), Point(10 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 3 * 10 - 9), Point(10 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 2 * 10 - 9), Point(10 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 1 * 10 - 9), Point(10 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 10 * 10 - 9), Point(9 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 9 * 10 - 9), Point(9 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 8 * 10 - 9), Point(9 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 7 * 10 - 9), Point(9 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 6 * 10 - 9), Point(9 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 5 * 10 - 9), Point(9 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 4 * 10 - 9), Point(9 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 3 * 10 - 9), Point(9 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 2 * 10 - 9), Point(9 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 1 * 10 - 9), Point(9 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 10 * 10 - 9), Point(8 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 9 * 10 - 9), Point(8 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 8 * 10 - 9), Point(8 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 7 * 10 - 9), Point(8 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 6 * 10 - 9), Point(8 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 5 * 10 - 9), Point(8 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 4 * 10 - 9), Point(8 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 3 * 10 - 9), Point(8 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 2 * 10 - 9), Point(8 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 1 * 10 - 9), Point(8 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 10 * 10 - 9), Point(7 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 9 * 10 - 9), Point(7 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 8 * 10 - 9), Point(7 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 7 * 10 - 9), Point(7 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 6 * 10 - 9), Point(7 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 5 * 10 - 9), Point(7 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 4 * 10 - 9), Point(7 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 3 * 10 - 9), Point(7 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 2 * 10 - 9), Point(7 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 1 * 10 - 9), Point(7 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 10 * 10 - 9), Point(6 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 9 * 10 - 9), Point(6 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 8 * 10 - 9), Point(6 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 7 * 10 - 9), Point(6 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 6 * 10 - 9), Point(6 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 5 * 10 - 9), Point(6 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 4 * 10 - 9), Point(6 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 3 * 10 - 9), Point(6 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 2 * 10 - 9), Point(6 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 1 * 10 - 9), Point(6 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 10 * 10 - 9), Point(5 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 9 * 10 - 9), Point(5 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 8 * 10 - 9), Point(5 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 7 * 10 - 9), Point(5 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 6 * 10 - 9), Point(5 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 5 * 10 - 9), Point(5 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 4 * 10 - 9), Point(5 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 3 * 10 - 9), Point(5 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 2 * 10 - 9), Point(5 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 1 * 10 - 9), Point(5 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 10 * 10 - 9), Point(4 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 9 * 10 - 9), Point(4 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 8 * 10 - 9), Point(4 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 7 * 10 - 9), Point(4 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 6 * 10 - 9), Point(4 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 5 * 10 - 9), Point(4 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 4 * 10 - 9), Point(4 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 3 * 10 - 9), Point(4 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 2 * 10 - 9), Point(4 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 1 * 10 - 9), Point(4 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 10 * 10 - 9), Point(3 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 9 * 10 - 9), Point(3 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 8 * 10 - 9), Point(3 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 7 * 10 - 9), Point(3 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 6 * 10 - 9), Point(3 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 5 * 10 - 9), Point(3 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 4 * 10 - 9), Point(3 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 3 * 10 - 9), Point(3 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 2 * 10 - 9), Point(3 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 1 * 10 - 9), Point(3 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 10 * 10 - 9), Point(2 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 9 * 10 - 9), Point(2 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 8 * 10 - 9), Point(2 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 7 * 10 - 9), Point(2 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 6 * 10 - 9), Point(2 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 5 * 10 - 9), Point(2 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 4 * 10 - 9), Point(2 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 3 * 10 - 9), Point(2 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 2 * 10 - 9), Point(2 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 1 * 10 - 9), Point(2 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 10 * 10 - 9), Point(1 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 9 * 10 - 9), Point(1 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 8 * 10 - 9), Point(1 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 7 * 10 - 9), Point(1 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 6 * 10 - 9), Point(1 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 5 * 10 - 9), Point(1 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 4 * 10 - 9), Point(1 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 3 * 10 - 9), Point(1 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 2 * 10 - 9), Point(1 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 1 * 10 - 9), Point(1 * 10, 1 * 10))); ALTER TABLE t2 ADD SPATIAL KEY(g); SHOW CREATE TABLE t2; Table Create Table @@ -309,406 +309,406 @@ fid AsText(g) 56 LINESTRING(41 41,50 50) 45 LINESTRING(51 51,60 60) 55 LINESTRING(41 51,50 60) -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 10 * 10 - 9), Point(10 * 10, 10 * 10))))); +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 10 * 10 - 9), Point(10 * 10, 10 * 10)))); SELECT count(*) FROM t2; count(*) -99 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 9 * 10 - 9), Point(10 * 10, 9 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 9 * 10 - 9), Point(10 * 10, 9 * 10)))); SELECT count(*) FROM t2; count(*) -98 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 8 * 10 - 9), Point(10 * 10, 8 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 8 * 10 - 9), Point(10 * 10, 8 * 10)))); SELECT count(*) FROM t2; count(*) -97 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 7 * 10 - 9), Point(10 * 10, 7 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 7 * 10 - 9), Point(10 * 10, 7 * 10)))); SELECT count(*) FROM t2; count(*) -96 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 6 * 10 - 9), Point(10 * 10, 6 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 6 * 10 - 9), Point(10 * 10, 6 * 10)))); SELECT count(*) FROM t2; count(*) -95 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 5 * 10 - 9), Point(10 * 10, 5 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 5 * 10 - 9), Point(10 * 10, 5 * 10)))); SELECT count(*) FROM t2; count(*) -94 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 4 * 10 - 9), Point(10 * 10, 4 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 4 * 10 - 9), Point(10 * 10, 4 * 10)))); SELECT count(*) FROM t2; count(*) -93 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 3 * 10 - 9), Point(10 * 10, 3 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 3 * 10 - 9), Point(10 * 10, 3 * 10)))); SELECT count(*) FROM t2; count(*) -92 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 2 * 10 - 9), Point(10 * 10, 2 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 2 * 10 - 9), Point(10 * 10, 2 * 10)))); SELECT count(*) FROM t2; count(*) -91 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 1 * 10 - 9), Point(10 * 10, 1 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 1 * 10 - 9), Point(10 * 10, 1 * 10)))); SELECT count(*) FROM t2; count(*) -90 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 10 * 10 - 9), Point(9 * 10, 10 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 10 * 10 - 9), Point(9 * 10, 10 * 10)))); SELECT count(*) FROM t2; count(*) -89 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 9 * 10 - 9), Point(9 * 10, 9 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 9 * 10 - 9), Point(9 * 10, 9 * 10)))); SELECT count(*) FROM t2; count(*) -88 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 8 * 10 - 9), Point(9 * 10, 8 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 8 * 10 - 9), Point(9 * 10, 8 * 10)))); SELECT count(*) FROM t2; count(*) -87 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 7 * 10 - 9), Point(9 * 10, 7 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 7 * 10 - 9), Point(9 * 10, 7 * 10)))); SELECT count(*) FROM t2; count(*) -86 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 6 * 10 - 9), Point(9 * 10, 6 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 6 * 10 - 9), Point(9 * 10, 6 * 10)))); SELECT count(*) FROM t2; count(*) -85 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 5 * 10 - 9), Point(9 * 10, 5 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 5 * 10 - 9), Point(9 * 10, 5 * 10)))); SELECT count(*) FROM t2; count(*) -84 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 4 * 10 - 9), Point(9 * 10, 4 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 4 * 10 - 9), Point(9 * 10, 4 * 10)))); SELECT count(*) FROM t2; count(*) -83 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 3 * 10 - 9), Point(9 * 10, 3 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 3 * 10 - 9), Point(9 * 10, 3 * 10)))); SELECT count(*) FROM t2; count(*) -82 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 2 * 10 - 9), Point(9 * 10, 2 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 2 * 10 - 9), Point(9 * 10, 2 * 10)))); SELECT count(*) FROM t2; count(*) -81 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 1 * 10 - 9), Point(9 * 10, 1 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 1 * 10 - 9), Point(9 * 10, 1 * 10)))); SELECT count(*) FROM t2; count(*) -80 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 10 * 10 - 9), Point(8 * 10, 10 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 10 * 10 - 9), Point(8 * 10, 10 * 10)))); SELECT count(*) FROM t2; count(*) -79 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 9 * 10 - 9), Point(8 * 10, 9 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 9 * 10 - 9), Point(8 * 10, 9 * 10)))); SELECT count(*) FROM t2; count(*) -78 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 8 * 10 - 9), Point(8 * 10, 8 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 8 * 10 - 9), Point(8 * 10, 8 * 10)))); SELECT count(*) FROM t2; count(*) -77 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 7 * 10 - 9), Point(8 * 10, 7 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 7 * 10 - 9), Point(8 * 10, 7 * 10)))); SELECT count(*) FROM t2; count(*) -76 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 6 * 10 - 9), Point(8 * 10, 6 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 6 * 10 - 9), Point(8 * 10, 6 * 10)))); SELECT count(*) FROM t2; count(*) -75 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 5 * 10 - 9), Point(8 * 10, 5 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 5 * 10 - 9), Point(8 * 10, 5 * 10)))); SELECT count(*) FROM t2; count(*) -74 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 4 * 10 - 9), Point(8 * 10, 4 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 4 * 10 - 9), Point(8 * 10, 4 * 10)))); SELECT count(*) FROM t2; count(*) -73 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 3 * 10 - 9), Point(8 * 10, 3 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 3 * 10 - 9), Point(8 * 10, 3 * 10)))); SELECT count(*) FROM t2; count(*) -72 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 2 * 10 - 9), Point(8 * 10, 2 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 2 * 10 - 9), Point(8 * 10, 2 * 10)))); SELECT count(*) FROM t2; count(*) -71 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 1 * 10 - 9), Point(8 * 10, 1 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 1 * 10 - 9), Point(8 * 10, 1 * 10)))); SELECT count(*) FROM t2; count(*) -70 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 10 * 10 - 9), Point(7 * 10, 10 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 10 * 10 - 9), Point(7 * 10, 10 * 10)))); SELECT count(*) FROM t2; count(*) -69 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 9 * 10 - 9), Point(7 * 10, 9 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 9 * 10 - 9), Point(7 * 10, 9 * 10)))); SELECT count(*) FROM t2; count(*) -68 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 8 * 10 - 9), Point(7 * 10, 8 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 8 * 10 - 9), Point(7 * 10, 8 * 10)))); SELECT count(*) FROM t2; count(*) -67 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 7 * 10 - 9), Point(7 * 10, 7 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 7 * 10 - 9), Point(7 * 10, 7 * 10)))); SELECT count(*) FROM t2; count(*) -66 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 6 * 10 - 9), Point(7 * 10, 6 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 6 * 10 - 9), Point(7 * 10, 6 * 10)))); SELECT count(*) FROM t2; count(*) -65 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 5 * 10 - 9), Point(7 * 10, 5 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 5 * 10 - 9), Point(7 * 10, 5 * 10)))); SELECT count(*) FROM t2; count(*) -64 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 4 * 10 - 9), Point(7 * 10, 4 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 4 * 10 - 9), Point(7 * 10, 4 * 10)))); SELECT count(*) FROM t2; count(*) -63 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 3 * 10 - 9), Point(7 * 10, 3 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 3 * 10 - 9), Point(7 * 10, 3 * 10)))); SELECT count(*) FROM t2; count(*) -62 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 2 * 10 - 9), Point(7 * 10, 2 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 2 * 10 - 9), Point(7 * 10, 2 * 10)))); SELECT count(*) FROM t2; count(*) -61 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 1 * 10 - 9), Point(7 * 10, 1 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 1 * 10 - 9), Point(7 * 10, 1 * 10)))); SELECT count(*) FROM t2; count(*) -60 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 10 * 10 - 9), Point(6 * 10, 10 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 10 * 10 - 9), Point(6 * 10, 10 * 10)))); SELECT count(*) FROM t2; count(*) -59 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 9 * 10 - 9), Point(6 * 10, 9 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 9 * 10 - 9), Point(6 * 10, 9 * 10)))); SELECT count(*) FROM t2; count(*) -58 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 8 * 10 - 9), Point(6 * 10, 8 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 8 * 10 - 9), Point(6 * 10, 8 * 10)))); SELECT count(*) FROM t2; count(*) -57 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 7 * 10 - 9), Point(6 * 10, 7 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 7 * 10 - 9), Point(6 * 10, 7 * 10)))); SELECT count(*) FROM t2; count(*) -56 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 6 * 10 - 9), Point(6 * 10, 6 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 6 * 10 - 9), Point(6 * 10, 6 * 10)))); SELECT count(*) FROM t2; count(*) -55 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 5 * 10 - 9), Point(6 * 10, 5 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 5 * 10 - 9), Point(6 * 10, 5 * 10)))); SELECT count(*) FROM t2; count(*) -54 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 4 * 10 - 9), Point(6 * 10, 4 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 4 * 10 - 9), Point(6 * 10, 4 * 10)))); SELECT count(*) FROM t2; count(*) -53 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 3 * 10 - 9), Point(6 * 10, 3 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 3 * 10 - 9), Point(6 * 10, 3 * 10)))); SELECT count(*) FROM t2; count(*) -52 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 2 * 10 - 9), Point(6 * 10, 2 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 2 * 10 - 9), Point(6 * 10, 2 * 10)))); SELECT count(*) FROM t2; count(*) -51 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 1 * 10 - 9), Point(6 * 10, 1 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 1 * 10 - 9), Point(6 * 10, 1 * 10)))); SELECT count(*) FROM t2; count(*) -50 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 10 * 10 - 9), Point(5 * 10, 10 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 10 * 10 - 9), Point(5 * 10, 10 * 10)))); SELECT count(*) FROM t2; count(*) -49 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 9 * 10 - 9), Point(5 * 10, 9 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 9 * 10 - 9), Point(5 * 10, 9 * 10)))); SELECT count(*) FROM t2; count(*) -48 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 8 * 10 - 9), Point(5 * 10, 8 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 8 * 10 - 9), Point(5 * 10, 8 * 10)))); SELECT count(*) FROM t2; count(*) -47 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 7 * 10 - 9), Point(5 * 10, 7 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 7 * 10 - 9), Point(5 * 10, 7 * 10)))); SELECT count(*) FROM t2; count(*) -46 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 6 * 10 - 9), Point(5 * 10, 6 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 6 * 10 - 9), Point(5 * 10, 6 * 10)))); SELECT count(*) FROM t2; count(*) -45 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 5 * 10 - 9), Point(5 * 10, 5 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 5 * 10 - 9), Point(5 * 10, 5 * 10)))); SELECT count(*) FROM t2; count(*) -44 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 4 * 10 - 9), Point(5 * 10, 4 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 4 * 10 - 9), Point(5 * 10, 4 * 10)))); SELECT count(*) FROM t2; count(*) -43 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 3 * 10 - 9), Point(5 * 10, 3 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 3 * 10 - 9), Point(5 * 10, 3 * 10)))); SELECT count(*) FROM t2; count(*) -42 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 2 * 10 - 9), Point(5 * 10, 2 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 2 * 10 - 9), Point(5 * 10, 2 * 10)))); SELECT count(*) FROM t2; count(*) -41 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 1 * 10 - 9), Point(5 * 10, 1 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 1 * 10 - 9), Point(5 * 10, 1 * 10)))); SELECT count(*) FROM t2; count(*) -40 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 10 * 10 - 9), Point(4 * 10, 10 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 10 * 10 - 9), Point(4 * 10, 10 * 10)))); SELECT count(*) FROM t2; count(*) -39 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 9 * 10 - 9), Point(4 * 10, 9 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 9 * 10 - 9), Point(4 * 10, 9 * 10)))); SELECT count(*) FROM t2; count(*) -38 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 8 * 10 - 9), Point(4 * 10, 8 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 8 * 10 - 9), Point(4 * 10, 8 * 10)))); SELECT count(*) FROM t2; count(*) -37 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 7 * 10 - 9), Point(4 * 10, 7 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 7 * 10 - 9), Point(4 * 10, 7 * 10)))); SELECT count(*) FROM t2; count(*) -36 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 6 * 10 - 9), Point(4 * 10, 6 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 6 * 10 - 9), Point(4 * 10, 6 * 10)))); SELECT count(*) FROM t2; count(*) -35 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 5 * 10 - 9), Point(4 * 10, 5 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 5 * 10 - 9), Point(4 * 10, 5 * 10)))); SELECT count(*) FROM t2; count(*) -34 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 4 * 10 - 9), Point(4 * 10, 4 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 4 * 10 - 9), Point(4 * 10, 4 * 10)))); SELECT count(*) FROM t2; count(*) -33 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 3 * 10 - 9), Point(4 * 10, 3 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 3 * 10 - 9), Point(4 * 10, 3 * 10)))); SELECT count(*) FROM t2; count(*) -32 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 2 * 10 - 9), Point(4 * 10, 2 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 2 * 10 - 9), Point(4 * 10, 2 * 10)))); SELECT count(*) FROM t2; count(*) -31 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 1 * 10 - 9), Point(4 * 10, 1 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 1 * 10 - 9), Point(4 * 10, 1 * 10)))); SELECT count(*) FROM t2; count(*) -30 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 10 * 10 - 9), Point(3 * 10, 10 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 10 * 10 - 9), Point(3 * 10, 10 * 10)))); SELECT count(*) FROM t2; count(*) -29 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 9 * 10 - 9), Point(3 * 10, 9 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 9 * 10 - 9), Point(3 * 10, 9 * 10)))); SELECT count(*) FROM t2; count(*) -28 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 8 * 10 - 9), Point(3 * 10, 8 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 8 * 10 - 9), Point(3 * 10, 8 * 10)))); SELECT count(*) FROM t2; count(*) -27 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 7 * 10 - 9), Point(3 * 10, 7 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 7 * 10 - 9), Point(3 * 10, 7 * 10)))); SELECT count(*) FROM t2; count(*) -26 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 6 * 10 - 9), Point(3 * 10, 6 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 6 * 10 - 9), Point(3 * 10, 6 * 10)))); SELECT count(*) FROM t2; count(*) -25 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 5 * 10 - 9), Point(3 * 10, 5 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 5 * 10 - 9), Point(3 * 10, 5 * 10)))); SELECT count(*) FROM t2; count(*) -24 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 4 * 10 - 9), Point(3 * 10, 4 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 4 * 10 - 9), Point(3 * 10, 4 * 10)))); SELECT count(*) FROM t2; count(*) -23 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 3 * 10 - 9), Point(3 * 10, 3 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 3 * 10 - 9), Point(3 * 10, 3 * 10)))); SELECT count(*) FROM t2; count(*) -22 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 2 * 10 - 9), Point(3 * 10, 2 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 2 * 10 - 9), Point(3 * 10, 2 * 10)))); SELECT count(*) FROM t2; count(*) -21 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 1 * 10 - 9), Point(3 * 10, 1 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 1 * 10 - 9), Point(3 * 10, 1 * 10)))); SELECT count(*) FROM t2; count(*) -20 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 10 * 10 - 9), Point(2 * 10, 10 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 10 * 10 - 9), Point(2 * 10, 10 * 10)))); SELECT count(*) FROM t2; count(*) -19 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 9 * 10 - 9), Point(2 * 10, 9 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 9 * 10 - 9), Point(2 * 10, 9 * 10)))); SELECT count(*) FROM t2; count(*) -18 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 8 * 10 - 9), Point(2 * 10, 8 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 8 * 10 - 9), Point(2 * 10, 8 * 10)))); SELECT count(*) FROM t2; count(*) -17 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 7 * 10 - 9), Point(2 * 10, 7 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 7 * 10 - 9), Point(2 * 10, 7 * 10)))); SELECT count(*) FROM t2; count(*) -16 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 6 * 10 - 9), Point(2 * 10, 6 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 6 * 10 - 9), Point(2 * 10, 6 * 10)))); SELECT count(*) FROM t2; count(*) -15 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 5 * 10 - 9), Point(2 * 10, 5 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 5 * 10 - 9), Point(2 * 10, 5 * 10)))); SELECT count(*) FROM t2; count(*) -14 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 4 * 10 - 9), Point(2 * 10, 4 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 4 * 10 - 9), Point(2 * 10, 4 * 10)))); SELECT count(*) FROM t2; count(*) -13 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 3 * 10 - 9), Point(2 * 10, 3 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 3 * 10 - 9), Point(2 * 10, 3 * 10)))); SELECT count(*) FROM t2; count(*) -12 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 2 * 10 - 9), Point(2 * 10, 2 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 2 * 10 - 9), Point(2 * 10, 2 * 10)))); SELECT count(*) FROM t2; count(*) -11 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 1 * 10 - 9), Point(2 * 10, 1 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 1 * 10 - 9), Point(2 * 10, 1 * 10)))); SELECT count(*) FROM t2; count(*) -10 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 10 * 10 - 9), Point(1 * 10, 10 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 10 * 10 - 9), Point(1 * 10, 10 * 10)))); SELECT count(*) FROM t2; count(*) -9 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 9 * 10 - 9), Point(1 * 10, 9 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 9 * 10 - 9), Point(1 * 10, 9 * 10)))); SELECT count(*) FROM t2; count(*) -8 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 8 * 10 - 9), Point(1 * 10, 8 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 8 * 10 - 9), Point(1 * 10, 8 * 10)))); SELECT count(*) FROM t2; count(*) -7 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 7 * 10 - 9), Point(1 * 10, 7 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 7 * 10 - 9), Point(1 * 10, 7 * 10)))); SELECT count(*) FROM t2; count(*) -6 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 6 * 10 - 9), Point(1 * 10, 6 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 6 * 10 - 9), Point(1 * 10, 6 * 10)))); SELECT count(*) FROM t2; count(*) -5 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 5 * 10 - 9), Point(1 * 10, 5 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 5 * 10 - 9), Point(1 * 10, 5 * 10)))); SELECT count(*) FROM t2; count(*) -4 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 4 * 10 - 9), Point(1 * 10, 4 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 4 * 10 - 9), Point(1 * 10, 4 * 10)))); SELECT count(*) FROM t2; count(*) -3 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 3 * 10 - 9), Point(1 * 10, 3 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 3 * 10 - 9), Point(1 * 10, 3 * 10)))); SELECT count(*) FROM t2; count(*) -2 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 2 * 10 - 9), Point(1 * 10, 2 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 2 * 10 - 9), Point(1 * 10, 2 * 10)))); SELECT count(*) FROM t2; count(*) -1 -DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 1 * 10 - 9), Point(1 * 10, 1 * 10))))); +100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 1 * 10 - 9), Point(1 * 10, 1 * 10)))); SELECT count(*) FROM t2; count(*) -0 +100 DROP TABLE t2; drop table if exists t1; Warnings: @@ -863,11 +863,11 @@ Table Op Msg_type Msg_text test.t1 check status OK DROP TABLE t1; CREATE TABLE t1 (foo GEOMETRY NOT NULL, SPATIAL INDEX(foo) ); -INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,1))); -INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,0))); -INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,1))); -INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,0))); -SELECT 1 FROM t1 WHERE foo != PointFromWKB(POINT(0,0)); +INSERT INTO t1 (foo) VALUES (POINT(1,1)); +INSERT INTO t1 (foo) VALUES (POINT(1,0)); +INSERT INTO t1 (foo) VALUES (POINT(0,1)); +INSERT INTO t1 (foo) VALUES (POINT(0,0)); +SELECT 1 FROM t1 WHERE foo != POINT(0,0); 1 1 1 @@ -1426,35 +1426,35 @@ Table Op Msg_type Msg_text test.t1 check status OK DROP TABLE t1; create table t1 (a geometry not null, spatial index(a)); -insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 131072))); -insert into t1 values (PointFromWKB(POINT(9.1248812352444e+192, 2.9740338169556e+284))); -insert into t1 values (PointFromWKB(POINT(4.7783097267365e-299, -0))); -insert into t1 values (PointFromWKB(POINT(1.49166814624e-154, 2.0880974297595e-53))); -insert into t1 values (PointFromWKB(POINT(4.0917382598702e+149, 1.2024538023802e+111))); -insert into t1 values (PointFromWKB(POINT(2.0349165139404e+236, 2.9993936277913e-241))); -insert into t1 values (PointFromWKB(POINT(2.5243548967072e-29, 1.2024538023802e+111))); -insert into t1 values (PointFromWKB(POINT(0, 6.9835074892995e-251))); -insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 3.1050361846014e+231))); -insert into t1 values (PointFromWKB(POINT(2.8728483499323e-188, 2.4600631144627e+260))); -insert into t1 values (PointFromWKB(POINT(3.0517578125e-05, 2.0349165139404e+236))); -insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 1.1818212630766e-125))); -insert into t1 values (PointFromWKB(POINT(2.481040258324e-265, 5.7766220027675e-275))); -insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 2.5243548967072e-29))); -insert into t1 values (PointFromWKB(POINT(5.7766220027675e-275, 9.9464647281957e+86))); -insert into t1 values (PointFromWKB(POINT(2.2181357552967e+130, 3.7857669957337e-270))); -insert into t1 values (PointFromWKB(POINT(4.5767114681874e-246, 3.6893488147419e+19))); -insert into t1 values (PointFromWKB(POINT(4.5767114681874e-246, 3.7537584144024e+255))); -insert into t1 values (PointFromWKB(POINT(3.7857669957337e-270, 1.8033161362863e-130))); -insert into t1 values (PointFromWKB(POINT(0, 5.8774717541114e-39))); -insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 2.2761049594727e-159))); -insert into t1 values (PointFromWKB(POINT(6.243497100632e+144, 3.7857669957337e-270))); -insert into t1 values (PointFromWKB(POINT(3.7857669957337e-270, 2.6355494858076e-82))); -insert into t1 values (PointFromWKB(POINT(2.0349165139404e+236, 3.8518598887745e-34))); -insert into t1 values (PointFromWKB(POINT(4.6566128730774e-10, 2.0880974297595e-53))); -insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 1.8827498946116e-183))); -insert into t1 values (PointFromWKB(POINT(1.8033161362863e-130, 9.1248812352444e+192))); -insert into t1 values (PointFromWKB(POINT(4.7783097267365e-299, 2.2761049594727e-159))); -insert into t1 values (PointFromWKB(POINT(1.94906280228e+289, 1.2338789709327e-178))); +insert into t1 values (POINT(1.1517219314031e+164, 131072)); +insert into t1 values (POINT(9.1248812352444e+192, 2.9740338169556e+284)); +insert into t1 values (POINT(4.7783097267365e-299, -0)); +insert into t1 values (POINT(1.49166814624e-154, 2.0880974297595e-53)); +insert into t1 values (POINT(4.0917382598702e+149, 1.2024538023802e+111)); +insert into t1 values (POINT(2.0349165139404e+236, 2.9993936277913e-241)); +insert into t1 values (POINT(2.5243548967072e-29, 1.2024538023802e+111)); +insert into t1 values (POINT(0, 6.9835074892995e-251)); +insert into t1 values (POINT(2.0880974297595e-53, 3.1050361846014e+231)); +insert into t1 values (POINT(2.8728483499323e-188, 2.4600631144627e+260)); +insert into t1 values (POINT(3.0517578125e-05, 2.0349165139404e+236)); +insert into t1 values (POINT(1.1517219314031e+164, 1.1818212630766e-125)); +insert into t1 values (POINT(2.481040258324e-265, 5.7766220027675e-275)); +insert into t1 values (POINT(2.0880974297595e-53, 2.5243548967072e-29)); +insert into t1 values (POINT(5.7766220027675e-275, 9.9464647281957e+86)); +insert into t1 values (POINT(2.2181357552967e+130, 3.7857669957337e-270)); +insert into t1 values (POINT(4.5767114681874e-246, 3.6893488147419e+19)); +insert into t1 values (POINT(4.5767114681874e-246, 3.7537584144024e+255)); +insert into t1 values (POINT(3.7857669957337e-270, 1.8033161362863e-130)); +insert into t1 values (POINT(0, 5.8774717541114e-39)); +insert into t1 values (POINT(1.1517219314031e+164, 2.2761049594727e-159)); +insert into t1 values (POINT(6.243497100632e+144, 3.7857669957337e-270)); +insert into t1 values (POINT(3.7857669957337e-270, 2.6355494858076e-82)); +insert into t1 values (POINT(2.0349165139404e+236, 3.8518598887745e-34)); +insert into t1 values (POINT(4.6566128730774e-10, 2.0880974297595e-53)); +insert into t1 values (POINT(2.0880974297595e-53, 1.8827498946116e-183)); +insert into t1 values (POINT(1.8033161362863e-130, 9.1248812352444e+192)); +insert into t1 values (POINT(4.7783097267365e-299, 2.2761049594727e-159)); +insert into t1 values (POINT(1.94906280228e+289, 1.2338789709327e-178)); drop table t1; CREATE TABLE t1(foo GEOMETRY NOT NULL, SPATIAL INDEX(foo) ); INSERT INTO t1(foo) VALUES (NULL); diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index e3b2ea751d9..5b7a58add06 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -47,26 +47,26 @@ INSERT INTO gis_point VALUES INSERT INTO gis_line VALUES (105, LineFromText('LINESTRING(0 0,0 10,10 0)')), (106, LineStringFromText('LINESTRING(10 10,20 10,20 20,10 20,10 10)')), -(107, LineStringFromWKB(LineString(Point(10, 10), Point(40, 10)))); +(107, LineStringFromWKB(AsWKB(LineString(Point(10, 10), Point(40, 10))))); INSERT INTO gis_polygon VALUES (108, PolygonFromText('POLYGON((10 10,20 10,20 20,10 20,10 10))')), (109, PolyFromText('POLYGON((0 0,50 0,50 50,0 50,0 0), (10 10,20 10,20 20,10 20,10 10))')), -(110, PolyFromWKB(Polygon(LineString(Point(0, 0), Point(30, 0), Point(30, 30), Point(0, 0))))); +(110, PolyFromWKB(AsWKB(Polygon(LineString(Point(0, 0), Point(30, 0), Point(30, 30), Point(0, 0)))))); INSERT INTO gis_multi_point VALUES (111, MultiPointFromText('MULTIPOINT(0 0,10 10,10 20,20 20)')), (112, MPointFromText('MULTIPOINT(1 1,11 11,11 21,21 21)')), -(113, MPointFromWKB(MultiPoint(Point(3, 6), Point(4, 10)))); +(113, MPointFromWKB(AsWKB(MultiPoint(Point(3, 6), Point(4, 10))))); INSERT INTO gis_multi_line VALUES (114, MultiLineStringFromText('MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))')), (115, MLineFromText('MULTILINESTRING((10 48,10 21,10 0))')), -(116, MLineFromWKB(MultiLineString(LineString(Point(1, 2), Point(3, 5)), LineString(Point(2, 5), Point(5, 8), Point(21, 7))))); +(116, MLineFromWKB(AsWKB(MultiLineString(LineString(Point(1, 2), Point(3, 5)), LineString(Point(2, 5), Point(5, 8), Point(21, 7)))))); INSERT INTO gis_multi_polygon VALUES (117, MultiPolygonFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))')), (118, MPolyFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))')), -(119, MPolyFromWKB(MultiPolygon(Polygon(LineString(Point(0, 3), Point(3, 3), Point(3, 0), Point(0, 3)))))); +(119, MPolyFromWKB(AsWKB(MultiPolygon(Polygon(LineString(Point(0, 3), Point(3, 3), Point(3, 0), Point(0, 3))))))); INSERT INTO gis_geometrycollection VALUES (120, GeomCollFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10 10))')), -(121, GeometryFromWKB(GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9))))); +(121, GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9)))))); INSERT into gis_geometry SELECT * FROM gis_point; INSERT into gis_geometry SELECT * FROM gis_line; INSERT into gis_geometry SELECT * FROM gis_polygon; diff --git a/mysql-test/t/gis-rtree.test b/mysql-test/t/gis-rtree.test index e68e5039adf..2c1632f8d40 100644 --- a/mysql-test/t/gis-rtree.test +++ b/mysql-test/t/gis-rtree.test @@ -41,7 +41,7 @@ while ($1) let $2=10; while ($2) { - eval INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point($1 * 10 - 9, $2 * 10 - 9), Point($1 * 10, $2 * 10)))); + eval INSERT INTO t2 (g) VALUES (LineString(Point($1 * 10 - 9, $2 * 10 - 9), Point($1 * 10, $2 * 10))); dec $2; } dec $1; @@ -61,7 +61,7 @@ while ($1) let $2=10; while ($2) { - eval DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point($1 * 10 - 9, $2 * 10 - 9), Point($1 * 10, $2 * 10))))); + eval DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point($1 * 10 - 9, $2 * 10 - 9), Point($1 * 10, $2 * 10)))); SELECT count(*) FROM t2; dec $2; } @@ -235,11 +235,11 @@ DROP TABLE t1; # Bug #21888: Query on GEOMETRY field using PointFromWKB() results in lost connection # CREATE TABLE t1 (foo GEOMETRY NOT NULL, SPATIAL INDEX(foo) ); -INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,1))); -INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,0))); -INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,1))); -INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,0))); -SELECT 1 FROM t1 WHERE foo != PointFromWKB(POINT(0,0)); +INSERT INTO t1 (foo) VALUES (POINT(1,1)); +INSERT INTO t1 (foo) VALUES (POINT(1,0)); +INSERT INTO t1 (foo) VALUES (POINT(0,1)); +INSERT INTO t1 (foo) VALUES (POINT(0,0)); +SELECT 1 FROM t1 WHERE foo != POINT(0,0); DROP TABLE t1; # @@ -802,35 +802,35 @@ DROP TABLE t1; # create table t1 (a geometry not null, spatial index(a)); -insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 131072))); -insert into t1 values (PointFromWKB(POINT(9.1248812352444e+192, 2.9740338169556e+284))); -insert into t1 values (PointFromWKB(POINT(4.7783097267365e-299, -0))); -insert into t1 values (PointFromWKB(POINT(1.49166814624e-154, 2.0880974297595e-53))); -insert into t1 values (PointFromWKB(POINT(4.0917382598702e+149, 1.2024538023802e+111))); -insert into t1 values (PointFromWKB(POINT(2.0349165139404e+236, 2.9993936277913e-241))); -insert into t1 values (PointFromWKB(POINT(2.5243548967072e-29, 1.2024538023802e+111))); -insert into t1 values (PointFromWKB(POINT(0, 6.9835074892995e-251))); -insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 3.1050361846014e+231))); -insert into t1 values (PointFromWKB(POINT(2.8728483499323e-188, 2.4600631144627e+260))); -insert into t1 values (PointFromWKB(POINT(3.0517578125e-05, 2.0349165139404e+236))); -insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 1.1818212630766e-125))); -insert into t1 values (PointFromWKB(POINT(2.481040258324e-265, 5.7766220027675e-275))); -insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 2.5243548967072e-29))); -insert into t1 values (PointFromWKB(POINT(5.7766220027675e-275, 9.9464647281957e+86))); -insert into t1 values (PointFromWKB(POINT(2.2181357552967e+130, 3.7857669957337e-270))); -insert into t1 values (PointFromWKB(POINT(4.5767114681874e-246, 3.6893488147419e+19))); -insert into t1 values (PointFromWKB(POINT(4.5767114681874e-246, 3.7537584144024e+255))); -insert into t1 values (PointFromWKB(POINT(3.7857669957337e-270, 1.8033161362863e-130))); -insert into t1 values (PointFromWKB(POINT(0, 5.8774717541114e-39))); -insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 2.2761049594727e-159))); -insert into t1 values (PointFromWKB(POINT(6.243497100632e+144, 3.7857669957337e-270))); -insert into t1 values (PointFromWKB(POINT(3.7857669957337e-270, 2.6355494858076e-82))); -insert into t1 values (PointFromWKB(POINT(2.0349165139404e+236, 3.8518598887745e-34))); -insert into t1 values (PointFromWKB(POINT(4.6566128730774e-10, 2.0880974297595e-53))); -insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 1.8827498946116e-183))); -insert into t1 values (PointFromWKB(POINT(1.8033161362863e-130, 9.1248812352444e+192))); -insert into t1 values (PointFromWKB(POINT(4.7783097267365e-299, 2.2761049594727e-159))); -insert into t1 values (PointFromWKB(POINT(1.94906280228e+289, 1.2338789709327e-178))); +insert into t1 values (POINT(1.1517219314031e+164, 131072)); +insert into t1 values (POINT(9.1248812352444e+192, 2.9740338169556e+284)); +insert into t1 values (POINT(4.7783097267365e-299, -0)); +insert into t1 values (POINT(1.49166814624e-154, 2.0880974297595e-53)); +insert into t1 values (POINT(4.0917382598702e+149, 1.2024538023802e+111)); +insert into t1 values (POINT(2.0349165139404e+236, 2.9993936277913e-241)); +insert into t1 values (POINT(2.5243548967072e-29, 1.2024538023802e+111)); +insert into t1 values (POINT(0, 6.9835074892995e-251)); +insert into t1 values (POINT(2.0880974297595e-53, 3.1050361846014e+231)); +insert into t1 values (POINT(2.8728483499323e-188, 2.4600631144627e+260)); +insert into t1 values (POINT(3.0517578125e-05, 2.0349165139404e+236)); +insert into t1 values (POINT(1.1517219314031e+164, 1.1818212630766e-125)); +insert into t1 values (POINT(2.481040258324e-265, 5.7766220027675e-275)); +insert into t1 values (POINT(2.0880974297595e-53, 2.5243548967072e-29)); +insert into t1 values (POINT(5.7766220027675e-275, 9.9464647281957e+86)); +insert into t1 values (POINT(2.2181357552967e+130, 3.7857669957337e-270)); +insert into t1 values (POINT(4.5767114681874e-246, 3.6893488147419e+19)); +insert into t1 values (POINT(4.5767114681874e-246, 3.7537584144024e+255)); +insert into t1 values (POINT(3.7857669957337e-270, 1.8033161362863e-130)); +insert into t1 values (POINT(0, 5.8774717541114e-39)); +insert into t1 values (POINT(1.1517219314031e+164, 2.2761049594727e-159)); +insert into t1 values (POINT(6.243497100632e+144, 3.7857669957337e-270)); +insert into t1 values (POINT(3.7857669957337e-270, 2.6355494858076e-82)); +insert into t1 values (POINT(2.0349165139404e+236, 3.8518598887745e-34)); +insert into t1 values (POINT(4.6566128730774e-10, 2.0880974297595e-53)); +insert into t1 values (POINT(2.0880974297595e-53, 1.8827498946116e-183)); +insert into t1 values (POINT(1.8033161362863e-130, 9.1248812352444e+192)); +insert into t1 values (POINT(4.7783097267365e-299, 2.2761049594727e-159)); +insert into t1 values (POINT(1.94906280228e+289, 1.2338789709327e-178)); drop table t1; # End of 4.1 tests diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index cc2ac5b7392..c01fa205349 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -36,32 +36,32 @@ INSERT INTO gis_point VALUES INSERT INTO gis_line VALUES (105, LineFromText('LINESTRING(0 0,0 10,10 0)')), (106, LineStringFromText('LINESTRING(10 10,20 10,20 20,10 20,10 10)')), -(107, LineStringFromWKB(LineString(Point(10, 10), Point(40, 10)))); +(107, LineStringFromWKB(AsWKB(LineString(Point(10, 10), Point(40, 10))))); INSERT INTO gis_polygon VALUES (108, PolygonFromText('POLYGON((10 10,20 10,20 20,10 20,10 10))')), (109, PolyFromText('POLYGON((0 0,50 0,50 50,0 50,0 0), (10 10,20 10,20 20,10 20,10 10))')), -(110, PolyFromWKB(Polygon(LineString(Point(0, 0), Point(30, 0), Point(30, 30), Point(0, 0))))); +(110, PolyFromWKB(AsWKB(Polygon(LineString(Point(0, 0), Point(30, 0), Point(30, 30), Point(0, 0)))))); INSERT INTO gis_multi_point VALUES (111, MultiPointFromText('MULTIPOINT(0 0,10 10,10 20,20 20)')), (112, MPointFromText('MULTIPOINT(1 1,11 11,11 21,21 21)')), -(113, MPointFromWKB(MultiPoint(Point(3, 6), Point(4, 10)))); +(113, MPointFromWKB(AsWKB(MultiPoint(Point(3, 6), Point(4, 10))))); INSERT INTO gis_multi_line VALUES (114, MultiLineStringFromText('MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))')), (115, MLineFromText('MULTILINESTRING((10 48,10 21,10 0))')), -(116, MLineFromWKB(MultiLineString(LineString(Point(1, 2), Point(3, 5)), LineString(Point(2, 5), Point(5, 8), Point(21, 7))))); +(116, MLineFromWKB(AsWKB(MultiLineString(LineString(Point(1, 2), Point(3, 5)), LineString(Point(2, 5), Point(5, 8), Point(21, 7)))))); INSERT INTO gis_multi_polygon VALUES (117, MultiPolygonFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))')), (118, MPolyFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))')), -(119, MPolyFromWKB(MultiPolygon(Polygon(LineString(Point(0, 3), Point(3, 3), Point(3, 0), Point(0, 3)))))); +(119, MPolyFromWKB(AsWKB(MultiPolygon(Polygon(LineString(Point(0, 3), Point(3, 3), Point(3, 0), Point(0, 3))))))); INSERT INTO gis_geometrycollection VALUES (120, GeomCollFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10 10))')), -(121, GeometryFromWKB(GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9))))); +(121, GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9)))))); INSERT into gis_geometry SELECT * FROM gis_point; INSERT into gis_geometry SELECT * FROM gis_line; diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index d088f68fc0c..71bd1347f6e 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -70,10 +70,17 @@ String *Item_func_geometry_from_wkb::val_str(String *str) { DBUG_ASSERT(fixed == 1); String arg_val; - String *wkb= args[0]->val_str(&arg_val); + String *wkb; Geometry_buffer buffer; uint32 srid= 0; + if (args[0]->field_type() == MYSQL_TYPE_GEOMETRY) + { + return args[0]->val_str(str); + } + + wkb= args[0]->val_str(&arg_val); + if ((arg_count == 2) && !args[1]->null_value) srid= (uint32)args[1]->val_int(); @@ -83,8 +90,8 @@ String *Item_func_geometry_from_wkb::val_str(String *str) str->length(0); str->q_append(srid); if ((null_value= - (args[0]->null_value || - !Geometry::create_from_wkb(&buffer, wkb->ptr(), wkb->length(), str)))) + (args[0]->null_value || + !Geometry::create_from_wkb(&buffer, wkb->ptr(), wkb->length(), str)))) return 0; return str; } @@ -337,14 +344,16 @@ String *Item_func_point::val_str(String *str) DBUG_ASSERT(fixed == 1); double x= args[0]->val_real(); double y= args[1]->val_real(); + uint32 srid= 0; if ((null_value= (args[0]->null_value || args[1]->null_value || - str->realloc(1 + 4 + SIZEOF_STORED_DOUBLE*2)))) + str->realloc(4/*SRID*/ + 1 + 4 + SIZEOF_STORED_DOUBLE*2)))) return 0; str->set_charset(&my_charset_bin); str->length(0); + str->q_append(srid); str->q_append((char)Geometry::wkb_ndr); str->q_append((uint32)Geometry::wkb_point); str->q_append(x); @@ -368,12 +377,14 @@ String *Item_func_spatial_collection::val_str(String *str) DBUG_ASSERT(fixed == 1); String arg_value; uint i; + uint32 srid= 0; str->set_charset(&my_charset_bin); str->length(0); - if (str->reserve(1 + 4 + 4, 512)) + if (str->reserve(4/*SRID*/ + 1 + 4 + 4, 512)) goto err; + str->q_append(srid); str->q_append((char) Geometry::wkb_ndr); str->q_append((uint32) coll_type); str->q_append((uint32) arg_count); @@ -391,13 +402,13 @@ String *Item_func_spatial_collection::val_str(String *str) In the case of GeometryCollection we don't need any checkings for item types, so just copy them into target collection */ - if (str->append(res->ptr(), len, (uint32) 512)) + if (str->append(res->ptr() + 4/*SRID*/, len - 4/*SRID*/, (uint32) 512)) goto err; } else { enum Geometry::wkbType wkb_type; - const char *data= res->ptr() + 1; + const char *data= res->ptr() + 4/*SRID*/ + 1; /* In the case of named collection we must check that items @@ -406,7 +417,7 @@ String *Item_func_spatial_collection::val_str(String *str) wkb_type= (Geometry::wkbType) uint4korr(data); data+= 4; - len-= 5; + len-= 5 + 4/*SRID*/; if (wkb_type != item_type) goto err; From d38e62634f4763d84d5bc54929c2c0c1595d51d2 Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Tue, 28 Apr 2009 14:46:07 +0300 Subject: [PATCH 93/99] Bug #38694 Race condition in replication thread shutdown The issue of the current bug is unguarded access to mi->slave_running by the shutdown thread calling end_slave() that is bug#29968 (alas happened not to be cross-linked with the current bug) Fixed: with removing the unguarded read of the running status and perform reading it in terminate_slave_thread() at time run_lock is taken (mostly bug#29968 backporting, still with some improvements over that patch - see the error reporting from terminate_slave_thread()). Issue of bug#38716 is fixed here for 5.0 branch as well. Note: There has been a separate artifact identified - a race condition between init_slave() and end_slave() - reported as Bug#44467. mysql-test/r/rpl_bug38694.result: a new results file is added. mysql-test/t/rpl_bug38694-slave.opt: simulating delay at slave threads shutdown. mysql-test/t/rpl_bug38694.test: A new test to check if a delay at the termination phase of slave threads could cause any issue. sql/slave.cc: The unguarded read of the running status is removed. Its reading is done in terminate_slave_thread() at time run_lock is taken; Calling terminate_slave_threads(skip_lock := !need_slave_mutex) in the failing branch of start_slave_threads() which is bug#38716 issue. sql/slave.h: removing terminate_slave_thread() out of the global interface scope. --- mysql-test/r/rpl_bug38694.result | 6 ++ mysql-test/t/rpl_bug38694-slave.opt | 1 + mysql-test/t/rpl_bug38694.test | 10 +++ sql/slave.cc | 105 +++++++++++++++++++++------- sql/slave.h | 4 -- 5 files changed, 96 insertions(+), 30 deletions(-) create mode 100644 mysql-test/r/rpl_bug38694.result create mode 100644 mysql-test/t/rpl_bug38694-slave.opt create mode 100644 mysql-test/t/rpl_bug38694.test diff --git a/mysql-test/r/rpl_bug38694.result b/mysql-test/r/rpl_bug38694.result new file mode 100644 index 00000000000..711c4a91c03 --- /dev/null +++ b/mysql-test/r/rpl_bug38694.result @@ -0,0 +1,6 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; diff --git a/mysql-test/t/rpl_bug38694-slave.opt b/mysql-test/t/rpl_bug38694-slave.opt new file mode 100644 index 00000000000..d96e981b198 --- /dev/null +++ b/mysql-test/t/rpl_bug38694-slave.opt @@ -0,0 +1 @@ +--loose-debug=d,simulate_slave_delay_at_terminate_bug38694 diff --git a/mysql-test/t/rpl_bug38694.test b/mysql-test/t/rpl_bug38694.test new file mode 100644 index 00000000000..41b11d271b9 --- /dev/null +++ b/mysql-test/t/rpl_bug38694.test @@ -0,0 +1,10 @@ +# Testing replication threads stopping concurrency issue +# at the server shutdown +# Related bugs: bug#38694, bug#29968, bug#25306 +# The test checks if a delay at the termination phase of slave threads +# DBUG_EXECUTE_IF("simulate_slave_delay_at_terminate_bug38694", sleep(5);); +# could cause any issue. + +source include/master-slave.inc; + +# End of tests diff --git a/sql/slave.cc b/sql/slave.cc index cc82710dec7..f9ae7eb92b6 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -78,6 +78,11 @@ static int request_table_dump(MYSQL* mysql, const char* db, const char* table); static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, const char* table_name, bool overwrite); static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi); +static int terminate_slave_thread(THD *thd, + pthread_mutex_t *term_lock, + pthread_cond_t *term_cond, + volatile uint *slave_running, + bool skip_lock); /* Find out which replications threads are running @@ -637,55 +642,96 @@ int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock) return 0; /* successfully do nothing */ int error,force_all = (thread_mask & SLAVE_FORCE_ALL); pthread_mutex_t *sql_lock = &mi->rli.run_lock, *io_lock = &mi->run_lock; - pthread_mutex_t *sql_cond_lock,*io_cond_lock; DBUG_ENTER("terminate_slave_threads"); - sql_cond_lock=sql_lock; - io_cond_lock=io_lock; - - if (skip_lock) - { - sql_lock = io_lock = 0; - } - if ((thread_mask & (SLAVE_IO|SLAVE_FORCE_ALL)) && mi->slave_running) + if (thread_mask & (SLAVE_IO|SLAVE_FORCE_ALL)) { DBUG_PRINT("info",("Terminating IO thread")); mi->abort_slave=1; - if ((error=terminate_slave_thread(mi->io_thd,io_lock, - io_cond_lock, + if ((error=terminate_slave_thread(mi->io_thd, io_lock, &mi->stop_cond, - &mi->slave_running)) && + &mi->slave_running, + skip_lock)) && !force_all) DBUG_RETURN(error); } - if ((thread_mask & (SLAVE_SQL|SLAVE_FORCE_ALL)) && mi->rli.slave_running) + if (thread_mask & (SLAVE_SQL|SLAVE_FORCE_ALL)) { DBUG_PRINT("info",("Terminating SQL thread")); - DBUG_ASSERT(mi->rli.sql_thd != 0) ; mi->rli.abort_slave=1; - if ((error=terminate_slave_thread(mi->rli.sql_thd,sql_lock, - sql_cond_lock, + if ((error=terminate_slave_thread(mi->rli.sql_thd, sql_lock, &mi->rli.stop_cond, - &mi->rli.slave_running)) && + &mi->rli.slave_running, + skip_lock)) && !force_all) DBUG_RETURN(error); } DBUG_RETURN(0); } +/** + Wait for a slave thread to terminate. -int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, - pthread_mutex_t *cond_lock, - pthread_cond_t* term_cond, - volatile uint *slave_running) + This function is called after requesting the thread to terminate + (by setting abort_slave member of Relay_log_info or + Master_info structure to 1). Termination of the thread is + controlled with the the predicate *slave_running. + + Function will acquire term_lock before waiting on the condition + unless skip_lock is true in which case the mutex should be owned + by the caller of this function and will remain acquired after + return from the function. + + term_lock + Associated lock to use when waiting for term_cond + + term_cond + Condition that is signalled when the thread has terminated + + slave_running + Pointer to predicate to check for slave thread termination + + skip_lock + If true the lock will not be acquired before waiting on + the condition. In this case, it is assumed that the calling + function acquires the lock before calling this function. + + + returns zero if success, ER_SLAVE_NOT_RUNNING otherwise. + + NOTE: + If the executing thread has to acquire term_lock (skip_lock is false), + the negative running status does not represent any issue therefore no error is reported. +*/ + +int terminate_slave_thread(THD* thd, + pthread_mutex_t *term_lock, + pthread_cond_t *term_cond, + volatile uint *slave_running, + bool skip_lock) { DBUG_ENTER("terminate_slave_thread"); - if (term_lock) + if (!skip_lock) { pthread_mutex_lock(term_lock); - if (!*slave_running) + } + else + { + safe_mutex_assert_owner(term_lock); + } + if (!*slave_running) + { + if (!skip_lock) { + /* + if run_lock (term_lock) is acquired locally then either + slave_running status is fine + */ pthread_mutex_unlock(term_lock); + DBUG_RETURN(0); + } + else + { DBUG_RETURN(ER_SLAVE_NOT_RUNNING); } } @@ -698,6 +744,7 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, while (*slave_running) // Should always be true { + int error; DBUG_PRINT("loop", ("killing slave thread")); pthread_mutex_lock(&thd->LOCK_delete); @@ -719,9 +766,13 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, */ struct timespec abstime; set_timespec(abstime,2); - pthread_cond_timedwait(term_cond, cond_lock, &abstime); + error= pthread_cond_timedwait(term_cond, term_lock, &abstime); + DBUG_ASSERT(error == ETIMEDOUT || error == 0); } - if (term_lock) + + DBUG_ASSERT(*slave_running == 0); + + if (!skip_lock) pthread_mutex_unlock(term_lock); DBUG_RETURN(0); } @@ -834,7 +885,7 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start, &mi->rli.slave_running, &mi->rli.slave_run_id, mi, 0); if (error) - terminate_slave_threads(mi, thread_mask & SLAVE_IO, 0); + terminate_slave_threads(mi, thread_mask & SLAVE_IO, !need_slave_mutex); } DBUG_RETURN(error); } @@ -3855,6 +3906,7 @@ err: delete the mi structure leading to a crash! (see BUG#25306 for details) */ pthread_cond_broadcast(&mi->stop_cond); // tell the world we are done + DBUG_EXECUTE_IF("simulate_slave_delay_at_terminate_bug38694", sleep(5);); pthread_mutex_unlock(&mi->run_lock); #ifndef DBUG_OFF if (abort_slave_event_count && !events_till_abort) @@ -4103,6 +4155,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ */ const int eta= rli->events_till_abort; #endif + DBUG_EXECUTE_IF("simulate_slave_delay_at_terminate_bug38694", sleep(5);); pthread_mutex_unlock(&rli->run_lock); // tell the world we are done #ifndef DBUG_OFF // TODO: reconsider the code below diff --git a/sql/slave.h b/sql/slave.h index da548e145d3..5ae596f1eb5 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -504,10 +504,6 @@ bool flush_relay_log_info(RELAY_LOG_INFO* rli); int register_slave_on_master(MYSQL* mysql); int terminate_slave_threads(MASTER_INFO* mi, int thread_mask, bool skip_lock = 0); -int terminate_slave_thread(THD* thd, pthread_mutex_t* term_mutex, - pthread_mutex_t* cond_lock, - pthread_cond_t* term_cond, - volatile uint* slave_running); int start_slave_threads(bool need_slave_mutex, bool wait_for_start, MASTER_INFO* mi, const char* master_info_fname, const char* slave_info_fname, int thread_mask); From 9f04d27027cd2ce0651ef3941af687abd65f4c1a Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Tue, 28 Apr 2009 18:16:17 +0200 Subject: [PATCH 94/99] Bug#35769 typo in mysqlhotcopy documentation Fixed a number of typos, and made punctuation and capitalization more consistent in documentation and help. --- scripts/mysqlhotcopy.sh | 60 ++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh index 4819f512a65..21fca0c0848 100644 --- a/scripts/mysqlhotcopy.sh +++ b/scripts/mysqlhotcopy.sh @@ -49,11 +49,11 @@ $0 Ver $VERSION Usage: $0 db_name[./table_regex/] [new_db_name | directory] - -?, --help display this helpscreen and exit + -?, --help display this help-screen and exit -u, --user=# user for database login if not current user -p, --password=# password to use when connecting to server (if not set in my.cnf, which is recommended) - -h, --host=# Hostname for local server when connecting over TCP/IP + -h, --host=# hostname for local server when connecting over TCP/IP -P, --port=# port to use when connecting to local server with TCP/IP -S, --socket=# socket to use when connecting to local server @@ -86,7 +86,7 @@ sub usage { # Do not initialize user or password options; that way, any user/password # options specified in option files will be used. If no values are specified -# all, the defaults will be used (login name, no password). +# at all, the defaults will be used (login name, no password). my %opt = ( noindices => 0, @@ -95,7 +95,7 @@ my %opt = ( method => "cp", flushlog => 0, ); -Getopt::Long::Configure(qw(no_ignore_case)); # disambuguate -p and -P +Getopt::Long::Configure(qw(no_ignore_case)); # disambiguate -p and -P GetOptions( \%opt, "help", "host|h=s", @@ -453,7 +453,7 @@ else { printf "Locked $num_tables tables in %d seconds.\n", time-$start unless $opt{quiet}; $hc_started = time; # count from time lock is granted - # flush tables to make on-disk copy uptodate + # flush tables to make on-disk copy up to date $start = time; $dbh->do("FLUSH TABLES /*!32323 $hc_tables */"); printf "Flushed tables ($hc_tables) in %d seconds.\n", time-$start unless $opt{quiet}; @@ -895,7 +895,7 @@ tables and you don't want to have all the tables locked for the whole duration. In this situation, I you are happy for groups of tables to be -backed up separately (and thus possibly not be logically consistant +backed up separately (and thus possibly not be logically consistent with one another) then you can run mysqlhotcopy several times on the same database each with different db_name./table_regex/. All but the first should use the --addtodest option so the tables @@ -920,7 +920,7 @@ server in a mutual replication setup. =item --regexp pattern -Copy all databases with names matching the pattern +Copy all databases with names matching the pattern. =item --regexp /pattern1/./pattern2/ @@ -933,7 +933,7 @@ names begin with 'bar' from all databases which names end with 'foo': =item db_name./pattern/ Copy only tables matching pattern. Shell metacharacters ( (, ), |, !, -etc.) have to be escaped (e.g. \). For example, to select all tables +etc.) have to be escaped (e.g., \). For example, to select all tables in database db1 whose names begin with 'foo' or 'bar': mysqlhotcopy --indices --method=cp db1./^\(foo\|bar\)/ @@ -947,19 +947,19 @@ that do not begin with foo nor bar: =item -?, --help -Display helpscreen and exit +Display help-screen and exit. =item -u, --user=# -user for database login if not current user +User for database login if not current user. =item -p, --password=# -password to use when connecting to the server. Note that you are strongly +Password to use when connecting to the server. Note that you are strongly encouraged *not* to use this option as every user would be able to see the password in the process list. Instead use the '[mysqlhotcopy]' section in one of the config files, normally /etc/my.cnf or your personal ~/.my.cnf. -(See the chapter 'my.cnf Option Files' in the manual) +(See the chapter 'my.cnf Option Files' in the manual.) =item -h, -h, --host=# @@ -968,12 +968,12 @@ different from 'localhost' will trigger mysqlhotcopy to use TCP/IP connection. =item -P, --port=# -port to use when connecting to MySQL server with TCP/IP. This is only used +Port to use when connecting to MySQL server with TCP/IP. This is only used when using the --host option. =item -S, --socket=# -UNIX domain socket to use when connecting to local server +UNIX domain socket to use when connecting to local server. =item --noindices @@ -983,7 +983,7 @@ on the backup. =item --method=# -method for copy (only "cp" currently supported). Alpha support for +Method for copy (only "cp" currently supported). Alpha support for "scp" was added in November 2000. Your experience with the scp method will vary with your ability to understand how scp works. 'man scp' and 'man ssh' are your friends. @@ -1000,15 +1000,15 @@ scp or rsync the files at your leisure. =item -q, --quiet -be silent except for errors +Be silent except for errors. =item --debug -Debug messages are displayed +Debug messages are displayed. =item -n, --dryrun -Display commands without actually doing them +Display commands without actually doing them. =back @@ -1030,18 +1030,18 @@ to be specified on the command line: mysqlhotcopy db newdb t1 t2 /^foo_/ : t3 /^bar_/ : + where ":" delimits the subsets, the /^foo_/ indicates all tables -with names begining with "foo_" and the "+" indicates all tables +with names beginning with "foo_" and the "+" indicates all tables not copied by the previous subsets. -newdb is either another not existing database or a full path to a directory -where we can create a directory 'db' +'newdb' is either the name of the new database, or the full path name +of the new database file. The database should not already exist. Add option to lock each table in turn for people who don\'t need cross-table integrity. Add option to FLUSH STATUS just before UNLOCK TABLES. -Add support for other copy methods (eg tar to single file?). +Add support for other copy methods (e.g., tar to single file?). Add support for forthcoming MySQL ``RAID'' table subdirectory layouts. @@ -1049,26 +1049,26 @@ Add support for forthcoming MySQL ``RAID'' table subdirectory layouts. Tim Bunce -Martin Waite - added checkpoint, flushlog, regexp and dryrun options +Martin Waite - Added checkpoint, flushlog, regexp and dryrun options. Fixed cleanup of targets when hotcopy fails. - Added --record_log_pos. + Added --record_log_pos. RAID tables are now copied (don't know if this works over scp). -Ralph Corderoy - added synonyms for commands +Ralph Corderoy - Added synonyms for commands. -Scott Wiersdorf - added table regex and scp support +Scott Wiersdorf - Added table regex and scp support. -Monty - working --noindex (copy only first 2048 bytes of index file) - Fixes for --method=scp +Monty - Working --noindex (copy only first 2048 bytes of index file). + Fixes for --method=scp. Ask Bjoern Hansen - Cleanup code to fix a few bugs and enable -w again. Emil S. Hansen - Added resetslave and resetmaster. -Jeremy D. Zawodny - Removed depricated DBI calls. Fixed bug which +Jeremy D. Zawodny - Removed deprecated DBI calls. Fixed bug which resulted in nothing being copied when a regexp was specified but no database name(s). Martin Waite - Fix to handle database name that contains space. -Paul DuBois - Remove end '/' from directory names +Paul DuBois - Remove end '/' from directory names. From 2328f9b13fe632ab9caf3ba82ba6ab892ce5cba3 Mon Sep 17 00:00:00 2001 From: Matthias Leich Date: Tue, 28 Apr 2009 20:12:18 +0200 Subject: [PATCH 95/99] Fix for Bug#43546 Several 5.0 tests do not pass MTR's --check option (moved from Bug 42308) Details: - insert_update Add DROP TABLE which was missing, error numbers -> names - varbinary Add DROP TABLE which was missing - sp_trans_log Add missing DROP function, improved formatting --- mysql-test/r/insert_update.result | 1 + mysql-test/r/sp_trans_log.result | 5 ++++- mysql-test/r/varbinary.result | 1 + mysql-test/t/insert_update.test | 19 ++++++++++--------- mysql-test/t/sp_trans_log.test | 19 ++++++++++++++----- mysql-test/t/varbinary.test | 1 + 6 files changed, 31 insertions(+), 15 deletions(-) diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result index 20cde86101e..b648531b455 100644 --- a/mysql-test/r/insert_update.result +++ b/mysql-test/r/insert_update.result @@ -393,6 +393,7 @@ id c1 cnt 1 0 3 2 2 1 DROP TABLE t1; +DROP TABLE t2; create table t1(f1 int primary key, f2 timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP); insert into t1(f1) values(1); diff --git a/mysql-test/r/sp_trans_log.result b/mysql-test/r/sp_trans_log.result index eb0770cb0a1..cce5a28fa2e 100644 --- a/mysql-test/r/sp_trans_log.result +++ b/mysql-test/r/sp_trans_log.result @@ -1,3 +1,5 @@ +drop function if exists bug23333| +drop table if exists t1,t2| CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM| CREATE TABLE t2 (a int NOT NULL auto_increment, b int, PRIMARY KEY (a)) ENGINE=InnoDB| insert into t2 values (1,1)| @@ -20,4 +22,5 @@ master-bin.000001 # Query 1 # # select count(*),@a from t1 /* must be 1,1 */| count(*) @a 1 1 -drop table t1, t2| +drop table t1,t2; +drop function if exists bug23333; diff --git a/mysql-test/r/varbinary.result b/mysql-test/r/varbinary.result index f584c22f98a..01af6979ca3 100644 --- a/mysql-test/r/varbinary.result +++ b/mysql-test/r/varbinary.result @@ -78,6 +78,7 @@ alter table t1 modify a varchar(255); select length(a) from t1; length(a) 6 +drop table t1; select 0b01000001; 0b01000001 A diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test index 67108744ec6..de38ae0b0d3 100644 --- a/mysql-test/t/insert_update.test +++ b/mysql-test/t/insert_update.test @@ -12,7 +12,7 @@ INSERT t1 VALUES (8,4,50) ON DUPLICATE KEY UPDATE c=c+1000; SELECT * FROM t1; INSERT t1 VALUES (1,4,60) ON DUPLICATE KEY UPDATE c=c+10000; SELECT * FROM t1; --- error 1062 +-- error ER_DUP_ENTRY INSERT t1 VALUES (1,9,70) ON DUPLICATE KEY UPDATE c=c+100000, b=4; SELECT * FROM t1; TRUNCATE TABLE t1; @@ -63,7 +63,7 @@ INSERT t1 SELECT 8,4,50 FROM DUAL ON DUPLICATE KEY UPDATE c=c+1000; SELECT * FROM t1; INSERT t1 SELECT 1,4,60 FROM DUAL ON DUPLICATE KEY UPDATE c=c+10000; SELECT * FROM t1; --- error 1062 +-- error ER_DUP_ENTRY INSERT t1 SELECT 1,9,70 FROM DUAL ON DUPLICATE KEY UPDATE c=c+100000, b=4; SELECT * FROM t1; TRUNCATE TABLE t1; @@ -76,7 +76,7 @@ INSERT t1 SELECT a,b,c FROM t2 WHERE d=1 ON DUPLICATE KEY UPDATE c=t1.c+100; SELECT * FROM t1; INSERT t1 SET a=5 ON DUPLICATE KEY UPDATE b=0; SELECT * FROM t1; ---error 1052 +--error ER_NON_UNIQ_ERROR INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=c+VALUES(a); INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=t1.c+VALUES(t1.a); SELECT *, VALUES(a) FROM t1; @@ -95,9 +95,9 @@ insert ignore into t1 select a from t1 as t2 on duplicate key update a=t1.a+1 ; select * from t1; insert into t1 select 1 on duplicate key update a=2; select * from t1; ---error 1052 +--error ER_NON_UNIQ_ERROR insert into t1 select a from t1 on duplicate key update a=a+1 ; ---error 1052 +--error ER_NON_UNIQ_ERROR insert ignore into t1 select a from t1 on duplicate key update a=t1.a+1 ; drop table t1; @@ -171,13 +171,13 @@ SET SQL_MODE = 'TRADITIONAL'; CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL); ---error 1364 +--error ER_NO_DEFAULT_FOR_FIELD INSERT INTO t1 (a) VALUES (1); ---error 1364 +--error ER_NO_DEFAULT_FOR_FIELD INSERT INTO t1 (a) VALUES (1) ON DUPLICATE KEY UPDATE a = b; ---error 1364 +--error ER_NO_DEFAULT_FOR_FIELD INSERT INTO t1 (a) VALUES (1) ON DUPLICATE KEY UPDATE b = b; SELECT * FROM t1; @@ -278,7 +278,7 @@ INSERT INTO t1 (id,c1) VALUES (1,10); SELECT * FROM t1; CREATE TABLE t2 (id INT, c1 INT); INSERT INTO t2 VALUES (1,NULL), (2,2); ---error 1048 +--error ER_BAD_NULL_ERROR INSERT INTO t1 (id,c1) SELECT 1,NULL ON DUPLICATE KEY UPDATE c1=NULL; SELECT * FROM t1; @@ -290,6 +290,7 @@ INSERT IGNORE INTO t1 (id,c1) SELECT * FROM t2 SELECT * FROM t1; DROP TABLE t1; +DROP TABLE t2; # # Bug#28904: INSERT .. ON DUPLICATE was silently updating rows when it diff --git a/mysql-test/t/sp_trans_log.test b/mysql-test/t/sp_trans_log.test index 93605722f6b..effa3ca80cf 100644 --- a/mysql-test/t/sp_trans_log.test +++ b/mysql-test/t/sp_trans_log.test @@ -4,11 +4,15 @@ delimiter |; # -# Bug #13270 INSERT,UPDATE,etc that calls func with side-effect does not binlog -# Bug #23333 stored function + non-transac table + transac table = -# breaks stmt-based binlog -# Bug #27395 OPTION_STATUS_NO_TRANS_UPDATE is not preserved at the end of SF() +# Bug#13270 INSERT,UPDATE,etc that calls func with side-effect does not binlog +# Bug#23333 stored function + non-transac table + transac table = +# breaks stmt-based binlog +# Bug#27395 OPTION_STATUS_NO_TRANS_UPDATE is not preserved at the end of SF() # +--disable_warnings +drop function if exists bug23333| +drop table if exists t1,t2| +--enable_warnings CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM| CREATE TABLE t2 (a int NOT NULL auto_increment, b int, PRIMARY KEY (a)) ENGINE=InnoDB| @@ -29,5 +33,10 @@ insert into t2 values (bug23333(),1)| --replace_column 2 # 5 # 6 # show binlog events from 98 /* with fixes for #23333 will show there are 2 queries */| select count(*),@a from t1 /* must be 1,1 */| -drop table t1, t2| +delimiter ;| + +# clean-up + +drop table t1,t2; +drop function if exists bug23333; diff --git a/mysql-test/t/varbinary.test b/mysql-test/t/varbinary.test index 427c1a6b84a..a53a3b8d5b4 100644 --- a/mysql-test/t/varbinary.test +++ b/mysql-test/t/varbinary.test @@ -83,6 +83,7 @@ insert into t1 values("aaa "); select length(a) from t1; alter table t1 modify a varchar(255); select length(a) from t1; +drop table t1; # # Bug#35658 (An empty binary value leads to mysqld crash) From 626a272ed47287a06f44e52a0459d9caf5d2b80e Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 30 Apr 2009 12:52:27 +0500 Subject: [PATCH 96/99] mysql_client_test fixed. per-file comments: tests/mysql_client_test.c the test for bug 37956 isn't relevant anymore. The query there 'select point(?,?)' doesn't produce an error. --- tests/mysql_client_test.c | 58 --------------------------------------- 1 file changed, 58 deletions(-) diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index d006a557819..9e026a27b6d 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -15904,61 +15904,6 @@ static void test_bug28934() } -#ifdef HAVE_SPATIAL -/** - Bug#37956 memory leak and / or crash with geometry and prepared statements! -*/ - -static void test_bug37956(void) -{ - const char *query="select point(?,?)"; - MYSQL_STMT *stmt=NULL; - ulong val=0; - MYSQL_BIND bind_param[2]; - unsigned char buff[2]= { 134, 211 }; - DBUG_ENTER("test_bug37956"); - myheader("test_bug37956"); - - stmt= mysql_simple_prepare(mysql, query); - check_stmt(stmt); - - val=1; - mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void *)&val); - val=CURSOR_TYPE_READ_ONLY; - mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void *)&val); - val=0; - mysql_stmt_attr_set(stmt, STMT_ATTR_PREFETCH_ROWS, (void *)&val); - - memset(bind_param, 0, sizeof(bind_param)); - bind_param[0].buffer_type=MYSQL_TYPE_TINY; - bind_param[0].buffer= (void *)buff; - bind_param[0].is_null=NULL; - bind_param[0].error=NULL; - bind_param[0].is_unsigned=1; - bind_param[1].buffer_type=MYSQL_TYPE_TINY; - bind_param[1].buffer= (void *)(buff+1); - bind_param[1].is_null=NULL; - bind_param[1].error=NULL; - bind_param[1].is_unsigned=1; - - if (mysql_stmt_bind_param(stmt, bind_param)) - { - mysql_stmt_close(stmt); - DIE_UNLESS(0); - } - - if (mysql_stmt_execute(stmt)) - { - mysql_stmt_close(stmt); - DBUG_VOID_RETURN; - } - /* Should never reach here: execution returns an error. */ - mysql_stmt_close(stmt); - DIE_UNLESS(0); - DBUG_VOID_RETURN; -} -#endif - /* Bug#27592 (stack overrun when storing datetime value using prepared statements) */ @@ -16945,9 +16890,6 @@ static struct my_tests_st my_tests[]= { { "test_bug32265", test_bug32265 }, { "test_bug38486", test_bug38486 }, { "test_bug40365", test_bug40365 }, -#ifdef HAVE_SPATIAL - { "test_bug37956", test_bug37956 }, -#endif #ifdef HAVE_QUERY_CACHE { "test_bug36326", test_bug36326 }, #endif From e5d859fab7e5973731b0816339b2a2714571487e Mon Sep 17 00:00:00 2001 From: Matthias Leich Date: Thu, 30 Apr 2009 12:26:11 +0200 Subject: [PATCH 97/99] Merge of fix for Bug#44522 main.not_embedded_server fails with "--check-testcases" into actual tree --- mysql-test/r/not_embedded_server.result | 7 +------ mysql-test/t/not_embedded_server.test | 10 ++++++++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/not_embedded_server.result b/mysql-test/r/not_embedded_server.result index edb698ade83..69175ca446f 100644 --- a/mysql-test/r/not_embedded_server.result +++ b/mysql-test/r/not_embedded_server.result @@ -4,9 +4,4 @@ Id User Host db Command Time State Info number root localhost test Query time NULL show full processlist deallocate prepare stmt1; FLUSH STATUS; -SHOW GLOBAL STATUS LIKE 'com_select'; -Variable_name Value -Com_select 101 -SHOW GLOBAL STATUS LIKE 'com_select'; -Variable_name Value -Com_select 101 +Value of com_select did not change diff --git a/mysql-test/t/not_embedded_server.test b/mysql-test/t/not_embedded_server.test index 044d8665a18..fcbcc389b15 100644 --- a/mysql-test/t/not_embedded_server.test +++ b/mysql-test/t/not_embedded_server.test @@ -39,8 +39,14 @@ while ($i) --enable_query_log --enable_result_log -SHOW GLOBAL STATUS LIKE 'com_select'; +let $before= query_get_value(SHOW GLOBAL STATUS LIKE 'com_select',Value,1); --change_user -SHOW GLOBAL STATUS LIKE 'com_select'; +let $after= query_get_value(SHOW GLOBAL STATUS LIKE 'com_select',Value,1); + +if (`select $after != $before`){ + SHOW GLOBAL STATUS LIKE 'com_select'; + die The value of com_select changed during change_user; +} +echo Value of com_select did not change; From d64c0e16759e25285487c709dda72663d8b8cec9 Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Fri, 1 May 2009 19:35:04 +0200 Subject: [PATCH 98/99] A few portability tweaks for Netware, SCO and QNX --- cmd-line-utils/libedit/readline/readline.h | 2 +- include/config-netware.h | 2 +- include/my_global.h | 69 +++++++++++----------- 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/cmd-line-utils/libedit/readline/readline.h b/cmd-line-utils/libedit/readline/readline.h index c77b080c439..0e300faed89 100644 --- a/cmd-line-utils/libedit/readline/readline.h +++ b/cmd-line-utils/libedit/readline/readline.h @@ -66,7 +66,7 @@ typedef KEYMAP_ENTRY *Keymap; #ifndef CTRL #include -#if !defined(__sun) && !defined(__hpux) && !defined(_AIX) +#if !defined(__sun) && !defined(__hpux) && !defined(_AIX) && !defined(__QNXNTO__) && !defined(__USLC__) #include #endif #ifndef CTRL diff --git a/include/config-netware.h b/include/config-netware.h index 9c99305789a..85a5ef86829 100644 --- a/include/config-netware.h +++ b/include/config-netware.h @@ -45,7 +45,7 @@ extern "C" { #undef HAVE_SYS_MMAN_H #undef HAVE_SYNCH_H #undef HAVE_MMAP -#undef HAVE_RINT +#undef HAVE_FESETROUND #define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 #define HAVE_PTHREAD_SIGMASK 1 diff --git a/include/my_global.h b/include/my_global.h index f5a3016bb1e..06d5b0f94b4 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -486,40 +486,6 @@ typedef unsigned short ushort; #define test_all_bits(a,b) (((a) & (b)) == (b)) #define set_bits(type, bit_count) (sizeof(type)*8 <= (bit_count) ? ~(type) 0 : ((((type) 1) << (bit_count)) - (type) 1)) #define array_elements(A) ((uint) (sizeof(A)/sizeof(A[0]))) -#ifndef HAVE_RINT -/** - All integers up to this number can be represented exactly as double precision - values (DBL_MANT_DIG == 53 for IEEE 754 hardware). -*/ -#define MAX_EXACT_INTEGER ((1LL << DBL_MANT_DIG) - 1) - -/** - rint(3) implementation for platforms that do not have it. - Always rounds to the nearest integer with ties being rounded to the nearest - even integer to mimic glibc's rint() behavior in the "round-to-nearest" - FPU mode. Hardware-specific optimizations are possible (frndint on x86). - Unlike this implementation, hardware will also honor the FPU rounding mode. -*/ - -static inline double rint(double x) -{ - double f, i; - f = modf(x, &i); - /* - All doubles with absolute values > MAX_EXACT_INTEGER are even anyway, - no need to check it. - */ - if (x > 0.0) - i += (double) ((f > 0.5) || (f == 0.5 && - i <= (double) MAX_EXACT_INTEGER && - (longlong) i % 2)); - else - i -= (double) ((f < -0.5) || (f == -0.5 && - i >= (double) -MAX_EXACT_INTEGER && - (longlong) i % 2)); - return i; -} -#endif /* HAVE_RINT */ /* Define some general constants */ #ifndef TRUE @@ -1391,4 +1357,39 @@ do { doubleget_union _tmp; \ #define MY_INT64_NUM_DECIMAL_DIGITS 21 +#ifndef HAVE_RINT +/** + All integers up to this number can be represented exactly as double precision + values (DBL_MANT_DIG == 53 for IEEE 754 hardware). +*/ +#define MAX_EXACT_INTEGER ((1LL << DBL_MANT_DIG) - 1) + +/** + rint(3) implementation for platforms that do not have it. + Always rounds to the nearest integer with ties being rounded to the nearest + even integer to mimic glibc's rint() behavior in the "round-to-nearest" + FPU mode. Hardware-specific optimizations are possible (frndint on x86). + Unlike this implementation, hardware will also honor the FPU rounding mode. +*/ + +static inline double rint(double x) +{ + double f, i; + f = modf(x, &i); + /* + All doubles with absolute values > MAX_EXACT_INTEGER are even anyway, + no need to check it. + */ + if (x > 0.0) + i += (double) ((f > 0.5) || (f == 0.5 && + i <= (double) MAX_EXACT_INTEGER && + (longlong) i % 2)); + else + i -= (double) ((f < -0.5) || (f == -0.5 && + i >= (double) -MAX_EXACT_INTEGER && + (longlong) i % 2)); + return i; +} +#endif /* HAVE_RINT */ + #endif /* my_global_h */ From 4822696ecb7302efc543e0be109f1c2a8f1bdf4e Mon Sep 17 00:00:00 2001 From: Chad MILLER Date: Tue, 5 May 2009 17:03:23 -0400 Subject: [PATCH 99/99] Pull 5.1 treatment of community features into 5.0. --- configure.in | 36 +++++++++++++++---- .../include/have_community_features.inc | 4 +++ mysql-test/include/have_profiling.inc | 4 +++ mysql-test/r/have_community_features.require | 2 ++ mysql-test/r/have_profiling.require | 2 ++ mysql-test/t/profiling.test | 2 ++ sql/mysql_priv.h | 2 ++ sql/mysqld.cc | 18 +++++++++- sql/set_var.cc | 4 ++- sql/sp_head.cc | 10 +++--- sql/sql_class.cc | 4 +-- sql/sql_class.h | 2 +- sql/sql_parse.cc | 14 ++++---- sql/sql_prepare.cc | 2 +- sql/sql_profile.cc | 4 +-- sql/sql_profile.h | 2 +- sql/sql_show.cc | 3 ++ 17 files changed, 88 insertions(+), 27 deletions(-) create mode 100644 mysql-test/include/have_community_features.inc create mode 100644 mysql-test/include/have_profiling.inc create mode 100644 mysql-test/r/have_community_features.require create mode 100644 mysql-test/r/have_profiling.require diff --git a/configure.in b/configure.in index afadd2e0c40..866f12c47a2 100644 --- a/configure.in +++ b/configure.in @@ -661,7 +661,6 @@ then fi fi - AC_ARG_WITH(server-suffix, [ --with-server-suffix Append value to the version string.], [ MYSQL_SERVER_SUFFIX=`echo "$withval" | sed -e 's/^\(...................................\)..*$/\1/'` ], @@ -724,17 +723,42 @@ else AC_MSG_RESULT([no]) fi +AC_MSG_CHECKING(whether features provided by the user community should be included.) +AC_ARG_ENABLE(community-features, + AC_HELP_STRING( + [--enable-community-features], + [Enable additional features provided by the user community.]), + [ ENABLE_COMMUNITY_FEATURES=$enableval ], + [ ENABLE_COMMUNITY_FEATURES=no ] + ) + +if test "$ENABLE_COMMUNITY_FEATURES" = "yes" +then + AC_DEFINE([COMMUNITY_SERVER], [1], + [Whether features provided by the user community should be included]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + # Add query profiler +AC_MSG_CHECKING(whether query profiling should be included) AC_ARG_ENABLE(profiling, - AS_HELP_STRING([--disable-profiling], [Build a version without query profiling code]), + AS_HELP_STRING([--enable-profiling], [Add query-profiling code.]), [ ENABLED_PROFILING=$enableval ], - [ ENABLED_PROFILING=yes ]) + [ ENABLED_PROFILING=no ]) if test "$ENABLED_PROFILING" = "yes" then - AC_DEFINE([ENABLED_PROFILING], [1], - [If SHOW PROFILE should be enabled]) - AC_MSG_RESULT([yes]) + if test "$ENABLE_COMMUNITY_FEATURES" = "yes"; + then + AC_DEFINE([ENABLED_PROFILING], [1], [If SHOW PROFILE should be enabled]) + AC_MSG_RESULT([yes]) + else + ENABLED_PROFILING="no" + AC_MSG_RESULT([no, overridden because community-features disabled]) + AC_MSG_ERROR([This is almost certainly wrong. Add --enable-community-features or remove --enable-profiling .]) + fi else AC_MSG_RESULT([no]) fi diff --git a/mysql-test/include/have_community_features.inc b/mysql-test/include/have_community_features.inc new file mode 100644 index 00000000000..66697d8dd00 --- /dev/null +++ b/mysql-test/include/have_community_features.inc @@ -0,0 +1,4 @@ +--require r/have_community_features.require +--disable_query_log +show variables like 'have_community_features'; +--enable_query_log diff --git a/mysql-test/include/have_profiling.inc b/mysql-test/include/have_profiling.inc new file mode 100644 index 00000000000..48f6668ff92 --- /dev/null +++ b/mysql-test/include/have_profiling.inc @@ -0,0 +1,4 @@ +--require r/have_profiling.require +--disable_query_log +show variables like 'have_profiling'; +--enable_query_log diff --git a/mysql-test/r/have_community_features.require b/mysql-test/r/have_community_features.require new file mode 100644 index 00000000000..9233bba91e1 --- /dev/null +++ b/mysql-test/r/have_community_features.require @@ -0,0 +1,2 @@ +Variable_name Value +have_community_features YES diff --git a/mysql-test/r/have_profiling.require b/mysql-test/r/have_profiling.require new file mode 100644 index 00000000000..54caeba1dae --- /dev/null +++ b/mysql-test/r/have_profiling.require @@ -0,0 +1,2 @@ +Variable_name Value +have_profiling YES diff --git a/mysql-test/t/profiling.test b/mysql-test/t/profiling.test index ffd38caf781..29b694fa0bd 100644 --- a/mysql-test/t/profiling.test +++ b/mysql-test/t/profiling.test @@ -1,3 +1,5 @@ +--source include/have_profiling.inc + # Verify that the protocol isn't violated if we ask for profiling info # before profiling has recorded anything. show profiles; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2e15883aeb4..261393353f8 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1479,6 +1479,8 @@ extern SHOW_COMP_OPTION have_query_cache; extern SHOW_COMP_OPTION have_geometry, have_rtree_keys; extern SHOW_COMP_OPTION have_crypt; extern SHOW_COMP_OPTION have_compress; +extern SHOW_COMP_OPTION have_community_features; +extern SHOW_COMP_OPTION have_profiling; #ifndef __WIN__ extern pthread_t signal_thread; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 877312a9129..16353e6f0f3 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -538,6 +538,8 @@ SHOW_COMP_OPTION have_isam; SHOW_COMP_OPTION have_raid, have_ssl, have_symlink, have_query_cache; SHOW_COMP_OPTION have_geometry, have_rtree_keys, have_dlopen; SHOW_COMP_OPTION have_crypt, have_compress; +SHOW_COMP_OPTION have_community_features; +SHOW_COMP_OPTION have_profiling; /* Thread specific variables */ @@ -5638,7 +5640,7 @@ Disable with --skip-ndbcluster (will save memory).", "Maximum time in seconds to wait for the port to become free. " "(Default: no wait)", (gptr*) &mysqld_port_timeout, (gptr*) &mysqld_port_timeout, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) {"profiling_history_size", OPT_PROFILING, "Limit of query profiling memory", (gptr*) &global_system_variables.profiling_history_size, (gptr*) &max_system_variables.profiling_history_size, @@ -6685,7 +6687,9 @@ 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}, +#ifdef COMMUNITY_SERVER {"Uptime_since_flush_status",(char*) 0, SHOW_FLUSHTIME}, +#endif {NullS, NullS, SHOW_LONG} }; @@ -6992,6 +6996,16 @@ static void mysql_init_variables(void) #if !defined(my_pthread_setprio) && !defined(HAVE_PTHREAD_SETSCHEDPARAM) opt_specialflag |= SPECIAL_NO_PRIOR; #endif +#ifdef ENABLED_PROFILING + have_profiling = SHOW_OPTION_YES; +#else + have_profiling = SHOW_OPTION_NO; +#endif +#ifdef COMMUNITY_SERVER + have_community_features = SHOW_OPTION_YES; +#else + have_community_features = SHOW_OPTION_NO; +#endif #if defined(__WIN__) || defined(__NETWARE__) /* Allow Win32 and NetWare users to move MySQL anywhere */ @@ -8016,7 +8030,9 @@ void refresh_status(THD *thd) /* Reset the counters of all key caches (default and named). */ process_key_caches(reset_key_cache_counters); +#ifdef COMMUNITY_SERVER flush_status_time= time((time_t*) 0); +#endif pthread_mutex_unlock(&LOCK_status); /* diff --git a/sql/set_var.cc b/sql/set_var.cc index 909496df045..dcc7a5a15d1 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -564,7 +564,7 @@ static sys_var_thd_bit sys_unique_checks("unique_checks", 0, set_option_bit, OPTION_RELAXED_UNIQUE_CHECKS, 1); -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) static sys_var_thd_bit sys_profiling("profiling", NULL, set_option_bit, ulonglong(OPTION_PROFILING)); static sys_var_thd_ulong sys_profiling_history_size("profiling_history_size", @@ -899,6 +899,8 @@ struct show_var_st init_vars[]= { {"have_bdb", (char*) &have_berkeley_db, SHOW_HAVE}, {"have_blackhole_engine", (char*) &have_blackhole_db, SHOW_HAVE}, {"have_compress", (char*) &have_compress, SHOW_HAVE}, + {"have_community_features", (char*) &have_community_features, SHOW_HAVE}, + {"have_profiling", (char*) &have_profiling, SHOW_HAVE}, {"have_crypt", (char*) &have_crypt, SHOW_HAVE}, {"have_csv", (char*) &have_csv_db, SHOW_HAVE}, {"have_dynamic_loading", (char*) &have_dlopen, SHOW_HAVE}, diff --git a/sql/sp_head.cc b/sql/sp_head.cc index f2b69ac09fd..dcb865744fd 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1103,7 +1103,7 @@ sp_head::execute(THD *thd) */ thd->spcont->callers_arena= &backup_arena; -#if defined(ENABLED_PROFILING) +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) /* Discard the initial part of executing routines. */ thd->profiling.discard_current_query(); #endif @@ -1112,7 +1112,7 @@ sp_head::execute(THD *thd) sp_instr *i; uint hip; // Handler ip -#if defined(ENABLED_PROFILING) +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) /* Treat each "instr" of a routine as discrete unit that could be profiled. Profiling only records information for segments of code that set the @@ -1125,7 +1125,7 @@ sp_head::execute(THD *thd) i = get_instr(ip); // Returns NULL when we're done. if (i == NULL) { -#if defined(ENABLED_PROFILING) +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.discard_current_query(); #endif break; @@ -1209,7 +1209,7 @@ sp_head::execute(THD *thd) } } while (!err_status && !thd->killed); -#if defined(ENABLED_PROFILING) +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.finish_current_query(); thd->profiling.start_new_query("tail end of routine"); #endif @@ -2633,7 +2633,7 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) query= thd->query; query_length= thd->query_length; -#if defined(ENABLED_PROFILING) +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) /* This s-p instr is profilable and will be captured. */ thd->profiling.set_query_source(m_query.str, m_query.length); #endif diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 8a0d84c6735..f2e04647452 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -173,7 +173,7 @@ const char *set_thd_proc_info(THD *thd, const char *info, { const char *old_info= thd->proc_info; DBUG_PRINT("proc_info", ("%s:%d %s", calling_file, calling_line, info)); -#if defined(ENABLED_PROFILING) +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.status_change(info, calling_function, calling_file, calling_line); #endif thd->proc_info= info; @@ -272,7 +272,7 @@ THD::THD() init(); /* Initialize sub structures */ init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE); -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) profiling.set_thd(this); #endif user_connect=(USER_CONN *)0; diff --git a/sql/sql_class.h b/sql/sql_class.h index 58f7d050d64..82c464cb475 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1434,7 +1434,7 @@ public: List warn_list; uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END]; uint total_warn_count; -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) PROFILING profiling; #endif diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a872585e704..fcb7047e998 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1355,7 +1355,7 @@ pthread_handler_t handle_bootstrap(void *arg) thd->db_length+1+QUERY_CACHE_FLAGS_SIZE); thd->query[length] = '\0'; DBUG_PRINT("query",("%-.4096s",thd->query)); -#if defined(ENABLED_PROFILING) +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.set_query_source(thd->query, length); #endif @@ -1594,7 +1594,7 @@ static bool do_command(THD *thd) net_new_transaction(net); packet_length= my_net_read(net); -#if defined(ENABLED_PROFILING) +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.start_new_query(); #endif if (packet_length == packet_error) @@ -1642,7 +1642,7 @@ static bool do_command(THD *thd) return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length)); out: -#if defined(ENABLED_PROFILING) +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.finish_current_query(); #endif DBUG_RETURN(return_value); @@ -1951,7 +1951,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, mysql_log.write(thd,command, format, thd->query_length, thd->query); DBUG_PRINT("query",("%-.4096s",thd->query)); -#if defined(ENABLED_PROFILING) +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.set_query_source(thd->query, thd->query_length); #endif @@ -1981,7 +1981,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, length--; } -#if defined(ENABLED_PROFILING) +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.finish_current_query(); thd->profiling.start_new_query("continuing"); thd->profiling.set_query_source(next_packet, length); @@ -2485,7 +2485,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, Mark this current profiling record to be discarded. We don't wish to have SHOW commands show up in profiling. */ -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.discard_current_query(); #endif break; @@ -2961,7 +2961,7 @@ mysql_execute_command(THD *thd) } case SQLCOM_SHOW_PROFILES: { -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.discard_current_query(); res= thd->profiling.show_profiles(); if (res) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index c152bde1b92..a20f61436a7 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2283,7 +2283,7 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute"))) DBUG_VOID_RETURN; -#ifdef ENABLED_PROFILING +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.set_query_source(stmt->query, stmt->query_length); #endif DBUG_PRINT("exec_query", ("%s", stmt->query)); diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 6ae70ab1d13..551a103da10 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -47,7 +47,7 @@ const char * const _unknown_func_ = ""; int fill_query_profile_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) { -#if defined(ENABLED_PROFILING) +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) return(thd->profiling.fill_statistics_info(thd, tables, cond)); #else my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROFILE", "enable-profiling"); @@ -129,7 +129,7 @@ int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table) } -#if defined(ENABLED_PROFILING) +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) #define RUSAGE_USEC(tv) ((tv).tv_sec*1000*1000 + (tv).tv_usec) #define RUSAGE_DIFF_USEC(tv1, tv2) (RUSAGE_USEC((tv1))-RUSAGE_USEC((tv2))) diff --git a/sql/sql_profile.h b/sql/sql_profile.h index 022422fbb81..2483cb3cb6a 100644 --- a/sql/sql_profile.h +++ b/sql/sql_profile.h @@ -54,7 +54,7 @@ int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table); #define PROFILE_ALL (~0) -#if defined(ENABLED_PROFILING) +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) #include "mysql_priv.h" #ifdef HAVE_SYS_RESOURCE_H diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 297061207cf..59679c96120 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1549,9 +1549,12 @@ static bool show_status_array(THD *thd, const char *wild, nr= (long) (thd->query_start() - server_start_time); end= int10_to_str(nr, buff, 10); break; +#ifdef COMMUNITY_SERVER case SHOW_FLUSHTIME: nr= (long) (thd->query_start() - flush_status_time); end= int10_to_str(nr, buff, 10); + break; +#endif case SHOW_QUERIES: end= int10_to_str((long) thd->query_id, buff, 10); break;