diff options
Diffstat (limited to 'sql')
-rwxr-xr-x | sql/CMakeLists.txt | 4 | ||||
-rw-r--r-- | sql/filesort.cc | 7 | ||||
-rw-r--r-- | sql/ha_ndbcluster.cc | 94 | ||||
-rw-r--r-- | sql/ha_ndbcluster.h | 8 | ||||
-rw-r--r-- | sql/ha_ndbcluster_binlog.cc | 15 | ||||
-rw-r--r-- | sql/handler.cc | 2 | ||||
-rw-r--r-- | sql/log_event.cc | 21 | ||||
-rw-r--r-- | sql/mysql_priv.h | 9 | ||||
-rw-r--r-- | sql/mysqld.cc | 212 | ||||
-rw-r--r-- | sql/set_var.cc | 12 | ||||
-rw-r--r-- | sql/sql_class.cc | 12 | ||||
-rw-r--r-- | sql/sql_connect.cc | 19 | ||||
-rw-r--r-- | sql/sql_parse.cc | 62 | ||||
-rw-r--r-- | sql/sql_plugin.cc | 7 | ||||
-rw-r--r-- | sql/stacktrace.c | 275 | ||||
-rw-r--r-- | sql/stacktrace.h | 22 |
16 files changed, 618 insertions, 163 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 1dffb6ffb58..c5c8c27bc4e 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -43,7 +43,7 @@ ADD_DEFINITIONS(-DMYSQL_SERVER -D_CONSOLE -DHAVE_DLOPEN) ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc - discover.cc ../libmysql/errmsg.c field.cc field_conv.cc + discover.cc ../libmysql/errmsg.c field.cc stacktrace.c stacktrace.h field_conv.cc filesort.cc gstream.cc ha_partition.cc handler.cc hash_filo.cc hash_filo.h @@ -168,5 +168,5 @@ SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "lex_hash.h;message.rc;message.h;sql_yacc.h;sql_yacc.cc") ADD_LIBRARY(udf_example MODULE udf_example.c udf_example.def) -ADD_DEPENDENCIES(udf_example strings) +ADD_DEPENDENCIES(udf_example strings GenError) TARGET_LINK_LIBRARIES(udf_example strings wsock32) diff --git a/sql/filesort.cc b/sql/filesort.cc index 3783aa2a06a..ac731616218 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -120,6 +120,13 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, FILESORT_INFO table_sort; TABLE_LIST *tab= table->pos_in_table_list; Item_subselect *subselect= tab ? tab->containing_subselect() : 0; + + /* + Release InnoDB's adaptive hash index latch (if holding) before + running a sort. + */ + ha_release_temporary_latches(thd); + /* Don't use table->sort in filesort as it is also used by QUICK_INDEX_MERGE_SELECT. Work with a copy and put it back at the end diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 441da21bf1c..fdee8f92331 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -316,6 +316,10 @@ int execute_no_commit_ie(ha_ndbcluster *h, NdbTransaction *trans, /* Place holder for ha_ndbcluster thread specific data */ +typedef struct st_thd_ndb_share { + const void *key; + struct Ndb_local_table_statistics stat; +} THD_NDB_SHARE; static uchar *thd_ndb_share_get_key(THD_NDB_SHARE *thd_ndb_share, size_t *length, my_bool not_used __attribute__((unused))) @@ -372,41 +376,6 @@ Thd_ndb::init_open_tables() my_hash_reset(&open_tables); } -THD_NDB_SHARE * -Thd_ndb::get_open_table(THD *thd, const void *key) -{ - DBUG_ENTER("Thd_ndb::get_open_table"); - HASH_SEARCH_STATE state; - THD_NDB_SHARE *thd_ndb_share= - (THD_NDB_SHARE*)hash_first(&open_tables, (uchar *)&key, sizeof(key), &state); - while (thd_ndb_share && thd_ndb_share->key != key) - thd_ndb_share= (THD_NDB_SHARE*)hash_next(&open_tables, (uchar *)&key, sizeof(key), &state); - if (thd_ndb_share == 0) - { - thd_ndb_share= (THD_NDB_SHARE *) alloc_root(&thd->transaction.mem_root, - sizeof(THD_NDB_SHARE)); - if (!thd_ndb_share) - { - mem_alloc_error(sizeof(THD_NDB_SHARE)); - DBUG_RETURN(NULL); - } - thd_ndb_share->key= key; - thd_ndb_share->stat.last_count= count; - thd_ndb_share->stat.no_uncommitted_rows_count= 0; - thd_ndb_share->stat.records= ~(ha_rows)0; - my_hash_insert(&open_tables, (uchar *)thd_ndb_share); - } - else if (thd_ndb_share->stat.last_count != count) - { - thd_ndb_share->stat.last_count= count; - thd_ndb_share->stat.no_uncommitted_rows_count= 0; - thd_ndb_share->stat.records= ~(ha_rows)0; - } - DBUG_PRINT("exit", ("thd_ndb_share: 0x%lx key: 0x%lx", - (long) thd_ndb_share, (long) key)); - DBUG_RETURN(thd_ndb_share); -} - inline Ndb *ha_ndbcluster::get_ndb() { @@ -2742,10 +2711,13 @@ ha_ndbcluster::set_auto_inc(Field *field) ("Trying to set next auto increment value to %s", llstr(next_val, buff))); #endif - Ndb_tuple_id_range_guard g(m_share); - if (ndb->setAutoIncrementValue(m_table, g.range, next_val, TRUE) - == -1) - ERR_RETURN(ndb->getNdbError()); + if (ndb->checkUpdateAutoIncrementValue(m_share->tuple_id_range, next_val)) + { + Ndb_tuple_id_range_guard g(m_share); + if (ndb->setAutoIncrementValue(m_table, g.range, next_val, TRUE) + == -1) + ERR_RETURN(ndb->getNdbError()); + } DBUG_RETURN(0); } @@ -4554,12 +4526,48 @@ int ha_ndbcluster::init_handler_for_statement(THD *thd, Thd_ndb *thd_ndb) thd_ndb->trans_options|= TNTO_INJECTED_APPLY_STATUS; } #endif - // TODO remove double pointers... - if (!(m_thd_ndb_share= thd_ndb->get_open_table(thd, m_table))) + + if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { - DBUG_RETURN(1); + const void *key= m_table; + HASH_SEARCH_STATE state; + THD_NDB_SHARE *thd_ndb_share= + (THD_NDB_SHARE*)hash_first(&thd_ndb->open_tables, (uchar *)&key, sizeof(key), &state); + while (thd_ndb_share && thd_ndb_share->key != key) + thd_ndb_share= (THD_NDB_SHARE*)hash_next(&thd_ndb->open_tables, (uchar *)&key, sizeof(key), &state); + if (thd_ndb_share == 0) + { + thd_ndb_share= (THD_NDB_SHARE *) alloc_root(&thd->transaction.mem_root, + sizeof(THD_NDB_SHARE)); + if (!thd_ndb_share) + { + mem_alloc_error(sizeof(THD_NDB_SHARE)); + DBUG_RETURN(1); + } + thd_ndb_share->key= key; + thd_ndb_share->stat.last_count= thd_ndb->count; + thd_ndb_share->stat.no_uncommitted_rows_count= 0; + thd_ndb_share->stat.records= ~(ha_rows)0; + my_hash_insert(&thd_ndb->open_tables, (uchar *)thd_ndb_share); + } + else if (thd_ndb_share->stat.last_count != thd_ndb->count) + { + thd_ndb_share->stat.last_count= thd_ndb->count; + thd_ndb_share->stat.no_uncommitted_rows_count= 0; + thd_ndb_share->stat.records= ~(ha_rows)0; + } + DBUG_PRINT("exit", ("thd_ndb_share: 0x%lx key: 0x%lx", + (long) thd_ndb_share, (long) key)); + m_table_info= &thd_ndb_share->stat; + } + else + { + struct Ndb_local_table_statistics &stat= m_table_info_instance; + stat.last_count= thd_ndb->count; + stat.no_uncommitted_rows_count= 0; + stat.records= ~(ha_rows)0; + m_table_info= &stat; } - m_table_info= &m_thd_ndb_share->stat; DBUG_RETURN(0); } diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index cc79402fe92..a17323d3fd6 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -195,11 +195,6 @@ struct Ndb_local_table_statistics { ha_rows records; }; -typedef struct st_thd_ndb_share { - const void *key; - struct Ndb_local_table_statistics stat; -} THD_NDB_SHARE; - class Thd_ndb { public: @@ -207,7 +202,6 @@ class Thd_ndb ~Thd_ndb(); void init_open_tables(); - THD_NDB_SHARE *get_open_table(THD *thd, const void *key); Ndb *ndb; ulong count; @@ -514,6 +508,7 @@ private: NdbScanOperation *m_active_cursor; const NdbDictionary::Table *m_table; struct Ndb_local_table_statistics *m_table_info; + struct Ndb_local_table_statistics m_table_info_instance; char m_dbname[FN_HEADLEN]; //char m_schemaname[FN_HEADLEN]; char m_tabname[FN_HEADLEN]; @@ -522,7 +517,6 @@ private: bool m_lock_tuple; NDB_SHARE *m_share; NDB_INDEX_DATA m_index[MAX_KEY]; - THD_NDB_SHARE *m_thd_ndb_share; // NdbRecAttr has no reference to blob NdbValue m_value[NDB_MAX_ATTRIBUTES_IN_TABLE]; uchar m_ref[NDB_HIDDEN_PRIMARY_KEY_LENGTH]; diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 841dce2d832..fc1568a5ea6 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -683,6 +683,18 @@ static void ndbcluster_reset_slave(THD *thd) /* Initialize the binlog part of the ndb handlerton */ + +/** + Upon the sql command flush logs, we need to ensure that all outstanding + ndb data to be logged has made it to the binary log to get a deterministic + behavior on the rotation of the log. + */ +static bool ndbcluster_flush_logs(handlerton *hton) +{ + ndbcluster_binlog_wait(current_thd); + return FALSE; +} + static int ndbcluster_binlog_func(handlerton *hton, THD *thd, enum_binlog_func fn, void *arg) @@ -711,6 +723,7 @@ static int ndbcluster_binlog_func(handlerton *hton, THD *thd, void ndbcluster_binlog_init_handlerton() { handlerton *h= ndbcluster_hton; + h->flush_logs= ndbcluster_flush_logs; h->binlog_func= ndbcluster_binlog_func; h->binlog_log_query= ndbcluster_binlog_log_query; } @@ -1002,7 +1015,7 @@ static void ndbcluster_get_schema(NDB_SHARE *share, uint blob_len= field_blob->get_length((*field)->ptr); uchar *blob_ptr= 0; field_blob->get_ptr(&blob_ptr); - assert(blob_len == 0 || blob_ptr != 0); + DBUG_ASSERT(blob_len == 0 || blob_ptr != 0); s->query_length= blob_len; s->query= sql_strmake((char*) blob_ptr, blob_len); } diff --git a/sql/handler.cc b/sql/handler.cc index 3c6937537a1..e52d9141143 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -4032,6 +4032,8 @@ int handler::ha_reset() DBUG_ASSERT(inited == NONE); /* Free cache used by filesort */ free_io_cache(table); + /* reset the bitmaps to point to defaults */ + table->default_column_bitmaps(); DBUG_RETURN(reset()); } diff --git a/sql/log_event.cc b/sql/log_event.cc index 62e04336d29..0d2f3e7e708 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -8104,7 +8104,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli) { DBUG_PRINT("info",("ha_index_init returns error %d",error)); table->file->print_error(error, MYF(0)); - DBUG_RETURN(error); + goto err; } /* Fill key data for the row */ @@ -8137,7 +8137,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli) DBUG_PRINT("info",("no record matching the key found in the table")); table->file->print_error(error, MYF(0)); table->file->ha_index_end(); - DBUG_RETURN(error); + goto err; } /* @@ -8165,7 +8165,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli) if (table->key_info->flags & HA_NOSAME) { table->file->ha_index_end(); - DBUG_RETURN(0); + goto ok; } /* @@ -8197,7 +8197,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli) DBUG_PRINT("info",("no record matching the given row found")); table->file->print_error(error, MYF(0)); table->file->ha_index_end(); - DBUG_RETURN(error); + goto err; } } @@ -8218,7 +8218,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli) DBUG_PRINT("info",("error initializing table scan" " (ha_rnd_init returns %d)",error)); table->file->print_error(error, MYF(0)); - DBUG_RETURN(error); + goto err; } /* Continue until we find the right record or have made a full loop */ @@ -8242,7 +8242,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli) " (rnd_next returns %d)",error)); table->file->print_error(error, MYF(0)); table->file->ha_rnd_end(); - DBUG_RETURN(error); + goto err; } } while (restart_count < 2 && record_compare(table)); @@ -8262,10 +8262,15 @@ int Rows_log_event::find_row(const Relay_log_info *rli) table->file->ha_rnd_end(); DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == HA_ERR_RECORD_DELETED || error == 0); - DBUG_RETURN(error); + goto err; } - +ok: + table->default_column_bitmaps(); DBUG_RETURN(0); + +err: + table->default_column_bitmaps(); + DBUG_RETURN(error); } #endif diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index adbcf33051d..905cce75094 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1035,7 +1035,6 @@ bool check_access(THD *thd, ulong access, const char *db, ulong *save_priv, bool no_grant, bool no_errors, bool schema_db); bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables, uint number, bool no_errors); -bool check_global_access(THD *thd, ulong want_access); #else inline bool check_access(THD *thd, ulong access, const char *db, ulong *save_priv, bool no_grant, bool no_errors, @@ -1048,10 +1047,14 @@ inline bool check_access(THD *thd, ulong access, const char *db, inline bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables, uint number, bool no_errors) { return false; } -inline bool check_global_access(THD *thd, ulong want_access) -{ return false; } #endif /*NO_EMBEDDED_ACCESS_CHECKS*/ +#endif /* MYSQL_SERVER */ +#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS +bool check_global_access(THD *thd, ulong want_access); +#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */ +#ifdef MYSQL_SERVER + /* Support routine for SQL parser on partitioning syntax */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9ca2ab5db0e..3a5eabbcb73 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -122,6 +122,13 @@ extern "C" { // Because of SCO 3.2V4.2 #include <sys/mman.h> #endif +#ifdef __WIN__ +#include <crtdbg.h> +#define SIGNAL_FMT "exception 0x%x" +#else +#define SIGNAL_FMT "signal %d" +#endif + #ifdef __NETWARE__ #define zVOLSTATE_ACTIVE 6 #define zVOLSTATE_DEACTIVE 2 @@ -218,6 +225,7 @@ inline void set_proper_floating_point_mode() extern "C" int gethostname(char *name, int namelen); #endif +extern "C" sig_handler handle_segfault(int sig); /* Constants */ @@ -1086,9 +1094,6 @@ static void __cdecl kill_server(int sig_ptr) close_connections(); if (sig != MYSQL_KILL_SIGNAL && -#ifdef __WIN__ - sig != SIGINT && /* Bug#18235 */ -#endif sig != 0) unireg_abort(1); /* purecov: inspected */ else @@ -1657,8 +1662,7 @@ static void network_init(void) FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); - MessageBox(NULL, (LPTSTR) lpMsgBuf, "Error from CreateNamedPipe", - MB_OK|MB_ICONINFORMATION); + sql_perror((char *)lpMsgBuf); LocalFree(lpMsgBuf); unireg_abort(1); } @@ -1917,16 +1921,162 @@ extern "C" sig_handler abort_thread(int sig __attribute__((unused))) ******************************************************************************/ #if defined(__WIN__) + + +/* + On Windows, we use native SetConsoleCtrlHandler for handle events like Ctrl-C + with graceful shutdown. + Also, we do not use signal(), but SetUnhandledExceptionFilter instead - as it + provides possibility to pass the exception to just-in-time debugger, collect + dumps and potentially also the exception and thread context used to output + callstack. +*/ + +static BOOL WINAPI console_event_handler( DWORD type ) +{ + DBUG_ENTER("console_event_handler"); + if(type == CTRL_C_EVENT) + { + /* + Do not shutdown before startup is finished and shutdown + thread is initialized. Otherwise there is a race condition + between main thread doing initialization and CTRL-C thread doing + cleanup, which can result into crash. + */ + if(hEventShutdown) + kill_mysql(); + else + sql_print_warning("CTRL-C ignored during startup"); + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); +} + + +/* + In Visual Studio 2005 and later, default SIGABRT handler will overwrite + any unhandled exception filter set by the application and will try to + call JIT debugger. This is not what we want, this we calling __debugbreak + to stop in debugger, if process is being debugged or to generate + EXCEPTION_BREAKPOINT and then handle_segfault will do its magic. +*/ + +#if (_MSC_VER >= 1400) +static void my_sigabrt_handler(int sig) +{ + __debugbreak(); +} +#endif /*_MSC_VER >=1400 */ + +void win_install_sigabrt_handler(void) +{ +#if (_MSC_VER >=1400) + /*abort() should not override our exception filter*/ + _set_abort_behavior(0,_CALL_REPORTFAULT); + signal(SIGABRT,my_sigabrt_handler); +#endif /* _MSC_VER >=1400 */ +} + +#ifdef DEBUG_UNHANDLED_EXCEPTION_FILTER +#define DEBUGGER_ATTACH_TIMEOUT 120 +/* + Wait for debugger to attach and break into debugger. If debugger is not attached, + resume after timeout. +*/ +static void wait_for_debugger(int timeout_sec) +{ + if(!IsDebuggerPresent()) + { + int i; + printf("Waiting for debugger to attach, pid=%u\n",GetCurrentProcessId()); + fflush(stdout); + for(i= 0; i < timeout_sec; i++) + { + Sleep(1000); + if(IsDebuggerPresent()) + { + /* Break into debugger */ + __debugbreak(); + return; + } + } + printf("pid=%u, debugger not attached after %d seconds, resuming\n",GetCurrentProcessId(), + timeout_sec); + fflush(stdout); + } +} +#endif /* DEBUG_UNHANDLED_EXCEPTION_FILTER */ + +LONG WINAPI my_unhandler_exception_filter(EXCEPTION_POINTERS *ex_pointers) +{ + static BOOL first_time= TRUE; + if(!first_time) + { + /* + This routine can be called twice, typically + when detaching in JIT debugger. + Return EXCEPTION_EXECUTE_HANDLER to terminate process. + */ + return EXCEPTION_EXECUTE_HANDLER; + } + first_time= FALSE; +#ifdef DEBUG_UNHANDLED_EXCEPTION_FILTER + /* + Unfortunately there is no clean way to debug unhandled exception filters, + as debugger does not stop there(also documented in MSDN) + To overcome, one could put a MessageBox, but this will not work in service. + Better solution is to print error message and sleep some minutes + until debugger is attached + */ + wait_for_debugger(DEBUGGER_ATTACH_TIMEOUT); +#endif /* DEBUG_UNHANDLED_EXCEPTION_FILTER */ + __try + { + set_exception_pointers(ex_pointers); + handle_segfault(ex_pointers->ExceptionRecord->ExceptionCode); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DWORD written; + const char msg[] = "Got exception in exception handler!\n"; + WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),msg, sizeof(msg)-1, + &written,NULL); + } + /* + Return EXCEPTION_CONTINUE_SEARCH to give JIT debugger + (drwtsn32 or vsjitdebugger) possibility to attach, + if JIT debugger is configured. + Windows Error reporting might generate a dump here. + */ + return EXCEPTION_CONTINUE_SEARCH; +} + + static void init_signals(void) { - int signals[] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGABRT } ; - for (uint i=0 ; i < sizeof(signals)/sizeof(int) ; i++) - signal(signals[i], kill_server) ; -#if defined(__WIN__) - signal(SIGBREAK,SIG_IGN); //ignore SIGBREAK for NT -#else - signal(SIGBREAK, kill_server); -#endif + win_install_sigabrt_handler(); + if(opt_console) + SetConsoleCtrlHandler(console_event_handler,TRUE); + else + { + /* Avoid MessageBox()es*/ + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + + /* + Do not use SEM_NOGPFAULTERRORBOX in the following SetErrorMode (), + because it would prevent JIT debugger and Windows error reporting + from working. We need WER or JIT-debugging, since our own unhandled + exception filter is not guaranteed to work in all situation + (like heap corruption or stack overflow) + */ + SetErrorMode(SetErrorMode(0)|SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + } + SetUnhandledExceptionFilter(my_unhandler_exception_filter); } @@ -2179,7 +2329,7 @@ static void check_data_home(const char *path) { } -#else /* if ! __WIN__ */ +#endif /*__WIN__ || __NETWARE */ #ifdef HAVE_LINUXTHREADS #define UNSAFE_DEFAULT_LINUX_THREADS 200 @@ -2209,7 +2359,7 @@ extern "C" sig_handler handle_segfault(int sig) */ if (segfaulted) { - fprintf(stderr, "Fatal signal %d while backtracing\n", sig); + fprintf(stderr, "Fatal " SIGNAL_FMT " while backtracing\n", sig); exit(1); } @@ -2219,7 +2369,7 @@ extern "C" sig_handler handle_segfault(int sig) localtime_r(&curr_time, &tm); fprintf(stderr,"\ -%02d%02d%02d %2d:%02d:%02d - mysqld got signal %d;\n\ +%02d%02d%02d %2d:%02d:%02d - mysqld got " SIGNAL_FMT " ;\n\ This could be because you hit a bug. It is also possible that this binary\n\ or one of the libraries it was linked against is corrupt, improperly built,\n\ or misconfigured. This error can also be caused by malfunctioning hardware.\n", @@ -2261,8 +2411,12 @@ the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n", if (!(test_flags & TEST_NO_STACKTRACE)) { fprintf(stderr,"thd: 0x%lx\n",(long) thd); + fprintf(stderr,"\ +Attempting backtrace. You can use the following information to find out\n\ +where mysqld died. If you see no messages after this, something went\n\ +terribly wrong...\n"); print_stacktrace(thd ? (uchar*) thd->thread_stack : (uchar*) 0, - my_thread_stack_size); + my_thread_stack_size); } if (thd) { @@ -2328,15 +2482,22 @@ of those buggy OS calls. You should consider whether you really need the\n\ bugs.\n"); } +#ifdef HAVE_WRITE_CORE if (test_flags & TEST_CORE_ON_SIGNAL) { fprintf(stderr, "Writing a core file\n"); fflush(stderr); write_core(sig); } +#endif + +#ifndef __WIN__ + /* On Windows, do not terminate, but pass control to exception filter */ exit(1); +#endif } +#if !defined(__WIN__) && !defined(__NETWARE__) #ifndef SA_RESETHAND #define SA_RESETHAND 0 #endif @@ -2717,18 +2878,6 @@ pthread_handler_t handle_shutdown(void *arg) kill_server(MYSQL_KILL_SIGNAL); return 0; } - - -int STDCALL handle_kill(ulong ctrl_type) -{ - if (ctrl_type == CTRL_CLOSE_EVENT || - ctrl_type == CTRL_SHUTDOWN_EVENT) - { - kill_server(MYSQL_KILL_SIGNAL); - return TRUE; - } - return FALSE; -} #endif #if !defined(EMBEDDED_LIBRARY) @@ -4096,11 +4245,6 @@ we force server id to 2, but this MySQL server will not act as a slave."); freopen(log_error_file,"a+",stderr); FreeConsole(); // Remove window } - else - { - /* Don't show error dialog box when on foreground: it stops the server */ - SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); - } #endif /* diff --git a/sql/set_var.cc b/sql/set_var.cc index f544aee78ee..77c57ed46b4 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1219,7 +1219,7 @@ static void throw_bounds_warning(THD *thd, const char *name, ulonglong num) static ulonglong fix_unsigned(THD *thd, ulonglong num, const struct my_option *option_limits) { - bool fixed= FALSE; + my_bool fixed= FALSE; ulonglong out= getopt_ull_limit_value(num, option_limits, &fixed); if (fixed) @@ -1279,7 +1279,7 @@ bool sys_var_long_ptr_global::update(THD *thd, set_var *var) void sys_var_long_ptr_global::set_default(THD *thd, enum_var_type type) { - bool not_used; + my_bool not_used; pthread_mutex_lock(guard); *value= (ulong) getopt_ull_limit_value((ulong) option_limits->def_value, option_limits, ¬_used); @@ -1302,7 +1302,7 @@ bool sys_var_ulonglong_ptr::update(THD *thd, set_var *var) void sys_var_ulonglong_ptr::set_default(THD *thd, enum_var_type type) { - bool not_used; + my_bool not_used; pthread_mutex_lock(&LOCK_global_system_variables); *value= getopt_ull_limit_value((ulonglong) option_limits->def_value, option_limits, ¬_used); @@ -1382,7 +1382,7 @@ void sys_var_thd_ulong::set_default(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) { - bool not_used; + my_bool not_used; /* We will not come here if option_limits is not set */ global_system_variables.*offset= (ulong) getopt_ull_limit_value((ulong) option_limits->def_value, @@ -1429,7 +1429,7 @@ void sys_var_thd_ha_rows::set_default(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) { - bool not_used; + my_bool not_used; /* We will not come here if option_limits is not set */ pthread_mutex_lock(&LOCK_global_system_variables); global_system_variables.*offset= @@ -1481,7 +1481,7 @@ void sys_var_thd_ulonglong::set_default(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) { - bool not_used; + my_bool not_used; pthread_mutex_lock(&LOCK_global_system_variables); global_system_variables.*offset= getopt_ull_limit_value((ulonglong) option_limits->def_value, diff --git a/sql/sql_class.cc b/sql/sql_class.cc index b6086388da5..132f840b003 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -683,6 +683,7 @@ void *thd_memdup(MYSQL_THD thd, const void* str, unsigned int size) return thd->memdup(str, size); } +extern "C" void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid) { *xid = *(MYSQL_XID *) &thd->transaction.xid_state.xid; @@ -2764,6 +2765,17 @@ extern "C" int thd_killed(const MYSQL_THD thd) return(thd->killed); } +/** + Return the thread id of a user thread + @param thd user thread + @return thread id +*/ +extern "C" unsigned long thd_get_thread_id(const MYSQL_THD thd) +{ + return((unsigned long)thd->thread_id); +} + + #ifdef INNODB_COMPATIBILITY_HOOKS extern "C" struct charset_info_st *thd_charset(MYSQL_THD thd) { diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 309a1c7ab5d..c3541cb4eb4 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -39,22 +39,7 @@ #endif /* HAVE_OPENSSL */ #ifdef __WIN__ -static void test_signal(int sig_ptr) -{ -#if !defined( DBUG_OFF) - MessageBox(NULL,"Test signal","DBUG",MB_OK); -#endif -#if defined(OS2) - fprintf(stderr, "Test signal %d\n", sig_ptr); - fflush(stderr); -#endif -} -static void init_signals(void) -{ - int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ; - for (int i=0 ; i < 7 ; i++) - signal( signals[i], test_signal) ; -} +extern void win_install_sigabrt_handler(); #endif /* @@ -626,7 +611,7 @@ bool init_new_connection_handler_thread() { pthread_detach_this_thread(); #if defined(__WIN__) - init_signals(); + win_install_sigabrt_handler(); #else /* Win32 calls this in pthread_create */ if (my_thread_init()) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a27bc5bdc19..bd7ff84a1d7 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4989,35 +4989,6 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, } -/** - check for global access and give descriptive error message if it fails. - - @param thd Thread handler - @param want_access Use should have any of these global rights - - @warning - One gets access right if one has ANY of the rights in want_access. - This is useful as one in most cases only need one global right, - but in some case we want to check if the user has SUPER or - REPL_CLIENT_ACL rights. - - @retval - 0 ok - @retval - 1 Access denied. In this case an error is sent to the client -*/ - -bool check_global_access(THD *thd, ulong want_access) -{ - char command[128]; - if ((thd->security_ctx->master_access & want_access)) - return 0; - get_privilege_desc(command, sizeof(command), want_access); - my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command); - return 1; -} - - static bool check_show_access(THD *thd, TABLE_LIST *table) { switch (get_schema_table_idx(table->schema_table)) { @@ -5260,6 +5231,39 @@ bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table) #endif /*NO_EMBEDDED_ACCESS_CHECKS*/ + +/** + check for global access and give descriptive error message if it fails. + + @param thd Thread handler + @param want_access Use should have any of these global rights + + @warning + One gets access right if one has ANY of the rights in want_access. + This is useful as one in most cases only need one global right, + but in some case we want to check if the user has SUPER or + REPL_CLIENT_ACL rights. + + @retval + 0 ok + @retval + 1 Access denied. In this case an error is sent to the client +*/ + +bool check_global_access(THD *thd, ulong want_access) +{ +#ifndef NO_EMBEDDED_ACCESS_CHECKS + char command[128]; + if ((thd->security_ctx->master_access & want_access)) + return 0; + get_privilege_desc(command, sizeof(command), want_access); + my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command); + return 1; +#else + return 0; +#endif +} + /**************************************************************************** Check stack size; Send error if there isn't enough stack to continue ****************************************************************************/ diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 34b2ea654d9..df408d0e61f 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1879,7 +1879,7 @@ err: static int check_func_int(THD *thd, struct st_mysql_sys_var *var, void *save, st_mysql_value *value) { - bool fixed; + my_bool fixed; long long tmp; struct my_option options; value->val_int(value, &tmp); @@ -1907,7 +1907,7 @@ static int check_func_int(THD *thd, struct st_mysql_sys_var *var, static int check_func_long(THD *thd, struct st_mysql_sys_var *var, void *save, st_mysql_value *value) { - bool fixed; + my_bool fixed; long long tmp; struct my_option options; value->val_int(value, &tmp); @@ -1935,12 +1935,11 @@ static int check_func_long(THD *thd, struct st_mysql_sys_var *var, static int check_func_longlong(THD *thd, struct st_mysql_sys_var *var, void *save, st_mysql_value *value) { - bool fixed; + my_bool fixed; long long tmp; struct my_option options; value->val_int(value, &tmp); plugin_opt_set_limits(&options, var); - *(ulonglong *)save= getopt_ull_limit_value(tmp, &options, &fixed); if (var->flags & PLUGIN_VAR_UNSIGNED) *(ulonglong *)save= getopt_ull_limit_value((ulonglong) tmp, &options, diff --git a/sql/stacktrace.c b/sql/stacktrace.c index 3d718dfd9d2..5c3411aa8b1 100644 --- a/sql/stacktrace.c +++ b/sql/stacktrace.c @@ -13,12 +13,16 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* Workaround for Bug#32082: VOID redefinition on Win results in compile errors*/ +#define DONT_DEFINE_VOID 1 + #include <my_global.h> #include "stacktrace.h" + +#ifndef __WIN__ #include <signal.h> #include <my_pthread.h> #include <m_string.h> - #ifdef HAVE_STACKTRACE #include <unistd.h> #include <strings.h> @@ -167,10 +171,7 @@ void print_stacktrace(uchar* stack_bottom, ulong thread_stack) #endif LINT_INIT(fp); - fprintf(stderr,"\ -Attempting backtrace. You can use the following information to find out\n\ -where mysqld died. If you see no messages after this, something went\n\ -terribly wrong...\n"); + #ifdef __i386__ __asm __volatile__ ("movl %%ebp,%0" :"=r"(fp) @@ -308,3 +309,267 @@ void write_core(int sig) #endif } #endif +#else /* __WIN__*/ + +#include <dbghelp.h> + +/* + Stack tracing on Windows is implemented using Debug Helper library(dbghelp.dll) + We do not redistribute dbghelp and the one comes with older OS (up to Windows 2000) + is missing some important functions like functions StackWalk64 or MinidumpWriteDump. + Hence, we have to load functions at runtime using LoadLibrary/GetProcAddress. +*/ + +typedef DWORD (WINAPI *SymSetOptions_FctType)(DWORD dwOptions); +typedef BOOL (WINAPI *SymGetModuleInfo64_FctType) + (HANDLE,DWORD64,PIMAGEHLP_MODULE64) ; +typedef BOOL (WINAPI *SymGetSymFromAddr64_FctType) + (HANDLE,DWORD64,PDWORD64,PIMAGEHLP_SYMBOL64) ; +typedef BOOL (WINAPI *SymGetLineFromAddr64_FctType) + (HANDLE,DWORD64,PDWORD,PIMAGEHLP_LINE64); +typedef BOOL (WINAPI *SymInitialize_FctType) + (HANDLE,PSTR,BOOL); +typedef BOOL (WINAPI *StackWalk64_FctType) + (DWORD,HANDLE,HANDLE,LPSTACKFRAME64,PVOID,PREAD_PROCESS_MEMORY_ROUTINE64, + PFUNCTION_TABLE_ACCESS_ROUTINE64,PGET_MODULE_BASE_ROUTINE64 , + PTRANSLATE_ADDRESS_ROUTINE64); +typedef BOOL (WINAPI *MiniDumpWriteDump_FctType)( + IN HANDLE hProcess, + IN DWORD ProcessId, + IN HANDLE hFile, + IN MINIDUMP_TYPE DumpType, + IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL + IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL + IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL + ); + +static SymSetOptions_FctType pSymSetOptions; +static SymGetModuleInfo64_FctType pSymGetModuleInfo64; +static SymGetSymFromAddr64_FctType pSymGetSymFromAddr64; +static SymInitialize_FctType pSymInitialize; +static StackWalk64_FctType pStackWalk64; +static SymGetLineFromAddr64_FctType pSymGetLineFromAddr64; +static MiniDumpWriteDump_FctType pMiniDumpWriteDump; + +static EXCEPTION_POINTERS *exception_ptrs; + +#define MODULE64_SIZE_WINXP 576 +#define STACKWALK_MAX_FRAMES 64 + +/* + Dynamically load dbghelp functions +*/ +BOOL init_dbghelp_functions() +{ + static BOOL first_time= TRUE; + static BOOL rc; + HMODULE hDbghlp; + + if(first_time) + { + first_time= FALSE; + hDbghlp= LoadLibrary("dbghelp"); + if(!hDbghlp) + { + rc= FALSE; + return rc; + } + pSymSetOptions= (SymSetOptions_FctType) + GetProcAddress(hDbghlp,"SymSetOptions"); + pSymInitialize= (SymInitialize_FctType) + GetProcAddress(hDbghlp,"SymInitialize"); + pSymGetModuleInfo64= (SymGetModuleInfo64_FctType) + GetProcAddress(hDbghlp,"SymGetModuleInfo64"); + pSymGetLineFromAddr64= (SymGetLineFromAddr64_FctType) + GetProcAddress(hDbghlp,"SymGetLineFromAddr64"); + pSymGetSymFromAddr64=(SymGetSymFromAddr64_FctType) + GetProcAddress(hDbghlp,"SymGetSymFromAddr64"); + pStackWalk64= (StackWalk64_FctType) + GetProcAddress(hDbghlp,"StackWalk64"); + pMiniDumpWriteDump = (MiniDumpWriteDump_FctType) + GetProcAddress(hDbghlp,"MiniDumpWriteDump"); + + rc = (BOOL)(pSymSetOptions && pSymInitialize && pSymGetModuleInfo64 + && pSymGetLineFromAddr64 && pSymGetSymFromAddr64 && pStackWalk64); + } + return rc; +} + +void set_exception_pointers(EXCEPTION_POINTERS *ep) +{ + exception_ptrs = ep; +} + +/* Platform SDK in VS2003 does not have definition for SYMOPT_NO_PROMPTS*/ +#ifndef SYMOPT_NO_PROMPTS +#define SYMOPT_NO_PROMPTS 0 +#endif + +void print_stacktrace(uchar* unused1, ulong unused2) +{ + HANDLE hProcess= GetCurrentProcess(); + HANDLE hThread= GetCurrentThread(); + static IMAGEHLP_MODULE64 module= {sizeof(module)}; + static IMAGEHLP_SYMBOL64_PACKAGE package; + DWORD64 addr; + DWORD machine; + int i; + CONTEXT context; + STACKFRAME64 frame={0}; + + if(!exception_ptrs || !init_dbghelp_functions()) + return; + + /* Copy context, as stackwalking on original will unwind the stack */ + context = *(exception_ptrs->ContextRecord); + /*Initialize symbols.*/ + pSymSetOptions(SYMOPT_LOAD_LINES|SYMOPT_NO_PROMPTS|SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG); + pSymInitialize(hProcess,NULL,TRUE); + + /*Prepare stackframe for the first StackWalk64 call*/ + frame.AddrFrame.Mode= frame.AddrPC.Mode= frame.AddrStack.Mode= AddrModeFlat; +#if (defined _M_IX86) + machine= IMAGE_FILE_MACHINE_I386; + frame.AddrFrame.Offset= context.Ebp; + frame.AddrPC.Offset= context.Eip; + frame.AddrStack.Offset= context.Esp; +#elif (defined _M_X64) + machine = IMAGE_FILE_MACHINE_AMD64; + frame.AddrFrame.Offset= context.Rbp; + frame.AddrPC.Offset= context.Rip; + frame.AddrStack.Offset= context.Rsp; +#else + /*There is currently no need to support IA64*/ +#pragma error ("unsupported architecture") +#endif + + package.sym.SizeOfStruct= sizeof(package.sym); + package.sym.MaxNameLength= sizeof(package.name); + + /*Walk the stack, output useful information*/ + for(i= 0; i< STACKWALK_MAX_FRAMES;i++) + { + DWORD64 function_offset= 0; + DWORD line_offset= 0; + IMAGEHLP_LINE64 line= {sizeof(line)}; + BOOL have_module= FALSE; + BOOL have_symbol= FALSE; + BOOL have_source= FALSE; + + if(!pStackWalk64(machine, hProcess, hThread, &frame, &context, 0, 0, 0 ,0)) + break; + addr= frame.AddrPC.Offset; + + have_module= pSymGetModuleInfo64(hProcess,addr,&module); +#ifdef _M_IX86 + if(!have_module) + { + /* + ModuleInfo structure has been "compatibly" extended in releases after XP, + and its size was increased. To make XP dbghelp.dll function + happy, pretend passing the old structure. + */ + module.SizeOfStruct= MODULE64_SIZE_WINXP; + have_module= pSymGetModuleInfo64(hProcess, addr, &module); + } +#endif + + have_symbol= pSymGetSymFromAddr64(hProcess, addr, &function_offset, + &(package.sym)); + have_source= pSymGetLineFromAddr64(hProcess, addr, &line_offset, &line); + + fprintf(stderr, "%p ", addr); + if(have_module) + { + char *base_image_name= strrchr(module.ImageName, '\\'); + if(base_image_name) + base_image_name++; + else + base_image_name= module.ImageName; + fprintf(stderr, "%s!", base_image_name); + } + if(have_symbol) + fprintf(stderr, "%s()", package.sym.Name); + else if(have_module) + fprintf(stderr, "???"); + + if(have_source) + { + char *base_file_name= strrchr(line.FileName, '\\'); + if(base_file_name) + base_file_name++; + else + base_file_name= line.FileName; + fprintf(stderr,"[%s:%u]", base_file_name, line.LineNumber); + } + fprintf(stderr, "\n"); + } + fflush(stderr); +} + + +/* + Write dump. The dump is created in current directory, + file name is constructed from executable name plus + ".dmp" extension +*/ +void write_core(int unused) +{ + char path[MAX_PATH]; + char dump_fname[MAX_PATH]= "core.dmp"; + MINIDUMP_EXCEPTION_INFORMATION info; + HANDLE hFile; + + if(!exception_ptrs || !init_dbghelp_functions() || !pMiniDumpWriteDump) + return; + + info.ExceptionPointers= exception_ptrs; + info.ClientPointers= FALSE; + info.ThreadId= GetCurrentThreadId(); + + if(GetModuleFileName(NULL, path, sizeof(path))) + { + _splitpath(path, NULL, NULL,dump_fname,NULL); + strncat(dump_fname, ".dmp", sizeof(dump_fname)); + } + + hFile= CreateFile(dump_fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + if(hFile) + { + /* Create minidump */ + if(pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), + hFile, MiniDumpNormal, &info, 0, 0)) + { + fprintf(stderr, "Minidump written to %s\n", + _fullpath(path, dump_fname, sizeof(path)) ? path : dump_fname); + } + else + { + fprintf(stderr,"MiniDumpWriteDump() failed, last error %u\n", + GetLastError()); + } + CloseHandle(hFile); + } + else + { + fprintf(stderr, "CreateFile(%s) failed, last error %u\n", dump_fname, + GetLastError()); + } + fflush(stderr); +} + + +void safe_print_str(const char *name, const char *val, int len) +{ + fprintf(stderr,"%s at %p", name, val); + __try + { + fprintf(stderr,"=%.*s\n", len, val); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + fprintf(stderr,"is an invalid string pointer\n"); + } +} +#endif /*__WIN__*/ diff --git a/sql/stacktrace.h b/sql/stacktrace.h index 96c09a21ad6..498f4f197fc 100644 --- a/sql/stacktrace.h +++ b/sql/stacktrace.h @@ -36,19 +36,33 @@ extern char* heap_start; #define init_stacktrace() do { \ heap_start = (char*) &__bss_start; \ } while(0); +void check_thread_lib(void); +#endif /* defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */ +#elif defined (__WIN__) +#define HAVE_STACKTRACE +extern void set_exception_pointers(EXCEPTION_POINTERS *ep); +#define init_stacktrace() {} +#endif + +#ifdef HAVE_STACKTRACE void print_stacktrace(uchar* stack_bottom, ulong thread_stack); void safe_print_str(const char* name, const char* val, int max_len); -#endif /* (defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */ -#endif /* TARGET_OS_LINUX */ - +#else /* Define empty prototypes for functions that are not implemented */ -#ifndef HAVE_STACKTRACE #define init_stacktrace() {} #define print_stacktrace(A,B) {} #define safe_print_str(A,B,C) {} #endif /* HAVE_STACKTRACE */ + +#if !defined(__NETWARE__) +#define HAVE_WRITE_CORE +#endif + +#ifdef HAVE_WRITE_CORE void write_core(int sig); +#endif + #ifdef __cplusplus } |