List:Commits« Previous MessageNext Message »
From:ahristov Date:January 18 2006 7:41pm
Subject:bk commit into 5.1 tree (andrey:1.2054) BUG#16432
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of andrey. When andrey does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.2054 06/01/18 20:41:22 andrey@lmy004. +12 -0
  - fix bug #16435 (Weekly events execute every second) (WL#1034 Internal CRON)
  Before the interval expression was considered to be in seconds, now it is
  just a number and the type of interval is considered.
  
  - this changeset introduces also fix for bug#16432 (Events: error re interval
    misrepresents the facts)
    the code of event_timed::set_interval() was refactored anyway so it is meaningful to
    fix the bug in the same changeset.

  sql/time.cc
    1.59 06/01/18 20:41:06 andrey@lmy004. +108 -0
    extract the core of Item_date_add_interval::get_date()
    to a function per Serg's request. The code can be reused
    to add und substract interval from a date.

  sql/sql_yacc.yy
    1.436 06/01/18 20:41:05 andrey@lmy004. +1 -1
    - change error message to be appropriate as fix for bug#16432
      (Events: error re interval misrepresents the facts)

  sql/share/errmsg.txt
    1.71 06/01/18 20:41:04 andrey@lmy004. +2 -2
    - change error message to be appropriate as fix for bug#16432
      (Events: error re interval misrepresents the facts)

  sql/mysql_priv.h
    1.366 06/01/18 20:41:04 andrey@lmy004. +3 -0
    export the new function date_add_interval() added to time.cc

  sql/item_timefunc.h
    1.66 06/01/18 20:41:04 andrey@lmy004. +3 -14
    - export get_interval_value() so it can be reused in event_timed.cc in
      function static get_next_time()
    - move enum interval_type to include/my_time.h so it can be used by functions
      in the whole server

  sql/item_timefunc.cc
    1.103 06/01/18 20:41:04 andrey@lmy004. +4 -99
    - export get_interval_date()
    - refactor Item_date_add_interval::get_date() and extract the core
      to date_add_interval() in time.cc so it can be reused by the
      scheduler code in event_timed.cc

  sql/event_timed.cc
    1.18 06/01/18 20:41:03 andrey@lmy004. +174 -42
    - more docs
    - add static get_next_time() which sums a TIME with an interval
    - fix bug #16435 (Weekly events execute every second)
    Before the interval expression was considered to be in seconds, now it is
    just a number and the type of interval is considered.
    - fix for bug#16432 (Events: error re interval misrepresents the facts)
      (return an error if a value is too big or is negative - errmsg changed)

  sql/event_priv.h
    1.14 06/01/18 20:41:03 andrey@lmy004. +1 -0
    - define the maximal possible value for interval_value

  sql/event_executor.cc
    1.19 06/01/18 20:41:03 andrey@lmy004. +19 -4
    - pass thd to event_timed::compute_next_execution_time()
    - a bit more DBUG info in the server log
    - handle error returned by event_timed::compute_next_execution_time()

  sql/event.h
    1.13 06/01/18 20:41:03 andrey@lmy004. +2 -2
    pass thd to mark_last_executed() to be able to call thd->end_time()

  sql/event.cc
    1.21 06/01/18 20:41:03 andrey@lmy004. +15 -4
    - don't use second_part
    - fix small problem with create event xyz, when xyz exists -> make it error
      instead of warning if create_if_not is false.

  include/my_time.h
    1.12 06/01/18 20:41:03 andrey@lmy004. +15 -0
    - move enum interval_type to include/my_time.h so it can be used by functions
      in the whole server

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	andrey
# Host:	lmy004.
# Root:	/work/mysql-5.1-tt-copy-works

--- 1.102/sql/item_timefunc.cc	2005-12-22 10:28:50 +01:00
+++ 1.103/sql/item_timefunc.cc	2006-01-18 20:41:04 +01:00
@@ -1135,7 +1135,7 @@
   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 @@
   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);
 }

--- 1.65/sql/item_timefunc.h	2005-12-22 10:28:50 +01:00
+++ 1.66/sql/item_timefunc.h	2006-01-18 20:41:04 +01:00
@@ -26,6 +26,9 @@
   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 @@
   }
 };
 
-/*
-  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
 {

--- 1.365/sql/mysql_priv.h	2006-01-11 09:26:01 +01:00
+++ 1.366/sql/mysql_priv.h	2006-01-18 20:41:04 +01:00
@@ -1452,6 +1452,9 @@
 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);

--- 1.435/sql/sql_yacc.yy	2006-01-11 12:49:43 +01:00
+++ 1.436/sql/sql_yacc.yy	2006-01-18 20:41:05 +01:00
@@ -1417,7 +1417,7 @@
                 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;
               }

--- 1.58/sql/time.cc	2005-12-02 12:01:38 +01:00
+++ 1.59/sql/time.cc	2006-01-18 20:41:06 +01:00
@@ -724,5 +724,113 @@
                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

--- 1.20/sql/event.cc	2006-01-11 12:49:43 +01:00
+++ 1.21/sql/event.cc	2006-01-18 20:41:03 +01:00
@@ -88,8 +88,14 @@
 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 @@
   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"));

--- 1.12/sql/event.h	2006-01-12 19:51:02 +01:00
+++ 1.13/sql/event.h	2006-01-18 20:41:03 +01:00
@@ -143,12 +143,12 @@
 
   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);

--- 1.18/sql/event_executor.cc	2006-01-12 16:51:18 +01:00
+++ 1.19/sql/event_executor.cc	2006-01-18 20:41:03 +01:00
@@ -334,9 +334,19 @@
     {
       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 @@
     }
     
     // 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."));
 

--- 1.13/sql/event_priv.h	2005-12-28 17:28:41 +01:00
+++ 1.14/sql/event_priv.h	2006-01-18 20:41:03 +01:00
@@ -46,6 +46,7 @@
 
 #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);

--- 1.17/sql/event_timed.cc	2006-01-12 16:51:19 +01:00
+++ 1.18/sql/event_timed.cc	2006-01-18 20:41:03 +01:00
@@ -191,16 +191,78 @@
 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 @@
  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 @@
 
 
 /*
-  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 @@
       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 @@
           dropped= true;
       }
       else
-        my_tz_UTC->gmt_sec_to_TIME(&execute_at, last);
+        execute_at= next_exec;
     }
     goto ret;
   }
@@ -628,14 +764,14 @@
   {
     // 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 @@
         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 @@
         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 @@
 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

--- 1.70/sql/share/errmsg.txt	2006-01-11 12:49:43 +01:00
+++ 1.71/sql/share/errmsg.txt	2006-01-18 20:41:04 +01:00
@@ -5757,8 +5757,8 @@
         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

--- 1.11/include/my_time.h	2005-07-31 11:49:46 +02:00
+++ 1.12/include/my_time.h	2006-01-18 20:41:03 +01:00
@@ -89,6 +89,21 @@
 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_ */
Thread
bk commit into 5.1 tree (andrey:1.2054) BUG#16432ahristov18 Jan