diff --git a/include/my_time.h b/include/my_time.h
index e52ef69475d4bd8c3a77ee845f9ca022a18f66f8..2b0dc4ac6ffcd28bad834a6dd4b0d612ea48e40c 100644
--- a/include/my_time.h
+++ b/include/my_time.h
@@ -89,6 +89,21 @@ int my_date_to_str(const MYSQL_TIME *l_time, char *to);
 int my_datetime_to_str(const MYSQL_TIME *l_time, char *to);
 int my_TIME_to_str(const MYSQL_TIME *l_time, char *to);
 
+/*
+  The following must be sorted so that simple intervals comes first.
+  (get_interval_value() depends on this)
+*/
+
+enum interval_type
+{
+  INTERVAL_YEAR, INTERVAL_QUARTER, INTERVAL_MONTH, INTERVAL_DAY, INTERVAL_HOUR,
+  INTERVAL_MINUTE, INTERVAL_WEEK, INTERVAL_SECOND, INTERVAL_MICROSECOND ,
+  INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE,
+  INTERVAL_DAY_SECOND, INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND,
+  INTERVAL_MINUTE_SECOND, INTERVAL_DAY_MICROSECOND, INTERVAL_HOUR_MICROSECOND,
+  INTERVAL_MINUTE_MICROSECOND, INTERVAL_SECOND_MICROSECOND
+};
+
 C_MODE_END
 
 #endif /* _my_time_h_ */
diff --git a/sql/event.cc b/sql/event.cc
index 6d62be903bd5c857c613197bd2cc276746366e96..e637493d10210bf938ab233dae1ca849f555e124 100644
--- a/sql/event.cc
+++ b/sql/event.cc
@@ -88,8 +88,14 @@ int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
 int
 my_time_compare(TIME *a, TIME *b)
 {
+
+#ifdef ENABLE_WHEN_WE_HAVE_MILLISECOND_IN_TIMESTAMPS
   my_ulonglong a_t= TIME_to_ulonglong_datetime(a)*100L + a->second_part;
   my_ulonglong b_t= TIME_to_ulonglong_datetime(b)*100L + b->second_part;
+#else
+  my_ulonglong a_t= TIME_to_ulonglong_datetime(a);
+  my_ulonglong b_t= TIME_to_ulonglong_datetime(b);
+#endif
 
   if (a_t > b_t)
     return 1;
@@ -355,10 +361,15 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
   DBUG_PRINT("info", ("check existance of an event with the same name"));
   if (!evex_db_find_event_aux(thd, et->dbname, et->name, table))
   {
-    push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
-		      ER_EVENT_ALREADY_EXISTS, ER(ER_EVENT_ALREADY_EXISTS),
-		      et->name.str);
-    goto ok;    
+    if (create_if_not)
+    {
+      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+		          ER_EVENT_ALREADY_EXISTS, ER(ER_EVENT_ALREADY_EXISTS),
+		          et->name.str);
+      goto ok;    
+    }
+    my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), et->name.str);
+    goto err;
   }
 
   DBUG_PRINT("info", ("non-existant, go forward"));
diff --git a/sql/event.h b/sql/event.h
index d302a2f70ab10b3eeacf4a8b6d9e2f3c93152567..80629fa0a70431477df91a6767f90ad5ca62c10c 100644
--- a/sql/event.h
+++ b/sql/event.h
@@ -143,12 +143,12 @@ class event_timed
 
   int
   load_from_row(MEM_ROOT *mem_root, TABLE *table);
-  
+
   bool
   compute_next_execution_time();  
 
   void
-  mark_last_executed();
+  mark_last_executed(THD *thd);
   
   int
   drop(THD *thd);
diff --git a/sql/event_executor.cc b/sql/event_executor.cc
index dd426c3254543edaea10e7b42760c19b6832ef42..1cb289efc74485c5b4b320e5d3b14ce16a55576a 100644
--- a/sql/event_executor.cc
+++ b/sql/event_executor.cc
@@ -334,9 +334,19 @@ event_executor_main(void *arg)
     {
       pthread_t th;
 
-      DBUG_PRINT("evex main thread",("mark_last_executed"));
-      et->mark_last_executed();
-      et->compute_next_execution_time();
+      DBUG_PRINT("evex main thread", ("[%10s] this exec at [%llu]", et->name.str,
+                               TIME_to_ulonglong_datetime(&et->execute_at)));
+      et->mark_last_executed(thd);
+      if (et->compute_next_execution_time())
+      {
+        sql_print_error("Error while computing time of %s.%s . "
+                        "Disabling after execution.",
+                        et->dbname.str, et->name.str);
+        et->status= MYSQL_EVENT_DISABLED;
+      }
+      DBUG_PRINT("evex main thread", ("[%10s] next exec at [%llu]", et->name.str,
+                               TIME_to_ulonglong_datetime(&et->execute_at)));
+
       et->update_fields(thd);
       DBUG_PRINT("info", ("  Spawning a thread %d", ++iter_num));
 #ifndef DBUG_FAULTY_THR
@@ -599,7 +609,12 @@ evex_load_events_from_db(THD *thd)
     }
     
     // let's find when to be executed  
-    et->compute_next_execution_time();
+    if (et->compute_next_execution_time())
+    {
+      sql_print_error("Error while computing execution time of %s.%s. Skipping",
+                       et->dbname.str, et->name.str);
+      continue;
+    }
     
     DBUG_PRINT("evex_load_events_from_db", ("Adding to the exec list."));
 
diff --git a/sql/event_priv.h b/sql/event_priv.h
index 05834383ae5b6c2ded25533fc470297efd9c6da9..42c60dd391d630aa3c072ab39b44e7f1df4bdaf2 100644
--- a/sql/event_priv.h
+++ b/sql/event_priv.h
@@ -46,6 +46,7 @@ enum evex_table_field
 
 #define EVEX_DB_FIELD_LEN 64
 #define EVEX_NAME_FIELD_LEN 64
+#define EVEX_MAX_INTERVAL_VALUE 2147483647L
 
 int
 my_time_compare(TIME *a, TIME *b);
diff --git a/sql/event_timed.cc b/sql/event_timed.cc
index cc8849364dacc5cf89343f68f1bc2f9fb1766cb7..2b7f2cc7ee3ca15defec917a9fcf5f8a6f3ed1a4 100644
--- a/sql/event_timed.cc
+++ b/sql/event_timed.cc
@@ -191,16 +191,78 @@ int
 event_timed::init_interval(THD *thd, Item *expr, interval_type new_interval)
 {
   longlong tmp;
+  String value;
+  INTERVAL interval;
+  
   DBUG_ENTER("event_timed::init_interval");
 
   if (expr->fix_fields(thd, &expr))
     DBUG_RETURN(EVEX_PARSE_ERROR);
 
-  if ((tmp= expr->val_int()) <= 0)
-    DBUG_RETURN(EVEX_BAD_PARAMS);
+  value.alloc(MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN);
+  if (get_interval_value(expr, new_interval, &value, &interval))
+    DBUG_RETURN(EVEX_PARSE_ERROR);
 
-  expression= tmp;
-  interval= new_interval;
+  expression= 0;
+
+  switch (new_interval) {
+  case INTERVAL_YEAR:
+    expression= interval.year;
+    break;
+  case INTERVAL_QUARTER:
+  case INTERVAL_MONTH:
+    expression= interval.month;
+    break;
+  case INTERVAL_WEEK:
+  case INTERVAL_DAY:
+    expression= interval.day;
+    break;
+  case INTERVAL_HOUR:
+    expression= interval.hour;
+    break;
+  case INTERVAL_MINUTE:
+    expression= interval.minute;
+    break;
+  case INTERVAL_SECOND:
+    expression= interval.second;
+    break;
+  case INTERVAL_YEAR_MONTH:			// Allow YEAR-MONTH YYYYYMM
+    expression= interval.year* 12 + interval.month;
+    break;
+  case INTERVAL_DAY_HOUR:
+    expression= interval.day* 24 + interval.hour;
+    break;
+  case INTERVAL_DAY_MINUTE:
+    expression= (interval.day* 24 + interval.hour) * 60 + interval.minute;
+    break;
+  case INTERVAL_HOUR_SECOND: // day is anyway 0
+  case INTERVAL_DAY_SECOND:
+    /* DAY_SECOND having problems because of leap seconds? */
+    expression= ((interval.day* 24 + interval.hour) * 60 + interval.minute)*60
+                 + interval.second;
+    break;
+  case INTERVAL_MINUTE_MICROSECOND: // day and hour are 0
+  case INTERVAL_HOUR_MICROSECOND:// day is anyway 0
+  case INTERVAL_DAY_MICROSECOND:
+    expression= ((((interval.day*24) + interval.hour)*60+interval.minute)*60 +
+                interval.second) * 1000000L + interval.second_part;
+    break;
+  case INTERVAL_HOUR_MINUTE:
+    expression= interval.hour * 60 + interval.minute;
+    break;
+  case INTERVAL_MINUTE_SECOND:
+    expression= interval.minute * 60 + interval.second;
+    break;
+  case INTERVAL_SECOND_MICROSECOND:
+    expression= interval.second * 1000000L + interval.second_part;
+    break;
+  default:
+    break;
+  }
+  if (interval.neg || expression > EVEX_MAX_INTERVAL_VALUE)
+    DBUG_RETURN(EVEX_BAD_PARAMS);
+  
+  this->interval= new_interval;
   DBUG_RETURN(0);
 }
 
@@ -355,7 +417,7 @@ event_timed::init_definer(THD *thd)
  Loads an event from a row from mysql.event
  
  SYNOPSIS
-   event_timed::load_from_row()
+   event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
    
  REMARKS
    This method is silent on errors and should behave like that. Callers
@@ -499,8 +561,83 @@ event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
 
 
 /*
-  Note: In the comments this->ends is referenced as m_ends
+ Computes the sum of a timestamp plus interval
+ 
+ SYNOPSIS
+   get_next_time(TIME *start, int interval_value, interval_type interval)
+   
+   next        - the sum
+   start       - add interval_value to this time
+   i_value - quantity of time type interval to add
+   i_type       - type of interval to add (SECOND, MINUTE, HOUR, WEEK ...) 
+*/
 
+static
+bool get_next_time(TIME *next, TIME *start, int i_value, interval_type i_type)
+{
+  bool ret;
+  INTERVAL interval;
+  TIME tmp;
+  
+  bzero(&interval, sizeof(interval));
+
+  switch (i_type) {
+  case INTERVAL_YEAR:
+    interval.year= (ulong) i_value;
+    break;
+  case INTERVAL_QUARTER:
+    interval.month= (ulong)(i_value*3);
+    break;
+  case INTERVAL_YEAR_MONTH:
+  case INTERVAL_MONTH:
+    interval.month= (ulong) i_value;
+    break;
+  case INTERVAL_WEEK:
+    interval.day= (ulong)(i_value*7);
+    break;
+  case INTERVAL_DAY:
+    interval.day= (ulong) i_value;
+    break;
+  case INTERVAL_DAY_HOUR:
+  case INTERVAL_HOUR:
+    interval.hour= (ulong) i_value;
+    break;
+  case INTERVAL_DAY_MINUTE:
+  case INTERVAL_HOUR_MINUTE:
+  case INTERVAL_MINUTE:
+    interval.minute=i_value;
+    break;
+  case INTERVAL_DAY_SECOND:
+  case INTERVAL_HOUR_SECOND:
+  case INTERVAL_MINUTE_SECOND:
+  case INTERVAL_SECOND:
+    interval.second=i_value;
+    break;
+  case INTERVAL_DAY_MICROSECOND:
+  case INTERVAL_HOUR_MICROSECOND:
+  case INTERVAL_MINUTE_MICROSECOND:
+  case INTERVAL_SECOND_MICROSECOND:
+  case INTERVAL_MICROSECOND:
+    interval.second_part=i_value;
+    break;
+  }
+  tmp= *start;
+  if (!(ret= date_add_interval(&tmp, i_type, interval)))
+    *next= tmp;
+
+  return ret;
+}
+
+
+/*
+ Computes next execution time. 
+ 
+ SYNOPSIS
+   event_timed::compute_next_execution_time()
+ 
+ REMARKS:
+   The time is set in execute_at, if no more executions the latter is set to
+   0000-00-00.
 */
 
 bool
@@ -605,14 +742,13 @@ event_timed::compute_next_execution_time()
       execute_at= time_now;
     else
     {
-      my_time_t last, ll_ends;
-
-      // There was previous execution     
-      last= sec_since_epoch_TIME(&last_executed) + expression;
-      ll_ends= sec_since_epoch_TIME(&ends);
-      //now convert back to TIME
-      //ToDo Andrey: maybe check for error here?
-      if (ll_ends < last)
+      TIME next_exec;
+      
+      if (get_next_time(&next_exec, &last_executed, expression, interval))
+        goto err;
+      
+      // There was previous execution
+      if (my_time_compare(&ends, &next_exec) == -1)
       {
         // Next execution after ends. No more executions
         set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
@@ -620,7 +756,7 @@ event_timed::compute_next_execution_time()
           dropped= true;
       }
       else
-        my_tz_UTC->gmt_sec_to_TIME(&execute_at, last);
+        execute_at= next_exec;
     }
     goto ret;
   }
@@ -628,14 +764,14 @@ event_timed::compute_next_execution_time()
   {
     // both starts and m_ends are not set, se we schedule for the next
     // based on last_executed
-    if (!last_executed.year)
+    if (last_executed.year)
+    {
+      if (get_next_time(&execute_at, &last_executed, expression, interval))
+        goto err;
+    }
+    else
        //last_executed not set. Schedule the event for now
       execute_at= time_now;
-    else
-      //ToDo Andrey: maybe check for error here?
-      my_tz_UTC->gmt_sec_to_TIME(&execute_at, 
-                   sec_since_epoch_TIME(&last_executed) + expression);
-    goto ret;
   }
   else
   {
@@ -648,17 +784,13 @@ event_timed::compute_next_execution_time()
         Hence schedule for starts + m_expression in case last_executed
         is not set, otherwise to last_executed + m_expression
       */
-      my_time_t last;
-
-      //convert either last_executed or starts to seconds
       if (last_executed.year)
-        last= sec_since_epoch_TIME(&last_executed) + expression;
+      {
+        if (get_next_time(&execute_at, &last_executed, expression, interval))
+          goto err;
+      }
       else
-        last= sec_since_epoch_TIME(&starts);
-
-      //now convert back to TIME
-      //ToDo Andrey: maybe check for error here?
-      my_tz_UTC->gmt_sec_to_TIME(&execute_at, last);
+        execute_at= starts;
     }
     else
     {
@@ -668,25 +800,24 @@ event_timed::compute_next_execution_time()
         Hence check for m_last_execute and increment with m_expression.
         If last_executed is not set then schedule for now
       */
-      my_time_t last, ll_ends;
 
       if (!last_executed.year)
         execute_at= time_now;
       else
       {
-        last= sec_since_epoch_TIME(&last_executed);
-        ll_ends= sec_since_epoch_TIME(&ends);
-        last+= expression;
-        //now convert back to TIME
-        //ToDo Andrey: maybe check for error here?
-        if (ll_ends < last)
+        TIME next_exec;
+
+        if (get_next_time(&next_exec, &last_executed, expression, interval))
+          goto err;
+
+        if (my_time_compare(&ends, &next_exec) == -1)
         {
           set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
           if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
             dropped= true;
         }
         else
-          my_tz_UTC->gmt_sec_to_TIME(&execute_at, last);
+          execute_at= next_exec;
       }
     }
     goto ret;
@@ -694,17 +825,18 @@ event_timed::compute_next_execution_time()
 ret:
 
   DBUG_RETURN(false);
+err:
+  DBUG_RETURN(true);
 }
 
 
 void
-event_timed::mark_last_executed()
+event_timed::mark_last_executed(THD *thd)
 {
   TIME time_now;
-  my_time_t now;
 
-  time((time_t *)&now);
-  my_tz_UTC->gmt_sec_to_TIME(&time_now, now);
+  thd->end_time();
+  my_tz_UTC->gmt_sec_to_TIME(&time_now, (my_time_t) thd->query_start());
 
   last_executed= time_now; // was execute_at
 #ifdef ANDREY_0
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 3560a74ddb22491a17d91d30f1b3ae57c987ee77..60bb72b699b7d2ccedd3b2dc894849f2f41b0c41 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1135,7 +1135,7 @@ longlong Item_func_time_to_sec::val_int()
   To make code easy, allow interval objects without separators.
 */
 
-static bool get_interval_value(Item *args,interval_type int_type,
+bool get_interval_value(Item *args,interval_type int_type,
 			       String *str_value, INTERVAL *interval)
 {
   ulonglong array[5];
@@ -1994,110 +1994,15 @@ bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date)
   long period,sign;
   INTERVAL interval;
 
-  ltime->neg= 0;
   if (args[0]->get_date(ltime, TIME_NO_ZERO_DATE) ||
       get_interval_value(args[1],int_type,&value,&interval))
     goto null_date;
-  sign= (interval.neg ? -1 : 1);
+
   if (date_sub_interval)
-    sign = -sign;
+    interval.neg = !interval.neg;
 
-  null_value=0;
-  switch (int_type) {
-  case INTERVAL_SECOND:
-  case INTERVAL_SECOND_MICROSECOND:
-  case INTERVAL_MICROSECOND:
-  case INTERVAL_MINUTE:
-  case INTERVAL_HOUR:
-  case INTERVAL_MINUTE_MICROSECOND:
-  case INTERVAL_MINUTE_SECOND:
-  case INTERVAL_HOUR_MICROSECOND:
-  case INTERVAL_HOUR_SECOND:
-  case INTERVAL_HOUR_MINUTE:
-  case INTERVAL_DAY_MICROSECOND:
-  case INTERVAL_DAY_SECOND:
-  case INTERVAL_DAY_MINUTE:
-  case INTERVAL_DAY_HOUR:
-  {
-    longlong sec, days, daynr, microseconds, extra_sec;
-    ltime->time_type= MYSQL_TIMESTAMP_DATETIME; // Return full date
-    microseconds= ltime->second_part + sign*interval.second_part;
-    extra_sec= microseconds/1000000L;
-    microseconds= microseconds%1000000L;
-
-    sec=((ltime->day-1)*3600*24L+ltime->hour*3600+ltime->minute*60+
-	 ltime->second +
-	 sign* (longlong) (interval.day*3600*24L +
-                           interval.hour*LL(3600)+interval.minute*LL(60)+
-                           interval.second))+ extra_sec;
-    if (microseconds < 0)
-    {
-      microseconds+= LL(1000000);
-      sec--;
-    }
-    days= sec/(3600*LL(24));
-    sec-= days*3600*LL(24);
-    if (sec < 0)
-    {
-      days--;
-      sec+= 3600*LL(24);
-    }
-    ltime->second_part= (uint) microseconds;
-    ltime->second= (uint) (sec % 60);
-    ltime->minute= (uint) (sec/60 % 60);
-    ltime->hour=   (uint) (sec/3600);
-    daynr= calc_daynr(ltime->year,ltime->month,1) + days;
-    /* Day number from year 0 to 9999-12-31 */
-    if ((ulonglong) daynr >= MAX_DAY_NUMBER)
-      goto invalid_date;
-    get_date_from_daynr((long) daynr, &ltime->year, &ltime->month,
-                        &ltime->day);
-    break;
-  }
-  case INTERVAL_DAY:
-  case INTERVAL_WEEK:
-    period= (calc_daynr(ltime->year,ltime->month,ltime->day) +
-             sign * (long) interval.day);
-    /* Daynumber from year 0 to 9999-12-31 */
-    if ((ulong) period >= MAX_DAY_NUMBER)
-      goto invalid_date;
-    get_date_from_daynr((long) period,&ltime->year,&ltime->month,&ltime->day);
-    break;
-  case INTERVAL_YEAR:
-    ltime->year+= sign * (long) interval.year;
-    if ((ulong) ltime->year >= 10000L)
-      goto invalid_date;
-    if (ltime->month == 2 && ltime->day == 29 &&
-	calc_days_in_year(ltime->year) != 366)
-      ltime->day=28;				// Was leap-year
-    break;
-  case INTERVAL_YEAR_MONTH:
-  case INTERVAL_QUARTER:
-  case INTERVAL_MONTH:
-    period= (ltime->year*12 + sign * (long) interval.year*12 +
-	     ltime->month-1 + sign * (long) interval.month);
-    if ((ulong) period >= 120000L)
-      goto invalid_date;
-    ltime->year= (uint) (period / 12);
-    ltime->month= (uint) (period % 12L)+1;
-    /* Adjust day if the new month doesn't have enough days */
-    if (ltime->day > days_in_month[ltime->month-1])
-    {
-      ltime->day = days_in_month[ltime->month-1];
-      if (ltime->month == 2 && calc_days_in_year(ltime->year) == 366)
-	ltime->day++;				// Leap-year
-    }
-    break;
-  default:
-    goto null_date;
-  }
-  return 0;					// Ok
+  return (null_value= date_add_interval(ltime, int_type, interval));
 
-invalid_date:
-  push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                      ER_DATETIME_FUNCTION_OVERFLOW,
-                      ER(ER_DATETIME_FUNCTION_OVERFLOW),
-                      "datetime");
  null_date:
   return (null_value=1);
 }
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 9a2cb7a4c9e2ab54b699c5c478f88e333e30545e..fd2f3945fca65c63772f9061967d4a6cebed06ce 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -26,6 +26,9 @@ enum date_time_format_types
   TIME_ONLY= 0, TIME_MICROSECOND, DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND
 };
 
+bool get_interval_value(Item *args,interval_type int_type,
+			       String *str_value, INTERVAL *interval);
+
 class Item_func_period_add :public Item_int_func
 {
 public:
@@ -626,20 +629,6 @@ class Item_func_sec_to_time :public Item_str_func
   }
 };
 
-/*
-  The following must be sorted so that simple intervals comes first.
-  (get_interval_value() depends on this)
-*/
-
-enum interval_type
-{
-  INTERVAL_YEAR, INTERVAL_QUARTER, INTERVAL_MONTH, INTERVAL_DAY, INTERVAL_HOUR,
-  INTERVAL_MINUTE, INTERVAL_WEEK, INTERVAL_SECOND, INTERVAL_MICROSECOND ,
-  INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE,
-  INTERVAL_DAY_SECOND, INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND,
-  INTERVAL_MINUTE_SECOND, INTERVAL_DAY_MICROSECOND, INTERVAL_HOUR_MICROSECOND,
-  INTERVAL_MINUTE_MICROSECOND, INTERVAL_SECOND_MICROSECOND
-};
 
 class Item_date_add_interval :public Item_date_func
 {
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index b3bc49b31d1a1ccf093e280613558c6d64edf1cc..d98a3ebde99a89dc225d5c49d706b0f24b8f3407 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -1452,6 +1452,9 @@ void calc_time_from_sec(TIME *to, long seconds, long microseconds);
 void make_truncated_value_warning(THD *thd, const char *str_val,
 				  uint str_length, timestamp_type time_type,
                                   const char *field_name);
+
+bool date_add_interval(TIME *ltime, interval_type int_type, INTERVAL interval);
+
 extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type,
 					       const char *format_str,
 					       uint format_length);
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 63fd9db4744d5360c01a137755c51c8aba58e87c..1a574e92b24c6331e1ebe1881c09f35d10ca234a 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5757,8 +5757,8 @@ ER_EVENT_CANT_ALTER
         eng "Failed to alter event '%-.64s'"
 ER_EVENT_DROP_FAILED
         eng "Failed to drop %s"
-ER_EVENT_INTERVAL_NOT_POSITIVE
-        eng "INTERVAL must be positive"
+ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG
+        eng "INTERVAL is either not positive or too big"
 ER_EVENT_ENDS_BEFORE_STARTS
         eng "ENDS must be after STARTS"
 ER_EVENT_EXEC_TIME_IN_THE_PAST
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index a3734a48c5c163b5521bb7ba9bd88b3bef41f187..fb78e47a10d6211a1b0d270de3156c4f533bef9a 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1417,7 +1417,7 @@ ev_schedule_time: EVERY_SYM expr interval
                 YYABORT;
                 break;
               case EVEX_BAD_PARAMS:
-                my_error(ER_EVENT_INTERVAL_NOT_POSITIVE, MYF(0));
+                my_error(ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG, MYF(0));
                 YYABORT;
                 break;
               }
diff --git a/sql/time.cc b/sql/time.cc
index 480cafaab345dee7da9cbb856b08ea4ba65dd41b..efe1cbf1c09c0db605c418ae073cd4696fdc43be 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -724,5 +724,113 @@ void make_truncated_value_warning(THD *thd, const char *str_val,
                ER_TRUNCATED_WRONG_VALUE, warn_buff);
 }
 
+#define MAX_DAY_NUMBER 3652424L
+
+bool date_add_interval(TIME *ltime, interval_type int_type, INTERVAL interval)
+{
+  long period, sign;
+
+  ltime->neg= 0;
+
+  sign= (interval.neg ? -1 : 1);
+
+  switch (int_type) {
+  case INTERVAL_SECOND:
+  case INTERVAL_SECOND_MICROSECOND:
+  case INTERVAL_MICROSECOND:
+  case INTERVAL_MINUTE:
+  case INTERVAL_HOUR:
+  case INTERVAL_MINUTE_MICROSECOND:
+  case INTERVAL_MINUTE_SECOND:
+  case INTERVAL_HOUR_MICROSECOND:
+  case INTERVAL_HOUR_SECOND:
+  case INTERVAL_HOUR_MINUTE:
+  case INTERVAL_DAY_MICROSECOND:
+  case INTERVAL_DAY_SECOND:
+  case INTERVAL_DAY_MINUTE:
+  case INTERVAL_DAY_HOUR:
+  {
+    longlong sec, days, daynr, microseconds, extra_sec;
+    ltime->time_type= MYSQL_TIMESTAMP_DATETIME; // Return full date
+    microseconds= ltime->second_part + sign*interval.second_part;
+    extra_sec= microseconds/1000000L;
+    microseconds= microseconds%1000000L;
+
+    sec=((ltime->day-1)*3600*24L+ltime->hour*3600+ltime->minute*60+
+	 ltime->second +
+	 sign* (longlong) (interval.day*3600*24L +
+                           interval.hour*LL(3600)+interval.minute*LL(60)+
+                           interval.second))+ extra_sec;
+    if (microseconds < 0)
+    {
+      microseconds+= LL(1000000);
+      sec--;
+    }
+    days= sec/(3600*LL(24));
+    sec-= days*3600*LL(24);
+    if (sec < 0)
+    {
+      days--;
+      sec+= 3600*LL(24);
+    }
+    ltime->second_part= (uint) microseconds;
+    ltime->second= (uint) (sec % 60);
+    ltime->minute= (uint) (sec/60 % 60);
+    ltime->hour=   (uint) (sec/3600);
+    daynr= calc_daynr(ltime->year,ltime->month,1) + days;
+    /* Day number from year 0 to 9999-12-31 */
+    if ((ulonglong) daynr >= MAX_DAY_NUMBER)
+      goto invalid_date;
+    get_date_from_daynr((long) daynr, &ltime->year, &ltime->month,
+                        &ltime->day);
+    break;
+  }
+  case INTERVAL_DAY:
+  case INTERVAL_WEEK:
+    period= (calc_daynr(ltime->year,ltime->month,ltime->day) +
+             sign * (long) interval.day);
+    /* Daynumber from year 0 to 9999-12-31 */
+    if ((ulong) period >= MAX_DAY_NUMBER)
+      goto invalid_date;
+    get_date_from_daynr((long) period,&ltime->year,&ltime->month,&ltime->day);
+    break;
+  case INTERVAL_YEAR:
+    ltime->year+= sign * (long) interval.year;
+    if ((ulong) ltime->year >= 10000L)
+      goto invalid_date;
+    if (ltime->month == 2 && ltime->day == 29 &&
+	calc_days_in_year(ltime->year) != 366)
+      ltime->day=28;				// Was leap-year
+    break;
+  case INTERVAL_YEAR_MONTH:
+  case INTERVAL_QUARTER:
+  case INTERVAL_MONTH:
+    period= (ltime->year*12 + sign * (long) interval.year*12 +
+	     ltime->month-1 + sign * (long) interval.month);
+    if ((ulong) period >= 120000L)
+      goto invalid_date;
+    ltime->year= (uint) (period / 12);
+    ltime->month= (uint) (period % 12L)+1;
+    /* Adjust day if the new month doesn't have enough days */
+    if (ltime->day > days_in_month[ltime->month-1])
+    {
+      ltime->day = days_in_month[ltime->month-1];
+      if (ltime->month == 2 && calc_days_in_year(ltime->year) == 366)
+	ltime->day++;				// Leap-year
+    }
+    break;
+  default:
+    return 1;
+  }
+  return 0;					// Ok
+
+invalid_date:
+  push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                      ER_DATETIME_FUNCTION_OVERFLOW,
+                      ER(ER_DATETIME_FUNCTION_OVERFLOW),
+                      "datetime");
+  return 1;
+}
+
 
 #endif