summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rwxr-xr-xsql/CMakeLists.txt4
-rw-r--r--sql/filesort.cc7
-rw-r--r--sql/ha_ndbcluster.cc94
-rw-r--r--sql/ha_ndbcluster.h8
-rw-r--r--sql/ha_ndbcluster_binlog.cc15
-rw-r--r--sql/handler.cc2
-rw-r--r--sql/log_event.cc21
-rw-r--r--sql/mysql_priv.h9
-rw-r--r--sql/mysqld.cc212
-rw-r--r--sql/set_var.cc12
-rw-r--r--sql/sql_class.cc12
-rw-r--r--sql/sql_connect.cc19
-rw-r--r--sql/sql_parse.cc62
-rw-r--r--sql/sql_plugin.cc7
-rw-r--r--sql/stacktrace.c275
-rw-r--r--sql/stacktrace.h22
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, &not_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, &not_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
}