diff --git a/include/my_pthread.h b/include/my_pthread.h
index 98072c304fa..22a731c25ab 100644
--- a/include/my_pthread.h
+++ b/include/my_pthread.h
@@ -76,19 +76,20 @@ typedef void * (__cdecl *pthread_handler)(void *);
   __int64 i64;
  };
 struct timespec {
-  union ft64 start;
+  union ft64 tv;
   /* The max timeout value in millisecond for pthread_cond_timedwait */
-  long timeout_msec;
+  long max_timeout_msec;
 };
 #define set_timespec(ABSTIME,SEC) { \
-  GetSystemTimeAsFileTime(&((ABSTIME).start.ft)); \
-  (ABSTIME).timeout_msec= (long)((SEC)*1000); \
+  GetSystemTimeAsFileTime(&((ABSTIME).tv.ft)); \
+  (ABSTIME).tv.i64+= (__int64)(SEC)*10000000; \
+  (ABSTIME).max_timeout_msec= (long)((SEC)*1000); \
 }
 #define set_timespec_nsec(ABSTIME,NSEC) { \
-  GetSystemTimeAsFileTime(&((ABSTIME).start.ft)); \
-  (ABSTIME).timeout_msec= (long)((NSEC)/1000000); \
+  GetSystemTimeAsFileTime(&((ABSTIME).tv.ft)); \
+  (ABSTIME).tv.i64+= (__int64)(NSEC)/100; \
+  (ABSTIME).max_timeout_msec= (long)((NSEC)/1000000); \
 }
-#define get_timespec_sec(ABSTIME) ((((ABSTIME).start.i64 / 10000) + (ABSTIME).timeout_msec ) / 1000)
 
 void win_pthread_init(void);
 int win_pthread_setspecific(void *A,void *B,uint length);
@@ -410,9 +411,6 @@ int my_pthread_mutex_trylock(pthread_mutex_t *mutex);
   (ABSTIME).ts_nsec= (now % ULL(10000000) * 100 + ((NSEC) % 100)); \
 }
 #endif /* !set_timespec_nsec */
-#ifndef get_timespec_sec
-#define get_timespec_sec(ABSTIME) (ABSTIME).ts_sec
-#endif /* !get_timespec_sec */
 #else
 #ifndef set_timespec
 #define set_timespec(ABSTIME,SEC) \
@@ -431,9 +429,6 @@ int my_pthread_mutex_trylock(pthread_mutex_t *mutex);
   (ABSTIME).tv_nsec= (long) (now % ULL(10000000) * 100 + ((NSEC) % 100)); \
 }
 #endif /* !set_timespec_nsec */
-#ifndef get_timespec_sec
-#define get_timespec_sec(ABSTIME) (ABSTIME).tv_sec
-#endif /* !get_timespec_sec */
 #endif /* HAVE_TIMESPEC_TS_SEC */
 
 	/* safe_mutex adds checking to mutex for easier debugging */
diff --git a/include/typelib.h b/include/typelib.h
index 4d6a90ad51e..fe19f1001d4 100644
--- a/include/typelib.h
+++ b/include/typelib.h
@@ -18,6 +18,8 @@
 #ifndef _typelib_h
 #define _typelib_h
 
+#include "my_alloc.h"
+
 typedef struct st_typelib {	/* Different types saved here */
   unsigned int count;		/* How many types */
   const char *name;		/* Name of typelib */
@@ -28,6 +30,7 @@ typedef struct st_typelib {	/* Different types saved here */
 extern int find_type(char *x,TYPELIB *typelib,unsigned int full_name);
 extern void make_type(char *to,unsigned int nr,TYPELIB *typelib);
 extern const char *get_type(TYPELIB *typelib,unsigned int nr);
+extern TYPELIB *copy_typelib(MEM_ROOT *root, TYPELIB *from);
 
 extern TYPELIB sql_protocol_typelib;
 
diff --git a/mysql-test/mysql-test-run-shell.sh b/mysql-test/mysql-test-run-shell.sh
index c6da525c159..953478fa9f4 100644
--- a/mysql-test/mysql-test-run-shell.sh
+++ b/mysql-test/mysql-test-run-shell.sh
@@ -2160,7 +2160,7 @@ then
     $MYSQLADMIN --no-defaults --socket=$MASTER_MYSOCK1 -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1
     $MYSQLADMIN --no-defaults --socket=$SLAVE_MYSOCK -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1
     $MYSQLADMIN --no-defaults --host=$hostname --port=$MASTER_MYPORT --protocol=tcp -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1
-    $MYSQLADMIN --no-defaults --host=$hostname --protocol=tcp --port=`expr $MASTER_MYPORT+1` -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1
+    $MYSQLADMIN --no-defaults --host=$hostname --protocol=tcp --port=`expr $MASTER_MYPORT + 1` -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1
     $MYSQLADMIN --no-defaults --host=$hostname --protocol=tcp --port=$SLAVE_MYPORT -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1
     $MYSQLADMIN --no-defaults --host=$hostname --protocol=tcp --port=`expr $SLAVE_MYPORT + 1` -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1
     sleep_until_file_deleted 0 $MASTER_MYPID
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index 6859de2ed63..fb2e456833c 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -5816,4 +5816,20 @@ DROP TABLE bug23760, bug23760_log|
 DROP PROCEDURE bug23760_update_log|
 DROP PROCEDURE bug23760_test_row_count|
 DROP FUNCTION bug23760_rc_test|
+DROP PROCEDURE IF EXISTS bug24117|
+DROP TABLE IF EXISTS t3|
+CREATE TABLE t3(c1 ENUM('abc'))|
+INSERT INTO t3 VALUES('abc')|
+CREATE PROCEDURE bug24117()
+BEGIN
+DECLARE t3c1 ENUM('abc');
+DECLARE mycursor CURSOR FOR SELECT c1 FROM t3;
+OPEN mycursor;
+FLUSH TABLES;
+FETCH mycursor INTO t3c1;
+CLOSE mycursor;
+END|
+CALL bug24117()|
+DROP PROCEDURE bug24117|
+DROP TABLE t3|
 drop table t1,t2;
diff --git a/mysql-test/r/symlink.result b/mysql-test/r/symlink.result
index 05c5e418552..8ffe88acfa4 100644
--- a/mysql-test/r/symlink.result
+++ b/mysql-test/r/symlink.result
@@ -114,13 +114,13 @@ drop table t1;
 show create table t1;
 Table	Create Table
 t1	CREATE TEMPORARY TABLE `t1` (
-  `a` int(11) default NULL
-) ENGINE=MyISAM DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQL_TEST_DIR/var/log/'
+  `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQLTEST_VARDIR/log/'
 show create table t1;
 Table	Create Table
 t1	CREATE TEMPORARY TABLE `t1` (
-  `a` int(11) default NULL
-) ENGINE=MyISAM DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQL_TEST_DIR/var/log/'
+  `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQLTEST_VARDIR/log/'
 create table t1 (a int) engine=myisam select 42 a;
 select * from t1;
 a
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index ba1180ffaff..19c70b1bd1e 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -6778,6 +6778,30 @@ DROP PROCEDURE bug23760_update_log|
 DROP PROCEDURE bug23760_test_row_count|
 DROP FUNCTION bug23760_rc_test|
 
+#
+# BUG#24117: server crash on a FETCH with a cursor on a table which is not in
+#            the table cache
+#
+
+--disable_warnings
+DROP PROCEDURE IF EXISTS bug24117|
+DROP TABLE IF EXISTS t3|
+--enable_warnings
+CREATE TABLE t3(c1 ENUM('abc'))|
+INSERT INTO t3 VALUES('abc')|
+CREATE PROCEDURE bug24117()
+BEGIN
+  DECLARE t3c1 ENUM('abc');
+  DECLARE mycursor CURSOR FOR SELECT c1 FROM t3;
+  OPEN mycursor;
+  FLUSH TABLES;
+  FETCH mycursor INTO t3c1;
+  CLOSE mycursor;
+END|
+CALL bug24117()|
+DROP PROCEDURE bug24117|
+DROP TABLE t3|
+
 #
 # NOTE: The delimiter is `|`, and not `;`. It is changed to `;`
 #       at the end of the file!
diff --git a/mysql-test/t/symlink.test b/mysql-test/t/symlink.test
index 7924f00a9c8..d79b6905224 100644
--- a/mysql-test/t/symlink.test
+++ b/mysql-test/t/symlink.test
@@ -147,20 +147,20 @@ connect (session2,localhost,root,,);
 
 connection session1;
 disable_query_log;
-eval create temporary table t1 (a int) engine=myisam data directory="$MYSQL_TEST_DIR/var/log" select 9 a;
+eval create temporary table t1 (a int) engine=myisam data directory="$MYSQLTEST_VARDIR/log" select 9 a;
 enable_query_log;
 # If running test suite with a non standard tmp dir, the "show create table"
 # will print "DATA_DIRECTORY=". Use replace_result to mask it out
---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
 show create table t1;
 
 connection session2;
 disable_query_log;
-eval create temporary table t1 (a int) engine=myisam data directory="$MYSQL_TEST_DIR/var/log" select 99 a;
+eval create temporary table t1 (a int) engine=myisam data directory="$MYSQLTEST_VARDIR/log" select 99 a;
 enable_query_log;
 # If running test suite with a non standard tmp dir, the "show create table"
 # will print "DATA_DIRECTORY=". Use replace_result to mask it out
---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
 show create table t1;
 
 connection default;
diff --git a/mysys/my_wincond.c b/mysys/my_wincond.c
index 327addff2cc..b56dacc135a 100644
--- a/mysys/my_wincond.c
+++ b/mysys/my_wincond.c
@@ -37,7 +37,7 @@ int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
 
 int pthread_cond_destroy(pthread_cond_t *cond)
 {
-	return CloseHandle(cond->semaphore) ? 0 : EINVAL;
+  return CloseHandle(cond->semaphore) ? 0 : EINVAL;
 }
 
 
@@ -51,6 +51,7 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
   return 0 ;
 }
 
+
 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
                            struct timespec *abstime)
 {
@@ -61,26 +62,26 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
   GetSystemTimeAsFileTime(&now.ft);
 
   /*
-    - subtract start time from current time(values are in 100ns units
+    Calculate time left to abstime
+    - subtract start time from current time(values are in 100ns units)
     - convert to millisec by dividing with 10000
-    - subtract time since start from max timeout
   */
-  timeout= abstime->timeout_msec - (long)((now.i64 - abstime->start.i64) / 10000);
+  timeout= (long)((abstime->tv.i64 - now.i64) / 10000);
   
   /* Don't allow the timeout to be negative */
   if (timeout < 0)
-    timeout = 0L;
+    timeout= 0L;
 
   /*
-    Make sure the calucated time does not exceed original timeout
+    Make sure the calucated timeout does not exceed original timeout
     value which could cause "wait for ever" if system time changes
   */
-  if (timeout > abstime->timeout_msec)
-    timeout= abstime->timeout_msec;
+  if (timeout > abstime->max_timeout_msec)
+    timeout= abstime->max_timeout_msec;
 
   InterlockedIncrement(&cond->waiting);
   LeaveCriticalSection(mutex);
-  result=WaitForSingleObject(cond->semaphore,timeout);
+  result= WaitForSingleObject(cond->semaphore,timeout);
   InterlockedDecrement(&cond->waiting);
   EnterCriticalSection(mutex);
 
diff --git a/mysys/typelib.c b/mysys/typelib.c
index d329b687668..8906b702aa8 100644
--- a/mysys/typelib.c
+++ b/mysys/typelib.c
@@ -119,3 +119,54 @@ const char *get_type(TYPELIB *typelib, uint nr)
     return(typelib->type_names[nr]);
   return "?";
 }
+
+
+/*
+  Create a copy of a specified TYPELIB structure.
+
+  SYNOPSIS
+    copy_typelib()
+    root	pointer to a MEM_ROOT object for allocations
+    from	pointer to a source TYPELIB structure
+
+  RETURN
+    pointer to the new TYPELIB structure on successful copy, or
+    NULL otherwise
+*/
+
+TYPELIB *copy_typelib(MEM_ROOT *root, TYPELIB *from)
+{
+  TYPELIB *to;
+  uint i;
+
+  if (!from)
+    return NULL;
+
+  if (!(to= (TYPELIB*) alloc_root(root, sizeof(TYPELIB))))
+    return NULL;
+
+  if (!(to->type_names= (const char **)
+        alloc_root(root, (sizeof(char *) + sizeof(int)) * (from->count + 1))))
+    return NULL;
+  to->type_lengths= (unsigned int *)(to->type_names + from->count + 1);
+  to->count= from->count;
+  if (from->name)
+  {
+    if (!(to->name= strdup_root(root, from->name)))
+      return NULL;
+  }
+  else
+    to->name= NULL;
+
+  for (i= 0; i < from->count; i++)
+  {
+    if (!(to->type_names[i]= strmake_root(root, from->type_names[i],
+                                          from->type_lengths[i])))
+      return NULL;
+    to->type_lengths[i]= from->type_lengths[i];
+  }
+  to->type_names[to->count]= NULL;
+  to->type_lengths[to->count]= 0;
+
+  return to;
+}
diff --git a/sql/event_queue.cc b/sql/event_queue.cc
index 53fa4f6b5cd..efd309e30e2 100644
--- a/sql/event_queue.cc
+++ b/sql/event_queue.cc
@@ -693,16 +693,11 @@ static const char *queue_wait_msg= "Waiting for next activation";
   SYNOPSIS
     Event_queue::get_top_for_execution_if_time()
       thd      [in]  Thread
-      now      [in]  Current timestamp
       job_data [out] The object to execute
-      abstime  [out] Time to sleep
 
   RETURN VALUE
     FALSE  No error. If *job_data==NULL then top not elligible for execution.
-           Could be that there is no top. If abstime->tv_sec is set to value
-           greater than zero then use abstime with pthread_cond_timedwait().
-           If abstime->tv_sec is zero then sleep with pthread_cond_wait().
-           abstime->tv_nsec is always zero.
+           Could be that there is no top.
     TRUE   Error
     
 */
@@ -712,7 +707,6 @@ Event_queue::get_top_for_execution_if_time(THD *thd, Event_job_data **job_data)
 {
   bool ret= FALSE;
   struct timespec top_time;
-  struct timespec *abstime;
   Event_queue_element *top= NULL;
   bool to_free= FALSE;
   bool to_drop= FALSE;
@@ -724,44 +718,40 @@ Event_queue::get_top_for_execution_if_time(THD *thd, Event_job_data **job_data)
   {
     int res;
 
-    thd->end_time();
-    time_t now= thd->query_start();
-    abstime= NULL;
-
-    if (queue.elements)
+    /* Break loop if thd has been killed */
+    if (thd->killed)
     {
-      top= ((Event_queue_element*) queue_element(&queue, 0));
-      set_timespec(top_time,
-                   sec_since_epoch_TIME(&top->execute_at) - now);
-
-      abstime= &top_time;
+      DBUG_PRINT("info", ("thd->killed=%d", thd->killed));
+      goto end;
     }
 
-    if (!abstime || get_timespec_sec(*abstime) > now)
+    if (!queue.elements)
     {
-      const char *msg;
-      if (abstime)
-      {
-        next_activation_at= top->execute_at;
-        msg= queue_wait_msg;
-      }
-      else
-      {
-        set_zero_time(&next_activation_at, MYSQL_TIMESTAMP_DATETIME);
-        msg= queue_empty_msg;
-      }
+      /* There are no events in the queue */
+      set_zero_time(&next_activation_at, MYSQL_TIMESTAMP_DATETIME);
 
-      cond_wait(thd, abstime, msg, SCHED_FUNC, __LINE__);
-      if (thd->killed)
-      {
-        DBUG_PRINT("info", ("thd->killed=%d", thd->killed));
-        goto end;
-      }
+      /* Wait on condition until signaled. Release LOCK_queue while waiting. */
+      cond_wait(thd, NULL, queue_empty_msg, SCHED_FUNC, __LINE__);
+
+      continue;
+    }
+
+    top= ((Event_queue_element*) queue_element(&queue, 0));
+
+    thd->end_time(); /* Get current time */
+
+    time_t seconds_to_next_event= 
+      sec_since_epoch_TIME(&top->execute_at) - thd->query_start();
+    next_activation_at= top->execute_at;
+    if (seconds_to_next_event > 0)
+    {
       /*
-        The queue could have been emptied. Therefore it's safe to start from
-        the beginning. Moreover, this way we will get also the new top, if
-        the element at the top has been changed.
+        Not yet time for top event, wait on condition with
+        time or until signaled. Release LOCK_queue while waiting.
       */
+      set_timespec(top_time, seconds_to_next_event);
+      cond_wait(thd, &top_time, queue_wait_msg, SCHED_FUNC, __LINE__);
+
       continue;
     }
 
@@ -803,7 +793,7 @@ Event_queue::get_top_for_execution_if_time(THD *thd, Event_job_data **job_data)
     else
       queue_replaced(&queue);
 
-    dbug_dump_queue(now);
+    dbug_dump_queue(thd->query_start());
     break;
   }
 end:
@@ -816,8 +806,7 @@ end:
   if (to_free)
     delete top;
 
-  DBUG_PRINT("info", ("returning %d  et_new: 0x%lx  get_timespec_sec(abstime): %ld ",
-             ret, (long) *job_data, abstime ? get_timespec_sec(*abstime) : 0));
+  DBUG_PRINT("info", ("returning %d  et_new: 0x%lx ", ret, (long) *job_data));
 
   if (*job_data)
     DBUG_PRINT("info", ("db: %s  name: %s  definer=%s", (*job_data)->dbname.str,
diff --git a/sql/field.cc b/sql/field.cc
index 4245d401f53..0dd3dd6b417 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -8029,6 +8029,16 @@ void Field_enum::sql_type(String &res) const
 }
 
 
+Field *Field_enum::new_field(MEM_ROOT *root, struct st_table *new_table,
+                             bool keep_type)
+{
+  Field_enum *res= (Field_enum*) Field::new_field(root, new_table, keep_type);
+  if (res)
+    res->typelib= copy_typelib(root, typelib);
+  return res;
+}
+
+
 /*
    set type.
    This is a string which can have a collection of different values.
diff --git a/sql/field.h b/sql/field.h
index 3e2be248627..9d979e81c9c 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1354,6 +1354,7 @@ public:
   {
       flags|=ENUM_FLAG;
   }
+  Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type);
   enum_field_types type() const { return FIELD_TYPE_STRING; }
   enum Item_result cmp_type () const { return INT_RESULT; }
   enum Item_result cast_to_int_type () const { return INT_RESULT; }