MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:ahristov Date:April 7 2006 7:18am
Subject:bk commit into 5.1 tree (andrey:1.2301)
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.2301 06/04/07 09:18:29 andrey@lmy004. +7 -0
  manual merge

  mysql-test/t/events.test
    1.26 06/04/07 09:18:22 andrey@lmy004. +19 -9
    manual merge

  sql/sql_show.cc
    1.325 06/04/07 09:13:20 andrey@lmy004. +0 -0
    Auto merged

  sql/mysql_priv.h
    1.390 06/04/07 09:13:20 andrey@lmy004. +0 -0
    Auto merged

  sql/item_timefunc.cc
    1.109 06/04/07 09:13:20 andrey@lmy004. +0 -0
    Auto merged

  sql/event_timed.cc
    1.48 06/04/07 09:13:20 andrey@lmy004. +0 -0
    Auto merged

  sql/event.cc
    1.39 06/04/07 09:13:20 andrey@lmy004. +0 -0
    Auto merged

  mysql-test/r/events.result
    1.31 06/04/07 09:13:20 andrey@lmy004. +0 -0
    Auto merged

# 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-bug17494-real/RESYNC

--- 1.108/sql/item_timefunc.cc	2006-03-28 19:34:29 +02:00
+++ 1.109/sql/item_timefunc.cc	2006-04-07 09:13:20 +02:00
@@ -772,81 +772,6 @@ static bool get_interval_info(const char
 }
 
 
-/*
-  Calculate difference between two datetime values as seconds + microseconds.
-
-  SYNOPSIS
-    calc_time_diff()
-      l_time1         - TIME/DATE/DATETIME value
-      l_time2         - TIME/DATE/DATETIME value
-      l_sign          - 1 absolute values are substracted,
-                        -1 absolute values are added.
-      seconds_out     - Out parameter where difference between
-                        l_time1 and l_time2 in seconds is stored.
-      microseconds_out- Out parameter where microsecond part of difference
-                        between l_time1 and l_time2 is stored.
-
-  NOTE
-    This function calculates difference between l_time1 and l_time2 absolute
-    values. So one should set l_sign and correct result if he want to take
-    signs into account (i.e. for TIME values).
-
-  RETURN VALUES
-    Returns sign of difference.
-    1 means negative result
-    0 means positive result
-
-*/
-
-static bool calc_time_diff(TIME *l_time1, TIME *l_time2, int l_sign,
-                           longlong *seconds_out, long *microseconds_out)
-{
-  long days;
-  bool neg;
-  longlong microseconds;
-
-  /*
-    We suppose that if first argument is MYSQL_TIMESTAMP_TIME
-    the second argument should be TIMESTAMP_TIME also.
-    We should check it before calc_time_diff call.
-  */
-  if (l_time1->time_type == MYSQL_TIMESTAMP_TIME)  // Time value
-    days= (long)l_time1->day - l_sign * (long)l_time2->day;
-  else
-  {
-    days= calc_daynr((uint) l_time1->year,
-		     (uint) l_time1->month,
-		     (uint) l_time1->day);
-    if (l_time2->time_type == MYSQL_TIMESTAMP_TIME)
-      days-= l_sign * (long)l_time2->day;
-    else
-      days-= l_sign*calc_daynr((uint) l_time2->year,
-			       (uint) l_time2->month,
-			       (uint) l_time2->day);
-  }
-
-  microseconds= ((longlong)days*LL(86400) +
-                 (longlong)(l_time1->hour*3600L +
-                            l_time1->minute*60L +
-                            l_time1->second) -
-                 l_sign*(longlong)(l_time2->hour*3600L +
-                                   l_time2->minute*60L +
-                                   l_time2->second)) * LL(1000000) +
-                (longlong)l_time1->second_part -
-                l_sign*(longlong)l_time2->second_part;
-
-  neg= 0;
-  if (microseconds < 0)
-  {
-    microseconds= -microseconds;
-    neg= 1;
-  }
-  *seconds_out= microseconds/1000000L;
-  *microseconds_out= (long) (microseconds%1000000L);
-  return neg;
-}
-
-
 longlong Item_func_period_add::val_int()
 {
   DBUG_ASSERT(fixed == 1);
@@ -2031,16 +1956,13 @@ bool Item_date_add_interval::get_date(TI
   INTERVAL interval;
 
   if (args[0]->get_date(ltime, TIME_NO_ZERO_DATE) ||
-      get_interval_value(args[1],int_type,&value,&interval))
-    goto null_date;
+      get_interval_value(args[1], int_type, &value, &interval))
+    return (null_value=1);
 
   if (date_sub_interval)
     interval.neg = !interval.neg;
 
   return (null_value= date_add_interval(ltime, int_type, interval));
-
- null_date:
-  return (null_value=1);
 }
 
 

--- 1.389/sql/mysql_priv.h	2006-04-01 09:38:28 +02:00
+++ 1.390/sql/mysql_priv.h	2006-04-07 09:13:20 +02:00
@@ -1549,6 +1549,8 @@ void make_truncated_value_warning(THD *t
                                   const char *field_name);
 
 bool date_add_interval(TIME *ltime, interval_type int_type, INTERVAL interval);
+bool calc_time_diff(TIME *l_time1, TIME *l_time2, int l_sign,
+                    longlong *seconds_out, long *microseconds_out);
 
 extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type,
 					       const char *format_str,

--- 1.324/sql/sql_show.cc	2006-04-01 06:03:02 +02:00
+++ 1.325/sql/sql_show.cc	2006-04-07 09:13:20 +02:00
@@ -3980,7 +3980,7 @@ fill_events_copy_to_schema_table(THD *th
   if (!(!wild || !wild[0] || !wild_compare(et.name.str, wild, 0)))
     DBUG_RETURN(0);
   
-  //->field[0] is EVENT_CATALOG and is by default NULL
+  /* ->field[0] is EVENT_CATALOG and is by default NULL */
   
   sch_table->field[1]->store(et.dbname.str, et.dbname.length, scs);
   sch_table->field[2]->store(et.name.str, et.name.length, scs);
@@ -4000,12 +4000,9 @@ fill_events_copy_to_schema_table(THD *th
   if (et.expression)
   {
     String show_str;
-    //type
+    /* type */
     sch_table->field[5]->store(STRING_WITH_LEN("RECURRING"), scs);
-    /* execute_at */
-    sch_table->field[6]->set_null();
-    /* interval_value */
-    //interval_type
+
     if (event_reconstruct_interval_expression(&show_str, et.interval,
                                               et.expression))
       DBUG_RETURN(1);
@@ -4058,9 +4055,10 @@ fill_events_copy_to_schema_table(THD *th
   sch_table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
 
   if (et.last_executed.year)
+  {
+    sch_table->field[16]->set_notnull();
     sch_table->field[16]->store_time(&et.last_executed,MYSQL_TIMESTAMP_DATETIME);
-  else
-    sch_table->field[16]->set_null();
+  }
 
   sch_table->field[17]->store(et.comment.str, et.comment.length, scs);
 

--- 1.30/mysql-test/r/events.result	2006-03-28 12:23:20 +02:00
+++ 1.31/mysql-test/r/events.result	2006-04-07 09:13:20 +02:00
@@ -106,7 +106,6 @@ drop event if exists event3;
 Warnings:
 Note	1305	Event event3 does not exist
 create event event3 on schedule every 50 + 10 minute starts date_add("20100101", interval 5 minute) ends date_add("20151010", interval 5 day) comment "portokala_comment" DO insert into t_event3 values (unix_timestamp(), rand());
-set max_allowed_packet=128000000;
 select count(*) from t_event3;
 count(*)
 0
@@ -232,6 +231,9 @@ Db	Name	Definer	Type	Execute at	Interval
 events_test	intact_check	root@localhost	RECURRING	NULL	10	HOUR	#	#	ENABLED
 CREATE TABLE event_like LIKE mysql.event;
 INSERT INTO event_like SELECT * FROM mysql.event;
+ALTER TABLE mysql.event MODIFY db char(64) character set cp1251 default '';
+SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
+ERROR HY000: Cannot load from mysql.event. Table probably corrupted. See error log.
 ALTER TABLE mysql.event MODIFY db char(20) character set utf8 collate utf8_bin default '';
 SHOW CREATE TABLE mysql.event;
 Table	Create Table
@@ -260,11 +262,10 @@ ALTER TABLE mysql.event MODIFY db char(6
 "This should work"
 SHOW EVENTS;
 Db	Name	Definer	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
-events_test	intact_check	root@localhost	RECURRING	NULL	10	HOUR	#	#	ENABLED
-ALTER TABLE mysql.event MODIFY db char(64) character set cp1251 default '';
-SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
-ERROR HY000: Cannot load from mysql.event. Table probably corrupted. See error log.
+events_test                                                 	intact_check	root@localhost	RECURRING	NULL	10	HOUR	#	#	ENABLED
 ALTER TABLE mysql.event MODIFY db varchar(64) character set utf8 collate utf8_bin default '';
+Warnings:
+Warning	1265	Data truncated for column 'db' at row 1
 SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
 ERROR HY000: Cannot load from mysql.event. Table probably corrupted. See error log.
 ALTER TABLE mysql.event DROP comment, DROP starts;

--- 1.25/mysql-test/t/events.test	2006-03-28 10:42:40 +02:00
+++ 1.26/mysql-test/t/events.test	2006-04-07 09:18:22 +02:00
@@ -101,7 +101,6 @@ set global event_scheduler = 0;
 create table t_event3 (a int, b float);
 drop event if exists event3;
 create event event3 on schedule every 50 + 10 minute starts date_add("20100101", interval 5 minute) ends date_add("20151010", interval 5 day) comment "portokala_comment" DO insert into t_event3 values (unix_timestamp(), rand());
-set max_allowed_packet=128000000;
 select count(*) from t_event3;
 drop event event3;
 drop table t_event3;
@@ -148,8 +147,8 @@ SHOW CREATE EVENT root19;
 create event root20 on schedule every '50:20:12:45' day_second do select 1;
 SHOW CREATE EVENT root20;
 set names cp1251;
+create event ðóóò21 on schedule every '50:23:59:95' day_second COMMENT 'òîâà å 1251 êîìåíòàð' do select 1;
+SHOW CREATE EVENT ðóóò21;
 insert into mysql.event (db, name, body, definer, interval_value, interval_field) values (database(), "root22", "select 1", user(), 100, "SECOND_MICROSECOND");
 --error 1235
 show create event root22;
@@ -174,7 +173,7 @@ drop event root17_1;
 drop event root18;
 drop event root19;
 drop event root20;
+drop event ðóóò21;
 
 set names latin1;
 #
@@ -202,6 +201,9 @@ CREATE TABLE event_like LIKE mysql.event
 INSERT INTO event_like SELECT * FROM mysql.event;
 #sleep a bit or we won't catch the change of time
 --sleep 1
+ALTER TABLE mysql.event MODIFY db char(64) character set cp1251 default '';
+--error 1526
+SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
 ALTER TABLE mysql.event MODIFY db char(20) character set utf8 collate utf8_bin default '';
 #wait a bit or we won't see the difference because of seconds resolution
 --sleep 1
@@ -220,6 +222,7 @@ ALTER TABLE mysql.event MODIFY db char(6
 SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
 --sleep 1
 ALTER TABLE mysql.event MODIFY db varchar(64) character set utf8 collate utf8_bin default '';
+--sleep 1
 --error ER_CANNOT_LOAD_FROM_TABLE
 SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
 --sleep 1
@@ -412,7 +415,8 @@ select 1;
 select event_schema, event_name, definer, event_body from information_schema.events where event_name='white_space';
 drop event white_space;
 create event white_space on schedule every 10 hour disable do
-
select 2;
+
+select 2;
 select event_schema, event_name, definer, event_body from information_schema.events where event_name='white_space';
 drop event white_space;
 create event white_space on schedule every 10 hour disable do	select 3;
@@ -422,7 +426,7 @@ drop event white_space;
 # END:  BUG #17453: Creating Event crash the server
 #
 
-#
+##set global event_scheduler=1;
 # Bug#17403 "Events: packets out of order with show create event"
 #
 create event e1 on schedule every 1 year do set @a = 5;
@@ -436,7 +440,7 @@ drop event e1;
 ##select get_lock("test_lock3", 20);
 ##create event закачка on schedule every 10 hour do select get_lock("test_lock3", 20);
 ##select sleep(2);
-##select /*7*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
+##show processlist;
 ##drop event закачка;
 ##select release_lock("test_lock3");
 
@@ -446,13 +450,14 @@ drop event e1;
 ##select get_lock("test_lock4", 20);
 ##create event закачка4 on schedule every 1 second do select get_lock("test_lock4", 20);
 ##select sleep(3);
-##select /*8*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
+##--replace_column 1 # 6 #
 ##drop event закачка4;
 ##select release_lock("test_lock4");
 
 ##set global event_scheduler=0;
 ##select sleep(2);
-##select /*9*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
+##--replace_column 1 # 6 #
 ##select count(*) from mysql.event;
 
 drop database events_test;
+

--- 1.38/sql/event.cc	2006-03-29 13:27:30 +02:00
+++ 1.39/sql/event.cc	2006-04-07 09:13:20 +02:00
@@ -1051,13 +1051,6 @@ evex_load_and_compile_event(THD * thd, s
   thd->restore_backup_open_tables_state(&backup);
   if (ret)
     goto done;
-
-  /*
-    allocate on evex_mem_root. if you call without evex_mem_root
-    then sphead will not be cleared!
-  */
-  if ((ret= ett->compile(thd, &evex_mem_root)))
-    goto done;
   
   ett->compute_next_execution_time();
   if (use_lock)

--- 1.47/sql/event_timed.cc	2006-03-17 09:36:32 +01:00
+++ 1.48/sql/event_timed.cc	2006-04-07 09:13:20 +02:00
@@ -593,28 +593,9 @@ Event_timed::load_from_row(MEM_ROOT *mem
   et->created= table->field[EVEX_FIELD_CREATED]->val_int();
   et->modified= table->field[EVEX_FIELD_MODIFIED]->val_int();
 
-  /*
-    ToDo Andrey : Ask PeterG & Serg what to do in this case.
-                  Whether on load last_executed_at should be loaded
-                  or it must be 0ed. If last_executed_at is loaded
-                  then an event can be scheduled for execution
-                  instantly. Let's say an event has to be executed
-                  every 15 mins. The server has been stopped for
-                  more than this time and then started. If L_E_AT
-                  is loaded from DB, execution at L_E_AT+15min
-                  will be scheduled. However this time is in the past.
-                  Hence immediate execution. Due to patch of
-                  ::mark_last_executed() last_executed gets time_now
-                  and not execute_at. If not like this a big
-                  queue can be scheduled for times which are still in
-                  the past (2, 3 and more executions which will be
-                  consequent).
-  */
-  set_zero_time(&last_executed, MYSQL_TIMESTAMP_DATETIME);
-#ifdef ANDREY_0
   table->field[EVEX_FIELD_LAST_EXECUTED]->
                      get_date(&et->last_executed, TIME_NO_ZERO_DATE);
-#endif
+
   last_executed_changed= false;
 
   /* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
@@ -648,70 +629,164 @@ error:
 
 
 /*
-  Computes the sum of a timestamp plus interval
+  Computes the sum of a timestamp plus interval. Presumed is that at least one
+  previous execution has occured.
 
   SYNOPSIS
     get_next_time(TIME *start, int interval_value, interval_type interval)
       next          the sum
       start         add interval_value to this time
+      time_now      current time
       i_value       quantity of time type interval to add
       i_type        type of interval to add (SECOND, MINUTE, HOUR, WEEK ...)
+  
+  RETURNS
+    0  OK
+    1  Error
+
+  NOTES
+    1) If the interval is conversible to SECOND, like MINUTE, HOUR, DAY, WEEK.
+       Then we use TIMEDIFF()'s implementation as underlying and number of
+       seconds as resolution for computation.
+    2) In all other cases - MONTH, QUARTER, YEAR we use MONTH as resolution
+       and PERIOD_DIFF()'s implementation
+    3) We get the difference between time_now and `start`, then divide it
+       by the months, respectively seconds and round up. Then we multiply
+       monts/seconds by the rounded value and add it to `start` -> we get
+       the next execution time.
 */
 
 static
-bool get_next_time(TIME *next, TIME *start, int i_value, interval_type i_type)
+bool get_next_time(TIME *next, TIME *start, TIME *time_now, TIME *last_exec,
+                   int i_value, interval_type i_type)
 {
   bool ret;
   INTERVAL interval;
   TIME tmp;
+  longlong months=0, seconds=0;
+  DBUG_ENTER("get_next_time");
+  DBUG_PRINT("enter", ("start=%llu now=%llu", TIME_to_ulonglong_datetime(start),
+                      TIME_to_ulonglong_datetime(time_now)));
 
   bzero(&interval, sizeof(interval));
 
   switch (i_type) {
   case INTERVAL_YEAR:
-    interval.year= (ulong) i_value;
+    months= i_value*12;
     break;
   case INTERVAL_QUARTER:
-    interval.month= (ulong)(i_value*3);
-    break;
+    /* Has already been converted to months */
   case INTERVAL_YEAR_MONTH:
   case INTERVAL_MONTH:
-    interval.month= (ulong) i_value;
+    months= i_value;
     break;
   case INTERVAL_WEEK:
-    interval.day= (ulong)(i_value*7);
-    break;
+    /* WEEK has already been converted to days */
   case INTERVAL_DAY:
-    interval.day= (ulong) i_value;
+    seconds= i_value*24*3600;
     break;
   case INTERVAL_DAY_HOUR:
   case INTERVAL_HOUR:
-    interval.hour= (ulong) i_value;
+    seconds= i_value*3600;
     break;
   case INTERVAL_DAY_MINUTE:
   case INTERVAL_HOUR_MINUTE:
   case INTERVAL_MINUTE:
-    interval.minute=i_value;
+    seconds= i_value*60;
     break;
   case INTERVAL_DAY_SECOND:
   case INTERVAL_HOUR_SECOND:
   case INTERVAL_MINUTE_SECOND:
   case INTERVAL_SECOND:
-    interval.second=i_value;
+    seconds= 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;
+    /*
+     We should return an error here so SHOW EVENTS/ SELECT FROM I_S.EVENTS
+     would give an error then.
+    */
+    DBUG_RETURN(1);
     break;
   }
-  tmp= *start;
-  if (!(ret= date_add_interval(&tmp, i_type, interval)))
+  DBUG_PRINT("info", ("seconds=%ld months=%ld", seconds, months));
+  if (seconds)
+  {
+    longlong seconds_diff;
+    long microsec_diff;
+    
+    if (calc_time_diff(time_now, start, 1, &seconds_diff, &microsec_diff))
+    {
+      DBUG_PRINT("error", ("negative difference"));
+      DBUG_ASSERT(0);
+    }
+    uint multiplier= seconds_diff / seconds;
+    /*
+      Increase the multiplier is the modulus is not zero to make round up.
+      Or if time_now==start then we should not execute the same 
+      event two times for the same time
+      get the next exec if the modulus is not
+    */
+    DBUG_PRINT("info", ("multiplier=%d", multiplier));
+    if (seconds_diff % seconds || (!seconds_diff && last_exec->year))
+      ++multiplier;
+    interval.second= seconds * multiplier;
+    DBUG_PRINT("info", ("multiplier=%u interval.second=%u", multiplier,
+                        interval.second));
+    tmp= *start;
+    if (!(ret= date_add_interval(&tmp, INTERVAL_SECOND, interval)))
+      *next= tmp;
+  }
+  else
+  {
+    /* PRESUMED is that at least one execution took already place */
+    int diff_months= (time_now->year - start->year)*12 +
+                     (time_now->month - start->month);
+    /*
+      Note: If diff_months is 0 that means we are in the same month as the
+      last execution which is also the first execution.
+    */
+    /*
+      First we try with the smaller if not then + 1, because if we try with
+      directly with +1 we will be after the current date but it could be that
+      we will be 1 month ahead, so 2 steps are necessary.
+    */
+    interval.month= (diff_months / months)*months;
+    /*
+      Check if the same month as last_exec (always set - prerequisite)
+      An event happens at most once per month so there is no way to schedule
+      it two times for the current month. This saves us from two calls to
+      date_add_interval() if the event was just executed.  But if the scheduler
+      is started and there was at least 1 scheduled date skipped this one does
+      not help and two calls to date_add_interval() will be done, which is a
+      bit more expensive but compared to the rareness of the case is neglectable.
+    */
+    if (time_now->year==last_exec->year && time_now->month==last_exec->month)
+      interval.month+= months;
+
+    tmp= *start;
+    if ((ret= date_add_interval(&tmp, INTERVAL_MONTH, interval)))
+      goto done;
+    
+    /* If `tmp` is still before time_now just add one more time the interval */
+    if (my_time_compare(&tmp, time_now) == -1)
+    { 
+      interval.month+= months;
+      tmp= *start;
+      if ((ret= date_add_interval(&tmp, INTERVAL_MONTH, interval)))
+        goto done;
+    }
     *next= tmp;
+    /* assert on that the next is after now */
+    DBUG_ASSERT(1==my_time_compare(next, time_now));
+  }
 
-  return ret;
+done:
+  DBUG_PRINT("info", ("next=%llu", TIME_to_ulonglong_datetime(next)));
+  DBUG_RETURN(ret);
 }
 
 
@@ -734,6 +809,10 @@ Event_timed::compute_next_execution_time
   int tmp;
 
   DBUG_ENTER("Event_timed::compute_next_execution_time");
+  DBUG_PRINT("enter", ("starts=%llu ends=%llu last_executed=%llu",
+                        TIME_to_ulonglong_datetime(&starts),
+                        TIME_to_ulonglong_datetime(&ends),
+                        TIME_to_ulonglong_datetime(&last_executed)));
 
   if (status == MYSQL_EVENT_DISABLED)
   {
@@ -757,29 +836,14 @@ Event_timed::compute_next_execution_time
     }
     goto ret;
   }
-  time((time_t *)&now);
-  my_tz_UTC->gmt_sec_to_TIME(&time_now, now);
+  my_tz_UTC->gmt_sec_to_TIME(&time_now, current_thd->query_start());
 
-#ifdef ANDREY_0
-  sql_print_information("[%s.%s]", dbname.str, name.str);
-  sql_print_information("time_now : [%d-%d-%d %d:%d:%d ]",
-                         time_now.year, time_now.month, time_now.day,
-                         time_now.hour, time_now.minute, time_now.second);
-  sql_print_information("starts : [%d-%d-%d %d:%d:%d ]", starts.year,
-                        starts.month, starts.day, starts.hour,
-                        starts.minute, starts.second);
-  sql_print_information("ends   : [%d-%d-%d %d:%d:%d ]", ends.year,
-                        ends.month, ends.day, ends.hour,
-                        ends.minute, ends.second);
-  sql_print_information("m_last_ex: [%d-%d-%d %d:%d:%d ]", last_executed.year,
-                        last_executed.month, last_executed.day,
-                        last_executed.hour, last_executed.minute,
-                        last_executed.second);
-#endif
+  DBUG_PRINT("info",("NOW=[%llu]", TIME_to_ulonglong_datetime(&time_now)));
 
   /* if time_now is after ends don't execute anymore */
   if (!ends_null && (tmp= my_time_compare(&ends, &time_now)) == -1)
   {
+    DBUG_PRINT("info", ("NOW after ENDS, don't execute anymore"));
     /* time_now is after ends. don't execute anymore */
     set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
     execute_at_null= TRUE;
@@ -807,6 +871,7 @@ Event_timed::compute_next_execution_time
     }
     else
     {
+      DBUG_PRINT("info", ("STARTS is future, NOW <= STARTS,sched for STARTS"));
       /*
         starts is in the future
         time_now before starts. Scheduling for starts
@@ -825,8 +890,10 @@ Event_timed::compute_next_execution_time
       after m_ends set execute_at to 0. And check for on_completion
       If not set then schedule for now.
     */
+    DBUG_PRINT("info", ("Both STARTS & ENDS are set"));
     if (!last_executed.year)
     {
+      DBUG_PRINT("info", ("Not executed so far. Execute NOW."));
       execute_at= time_now;
       execute_at_null= FALSE;
     }
@@ -834,12 +901,15 @@ Event_timed::compute_next_execution_time
     {
       TIME next_exec;
 
-      if (get_next_time(&next_exec, &last_executed, expression, interval))
+      DBUG_PRINT("info", ("Executed at least once"));
+      if (get_next_time(&next_exec, &starts, &time_now, &last_executed,
+                        expression, interval))
         goto err;
 
       /* There was previous execution */
       if (my_time_compare(&ends, &next_exec) == -1)
       {
+        DBUG_PRINT("info", ("Next execution after ENDS. Stop executing."));
         /* Next execution after ends. No more executions */
         set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
         execute_at_null= TRUE;
@@ -848,6 +918,7 @@ Event_timed::compute_next_execution_time
       }
       else
       {
+        DBUG_PRINT("info",("Next[%llu]",TIME_to_ulonglong_datetime(&next_exec)));
         execute_at= next_exec;
         execute_at_null= FALSE;
       }
@@ -856,18 +927,24 @@ Event_timed::compute_next_execution_time
   }
   else if (starts_null && ends_null)
   {
+    DBUG_PRINT("info", ("Neither STARTS nor ENDS are set"));
     /*
       Both starts and m_ends are not set, so we schedule for the next
       based on last_executed.
     */
     if (last_executed.year)
     {
-      if (get_next_time(&execute_at, &last_executed, expression, interval))
+      TIME next_exec;
+      if (get_next_time(&next_exec, &starts, &time_now, &last_executed,
+                        expression, interval))
         goto err;
+      execute_at= next_exec;
+      DBUG_PRINT("info",("Next[%llu]",TIME_to_ulonglong_datetime(&next_exec)));
     }
     else
     {
       /* last_executed not set. Schedule the event for now */
+      DBUG_PRINT("info", ("Execute NOW"));
       execute_at= time_now;
     }
     execute_at_null= FALSE;
@@ -877,6 +954,7 @@ Event_timed::compute_next_execution_time
     /* either starts or m_ends is set */
     if (!starts_null)
     {
+      DBUG_PRINT("info", ("STARTS is set"));
       /*
         - starts is set.
         - starts is not in the future according to check made before
@@ -885,15 +963,24 @@ Event_timed::compute_next_execution_time
       */
       if (last_executed.year)
       {
-        if (get_next_time(&execute_at, &last_executed, expression, interval))
+        TIME next_exec;
+        DBUG_PRINT("info", ("Executed at least once."));
+        if (get_next_time(&next_exec, &starts, &time_now, &last_executed,
+                          expression, interval))
           goto err;
+        execute_at= next_exec;
+        DBUG_PRINT("info",("Next[%llu]",TIME_to_ulonglong_datetime(&next_exec)));
       }
       else
+      {
+        DBUG_PRINT("info", ("Not executed so far. Execute at STARTS"));
         execute_at= starts;
+      }
       execute_at_null= FALSE;
     }
     else
     {
+      DBUG_PRINT("info", ("STARTS is not set. ENDS is set"));
       /*
         - m_ends is set
         - m_ends is after time_now or is equal
@@ -907,11 +994,13 @@ Event_timed::compute_next_execution_time
       {
         TIME next_exec;
 
-        if (get_next_time(&next_exec, &last_executed, expression, interval))
+        if (get_next_time(&next_exec, &starts, &time_now, &last_executed,
+                          expression, interval))
           goto err;
 
         if (my_time_compare(&ends, &next_exec) == -1)
         {
+          DBUG_PRINT("info", ("Next execution after ENDS. Stop executing."));
           set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
           execute_at_null= TRUE;
           if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
@@ -919,6 +1008,8 @@ Event_timed::compute_next_execution_time
         }
         else
         {
+          DBUG_PRINT("info", ("Next[%llu]",
+                              TIME_to_ulonglong_datetime(&next_exec)));
           execute_at= next_exec;
           execute_at_null= FALSE;
         }
@@ -927,9 +1018,10 @@ Event_timed::compute_next_execution_time
     goto ret;
   }
 ret:
-
+  DBUG_PRINT("info", ("ret=0"));
   DBUG_RETURN(false);
 err:
+  DBUG_PRINT("info", ("ret=1"));
   DBUG_RETURN(true);
 }
 
@@ -1462,6 +1554,7 @@ Event_timed::spawn_now(void * (*thread_f
   int ret= EVENT_EXEC_STARTED;
   static uint exec_num= 0;
   DBUG_ENTER("Event_timed::spawn_now");
+  DBUG_PRINT("info", ("this=0x%lx", this));
   DBUG_PRINT("info", ("[%s.%s]", dbname.str, name.str));
 
   VOID(pthread_mutex_lock(&this->LOCK_running));
Thread
bk commit into 5.1 tree (andrey:1.2301)ahristov7 Apr