List:Commits« Previous MessageNext Message »
From:ahristov Date:July 10 2006 11:45am
Subject:bk commit into 5.1 tree (andrey:1.2229)
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.2229 06/07/10 13:44:43 andrey@lmy004. +21 -0
  WL#3337 (Event scheduler new architecture)
  This patch introduces specialized Event data objects
  Event_basic as parent.
  Event_queue_element used for queue storage
  Event_timed used for SHOW EVENTS/ I_S.EVENTS / SHOW CREATE EVENT
  Event_job_data using during execution.
  Methods were moved out of Event_timed to other classes.
  
  This patch also introduces Events::LOCK_event_metadata.
  This patch gives new implementation of Events::dump_internal_status().
  Now both the Event_scheduler and Event_queue return information during
  their ::dump_internal_status().
  
  Shortened a bit the runtime for executing events test cases.

  sql/sql_parse.cc
    1.569 06/07/10 13:44:33 andrey@lmy004. +6 -2
    Events::drop_event() has new signature

  sql/share/errmsg.txt
    1.115 06/07/10 13:44:33 andrey@lmy004. +1 -1
    Fix error message

  sql/events.h
    1.40 06/07/10 13:44:33 andrey@lmy004. +11 -6
    Change the signature of Events::drop_event() not to use sp_name but LEX_STRING

  sql/events.cc
    1.52 06/07/10 13:44:33 andrey@lmy004. +152 -76
    Documentation
    Add LOCK_event_metadata

  sql/event_scheduler_ng.h
    1.3 06/07/10 13:44:33 andrey@lmy004. +10 -4
    Add back Event_scheduler::cond_wait()
    Add back Event_scheduler::dump_internal_status()
    Using Event_job_data for execution.

  sql/event_scheduler_ng.cc
    1.3 06/07/10 13:44:33 andrey@lmy004. +365 -90
    Add back Event_scheduler::cond_wait()
    Add back Event_scheduler::dump_internal_status()
    Using Event_job_data for execution. Make the scheduler thread unkillable (thd->command= COM_DAEMON).
    Add a lot of documentation.

  sql/event_queue.h
    1.5 06/07/10 13:44:33 andrey@lmy004. +18 -31
    Cosmetics.
    Don't use Event_timed for the queue and giving back object for execution.
    Event_queue_element is for the queue, Event_job_data is for execution.
    Add Event_queue::dump_internal_status() for SHOW SCHEDULER STATUS command

  sql/event_queue.cc
    1.5 06/07/10 13:44:33 andrey@lmy004. +365 -288
    Cosmetics.
    Don't use Event_timed for the queue and giving back object for execution.
    Event_queue_element is for the queue, Event_job_data is for execution.
    Add Event_queue::dump_internal_status() for SHOW SCHEDULER STATUS command

  sql/event_db_repository.h
    1.7 06/07/10 13:44:33 andrey@lmy004. +3 -26
    Event_db_repository depends only on Event_basic's interface

  sql/event_db_repository.cc
    1.9 06/07/10 13:44:33 andrey@lmy004. +171 -354
    Cosmetics.
    load_named_event now uses Event_basic, for polymorphism
    find_event uses Event_basic, to be polymorphic.
    use Field **fields= table->field and then index fields[...]
    Add documentation.
    Fix documentation.

  sql/event_data_objects.h
    1.9 06/07/10 13:44:33 andrey@lmy004. +117 -85
    Event_timed is no more used during execution.
    Event_timed is no more used during in the memory queue.
    Event_timed is only used for SHOW CREATE EVENT/ I_S.EVENTS/ SHOW EVENTS
    Event_basic is the parent of almost all Event data objects.
    Event_basic -> Event_queue_element (used for the memory queue) -> Event_timed
    Event_basic -> Event_job_data (the object used for execution)
    Sql_alloc -> Event_parse_data (used during parsing)

  sql/event_data_objects.cc
    1.67 06/07/10 13:44:33 andrey@lmy004. +535 -231
    Event_timed is no more used during execution.
    Event_timed is no more used during in the memory queue.
    Event_timed is only used for SHOW CREATE EVENT/ I_S.EVENTS/ SHOW EVENTS
    Event_basic is the parent of almost all Event data objects.
    Event_basic -> Event_queue_element (used for the memory queue) -> Event_timed
    Event_basic -> Event_job_data (the object used for execution)
    Sql_alloc -> Event_parse_data (used during parsing)

  mysql-test/t/events_stress.test
    1.8 06/07/10 13:44:33 andrey@lmy004. +2 -2
    sleep 2.5secs for shorter stress test

  mysql-test/t/events_scheduling.test
    1.7 06/07/10 13:44:33 andrey@lmy004. +1 -1
    when selecting always use ORDER BY

  mysql-test/t/events_logs_tests.test
    1.11 06/07/10 13:44:33 andrey@lmy004. +7 -8
    make the test shorter by time

  mysql-test/t/events_bugs.test
    1.12 06/07/10 13:44:33 andrey@lmy004. +34 -13
    update test
    make --sleep more appropriate . saving some time could mean failure on loaded boxes though :(
    add tests for previously uncovered branches.

  mysql-test/t/events.test
    1.35 06/07/10 13:44:32 andrey@lmy004. +10 -6
    update test
    make --sleep more appropriate . saving some time could mean failure on loaded boxes though :(
    add tests for previously uncovered branches.

  mysql-test/r/events_scheduling.result
    1.5 06/07/10 13:44:32 andrey@lmy004. +1 -1
    update results

  mysql-test/r/events_logs_tests.result
    1.11 06/07/10 13:44:32 andrey@lmy004. +5 -5
    update results

  mysql-test/r/events_bugs.result
    1.15 06/07/10 13:44:32 andrey@lmy004. +32 -16
    update results

  mysql-test/r/events.result
    1.40 06/07/10 13:44:32 andrey@lmy004. +6 -3
    update results

# 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-runtime-wl3337

--- 1.568/sql/sql_parse.cc	2006-07-05 17:12:41 +02:00
+++ 1.569/sql/sql_parse.cc	2006-07-10 13:44:33 +02:00
@@ -3886,8 +3886,12 @@ end_with_restore_list:
     else
     {
       uint affected= 1;
-      if (!(res= Events::get_instance()->
-                  drop_event(thd, lex->spname, lex->drop_if_exists, &affected)))
+      if (!(res= Events::get_instance()->drop_event(thd,
+                                                    lex->spname->m_db,
+                                                    lex->spname->m_name,
+                                                    lex->drop_if_exists,
+                                                    &affected,
+                                                    FALSE)))
         send_ok(thd, affected);     
     }
     break;

--- 1.39/mysql-test/r/events.result	2006-07-04 18:44:07 +02:00
+++ 1.40/mysql-test/r/events.result	2006-07-10 13:44:32 +02:00
@@ -87,7 +87,6 @@ events_test	event_starts_test	root@local
 DROP EVENT event_starts_test;
 create table test_nested(a int);
 create event e_43 on schedule every 1 second do set @a = 5;
-set global event_scheduler = 1;
 alter event e_43 do alter event e_43 do set @a = 4;
 ERROR HY000: Recursivity of EVENT DDL statements is forbidden when body is present
 alter event e_43 do
@@ -207,6 +206,10 @@ ERROR 42000: This version of MySQL doesn
 SHOW EVENTS;
 ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
 drop event root22;
+create event root23 on schedule every -100 year do select 1;
+ERROR HY000: INTERVAL is either not positive or too big
+create event root23 on schedule every 222222222222222222222 year do select 1;
+ERROR HY000: INTERVAL is either not positive or too big
 drop event root6;
 drop event root7;
 drop event root8;
@@ -342,7 +345,7 @@ create event закачка on schedule 
 "Should have only 2 processes: the scheduler and the locked event"
 select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
 user	host	db	command	state	info
-event_scheduler	localhost	NULL	Connect	Waiting for next activation	NULL
+event_scheduler	localhost	NULL	Daemon	Waiting for next activation	NULL
 root	localhost	events_test	Connect	User lock	select get_lock("test_lock2", 20)
 "Release the mutex, the event worker should finish."
 "Release the mutex, the event worker should finish."
@@ -358,7 +361,7 @@ create event закачка21 on schedul
 "Should have only 3 processes: the scheduler, our conn and the locked event"
 select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
 user	host	db	command	state	info
-event_scheduler	localhost	NULL	Connect	Waiting for next activation	NULL
+event_scheduler	localhost	NULL	Daemon	Waiting for next activation	NULL
 root	localhost	events_test	Connect	User lock	select get_lock("test_lock2_1", 20)
 set global event_scheduler=2;
 "Should have only our process now:"

--- 1.14/mysql-test/r/events_bugs.result	2006-07-04 18:44:07 +02:00
+++ 1.15/mysql-test/r/events_bugs.result	2006-07-10 13:44:32 +02:00
@@ -24,8 +24,19 @@ create event e_55 on schedule every 10 h
 ERROR HY000: Incorrect STARTS value: '99990101000000'
 create event e_55 on schedule every 10 minute ends 99990101000000 do drop table t;
 ERROR HY000: ENDS is either invalid or before STARTS
+create event e_55 on schedule at 10000101000000 do drop table t;
+ERROR HY000: Activation (AT) time is in the past
+create event e_55 on schedule at 20000101000000 do drop table t;
+ERROR HY000: Activation (AT) time is in the past
+create event e_55 on schedule at 20200101000000 starts 10000101000000 do drop table t;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'starts 10000101000000 do drop table t' at line 1
+create event e_55 on schedule at 20200101000000 ends 10000101000000 do drop table t;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ends 10000101000000 do drop table t' at line 1
+create event e_55 on schedule at 20200101000000 starts 10000101000000 ends 10000101000000 do drop table t;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'starts 10000101000000 ends 10000101000000 do drop table t' at line 1
+create event e_55 on schedule every 10 hour starts 10000101000000 do drop table t;
+ERROR HY000: Incorrect STARTS value: '10000101000000'
 set global event_scheduler=2;
-"Wait a bit to settle down"
 delete from mysql.event;
 set global event_scheduler= 1;
 set @old_sql_mode:=@@sql_mode;
@@ -41,7 +52,7 @@ end|
 "Now if everything is fine the event has compiled and is locked
 select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
 user	host	db	command	state	info
-event_scheduler	localhost	NULL	Connect	Waiting for next activation	NULL
+event_scheduler	localhost	NULL	Daemon	Waiting for next activation	NULL
 root	localhost	events_test	Connect	User lock	select get_lock('test_bug16407', 60)
 select release_lock('test_bug16407');
 release_lock('test_bug16407')
@@ -57,6 +68,11 @@ select event_schema, event_name, sql_mod
 event_schema	event_name	sql_mode
 events_test	e_16407	STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER
 drop event e_16407;
+set sql_mode="ansi";
+select get_lock('ee_16407_2', 60);
+get_lock('ee_16407_2', 60)
+1
+set global event_scheduler= 1;
 "Another sql_mode test"
 set sql_mode="traditional";
 create table events_smode_test(ev_name char(10), a date) engine=myisam;
@@ -64,6 +80,7 @@ create table events_smode_test(ev_name c
 create event ee_16407_2 on schedule every 60 second do
 begin
 select get_lock('ee_16407_2', 60) /*ee_16407_2*/;
+select release_lock('ee_16407_2');
 insert into events_test.events_smode_test values('ee_16407_2','1980-19-02');
 end|
 insert into events_smode_test values ('test','1980-19-02')|
@@ -72,6 +89,7 @@ ERROR 22007: Incorrect date value: '1980
 create event ee_16407_3 on schedule every 60 second do
 begin
 select get_lock('ee_16407_2', 60) /*ee_16407_3*/;
+select release_lock('ee_16407_2');
 insert into events_test.events_smode_test values ('ee_16407_3','1980-02-19');
 insert into events_test.events_smode_test values ('ee_16407_3','1980-02-29');
 end|
@@ -80,6 +98,7 @@ set sql_mode=""|
 create event ee_16407_4 on schedule every 60 second do
 begin
 select get_lock('ee_16407_2', 60) /*ee_16407_4*/;
+select release_lock('ee_16407_2');
 insert into events_test.events_smode_test values ('ee_16407_4','10-11-1956');
 end|
 select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
@@ -87,14 +106,9 @@ event_schema	event_name	sql_mode
 events_test	ee_16407_2	STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER
 events_test	ee_16407_3	STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER
 events_test	ee_16407_4	
-set sql_mode="ansi";
-select get_lock('ee_16407_2', 60);
-get_lock('ee_16407_2', 60)
-1
-set global event_scheduler= 1;
 select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
 user	host	db	command	state	info
-event_scheduler	localhost	NULL	Connect	Waiting for next activation	NULL
+event_scheduler	localhost	NULL	Daemon	Waiting for next activation	NULL
 root	localhost	events_test	Connect	User lock	select get_lock('ee_16407_2', 60) /*ee_16407_2*/
 root	localhost	events_test	Connect	User lock	select get_lock('ee_16407_2', 60) /*ee_16407_3*/
 root	localhost	events_test	Connect	User lock	select get_lock('ee_16407_2', 60) /*ee_16407_4*/
@@ -103,7 +117,7 @@ release_lock('ee_16407_2')
 1
 select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
 user	host	db	command	state	info
-event_scheduler	localhost	NULL	Connect	Waiting for next activation	NULL
+event_scheduler	localhost	NULL	Daemon	Waiting for next activation	NULL
 set global event_scheduler= 2;
 select * from events_smode_test order by ev_name, a;
 ev_name	a
@@ -121,28 +135,30 @@ drop event ee_16407_3;
 drop event ee_16407_4;
 "And now one last test regarding sql_mode and call of SP from an event"
 delete from events_smode_test;
+set sql_mode='ansi';
+select get_lock('ee_16407_5', 60);
+get_lock('ee_16407_5', 60)
+1
+set global event_scheduler= 1;
 set sql_mode='traditional';
 create procedure ee_16407_5_pendant() begin insert into events_test.events_smode_test values('ee_16407_5','2001-02-29'); end|
 create procedure ee_16407_6_pendant() begin insert into events_test.events_smode_test values('ee_16407_6','2004-02-29'); end|
 create event ee_16407_5 on schedule every 60 second do
 begin
 select get_lock('ee_16407_5', 60) /*ee_16407_5*/;
+select release_lock('ee_16407_5');
 call events_test.ee_16407_5_pendant();
 end|
 create event ee_16407_6 on schedule every 60 second do
 begin
 select get_lock('ee_16407_5', 60) /*ee_16407_6*/;
+select release_lock('ee_16407_5');
 call events_test.ee_16407_6_pendant();
 end|
-set sql_mode='ansi';
-select get_lock('ee_16407_5', 60);
-get_lock('ee_16407_5', 60)
-1
-set global event_scheduler= 1;
 "Should have 2 locked processes"
 select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
 user	host	db	command	state	info
-event_scheduler	localhost	NULL	Connect	Waiting for next activation	NULL
+event_scheduler	localhost	NULL	Daemon	Waiting for next activation	NULL
 root	localhost	events_test	Connect	User lock	select get_lock('ee_16407_5', 60) /*ee_16407_5*/
 root	localhost	events_test	Connect	User lock	select get_lock('ee_16407_5', 60) /*ee_16407_6*/
 select release_lock('ee_16407_5');
@@ -151,7 +167,7 @@ release_lock('ee_16407_5')
 "Should have 0 processes locked"
 select /*5*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
 user	host	db	command	state	info
-event_scheduler	localhost	NULL	Connect	Waiting for next activation	NULL
+event_scheduler	localhost	NULL	Daemon	Waiting for next activation	NULL
 select * from events_smode_test order by ev_name, a;
 ev_name	a
 ee_16407_6	2004-02-29

--- 1.4/mysql-test/r/events_scheduling.result	2006-06-06 01:47:25 +02:00
+++ 1.5/mysql-test/r/events_scheduling.result	2006-07-10 13:44:32 +02:00
@@ -39,7 +39,7 @@ DROP EVENT start_n_end;
 DROP EVENT only_one_time;
 ERROR HY000: Unknown event 'only_one_time'
 "Should be preserved"
-SELECT EVENT_NAME, STATUS FROM INFORMATION_SCHEMA.EVENTS;
+SELECT EVENT_NAME, STATUS FROM INFORMATION_SCHEMA.EVENTS ORDER BY EVENT_NAME;
 EVENT_NAME	STATUS
 E19170	ENABLED
 two_time	DISABLED

--- 1.10/mysql-test/r/events_logs_tests.result	2006-06-22 16:13:09 +02:00
+++ 1.11/mysql-test/r/events_logs_tests.result	2006-07-10 13:44:32 +02:00
@@ -9,7 +9,7 @@ SELECT user_host, argument FROM mysql.ge
 END|
 "Check General Query Log"
 SET GLOBAL event_scheduler=2;
-create event log_general on schedule every 1 minute do SELect 'alabala', sleep(3) from dual;
+create event log_general on schedule every 1 minute do SELect 'alabala', sleep(1) from dual;
 TRUNCATE mysql.general_log;
 "1 row, the current statement!"
 call select_general_log();
@@ -19,7 +19,7 @@ SET GLOBAL event_scheduler=1;
 "Should see 3 rows - the 'SELect' is in the middle. The other two are selects from general_log"
 call select_general_log();
 user_host	argument
-USER_HOST	SELect 'alabala', sleep(3) from dual
+USER_HOST	SELect 'alabala', sleep(1) from dual
 DROP PROCEDURE select_general_log;
 DROP EVENT log_general;
 SET GLOBAL event_scheduler=2;
@@ -49,13 +49,13 @@ USER_HOST	SLEEPVAL	events_test	SELECT SL
 SET SESSION long_query_time=300;
 "Make it quite long"
 TRUNCATE mysql.slow_log;
-SET SESSION long_query_time=1;
 CREATE TABLE slow_event_test (slo_val tinyint, val tinyint);
 "This won't go to the slow log"
-CREATE EVENT long_event ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(3);
 SELECT * FROM slow_event_test;
 slo_val	val
+SET SESSION long_query_time=1;
 SET GLOBAL event_scheduler=1;
+CREATE EVENT long_event ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(1.5);
 "Sleep some more time than the actual event run will take"
 SHOW VARIABLES LIKE 'event_scheduler';
 Variable_name	Value
@@ -64,7 +64,7 @@ event_scheduler	1
 SELECT * FROM slow_event_test;
 slo_val	val
 4	0
-"Check slow log. Should not see anything because 3 is under the threshold of 4 for GLOBAL, though over SESSION which is 2"
+"Check slow log. Should not see anything because 1.5 is under the threshold of 300 for GLOBAL, though over SESSION which is 2"
 SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
 user_host	query_time	db	sql_text
 "This should go to the slow log"

--- 1.34/mysql-test/t/events.test	2006-06-29 00:42:13 +02:00
+++ 1.35/mysql-test/t/events.test	2006-07-10 13:44:32 +02:00
@@ -18,7 +18,7 @@ CREATE EVENT e_x2 ON SCHEDULE EVERY 1 SE
 connection default;
 SHOW DATABASES LIKE 'db_x';
 SET GLOBAL event_scheduler=1;
---sleep 1.5
+--sleep 0.8
 SHOW DATABASES LIKE 'db_x';
 SHOW TABLES FROM db_x;
 SET GLOBAL event_scheduler=2;
@@ -83,7 +83,6 @@ DROP EVENT event_starts_test;
 #
 create table test_nested(a int);
 create event e_43 on schedule every 1 second do set @a = 5;
-set global event_scheduler = 1;
 --error 1562
 alter event e_43 do alter event e_43 do set @a = 4;
 delimiter |;
@@ -94,7 +93,7 @@ begin
 end|
 delimiter ;|
 set global event_scheduler = 1;
---sleep 1
+--sleep 3
 select db, name, body, status, interval_field, interval_value from mysql.event;
 drop event e_43;
 drop table test_nested;
@@ -102,7 +101,7 @@ drop table test_nested;
 --echo "Let's check whether we can use non-qualified names"
 create table non_qualif(a int);
 create event non_qualif_ev on schedule every 10 minute do insert into non_qualif values (800219);
---sleep 1
+--sleep 0.5
 select * from non_qualif;
 drop event non_qualif_ev;
 drop table non_qualif;
@@ -165,6 +164,10 @@ show create event root22;
 --error ER_NOT_SUPPORTED_YET
 SHOW EVENTS;
 drop event root22;
+--error ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG
+create event root23 on schedule every -100 year do select 1;
+--error ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG
+create event root23 on schedule every 222222222222222222222 year do select 1;
 drop event root6;
 drop event root7;
 drop event root8;
@@ -294,7 +297,7 @@ select get_lock("test_lock2", 20);
 --echo "Create an event which tries to acquire a mutex. The event locks on the mutex"
 create event закачка on schedule every 10 hour do select get_lock("test_lock2", 20);
 --echo "Let some time pass to the event starts"
---sleep 1
+--sleep 0.5
 --echo "Should have only 2 processes: the scheduler and the locked event"
 select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;--echo "Release the mutex, the event worker should finish."
 --echo "Release the mutex, the event worker should finish."
@@ -312,10 +315,11 @@ drop event закачка;
 set global event_scheduler=1;
 select get_lock("test_lock2_1", 20);
 create event закачка21 on schedule every 10 hour do select get_lock("test_lock2_1", 20);
---sleep 1
+--sleep 0.5
 --echo "Should have only 3 processes: the scheduler, our conn and the locked event"
 select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
 set global event_scheduler=2;
+--sleep 0.3
 --echo "Should have only our process now:"
 select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
 drop event закачка21;

--- 1.11/mysql-test/t/events_bugs.test	2006-06-29 11:53:42 +02:00
+++ 1.12/mysql-test/t/events_bugs.test	2006-07-10 13:44:33 +02:00
@@ -45,6 +45,19 @@ create event e_55 on schedule at 9999010
 create event e_55 on schedule every 10 hour starts 99990101000000 do drop table t;
 --error ER_EVENT_ENDS_BEFORE_STARTS
 create event e_55 on schedule every 10 minute ends 99990101000000 do drop table t;
+--error ER_EVENT_EXEC_TIME_IN_THE_PAST
+create event e_55 on schedule at 10000101000000 do drop table t;
+--error ER_EVENT_EXEC_TIME_IN_THE_PAST
+create event e_55 on schedule at 20000101000000 do drop table t;
+--error ER_PARSE_ERROR
+create event e_55 on schedule at 20200101000000 starts 10000101000000 do drop table t;
+--error ER_PARSE_ERROR
+create event e_55 on schedule at 20200101000000 ends 10000101000000 do drop table t;
+--error ER_PARSE_ERROR
+create event e_55 on schedule at 20200101000000 starts 10000101000000 ends 10000101000000 do drop table t;
+--error ER_WRONG_VALUE
+create event e_55 on schedule every 10 hour starts 10000101000000 do drop table t;
+
 #
 # End  -  16396: Events: Distant-future dates become past dates
 #
@@ -53,8 +66,6 @@ create event e_55 on schedule every 10 m
 # Start - 16407: Events: Changes in sql_mode won't be taken into account
 #
 set global event_scheduler=2;
---echo "Wait a bit to settle down"
---sleep 1
 delete from mysql.event;
 set global event_scheduler= 1;
 set @old_sql_mode:=@@sql_mode;
@@ -67,11 +78,13 @@ begin
   drop table "hashed_num";
 end|
 delimiter ;|
---sleep 1
+--sleep 0.5
 --echo "Now if everything is fine the event has compiled and is locked
 select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
 select release_lock('test_bug16407');
+
 set global event_scheduler= 2;
+
 select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
 --echo "Let's check whether we change the sql_mode on ALTER EVENT"
 set sql_mode='traditional';
@@ -79,6 +92,10 @@ alter event e_16407 do select 1;
 select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
 drop event e_16407;
 
+set sql_mode="ansi";
+select get_lock('ee_16407_2', 60);
+
+set global event_scheduler= 1;
 --echo "Another sql_mode test"
 set sql_mode="traditional";
 create table events_smode_test(ev_name char(10), a date) engine=myisam;
@@ -87,6 +104,7 @@ delimiter |;
 create event ee_16407_2 on schedule every 60 second do
 begin
   select get_lock('ee_16407_2', 60) /*ee_16407_2*/;
+  select release_lock('ee_16407_2');
   insert into events_test.events_smode_test values('ee_16407_2','1980-19-02');
 end|
 --error ER_TRUNCATED_WRONG_VALUE
@@ -95,6 +113,7 @@ insert into events_smode_test values ('t
 create event ee_16407_3 on schedule every 60 second do
 begin
   select get_lock('ee_16407_2', 60) /*ee_16407_3*/;
+  select release_lock('ee_16407_2');
   insert into events_test.events_smode_test values ('ee_16407_3','1980-02-19');
   insert into events_test.events_smode_test values ('ee_16407_3','1980-02-29');
 end|
@@ -103,17 +122,15 @@ set sql_mode=""|
 create event ee_16407_4 on schedule every 60 second do
 begin
   select get_lock('ee_16407_2', 60) /*ee_16407_4*/;
+  select release_lock('ee_16407_2');
   insert into events_test.events_smode_test values ('ee_16407_4','10-11-1956');
 end|
 delimiter ;|
 select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
-set sql_mode="ansi";
-select get_lock('ee_16407_2', 60);
-set global event_scheduler= 1;
---sleep 1
+--sleep 0.5
 select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
 select release_lock('ee_16407_2');
---sleep 2
+--sleep 0.8
 select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
 set global event_scheduler= 2;
 select * from events_smode_test order by ev_name, a;
@@ -126,6 +143,11 @@ drop event ee_16407_4;
 
 --echo "And now one last test regarding sql_mode and call of SP from an event"
 delete from events_smode_test;
+set sql_mode='ansi';
+select get_lock('ee_16407_5', 60);
+
+set global event_scheduler= 1;
+
 set sql_mode='traditional';
 delimiter |;
 create procedure ee_16407_5_pendant() begin insert into events_test.events_smode_test values('ee_16407_5','2001-02-29'); end|
@@ -133,22 +155,21 @@ create procedure ee_16407_6_pendant() be
 create event ee_16407_5 on schedule every 60 second do
 begin
   select get_lock('ee_16407_5', 60) /*ee_16407_5*/;
+  select release_lock('ee_16407_5');
   call events_test.ee_16407_5_pendant();
 end|
 create event ee_16407_6 on schedule every 60 second do
 begin
   select get_lock('ee_16407_5', 60) /*ee_16407_6*/;
+  select release_lock('ee_16407_5');
   call events_test.ee_16407_6_pendant();
 end|
 delimiter ;|
-set sql_mode='ansi';
-select get_lock('ee_16407_5', 60);
-set global event_scheduler= 1;
---sleep 1
+--sleep 0.5
 --echo "Should have 2 locked processes"
 select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
 select release_lock('ee_16407_5');
---sleep 2
+--sleep 0.8
 --echo "Should have 0 processes locked"
 select /*5*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
 select * from events_smode_test order by ev_name, a;

--- 1.6/mysql-test/t/events_scheduling.test	2006-06-23 09:39:58 +02:00
+++ 1.7/mysql-test/t/events_scheduling.test	2006-07-10 13:44:33 +02:00
@@ -34,7 +34,7 @@ DROP EVENT start_n_end;
 --error ER_EVENT_DOES_NOT_EXIST
 DROP EVENT only_one_time;
 --echo "Should be preserved"
-SELECT EVENT_NAME, STATUS FROM INFORMATION_SCHEMA.EVENTS;
+SELECT EVENT_NAME, STATUS FROM INFORMATION_SCHEMA.EVENTS ORDER BY EVENT_NAME;
 DROP EVENT two_time;
 DROP TABLE table_1;
 DROP TABLE table_2;

--- 1.10/mysql-test/t/events_logs_tests.test	2006-06-23 09:39:58 +02:00
+++ 1.11/mysql-test/t/events_logs_tests.test	2006-07-10 13:44:33 +02:00
@@ -14,7 +14,7 @@ END|
 delimiter ;|
 --echo "Check General Query Log"
 SET GLOBAL event_scheduler=2;
-create event log_general on schedule every 1 minute do SELect 'alabala', sleep(3) from dual;
+create event log_general on schedule every 1 minute do SELect 'alabala', sleep(1) from dual;
 TRUNCATE mysql.general_log;
 --echo "1 row, the current statement!"
 --replace_column 1 USER_HOST
@@ -22,13 +22,12 @@ call select_general_log();
 SET GLOBAL event_scheduler=1;
 --echo "Wait the scheduler to start"
 --echo "Should see 3 rows - the 'SELect' is in the middle. The other two are selects from general_log"
---sleep 2
+--sleep 0.7
 --replace_column 1 USER_HOST
 call select_general_log();
 DROP PROCEDURE select_general_log;
 DROP EVENT log_general;
 SET GLOBAL event_scheduler=2;
---sleep 1
 
 --echo "Check slow query log"
 --disable_query_log
@@ -69,18 +68,18 @@ SELECT user_host, query_time, db, sql_te
 SET SESSION long_query_time=300;
 --echo "Make it quite long"
 TRUNCATE mysql.slow_log;
-SET SESSION long_query_time=1;
 CREATE TABLE slow_event_test (slo_val tinyint, val tinyint);
 --echo "This won't go to the slow log"
-CREATE EVENT long_event ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(3);
 SELECT * FROM slow_event_test;
+SET SESSION long_query_time=1;
 SET GLOBAL event_scheduler=1;
+CREATE EVENT long_event ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(1.5);
 --echo "Sleep some more time than the actual event run will take"
---sleep 5
+--sleep 2
 SHOW VARIABLES LIKE 'event_scheduler';
 --echo "Check our table. Should see 1 row"
 SELECT * FROM slow_event_test;
---echo "Check slow log. Should not see anything because 3 is under the threshold of 4 for GLOBAL, though over SESSION which is 2"
+--echo "Check slow log. Should not see anything because 1.5 is under the threshold of 300 for GLOBAL, though over SESSION which is 2"
 SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
 --echo "This should go to the slow log"
 DROP EVENT long_event;
@@ -88,7 +87,7 @@ SET SESSION long_query_time=10;
 SET GLOBAL long_query_time=1;
 CREATE EVENT long_event2 ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(2);
 --echo "Sleep some more time than the actual event run will take"
---sleep 3
+--sleep 2.5
 --echo "Check our table. Should see 2 rows"
 SELECT * FROM slow_event_test;
 --echo "Check slow log. Should see 1 row because 4 is over the threshold of 3 for GLOBAL, though under SESSION which is 10"

--- 1.7/mysql-test/t/events_stress.test	2006-07-04 18:44:11 +02:00
+++ 1.8/mysql-test/t/events_stress.test	2006-07-10 13:44:33 +02:00
@@ -61,7 +61,7 @@ while ($1)
 --enable_query_log
 SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
 SET GLOBAL event_scheduler=1;
---sleep 12
+--sleep 2.5
 DROP DATABASE events_conn1_test2;
 
 SET GLOBAL event_scheduler=2;
@@ -100,7 +100,7 @@ while ($1)
 }
 --enable_query_log
 SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
---sleep 12
+--sleep 2.5
 connection conn2;
 --send
 DROP DATABASE events_conn2_db;

--- 1.51/sql/events.cc	2006-07-05 17:12:41 +02:00
+++ 1.52/sql/events.cc	2006-07-10 13:44:33 +02:00
@@ -291,11 +291,11 @@ Events::open_event_table(THD *thd, enum 
 
   RETURN VALUE
     0   OK
-    !0  Error
+    !0  Error (Reported)
 
   NOTES
-    - in case there is an event with the same name (db) and 
-      IF NOT EXISTS is specified, an warning is put into the W stack.
+    In case there is an event with the same name (db) and 
+    IF NOT EXISTS is specified, an warning is put into the stack.
 */
 
 int
@@ -304,13 +304,20 @@ Events::create_event(THD *thd, Event_par
 {
   int ret;
   DBUG_ENTER("Events::create_event");
+
+  pthread_mutex_lock(&LOCK_event_metadata);
+  /* On error conditions my_error() is called so no need to handle here */
   if (!(ret= db_repository->create_event(thd, parse_data, if_not_exists,
                                          rows_affected)))
   {
-    if ((ret= event_queue->create_event(thd, parse_data)))
-      my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
+    if ((ret= event_queue->create_event(thd, parse_data->dbname,
+                                        parse_data->name)))
+    {
+      DBUG_ASSERT(ret == OP_LOAD_ERROR);
+      my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0));
+    }
   }
-  /* No need to close the table, it will be closed in sql_parse::do_command */
+  pthread_mutex_unlock(&LOCK_event_metadata);
 
   DBUG_RETURN(ret);
 }
@@ -322,8 +329,8 @@ Events::create_event(THD *thd, Event_par
   SYNOPSIS
     Events::update_event()
       thd        THD
-      et         event's data
-      new_name   set in case of RENAME TO.
+      et         Event's data from parsing stage
+      new_name   Set in case of RENAME TO.
 
   RETURN VALUE
     0   OK
@@ -341,18 +348,23 @@ Events::update_event(THD *thd, Event_par
 {
   int ret;
   DBUG_ENTER("Events::update_event");
-  /*
-    db_update_event() opens & closes the table to prevent
-    crash later in the code when loading and compiling the new definition.
-    Also on error conditions my_error() is called so no need to handle here
-  */
+
+  pthread_mutex_lock(&LOCK_event_metadata);
+  /* On error conditions my_error() is called so no need to handle here */
   if (!(ret= db_repository->update_event(thd, parse_data, new_name)))
   {
-    if ((ret= event_queue->update_event(thd, parse_data,
+    if ((ret= event_queue->update_event(thd,
+                                        parse_data->dbname,
+                                        parse_data->name,
                                         new_name? &new_name->m_db: NULL,
                                         new_name? &new_name->m_name: NULL)))
-      my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
+    {
+      DBUG_ASSERT(ret == OP_LOAD_ERROR);
+      my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0));
+    }
   }
+  pthread_mutex_unlock(&LOCK_event_metadata);
+
   DBUG_RETURN(ret);
 }
 
@@ -363,10 +375,15 @@ Events::update_event(THD *thd, Event_par
   SYNOPSIS
     Events::drop_event()
       thd             THD
+      dbname          Event's schema
       name            Event's name
       if_exists       When set and the event does not exist => warning onto
                       the stack
       rows_affected   Affected number of rows is returned heres
+      only_from_disk  Whether to remove the event from the queue too. In case
+                      of Event_job_data::drop() it's needed to do only disk
+                      drop because Event_queue will handle removal from memory
+                      queue.
 
   RETURN VALUE
      0  OK
@@ -374,17 +391,52 @@ Events::update_event(THD *thd, Event_par
 */
 
 int
-Events::drop_event(THD *thd, sp_name *name, bool if_exists, uint *rows_affected)
+Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists,
+                   uint *rows_affected, bool only_from_disk)
 {
   int ret;
   DBUG_ENTER("Events::drop_event");
 
-  if (!(ret= db_repository->drop_event(thd, name->m_db, name->m_name, if_exists,
+  pthread_mutex_lock(&LOCK_event_metadata);
+  /* On error conditions my_error() is called so no need to handle here */
+  if (!(ret= db_repository->drop_event(thd, dbname, name, if_exists,
                                        rows_affected)))
   {
-    if ((ret= event_queue->drop_event(thd, name)))
-      my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
+    if (!only_from_disk)
+      event_queue->drop_event(thd, dbname, name);
   }
+  pthread_mutex_unlock(&LOCK_event_metadata);
+  DBUG_RETURN(ret);
+}
+
+
+/*
+  Drops all events from a schema
+
+  SYNOPSIS
+    Events::drop_schema_events()
+      thd  Thread
+      db   ASCIIZ schema name
+
+  RETURN VALUE
+    0   OK
+    !0  Error
+*/
+
+int
+Events::drop_schema_events(THD *thd, char *db)
+{
+  int ret= 0;
+  LEX_STRING db_lex= {db, strlen(db)};
+  
+  DBUG_ENTER("evex_drop_db_events");  
+  DBUG_PRINT("enter", ("dropping events from %s", db));
+
+  pthread_mutex_lock(&LOCK_event_metadata);
+  event_queue->drop_schema_events(thd, db_lex);
+  ret= db_repository->drop_schema_events(thd, db_lex);
+  pthread_mutex_unlock(&LOCK_event_metadata);
+
   DBUG_RETURN(ret);
 }
 
@@ -406,14 +458,14 @@ int
 Events::show_create_event(THD *thd, sp_name *spn)
 {
   int ret;
-  Event_timed *et= NULL;
+  Event_timed *et= new Event_timed();
   Open_tables_state backup;
 
   DBUG_ENTER("Events::show_create_event");
   DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str));
 
   thd->reset_n_backup_open_tables_state(&backup);
-  ret= db_repository->find_event(thd, spn->m_db, spn->m_name, &et, NULL);
+  ret= db_repository->find_event(thd, spn->m_db, spn->m_name, et);
   thd->restore_backup_open_tables_state(&backup);
 
   if (!ret)
@@ -458,36 +510,43 @@ Events::show_create_event(THD *thd, sp_n
   DBUG_RETURN(ret);
 err:
   delete et;
-  DBUG_RETURN(1);  
+  DBUG_RETURN(1);
 }
 
 
 /*
-  Drops all events from a schema
+  Proxy for Event_db_repository::fill_schema_events.
+  Callback for I_S from sql_show.cc
 
   SYNOPSIS
-    Events::drop_schema_events()
-      thd  Thread
-      db   ASCIIZ schema name
+    Events::fill_schema_events()
+      thd     Thread
+      tables  The schema table
+      cond    Unused
 
   RETURN VALUE
-    0   OK
-    !0  Error
+    0  OK
+    !0 Error
 */
 
 int
-Events::drop_schema_events(THD *thd, char *db)
+Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
 {
-  int ret= 0;
-  LEX_STRING db_lex= {db, strlen(db)};
-  
-  DBUG_ENTER("evex_drop_db_events");  
-  DBUG_PRINT("enter", ("dropping events from %s", db));
-
-  event_queue->drop_schema_events(thd, db_lex);
-  ret= db_repository->drop_schema_events(thd, db_lex);
-
-  DBUG_RETURN(ret);
+  char *db= NULL;
+  DBUG_ENTER("Events::fill_schema_events");
+  /*
+    If it's SHOW EVENTS then thd->lex->select_lex.db is guaranteed not to
+    be NULL. Let's do an assert anyway.
+  */
+  if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS)
+  {
+    DBUG_ASSERT(thd->lex->select_lex.db);
+    if (check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0,
+                     is_schema_db(thd->lex->select_lex.db)))
+      DBUG_RETURN(1);
+    db= thd->lex->select_lex.db;
+  }
+  DBUG_RETURN(get_instance()->db_repository->fill_schema_events(thd, tables, db));
 }
 
 
@@ -511,7 +570,6 @@ Events::init()
   int ret= 0;
   Event_db_repository *db_repo;
   DBUG_ENTER("Events::init");
-  db_repository->init_repository();
   event_queue->init_queue(db_repository, scheduler_ng);
   scheduler_ng->init_scheduler(event_queue);
 
@@ -546,7 +604,6 @@ Events::deinit()
   scheduler_ng->deinit_scheduler();
 
   event_queue->deinit_queue();
-  db_repository->deinit_repository();
 
   DBUG_VOID_RETURN;
 }
@@ -563,6 +620,8 @@ Events::deinit()
 void
 Events::init_mutexes()
 {
+  pthread_mutex_init(&LOCK_event_metadata, MY_MUTEX_INIT_FAST);
+
   db_repository= new Event_db_repository;
 
   event_queue= new Event_queue;
@@ -585,9 +644,11 @@ Events::destroy_mutexes()
 {
   event_queue->deinit_mutexes();
   scheduler_ng->deinit_mutexes();
-  
+
   delete scheduler_ng;
   delete db_repository;
+
+  pthread_mutex_destroy(&LOCK_event_metadata);
 }
 
 
@@ -597,55 +658,45 @@ Events::destroy_mutexes()
   SYNOPSIS
     Events::dump_internal_status()
       thd  Thread
-  
+
   RETURN VALUE
-    0  OK
-    !0 Error
+    FALSE  OK
+    TRUE   Error
 */
 
-int
+bool
 Events::dump_internal_status(THD *thd)
 {
-  return Event_scheduler_ng::dump_internal_status(thd);
+  DBUG_ENTER("Events::dump_internal_status");
+  Protocol *protocol= thd->protocol;
+  List<Item> field_list;
+
+  field_list.push_back(new Item_empty_string("Name", 30));
+  field_list.push_back(new Item_empty_string("Value",20));
+  if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
+                                         Protocol::SEND_EOF))
+    DBUG_RETURN(TRUE);
+
+  if (scheduler_ng->dump_internal_status(thd) ||
+      event_queue->dump_internal_status(thd))
+    DBUG_RETURN(TRUE);
+
+  send_eof(thd);
+  DBUG_RETURN(FALSE);
 }
 
 
 /*
-  Proxy for Event_db_repository::fill_schema_events.
-  Callback for I_S from sql_show.cc
+  Starts execution of events by the scheduler
 
   SYNOPSIS
-    Events::fill_schema_events()
-      thd     Thread
-      tables  The schema table
-      cond    Unused
+    Events::start_execution_of_events()
 
   RETURN VALUE
-    0  OK
-    !0 Error
+    FALSE  OK
+    TRUE   Error
 */
 
-int
-Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
-{
-  char *db= NULL;
-  DBUG_ENTER("Events::fill_schema_events");
-  /*
-    If it's SHOW EVENTS then thd->lex->select_lex.db is guaranteed not to
-    be NULL. Let's do an assert anyway.
-  */
-  if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS)
-  {
-    DBUG_ASSERT(thd->lex->select_lex.db);
-    if (check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0,
-                     is_schema_db(thd->lex->select_lex.db)))
-      DBUG_RETURN(1);
-    db= thd->lex->select_lex.db;
-  }
-  DBUG_RETURN(get_instance()->db_repository->fill_schema_events(thd, tables, db));
-}
-
-
 bool
 Events::start_execution_of_events()
 {
@@ -654,12 +705,37 @@ Events::start_execution_of_events()
 }
 
 
+/*
+  Stops execution of events by the scheduler.
+  Already running events will not be stopped. If the user needs
+  them stopped manual intervention is needed.
+
+  SYNOPSIS
+    Events::stop_execution_of_events()
+
+  RETURN VALUE
+    FALSE  OK
+    TRUE   Error
+*/
+
 bool
 Events::stop_execution_of_events()
 {
   DBUG_ENTER("Events::stop_execution_of_events");
   DBUG_RETURN(scheduler_ng->stop());
 }
+
+
+/*
+  Checks whether the scheduler is running or not.
+
+  SYNOPSIS
+    Events::is_started()
+
+  RETURN VALUE
+    TRUE  Yes
+    FALSE No
+*/
 
 bool
 Events::is_started()

--- 1.39/sql/events.h	2006-07-05 17:12:41 +02:00
+++ 1.40/sql/events.h	2006-07-10 13:44:33 +02:00
@@ -20,6 +20,7 @@ class sp_name;
 class Event_parse_data;
 class Event_db_repository;
 class Event_queue;
+class Event_queue_element;
 class Event_scheduler_ng;
 
 /* Return codes */
@@ -41,6 +42,7 @@ sortcmp_lex_string(LEX_STRING s, LEX_STR
 class Events
 {
 public:
+  friend class Event_queue_element;
   /*
     Quite NOT the best practice and will be removed once
     Event_timed::drop() and Event_timed is fixed not do drop directly
@@ -83,7 +85,8 @@ public:
                uint *rows_affected);
 
   int
-  drop_event(THD *thd, sp_name *name, bool if_exists, uint *rows_affected);
+  drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists,
+             uint *rows_affected, bool only_from_disk);
 
   int
   drop_schema_events(THD *thd, char *db);
@@ -102,13 +105,9 @@ public:
   static int
   fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */);
   
-  int
+  bool
   dump_internal_status(THD *thd);
 
-  Event_queue         *event_queue;
-  Event_scheduler_ng  *scheduler_ng;
-  Event_db_repository *db_repository;
-
 private:
   /* Singleton DP is used */
   Events(){}
@@ -116,6 +115,12 @@ private:
 
   /* Singleton instance */
   static Events singleton;
+
+  Event_queue         *event_queue;
+  Event_scheduler_ng  *scheduler_ng;
+  Event_db_repository *db_repository;
+
+  pthread_mutex_t LOCK_event_metadata;  
 
   /* Prevent use of these */
   Events(const Events &);

--- 1.8/sql/event_db_repository.cc	2006-07-05 17:12:41 +02:00
+++ 1.9/sql/event_db_repository.cc	2006-07-10 13:44:33 +02:00
@@ -29,7 +29,8 @@
 time_t mysql_event_last_create_time= 0L;
 
 static
-TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] = {
+TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] =
+{
   {
     {(char *) STRING_WITH_LEN("db")},
     {(char *) STRING_WITH_LEN("char(64)")},
@@ -128,50 +129,49 @@ TABLE_FIELD_W_TYPE event_table_fields[ET
   Puts some data common to CREATE and ALTER EVENT into a row.
 
   SYNOPSIS
-    evex_fill_row()
+    mysql_event_fill_row()
       thd        THD
       table      The row to fill out
       et         Event's data
       is_update  CREATE EVENT or ALTER EVENT
 
   RETURN VALUE
-    0 - OK
-    EVEX_GENERAL_ERROR    - bad data
-    EVEX_GET_FIELD_FAILED - field count does not match. table corrupted?
+    0                       OK
+    EVEX_GENERAL_ERROR      Bad data
+    EVEX_GET_FIELD_FAILED   Field count does not match. table corrupted?
 
   DESCRIPTION 
     Used both when an event is created and when it is altered.
 */
 
 static int
-evex_fill_row(THD *thd, TABLE *table, Event_parse_data *et, my_bool is_update)
+mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et,
+                     my_bool is_update)
 {
   CHARSET_INFO *scs= system_charset_info;
-  enum enum_events_table_field field_num;
+  enum enum_events_table_field f_num;
+  Field **fields= table->field;
 
-  DBUG_ENTER("evex_fill_row");
+  DBUG_ENTER("mysql_event_fill_row");
 
   DBUG_PRINT("info", ("dbname=[%s]", et->dbname.str));
   DBUG_PRINT("info", ("name  =[%s]", et->name.str));
   DBUG_PRINT("info", ("body  =[%s]", et->body.str));
 
-  if (table->field[field_num= ET_FIELD_DEFINER]->
-                  store(et->definer.str, et->definer.length, scs))
+  if (fields[f_num= ET_FIELD_DEFINER]->
+                              store(et->definer.str, et->definer.length, scs))
     goto err_truncate;
 
-  if (table->field[field_num= ET_FIELD_DB]->
-                  store(et->dbname.str, et->dbname.length, scs))
+  if (fields[f_num= ET_FIELD_DB]->store(et->dbname.str, et->dbname.length, scs))
     goto err_truncate;
 
-  if (table->field[field_num= ET_FIELD_NAME]->
-                  store(et->name.str, et->name.length, scs))
+  if (fields[f_num= ET_FIELD_NAME]->store(et->name.str, et->name.length, scs))
     goto err_truncate;
 
   /* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()*/
-  table->field[ET_FIELD_ON_COMPLETION]->
-                                       store((longlong)et->on_completion, true);
+  fields[ET_FIELD_ON_COMPLETION]->store((longlong)et->on_completion, TRUE);
 
-  table->field[ET_FIELD_STATUS]->store((longlong)et->status, true);
+  fields[ET_FIELD_STATUS]->store((longlong)et->status, TRUE);
 
   /*
     Change the SQL_MODE only if body was present in an ALTER EVENT and of course
@@ -179,52 +179,46 @@ evex_fill_row(THD *thd, TABLE *table, Ev
   */ 
   if (et->body.str)
   {
-    table->field[ET_FIELD_SQL_MODE]->
-                               store((longlong)thd->variables.sql_mode, true);
-
-    if (table->field[field_num= ET_FIELD_BODY]->
-                     store(et->body.str, et->body.length, scs))
+    fields[ET_FIELD_SQL_MODE]->store((longlong)thd->variables.sql_mode, TRUE);
+    if (fields[f_num= ET_FIELD_BODY]->store(et->body.str, et->body.length, scs))
       goto err_truncate;
   }
 
   if (et->expression)
   {
-    table->field[ET_FIELD_INTERVAL_EXPR]->set_notnull();
-    table->field[ET_FIELD_INTERVAL_EXPR]->store((longlong)et->expression, true);
+    fields[ET_FIELD_INTERVAL_EXPR]->set_notnull();
+    fields[ET_FIELD_INTERVAL_EXPR]->store((longlong)et->expression, TRUE);
 
-    table->field[ET_FIELD_TRANSIENT_INTERVAL]->set_notnull();
+    fields[ET_FIELD_TRANSIENT_INTERVAL]->set_notnull();
     /*
-      In the enum (C) intervals start from 0 but in mysql enum valid values start
-      from 1. Thus +1 offset is needed!
+      In the enum (C) intervals start from 0 but in mysql enum valid values
+      start from 1. Thus +1 offset is needed!
     */
-    table->field[ET_FIELD_TRANSIENT_INTERVAL]->
-                                         store((longlong)et->interval+1, true);
+    fields[ET_FIELD_TRANSIENT_INTERVAL]->store((longlong)et->interval+1, TRUE);
 
-    table->field[ET_FIELD_EXECUTE_AT]->set_null();
+    fields[ET_FIELD_EXECUTE_AT]->set_null();
 
     if (!et->starts_null)
     {
-      table->field[ET_FIELD_STARTS]->set_notnull();
-      table->field[ET_FIELD_STARTS]->
-                            store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
+      fields[ET_FIELD_STARTS]->set_notnull();
+      fields[ET_FIELD_STARTS]->store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
     }
 
     if (!et->ends_null)
     {
-      table->field[ET_FIELD_ENDS]->set_notnull();
-      table->field[ET_FIELD_ENDS]->
-                            store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
+      fields[ET_FIELD_ENDS]->set_notnull();
+      fields[ET_FIELD_ENDS]->store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
     }
   }
   else if (et->execute_at.year)
   {
-    table->field[ET_FIELD_INTERVAL_EXPR]->set_null();
-    table->field[ET_FIELD_TRANSIENT_INTERVAL]->set_null();
-    table->field[ET_FIELD_STARTS]->set_null();
-    table->field[ET_FIELD_ENDS]->set_null();
+    fields[ET_FIELD_INTERVAL_EXPR]->set_null();
+    fields[ET_FIELD_TRANSIENT_INTERVAL]->set_null();
+    fields[ET_FIELD_STARTS]->set_null();
+    fields[ET_FIELD_ENDS]->set_null();
     
-    table->field[ET_FIELD_EXECUTE_AT]->set_notnull();
-    table->field[ET_FIELD_EXECUTE_AT]->
+    fields[ET_FIELD_EXECUTE_AT]->set_notnull();
+    fields[ET_FIELD_EXECUTE_AT]->
                         store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME);
   }
   else
@@ -236,48 +230,24 @@ evex_fill_row(THD *thd, TABLE *table, Ev
     */
   }
     
-  ((Field_timestamp *)table->field[ET_FIELD_MODIFIED])->set_time();
+  ((Field_timestamp *)fields[ET_FIELD_MODIFIED])->set_time();
 
   if (et->comment.str)
   {
-    if (table->field[field_num= ET_FIELD_COMMENT]->
-                 store(et->comment.str, et->comment.length, scs))
+    if (fields[f_num= ET_FIELD_COMMENT]->
+                          store(et->comment.str, et->comment.length, scs))
       goto err_truncate;
   }
 
   DBUG_RETURN(0);
+
 err_truncate:
-  my_error(ER_EVENT_DATA_TOO_LONG, MYF(0), table->field[field_num]->field_name);
+  my_error(ER_EVENT_DATA_TOO_LONG, MYF(0), fields[f_num]->field_name);
   DBUG_RETURN(EVEX_GENERAL_ERROR);
 }
 
 
 /*
-  Find row in open mysql.event table representing event
-
-  SYNOPSIS
-    evex_db_find_event_by_name()
-      thd    Thread context
-      dbname Name of event's database
-      rname  Name of the event inside the db  
-      table  TABLE object for open mysql.event table.
-
-  RETURN VALUE
-    0                  - Routine found
-    EVEX_KEY_NOT_FOUND - No routine with given name
-*/
-
-int
-evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
-                          const LEX_STRING ev_name,
-                          TABLE *table)
-{
-  return Events::get_instance()->db_repository->
-            find_event_by_name(thd, dbname, ev_name, table);
-}
-
-
-/*
   Performs an index scan of event_table (mysql.event) and fills schema_table.
 
   Synopsis
@@ -313,7 +283,7 @@ Event_db_repository::index_read_for_db_f
   if (!(key_buf= (byte *)alloc_root(thd->mem_root, key_len)))
   {
     ret= 1;
-    /* don't send error, it would be done by sql_alloc_error_handler() */
+    /* Don't send error, it would be done by sql_alloc_error_handler() */
   }
   else
   {
@@ -441,99 +411,13 @@ Event_db_repository::fill_schema_events(
 
 
 /*
-  Looks for a named event in mysql.event and in case of success returns
-  an object will data loaded from the table.
-
-  SYNOPSIS
-    Event_db_repository::find_event()
-      thd      THD
-      name     the name of the event to find
-      ett      event's data if event is found
-      tbl      TABLE object to use when not NULL
-      root     On which root to load the event
-
-  NOTES
-    1) Use sp_name for look up, return in **ett if found
-    2) tbl is not closed at exit
-
-  RETURN VALUE
-    0  ok     In this case *ett is set to the event
-    #  error  *ett == 0
-*/
-
-int
-Event_db_repository::find_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
-                                Event_timed **ett, TABLE *tbl)
-{
-  TABLE *table;
-  int ret;
-  Event_timed *et= NULL;
-  DBUG_ENTER("Event_db_repository::find_event");
-  DBUG_PRINT("enter", ("name: %*s", name.length, name.str));
-
-  if (tbl)
-    table= tbl;
-  else if (open_event_table(thd, TL_READ, &table))
-  {
-    my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
-    ret= EVEX_GENERAL_ERROR;
-    goto done;
-  }
-
-  if ((ret= evex_db_find_event_by_name(thd, dbname, name, table)))
-  {
-    my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
-    goto done;
-  }
-  et= new Event_timed;
-
-  /*
-    1)The table should not be closed beforehand. ::load_from_row() only loads
-      and does not compile
-
-    2)::load_from_row() is silent on error therefore we emit error msg here
-  */
-  if ((ret= et->load_from_row(table)))
-  {
-    my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
-    goto done;
-  }
-
-done:
-  if (ret)
-  {
-    delete et;
-    et= NULL;
-  }
-  /* don't close the table if we haven't opened it ourselves */
-  if (!tbl && table)
-    close_thread_tables(thd);
-  *ett= et;
-  DBUG_RETURN(ret);
-}
-
-
-int
-Event_db_repository::init_repository()
-{
-  return 0;
-}
-
-
-void
-Event_db_repository::deinit_repository()
-{
-}
-
-
-/*
   Open mysql.event table for read
 
   SYNOPSIS
     Events::open_event_table()
-    thd         Thread context
-    lock_type   How to lock the table
-    table       We will store the open table here
+    thd         [in]  Thread context
+    lock_type   [in]  How to lock the table
+    table       [out] We will store the open table here
 
   RETURN VALUE
     1   Cannot lock table
@@ -574,33 +458,26 @@ Event_db_repository::open_event_table(TH
    Checks parameters which we got from the parsing phase.
 
    SYNOPSIS
-     evex_check_params()
+     check_parse_params()
        thd            THD
        et             event's data
   
    RETURNS
      0                OK
-     EVEX_BAD_PARAMS  Error
-  
-   REMARKS
-     Issues error messages
+     EVEX_BAD_PARAMS  Error (reported)
 */
 
-int
-evex_check_params(THD *thd, Event_parse_data *parse_data)
+static int
+check_parse_params(THD *thd, Event_parse_data *parse_data)
 {
   const char *pos= NULL;
   Item *bad_item;
+  int res;
 
-  DBUG_ENTER("evex_check_params");
-  DBUG_PRINT("info", ("execute_at=0x%d expr=0x%d starts=0x%d ends=0x%d",
-                      parse_data->item_execute_at,
-                      parse_data->item_expression,
-                      parse_data->item_starts,
-                      parse_data->item_ends));
+  DBUG_ENTER("check_parse_params");
 
-  parse_data->init_name(thd, parse_data->identifier);
-  parse_data->init_definer(thd);
+  if (parse_data->check_parse_data(thd))
+    DBUG_RETURN(EVEX_BAD_PARAMS);
 
   if (!parse_data->dbname.str ||
       (thd->lex->sql_command == SQLCOM_ALTER_EVENT && thd->lex->spname &&
@@ -617,68 +494,7 @@ evex_check_params(THD *thd, Event_parse_
                      is_schema_db(thd->lex->spname->m_db.str)))))
     DBUG_RETURN(EVEX_BAD_PARAMS);
 
-  if (parse_data->item_execute_at)
-  {
-    DBUG_PRINT("info", ("ONE TIME"));
-    if (parse_data->init_execute_at(thd, parse_data->item_execute_at))
-    {
-      pos= "AT";
-      bad_item= parse_data->item_execute_at;
-      goto wrong_value;
-    }
-  }
-  else
-  {
-    int res;
-    DBUG_PRINT("info", ("RECURRING"));
-
-    if (parse_data->item_expression &&
-        (res= parse_data->init_interval(thd, parse_data->item_expression,
-                                        parse_data->interval)))
-    {
-      switch (res) {
-      case EVEX_BAD_PARAMS:
-        my_error(ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG, MYF(0));
-        break;
-      case EVEX_MICROSECOND_UNSUP:
-        my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND");
-        break;
-      default:
-        pos= "INTERVAL";
-        bad_item= parse_data->item_expression;
-        goto wrong_value;
-      }
-      DBUG_RETURN(EVEX_BAD_PARAMS);
-    }
-
-    if (parse_data->item_starts &&
-        parse_data->init_starts(thd, parse_data->item_starts))
-    {
-      pos= "STARTS";
-      bad_item= parse_data->item_starts;
-      goto wrong_value;
-    }
-
-    if (parse_data->item_ends &&
-        parse_data->init_ends(thd, parse_data->item_ends))
-    {
-      /*
-        despite the error name the value is
-        eng "ENDS is either invalid or before STARTS"
-      */
-      my_error(ER_EVENT_ENDS_BEFORE_STARTS, MYF(0));
-      DBUG_RETURN(EVEX_BAD_PARAMS);
-    }
-  }
   DBUG_RETURN(0);
-wrong_value:
-  {
-    char buff[120];
-    String str(buff,(uint32) sizeof(buff), system_charset_info);
-    String *str2= bad_item->fixed? bad_item->val_str(&str):NULL;
-    my_error(ER_WRONG_VALUE, MYF(0), pos, str2? str2->c_ptr():"NULL");
-    DBUG_RETURN(EVEX_BAD_PARAMS);
-  }
 }
 
 
@@ -687,18 +503,18 @@ wrong_value:
 
   SYNOPSIS
     Event_db_repository::create_event()
-      thd             THD
-      et              Event_timed object containing information for the event
-      create_if_not   If an warning should be generated in case event exists
-      rows_affected   How many rows were affected
+      thd             [in]  THD
+      et              [in]  Object containing info about the event
+      create_if_not   [in]  Whether to generate anwarning in case event exists
+      rows_affected   [out] How many rows were affected
 
   RETURN VALUE
                      0 - OK
     EVEX_GENERAL_ERROR - Failure
 
   DESCRIPTION 
-    Creates an event. Relies on evex_fill_row which is shared with
-    db_update_event. The name of the event is inside "et".
+    Creates an event. Relies on mysql_event_fill_row which is shared with
+    ::update_event. The name of the event is inside "et".
 */
 
 int
@@ -709,7 +525,7 @@ Event_db_repository::create_event(THD *t
   CHARSET_INFO *scs= system_charset_info;
   TABLE *table;
   char olddb[128];
-  bool dbchanged= false;
+  bool dbchanged= FALSE;
   DBUG_ENTER("Event_db_repository::create_event");
 
   *rows_affected= 0;
@@ -720,15 +536,14 @@ Event_db_repository::create_event(THD *t
     goto err;
   }
 
-  if (evex_check_params(thd, parse_data))
+  if (check_parse_params(thd, parse_data))
     goto err;
 
   DBUG_PRINT("info", ("name: %.*s", parse_data->name.length,
              parse_data->name.str));
 
   DBUG_PRINT("info", ("check existance of an event with the same name"));
-  if (!evex_db_find_event_by_name(thd, parse_data->dbname,
-                                  parse_data->name, table))
+  if (!find_event_by_name(thd, parse_data->dbname, parse_data->name, table))
   {
     if (create_if_not)
     {
@@ -784,10 +599,10 @@ Event_db_repository::create_event(THD *t
   ((Field_timestamp *)table->field[ET_FIELD_CREATED])->set_time();
 
   /*
-    evex_fill_row() calls my_error() in case of error so no need to
+    mysql_event_fill_row() calls my_error() in case of error so no need to
     handle it here
   */
-  if ((ret= evex_fill_row(thd, table, parse_data, false)))
+  if ((ret= mysql_event_fill_row(thd, table, parse_data, FALSE)))
     goto err; 
 
   /* Close active transaction only if We are going to modify disk */
@@ -800,16 +615,6 @@ Event_db_repository::create_event(THD *t
     goto err;
   }
 
-#ifdef USE_THIS_CODE_AS_TEMPLATE_WHEN_EVENT_REPLICATION_IS_AGREED
-  if (mysql_bin_log.is_open())
-  {
-    thd->clear_error();
-    /* Such a statement can always go directly to binlog, no trans cache */
-    thd->binlog_query(THD::MYSQL_QUERY_TYPE, thd->query, thd->query_length,
-                      FALSE, FALSE);
-  }
-#endif
-
   *rows_affected= 1;
 ok:
   if (dbchanged)
@@ -838,7 +643,7 @@ err:
 
   RETURN VALUE
     0  OK
-    EVEX_GENERAL_ERROR  Error occured (my_error() called)
+    EVEX_GENERAL_ERROR  Error occured and reported
 
   NOTES
     sp_name is passed since this is the name of the event to
@@ -860,7 +665,7 @@ Event_db_repository::update_event(THD *t
     goto err;
   }
 
-  if (evex_check_params(thd, parse_data))
+  if (check_parse_params(thd, parse_data))
     goto err;
 
   DBUG_PRINT("info", ("dbname: %s", parse_data->dbname.str));
@@ -879,7 +684,7 @@ Event_db_repository::update_event(THD *t
       goto err;
     }
 
-    if (!evex_db_find_event_by_name(thd,new_name->m_db,new_name->m_name,table))
+    if (!find_event_by_name(thd, new_name->m_db, new_name->m_name, table))
     {
       my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->m_name.str);
       goto err;
@@ -904,10 +709,10 @@ Event_db_repository::update_event(THD *t
   table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
 
   /*
-    evex_fill_row() calls my_error() in case of error so no need to
+    mysql_event_fill_row() calls my_error() in case of error so no need to
     handle it here
   */
-  if ((ret= evex_fill_row(thd, table, parse_data, true)))
+  if ((ret= mysql_event_fill_row(thd, table, parse_data, TRUE)))
     goto err;
 
   if (new_name)
@@ -944,11 +749,12 @@ err:
 
   SYNOPSIS
     Event_db_repository::drop_event()
-      thd             THD
-      db              database name
-      name            event's name
-      drop_if_exists  if set and the event not existing => warning onto the stack
-      rows_affected   affected number of rows is returned heres
+      thd             [in]  THD
+      db              [in]  Database name
+      name            [in]  Event's name
+      drop_if_exists  [in]  If set and the event not existing => warning
+                            onto the stack
+      rows_affected   [out] Affected number of rows is returned heres
 
   RETURN VALUE
     0   OK
@@ -974,17 +780,16 @@ Event_db_repository::drop_event(THD *thd
     goto done;
   }
 
-  if (!(ret= evex_db_find_event_by_name(thd, db, name, table)))
-  {
-    /* Close active transaction only if We are going to modify disk */
+  switch ((ret= find_event_by_name(thd, db, name, table))) {
+  case 0:
+    /* Close active transaction only if we are actually going to modify disk */
     if ((ret= end_active_trans(thd)))
-      goto done;
+      break;
 
     if ((ret= table->file->ha_delete_row(table->record[0])))
       my_error(ER_EVENT_CANNOT_DELETE, MYF(0));
-  }
-  else if (ret == EVEX_KEY_NOT_FOUND)
-  { 
+    break;
+  case EVEX_KEY_NOT_FOUND:
     if (drop_if_exists)
     {
       push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
@@ -993,19 +798,34 @@ Event_db_repository::drop_event(THD *thd
       ret= 0;
     } else
       my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
+    break;
+  default:
+    ;
   }
 
 done:
-  /*
-    evex_drop_event() is used by Event_timed::drop therefore
-    we have to close our thread tables.
-  */
   close_thread_tables(thd);
   thd->restore_backup_open_tables_state(&backup);
   DBUG_RETURN(ret);
 }
 
 
+/*
+  Positions the internal pointer of `table` to the place where (db, name)
+  is stored.
+
+  SYNOPSIS
+    Event_db_repository::find_event_by_name()
+      thd    Thread
+      db     Schema
+      name   Event name
+      table  Opened mysql.event
+
+  RETURN VALUE
+    0                   OK
+    EVEX_KEY_NOT_FOUND  No such event
+*/
+
 int
 Event_db_repository::find_event_by_name(THD *thd, LEX_STRING db,
                                         LEX_STRING name, TABLE *table)
@@ -1043,25 +863,31 @@ Event_db_repository::find_event_by_name(
 }
 
 
-int
-Event_db_repository::drop_schema_events(THD *thd, LEX_STRING schema)
-{
-  return drop_events_by_field(thd, ET_FIELD_DB, schema);
-}
+/*
+  Drops all events in the selected database, from mysql.event.
 
+  SYNOPSIS
+    Event_db_repository::drop_schema_events()
+      thd     Thread
+      schema  The database to clean from events
+
+  RETURN VALUE
+    0  OK
+   !0  Error (Reported)
+*/
 
 int
-Event_db_repository::drop_user_events(THD *thd, LEX_STRING definer)
+Event_db_repository::drop_schema_events(THD *thd, LEX_STRING schema)
 {
-  return drop_events_by_field(thd, ET_FIELD_DEFINER, definer);
+  return drop_events_by_field(thd, ET_FIELD_DB, schema);
 }
 
 
 /*
-  Drops all events in the selected database, from mysql.event.
+  Drops all events by field which has specific value of the field
 
   SYNOPSIS
-    drop_events_from_table_by_field()
+    Event_db_repository::drop_events_by_field()
       thd         Thread
       table       mysql.event TABLE
       field       Which field of the row to use for matching
@@ -1116,56 +942,63 @@ Event_db_repository::drop_events_by_fiel
 
 
 /*
-  Looks for a named event in mysql.event and then loads it from
-  the table, compiles and inserts it into the cache.
+  Looks for a named event in mysql.event and in case of success returns
+  an object will data loaded from the table.
 
   SYNOPSIS
-    Event_db_repository::load_named_event_timed()
-      thd      THD
-      etn      The name of the event to load and compile on scheduler's root
-      etn_new  The loaded event
+    Event_db_repository::find_event()
+      thd   [in]  THD
+      name  [in]  The name of the event to find
+      ett   [out] Event's data if event is found
+      tbl   [in]  TABLE object to use when not NULL
+
+  NOTES
+    1) Use sp_name for look up, return in **ett if found
+    2) tbl is not closed at exit
 
   RETURN VALUE
-    NULL       Error during compile or the event is non-enabled.
-    otherwise  Address
+    0  ok     In this case *ett is set to the event
+    #  error  *ett == 0
 */
 
 int
-Event_db_repository::load_named_event_timed(THD *thd, LEX_STRING dbname,
-                                            LEX_STRING name,
-                                            Event_timed **etn_new)
+Event_db_repository::find_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
+                                Event_basic *et)
 {
-  int ret= 0;
-  MEM_ROOT *tmp_mem_root;
-  Event_timed *et_loaded= NULL;
-  Open_tables_state backup;
+  TABLE *table;
+  int ret;
+  DBUG_ENTER("Event_db_repository::find_event");
+  DBUG_PRINT("enter", ("name: %*s", name.length, name.str));
 
-  DBUG_ENTER("Event_db_repository::load_named_event_timed");
-  DBUG_PRINT("enter",("thd=%p name:%*s",thd, name.length, name.str));
+  if (open_event_table(thd, TL_READ, &table))
+  {
+    my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
+    ret= EVEX_GENERAL_ERROR;
+    goto done;
+  }
 
-  thd->reset_n_backup_open_tables_state(&backup);
-  /* No need to use my_error() here because db_find_event() has done it */
-  ret= find_event(thd, dbname, name, &et_loaded, NULL);
-  thd->restore_backup_open_tables_state(&backup);
-  /* In this case no memory was allocated so we don't need to clean */
-  if (ret)
-    DBUG_RETURN(OP_LOAD_ERROR);
+  if ((ret= find_event_by_name(thd, dbname, name, table)))
+  {
+    my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
+    goto done;
+  }
+  /*
+    1)The table should not be closed beforehand. ::load_from_row() only loads
+      and does not compile
 
-  if (et_loaded->status != Event_timed::ENABLED)
+    2)::load_from_row() is silent on error therefore we emit error msg here
+  */
+  if ((ret= et->load_from_row(table)))
   {
-    /*
-      We don't load non-enabled events.
-      In db_find_event() `et_new` was allocated on the heap and not on
-      scheduler_root therefore we delete it here.
-    */
-    delete et_loaded;
-    DBUG_RETURN(OP_DISABLED_EVENT);
+    my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
+    goto done;
   }
 
-  et_loaded->compute_next_execution_time();
-  *etn_new= et_loaded;
+done:
+  if (table)
+    close_thread_tables(thd);
 
-  DBUG_RETURN(OP_OK);
+  DBUG_RETURN(ret);
 }
 
 
@@ -1174,50 +1007,34 @@ Event_db_repository::load_named_event_ti
   the table, compiles and inserts it into the cache.
 
   SYNOPSIS
-    Event_db_repository::load_named_event_job()
-      thd      THD
-      etn      The name of the event to load and compile on scheduler's root
-      etn_new  The loaded event
+    Event_db_repository::load_named_event()
+      thd      [in]  THD
+      dbname   [in]  Event's db name
+      name     [in]  Event's name
+      etn_new  [out] The loaded event
 
   RETURN VALUE
-    NULL       Error during compile or the event is non-enabled.
-    otherwise  Address
+    OP_OK          OK
+    OP_LOAD_ERROR  Error during loading from disk
 */
 
 int
-Event_db_repository::load_named_event_job(THD *thd, LEX_STRING dbname,
-                                          LEX_STRING name,
-                                          Event_job_data **etn_new)
+Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname,
+                                      LEX_STRING name, Event_basic *etn)
 {
   int ret= 0;
-  MEM_ROOT *tmp_mem_root;
-  Event_timed *et_loaded= NULL;
   Open_tables_state backup;
 
-  DBUG_ENTER("Event_db_repository::load_named_event_job");
-  DBUG_PRINT("enter",("thd=%p name:%*s",thd, name.length, name.str));
-#if 0
+  DBUG_ENTER("Event_db_repository::load_named_event");
+  DBUG_PRINT("enter",("thd=0x%lx name:%*s",thd, name.length, name.str));
+
   thd->reset_n_backup_open_tables_state(&backup);
-  /* No need to use my_error() here because db_find_event() has done it */
-  ret= find_event(thd, dbname, name, &et_loaded, NULL);
+  /* No need to use my_error() here because find_event() has done it */
+  ret= find_event(thd, dbname, name, etn);
   thd->restore_backup_open_tables_state(&backup);
   /* In this case no memory was allocated so we don't need to clean */
   if (ret)
     DBUG_RETURN(OP_LOAD_ERROR);
 
-  if (et_loaded->status != Event_timed::ENABLED)
-  {
-    /*
-      We don't load non-enabled events.
-      In db_find_event() `et_new` was allocated on the heap and not on
-      scheduler_root therefore we delete it here.
-    */
-    delete et_loaded;
-    DBUG_RETURN(OP_DISABLED_EVENT);
-  }
-
-  et_loaded->compute_next_execution_time();
-  *etn_new= et_loaded;
-#endif
   DBUG_RETURN(OP_OK);
 }

--- 1.6/sql/event_db_repository.h	2006-07-05 17:12:41 +02:00
+++ 1.7/sql/event_db_repository.h	2006-07-10 13:44:33 +02:00
@@ -39,11 +39,6 @@ enum enum_events_table_field
 
 
 int
-evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
-                           const LEX_STRING ev_name,
-                           TABLE *table);
-
-int
 events_table_index_read_for_db(THD *thd, TABLE *schema_table,
                                TABLE *event_table);
 
@@ -53,22 +48,13 @@ events_table_scan_all(THD *thd, TABLE *s
 int
 fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */);
 
-class Event_timed;
+class Event_basic;
 class Event_parse_data;
-class Event_queue_element;
-class Event_job_data;
 
 class Event_db_repository
 {
 public:
   Event_db_repository(){}
-  ~Event_db_repository(){}
-
-  int
-  init_repository();
-
-  void
-  deinit_repository();
 
   int
   create_event(THD *thd, Event_parse_data *parse_data, my_bool create_if_not,
@@ -85,19 +71,10 @@ public:
   drop_schema_events(THD *thd, LEX_STRING schema);
 
   int
-  drop_user_events(THD *thd, LEX_STRING definer);
-
-  int
-  find_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_timed **ett,
-             TABLE *tbl);
-
-  int
-  load_named_event_timed(THD *thd, LEX_STRING dbname, LEX_STRING name,
-                         Event_timed **etn_new);
+  find_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_basic *et);
 
   int
-  load_named_event_job(THD *thd, LEX_STRING dbname, LEX_STRING name,
-                       Event_job_data **etn_new);
+  load_named_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_basic *et);
 
   int
   find_event_by_name(THD *thd, LEX_STRING db, LEX_STRING name, TABLE *table);

--- 1.4/sql/event_queue.cc	2006-07-05 17:12:41 +02:00
+++ 1.5/sql/event_queue.cc	2006-07-10 13:44:33 +02:00
@@ -36,16 +36,16 @@
 
 
 /*
-  Compares the execute_at members of 2 Event_timed instances.
+  Compares the execute_at members of 2 Event_queue_element instances.
   Used as callback for the prioritized queue when shifting
   elements inside.
 
   SYNOPSIS
-    event_timed_compare_q()
+    event_queue_element_data_compare_q()
   
       vptr - not used (set it to NULL)
-      a    - first Event_timed object
-      b    - second Event_timed object
+      a    - first Event_queue_element object
+      b    - second Event_queue_element object
 
   RETURN VALUE
    -1   - a->execute_at < b->execute_at
@@ -57,14 +57,13 @@
 */
 
 static int 
-event_timed_compare_q(void *vptr, byte* a, byte *b)
+event_queue_element_compare_q(void *vptr, byte* a, byte *b)
 {
-  return my_time_compare(&((Event_timed *)a)->execute_at,
-                         &((Event_timed *)b)->execute_at);
+  return my_time_compare(&((Event_queue_element *)a)->execute_at,
+                         &((Event_queue_element *)b)->execute_at);
 }
 
 
-
 /*
   Constructor of class Event_queue.
 
@@ -79,6 +78,120 @@ Event_queue::Event_queue()
   mutex_queue_data_locked= FALSE;
 }
 
+
+/*
+  Inits mutexes.
+
+  SYNOPSIS
+    Event_queue::init_mutexes()
+*/
+
+void
+Event_queue::init_mutexes()
+{
+  pthread_mutex_init(&LOCK_event_queue, MY_MUTEX_INIT_FAST);
+}
+
+
+/*
+  Destroys mutexes.
+
+  SYNOPSIS
+    Event_queue::deinit_mutexes()
+*/
+
+void
+Event_queue::deinit_mutexes()
+{
+  pthread_mutex_destroy(&LOCK_event_queue);
+}
+
+
+/*
+  Signals the main scheduler thread that the queue has changed
+  its state.
+
+  SYNOPSIS
+    Event_queue::notify_observers()
+*/
+
+void
+Event_queue::notify_observers()
+{
+  DBUG_ENTER("Event_queue::notify_observers");
+  DBUG_PRINT("info", ("Signalling change of the queue"));
+  scheduler->queue_changed();
+  DBUG_VOID_RETURN;
+}
+
+
+/*
+  Inits the queue
+
+  SYNOPSIS
+    Event_queue::init()
+
+  RETURN VALUE
+    FALSE  OK
+    TRUE   Error
+*/
+
+bool
+Event_queue::init_queue(Event_db_repository *db_repo, Event_scheduler_ng *sched)
+{
+  int i= 0;
+  bool ret= FALSE;
+  DBUG_ENTER("Event_queue::init_queue");
+  DBUG_PRINT("enter", ("this=0x%lx", this));
+
+  LOCK_QUEUE_DATA();
+  db_repository= db_repo;
+  scheduler= sched;
+
+  if (init_queue_ex(&queue, 30 /*num_el*/, 0 /*offset*/, 0 /*smallest_on_top*/,
+                    event_queue_element_compare_q, NULL, 30 /*auto_extent*/))
+  {
+    sql_print_error("SCHEDULER: Can't initialize the execution queue");
+    ret= TRUE;
+    goto end;
+  }
+
+  if (sizeof(my_time_t) != sizeof(time_t))
+  {
+    sql_print_error("SCHEDULER: sizeof(my_time_t) != sizeof(time_t) ."
+                    "The scheduler may not work correctly. Stopping.");
+    DBUG_ASSERT(0);
+    ret= TRUE;
+    goto end;
+  }
+
+end:
+  UNLOCK_QUEUE_DATA();
+  DBUG_RETURN(ret);
+}
+
+
+/*
+  Deinits the queue
+
+  SYNOPSIS
+    Event_queue::deinit_queue()
+*/
+
+void
+Event_queue::deinit_queue()
+{
+  DBUG_ENTER("Event_queue::deinit_queue");
+
+  LOCK_QUEUE_DATA();
+  empty_queue();
+  delete_queue(&queue);
+  UNLOCK_QUEUE_DATA();
+
+  DBUG_VOID_RETURN;
+}
+
+
 /*
   Creates an event in the scheduler queue
 
@@ -90,28 +203,31 @@ Event_queue::Event_queue()
   RETURN VALUE
     OP_OK             OK or scheduler not working
     OP_LOAD_ERROR     Error during loading from disk
-    OP_ALREADY_EXISTS Event already in the queue    
 */
 
 int
-Event_queue::create_event(THD *thd, Event_parse_data *et)
+Event_queue::create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
 {
   int res;
-  Event_timed *et_new;
+  Event_queue_element *element_new;
   DBUG_ENTER("Event_queue::create_event");
-  DBUG_PRINT("enter", ("thd=%p et=%p lock=%p",thd,et, &LOCK_event_queue));
+  DBUG_PRINT("enter", ("thd=0x%lx et=%s.%s",thd, dbname.str, name.str));
 
-  res= db_repository->load_named_event_timed(thd, et->dbname, et->name, &et_new);
-  LOCK_QUEUE_DATA();
-  if (!res)
+  element_new= new Event_queue_element();
+  res= db_repository->load_named_event(thd, dbname, name, element_new);
+  if (res || element_new->status == Event_queue_element::DISABLED)
+    delete element_new;
+  else
   {
-    DBUG_PRINT("info", ("new event in the queue %p", et_new));
-    queue_insert_safe(&queue, (byte *) et_new);
+    element_new->compute_next_execution_time();
+
+    LOCK_QUEUE_DATA();
+    DBUG_PRINT("info", ("new event in the queue 0x%lx", element_new));
+    queue_insert_safe(&queue, (byte *) element_new);
+    UNLOCK_QUEUE_DATA();
+
     notify_observers();
   }
-  else if (res == OP_DISABLED_EVENT)
-    res= OP_OK;
-  UNLOCK_QUEUE_DATA();
 
   DBUG_RETURN(res);
 }
@@ -123,9 +239,10 @@ Event_queue::create_event(THD *thd, Even
   SYNOPSIS
     Event_queue::update_event()
       thd        Thread
-      et         The event to replace(add) into the queue
-      new_schema New schema, in case of RENAME TO
-      new_name   New name, in case of RENAME TO
+      dbname     Schema of the event
+      name       Name of the event
+      new_schema New schema, in case of RENAME TO, otherwise NULL
+      new_name   New name, in case of RENAME TO, otherwise NULL
 
   RETURN VALUE
     OP_OK             OK or scheduler not working
@@ -133,43 +250,57 @@ Event_queue::create_event(THD *thd, Even
 */
 
 int
-Event_queue::update_event(THD *thd, Event_parse_data *et,
+Event_queue::update_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
                           LEX_STRING *new_schema, LEX_STRING *new_name)
 {
   int res;
-  Event_timed *et_old= NULL, *et_new= NULL;
+  Event_queue_element *element_old= NULL,
+                      *element_new;
 
   DBUG_ENTER("Event_queue::update_event");
-  DBUG_PRINT("enter", ("thd=%p et=%p et=[%s.%s] lock=%p",
-             thd, et, et->dbname.str, et->name.str, &LOCK_event_queue));
+  DBUG_PRINT("enter", ("thd=0x%lx et=[%s.%s]", thd, dbname.str, name.str));
 
-  res= db_repository->
-            load_named_event_timed(thd, new_schema?*new_schema:et->dbname,
-                                   new_name? *new_name:et->name, &et_new);
+  element_new= new Event_queue_element();
 
-  if (res && res != OP_DISABLED_EVENT)
+  res= db_repository->load_named_event(thd, new_schema? *new_schema:dbname,
+                                       new_name? *new_name:name, element_new);
+  if (res)
+  {
+    delete element_new;
     goto end;
+  }
+  else if (element_new->status == Event_queue_element::DISABLED)
+  {
+    DBUG_PRINT("info", ("The event is disabled."));
+    /*
+      Destroy the object but don't skip to end: because we may have to remove
+      object from the cache.
+    */
+    delete element_new;
+    element_new= NULL;
+  }
+  else
+    element_new->compute_next_execution_time();
 
   LOCK_QUEUE_DATA();
-  if (!(et_old= find_event(et->dbname, et->name, TRUE)))
+  if (!(element_old= find_event(dbname, name, TRUE)))
   {
-    DBUG_PRINT("info", ("%s.%s not found cached, probably was DISABLED",
-                        et->dbname.str, et->name.str));
+    DBUG_PRINT("info", ("%s.%s not cached, probably was DISABLED",
+                        dbname.str, name.str));
   }
-
-  if (!res)
+  /* If not disabled event */
+  if (element_new)
   {
-    DBUG_PRINT("info", ("new event in the queue %p old %p", et_new, et_old));
-    queue_insert_safe(&queue, (byte *) et_new);
+    DBUG_PRINT("info", ("new event in the Q 0x%lx old 0x%lx",
+                        element_new, element_old));
+    queue_insert_safe(&queue, (byte *) element_new);
   }
-  else if (res == OP_DISABLED_EVENT)
-    res= OP_OK;
   UNLOCK_QUEUE_DATA();
 
   notify_observers();
 
-  if (et_old)
-    delete et_old;
+  if (element_old)
+    delete element_old;
 end:
   DBUG_PRINT("info", ("res=%d", res));
   DBUG_RETURN(res);
@@ -181,35 +312,34 @@ end:
 
   SYNOPSIS
     Event_queue::drop_event()
-      thd    Thread
-      name   The event to drop
-
-  RETURN VALUE
-    FALSE OK (replaced or scheduler not working)
-    TRUE  Failure
+      thd     Thread
+      dbname  Schema of the event to drop
+      name    Name of the event to drop
 */
 
-bool
-Event_queue::drop_event(THD *thd, sp_name *name)
+void
+Event_queue::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
 {
   int res;
-  Event_timed *et_old;
+  Event_queue_element *element;
   DBUG_ENTER("Event_queue::drop_event");
-  DBUG_PRINT("enter", ("thd=%p name=%p lock=%p", thd, name,
-             &LOCK_event_queue));
+  DBUG_PRINT("enter", ("thd=0x%lx name=0x%lx", thd, name));
 
   LOCK_QUEUE_DATA();
-  if (!(et_old= find_event(name->m_db, name->m_name, TRUE)))
-    DBUG_PRINT("info", ("No such event found, probably DISABLED"));
+  element= find_event(dbname, name, TRUE);
   UNLOCK_QUEUE_DATA();
-  if (et_old)
-    delete et_old;
+
+  if (element)
+    delete element;
+  else
+    DBUG_PRINT("info", ("No such event found, probably DISABLED"));
+  
   /*
     We don't signal here because the scheduler will catch the change
     next time it wakes up.
   */
 
-  DBUG_RETURN(FALSE);
+  DBUG_VOID_RETURN;
 }
 
 
@@ -232,7 +362,7 @@ Event_queue::drop_event(THD *thd, sp_nam
     (signalling COND_new_work for instance).
 */
 
-Event_timed *
+Event_queue_element *
 Event_queue::find_event(LEX_STRING db, LEX_STRING name, bool remove_from_q)
 {
   uint i;
@@ -240,10 +370,10 @@ Event_queue::find_event(LEX_STRING db, L
 
   for (i= 0; i < queue.elements; ++i)
   {
-    Event_timed *et= (Event_timed *) queue_element(&queue, i);
+    Event_queue_element *et= (Event_queue_element *) queue_element(&queue, i);
     DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?", db.str, name.str,
                         et->dbname.str, et->name.str));
-    if (event_timed_identifier_equal(db, name, et))
+    if (event_basic_identifier_equal(db, name, et))
     {
       if (remove_from_q)
         queue_remove(&queue, i);
@@ -274,7 +404,7 @@ Event_queue::find_event(LEX_STRING db, L
 
 void
 Event_queue::drop_matching_events(THD *thd, LEX_STRING pattern,
-                           bool (*comparator)(Event_timed *,LEX_STRING *))
+                           bool (*comparator)(LEX_STRING *, Event_basic *))
 {
   DBUG_ENTER("Event_queue::drop_matching_events");
   DBUG_PRINT("enter", ("pattern=%*s state=%d", pattern.length, pattern.str));
@@ -282,9 +412,9 @@ Event_queue::drop_matching_events(THD *t
   uint i= 0;   
   while (i < queue.elements)
   {
-    Event_timed *et= (Event_timed *) queue_element(&queue, i);
+    Event_queue_element *et= (Event_queue_element *) queue_element(&queue, i);
     DBUG_PRINT("info", ("[%s.%s]?", et->dbname.str, et->name.str));
-    if (comparator(et, &pattern))
+    if (comparator(&pattern, et))
     {
       /*
         The queue is ordered. If we remove an element, then all elements after
@@ -331,67 +461,20 @@ Event_queue::drop_schema_events(THD *thd
 {
   DBUG_ENTER("Event_queue::drop_schema_events");
   LOCK_QUEUE_DATA();
-  drop_matching_events(thd, schema, event_timed_db_equal);
+  drop_matching_events(thd, schema, event_basic_db_equal);
   UNLOCK_QUEUE_DATA();
   DBUG_VOID_RETURN;
 }
 
 
 /*
-  Wrapper for pthread_mutex_lock
-
-  SYNOPSIS
-    Event_queue::lock_data()
-      mutex Mutex to lock
-      line  The line number on which the lock is done
-
-  RETURN VALUE
-    Error code of pthread_mutex_lock()
-*/
-
-void
-Event_queue::lock_data(const char *func, uint line)
-{
-  DBUG_ENTER("Event_queue::lock_mutex");
-  DBUG_PRINT("enter", ("func=%s line=%u", func, line));
-  pthread_mutex_lock(&LOCK_event_queue);
-  mutex_last_locked_in_func= func;
-  mutex_last_locked_at_line= line;
-  mutex_queue_data_locked= TRUE;
-  DBUG_VOID_RETURN;
-}
-
-
-/*
-  Wrapper for pthread_mutex_unlock
-
-  SYNOPSIS
-    Event_queue::unlock_data()
-      mutex Mutex to unlock
-      line  The line number on which the unlock is done
-*/
-
-void
-Event_queue::unlock_data(const char *func, uint line)
-{
-  DBUG_ENTER("Event_queue::unlock_mutex");
-  DBUG_PRINT("enter", ("func=%s line=%u", func, line));
-  mutex_last_unlocked_at_line= line;
-  mutex_queue_data_locked= FALSE;
-  mutex_last_unlocked_in_func= func;
-  pthread_mutex_unlock(&LOCK_event_queue);
-  DBUG_VOID_RETURN;
-}
-
-
-/*
   Returns the number of elements in the queue
 
   SYNOPSIS
     Event_queue::events_count()
 
   RETURN VALUE
-    0  Number of Event_timed objects in the queue
+    Number of Event_queue_element objects in the queue
 */
 
 uint
@@ -408,31 +491,9 @@ Event_queue::events_count()
 
 
 /*
-  Returns the number of elements in the queue
-
-  SYNOPSIS
-    Event_queue::events_count_no_lock()
-
-  RETURN VALUE
-    0  Number of Event_timed objects in the queue
-*/
-
-uint
-Event_queue::events_count_no_lock()
-{
-  uint n;
-  DBUG_ENTER("Event_queue::events_count_no_lock");
-
-  n= queue.elements;
-
-  DBUG_RETURN(n);
-}
-
-
-/*
   Loads all ENABLED events from mysql.event into the prioritized
   queue. Called during scheduler main thread initialization. Compiles
-  the events. Creates Event_timed instances for every ENABLED event
+  the events. Creates Event_queue_element instances for every ENABLED event
   from mysql.event.
 
   SYNOPSIS
@@ -461,7 +522,7 @@ Event_queue::load_events_from_db(THD *th
   MEM_ROOT boot_root;
 
   DBUG_ENTER("Event_queue::load_events_from_db");
-  DBUG_PRINT("enter", ("thd=%p", thd));
+  DBUG_PRINT("enter", ("thd=0x%lx", thd));
 
   if ((ret= db_repository->open_event_table(thd, TL_READ, &table)))
   {
@@ -469,12 +530,11 @@ Event_queue::load_events_from_db(THD *th
     DBUG_RETURN(EVEX_OPEN_TABLE_FAILED);
   }
 
-  init_alloc_root(&boot_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
   init_read_record(&read_record_info, thd, table ,NULL,1,0);
   while (!(read_record_info.read_record(&read_record_info)))
   {
-    Event_timed *et;
-    if (!(et= new Event_timed))
+    Event_queue_element *et;
+    if (!(et= new Event_queue_element))
     {
       DBUG_PRINT("info", ("Out of memory"));
       clean_the_queue= TRUE;
@@ -489,13 +549,14 @@ Event_queue::load_events_from_db(THD *th
                       "Table probably corrupted");
       break;
     }
-    if (et->status != Event_timed::ENABLED)
+    if (et->status != Event_queue_element::ENABLED)
     {
       DBUG_PRINT("info",("%s is disabled",et->name.str));
       delete et;
       continue;
     }
-
+#if 0
+    init_alloc_root(&boot_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
     DBUG_PRINT("info", ("Event %s loaded from row. ", et->name.str));
 
     /* We load only on scheduler root just to check whether the body compiles */
@@ -514,6 +575,7 @@ Event_queue::load_events_from_db(THD *th
       et->free_sp();
       break;
     }
+    free_root(&boot_root, MYF(0));
 
     /* let's find when to be executed */
     if (et->compute_next_execution_time())
@@ -522,19 +584,17 @@ Event_queue::load_events_from_db(THD *th
                       " Skipping", et->dbname.str, et->name.str);
       continue;
     }
-
-    DBUG_PRINT("load_events_from_db", ("Adding %p to the exec list."));
+#endif
+    DBUG_PRINT("load_events_from_db", ("Adding 0x%lx to the exec list."));
     queue_insert_safe(&queue,  (byte *) et);
     count++;
   }
 end:
   end_read_record(&read_record_info);
-  free_root(&boot_root, MYF(0));
 
   if (clean_the_queue)
   {
-    for (count= 0; count < queue.elements; ++count)
-      queue_remove(&queue, 0);
+    empty_queue();
     ret= -1;
   }
   else
@@ -571,7 +631,7 @@ Event_queue::check_system_tables(THD *th
   bool ret;
 
   DBUG_ENTER("Event_queue::check_system_tables");
-  DBUG_PRINT("enter", ("thd=%p", thd));
+  DBUG_PRINT("enter", ("thd=0x%lx", thd));
 
   thd->reset_n_backup_open_tables_state(&backup);
 
@@ -618,123 +678,48 @@ Event_queue::check_system_tables(THD *th
 
 
 /*
-  Inits mutexes.
-
-  SYNOPSIS
-    Event_queue::init_mutexes()
-*/
-
-void
-Event_queue::init_mutexes()
-{
-  pthread_mutex_init(&LOCK_event_queue, MY_MUTEX_INIT_FAST);
-}
-
-
-/*
-  Destroys mutexes.
+  Recalculates activation times in the queue. There is one reason for
+  that. Because the values (execute_at) by which the queue is ordered are
+  changed by calls to compute_next_execution_time() on a request from the
+  scheduler thread, if it is not running then the values won't be updated.
+  Once the scheduler is started again the values has to be recalculated
+  so they are right for the current time.
 
   SYNOPSIS
-    Event_queue::deinit_mutexes()
+    Event_queue::recalculate_activation_times()
+      thd  Thread
 */
 
 void
-Event_queue::deinit_mutexes()
+Event_queue::recalculate_activation_times(THD *thd)
 {
-  pthread_mutex_destroy(&LOCK_event_queue);
-}
-
-
-/*
-  Signals the main scheduler thread that the queue has changed
-  its state.
-
-  SYNOPSIS
-    Event_queue::notify_observers()
-*/
-
-void
-Event_queue::notify_observers()
-{
-  DBUG_ENTER("Event_queue::notify_observers");
-  DBUG_PRINT("info", ("Signalling change of the queue"));
-  scheduler->queue_changed();
-  DBUG_VOID_RETURN;
-}
-
-
-/*
-  The implementation of full-fledged initialization.
-
-  SYNOPSIS
-    Event_queue::init()
-
-  RETURN VALUE
-    FALSE  OK
-    TRUE   Error
-*/
-
-bool
-Event_queue::init_queue(Event_db_repository *db_repo, Event_scheduler_ng *sched)
-{
-  int i= 0;
-  bool ret= FALSE;
-  DBUG_ENTER("Event_queue::init_queue");
-  DBUG_PRINT("enter", ("this=%p", this));
+  uint i;
+  DBUG_ENTER("Event_queue::recalculate_activation_times");
 
   LOCK_QUEUE_DATA();
-  db_repository= db_repo;
-  scheduler= sched;
-
-  if (init_queue_ex(&queue, 30 /*num_el*/, 0 /*offset*/, 0 /*smallest_on_top*/,
-                    event_timed_compare_q, NULL, 30 /*auto_extent*/))
-  {
-    sql_print_error("SCHEDULER: Can't initialize the execution queue");
-    ret= TRUE;
-    goto end;
-  }
-
-  if (sizeof(my_time_t) != sizeof(time_t))
+  DBUG_PRINT("info", ("%u loaded events to be recalculated", queue.elements));
+  for (i= 0; i < queue.elements; i++)
   {
-    sql_print_error("SCHEDULER: sizeof(my_time_t) != sizeof(time_t) ."
-                    "The scheduler may not work correctly. Stopping.");
-    DBUG_ASSERT(0);
-    ret= TRUE;
-    goto end;
+    ((Event_queue_element*)queue_element(&queue, i))->compute_next_execution_time();
+    ((Event_queue_element*)queue_element(&queue, i))->update_timing_fields(thd);
   }
-
-end:
-  UNLOCK_QUEUE_DATA();
-  DBUG_RETURN(ret);
-}
-
-
-void
-Event_queue::deinit_queue()
-{
-  DBUG_ENTER("Event_queue::deinit_queue");
-
-  LOCK_QUEUE_DATA();
-  empty_queue();
-  delete_queue(&queue);
+  queue_fix(&queue);
   UNLOCK_QUEUE_DATA();
 
   DBUG_VOID_RETURN;
 }
 
 
-void
-Event_queue::recalculate_queue(THD *thd)
-{
-  uint i;
-  for (i= 0; i < queue.elements; i++)
-  {
-    ((Event_timed*)queue_element(&queue, i))->compute_next_execution_time();
-    ((Event_timed*)queue_element(&queue, i))->update_fields(thd);
-  }
-  queue_fix(&queue);
-}
+/*
+  Empties the queue and destroys the Event_queue_element objects in the
+  queue.
 
+  SYNOPSIS
+    Event_queue::empty_queue()
+
+  NOTE
+    Should be called with LOCK_event_queue locked  
+*/
 
 void
 Event_queue::empty_queue()
@@ -743,9 +728,9 @@ Event_queue::empty_queue()
   DBUG_ENTER("Event_queue::empty_queue");
   DBUG_PRINT("enter", ("Purging the queue. %d element(s)", queue.elements));
   /* empty the queue */
-  for (i= 0; i < events_count_no_lock(); ++i)
+  for (i= 0; i < queue.elements; ++i)
   {
-    Event_timed *et= (Event_timed *) queue_element(&queue, i);
+    Event_queue_element *et= (Event_queue_element *) queue_element(&queue, i);
     delete et;
   }
   resize_queue(&queue, 0);
@@ -753,38 +738,17 @@ Event_queue::empty_queue()
 }
 
 
-Event_timed*
-Event_queue::get_top()
-{
-  return (Event_timed *)queue_top(&queue); 
-}
-
-
-void
-Event_queue::remove_top()
-{
-  queue_remove(&queue, 0);// 0 is top, internally 1
-}
-
-
-void
-Event_queue::top_changed()
-{
-  queue_replaced(&queue);
-}
-
-
 inline void
 Event_queue::dbug_dump_queue(time_t now)
 {
 #ifndef DBUG_OFF
-  Event_timed *et;
+  Event_queue_element *et;
   uint i;
   DBUG_PRINT("info", ("Dumping queue . Elements=%u", queue.elements));
   for (i = 0; i < queue.elements; i++)
   {
-    et= ((Event_timed*)queue_element(&queue, i));
-    DBUG_PRINT("info",("et=%p db=%s name=%s",et, et->dbname.str, et->name.str));
+    et= ((Event_queue_element*)queue_element(&queue, i));
+    DBUG_PRINT("info",("et=0x%lx db=%s name=%s",et, et->dbname.str, et->name.str));
     DBUG_PRINT("info", ("exec_at=%llu starts=%llu ends=%llu "
                " expr=%lld et.exec_at=%d now=%d (et.exec_at - now)=%d if=%d",
                TIME_to_ulonglong_datetime(&et->execute_at),
@@ -797,14 +761,14 @@ Event_queue::dbug_dump_queue(time_t now)
 #endif
 }
 
-Event_timed *
+Event_job_data *
 Event_queue::get_top_for_execution_if_time(THD *thd, time_t now,
                                            struct timespec *abstime)
 {
   struct timespec top_time;
-  Event_timed *et_new= NULL;
+  Event_job_data *et_new= NULL;
   DBUG_ENTER("Event_queue::get_top_for_execution_if_time");
-  DBUG_PRINT("enter", ("thd=%p now=%d", thd, now));
+  DBUG_PRINT("enter", ("thd=0x%lx now=%d", thd, now));
   abstime->tv_nsec= 0;
   LOCK_QUEUE_DATA();
   do {
@@ -816,28 +780,31 @@ Event_queue::get_top_for_execution_if_ti
     }
     dbug_dump_queue(now);
 
-    Event_timed *et= ((Event_timed*)queue_element(&queue, 0));
+    Event_queue_element *et= ((Event_queue_element*) queue_element(&queue, 0));
     top_time.tv_sec= sec_since_epoch_TIME(&et->execute_at);
 
     if (top_time.tv_sec <= now)
     {
       DBUG_PRINT("info", ("Ready for execution"));
       abstime->tv_sec= 0;
-      if ((res= db_repository->load_named_event_timed(thd, et->dbname, et->name,
-                                                      &et_new)))
+      et_new= new Event_job_data();
+      if ((res= db_repository->load_named_event(thd, et->dbname, et->name,
+                                                et_new)))
       {
+        delete et_new;
+        et_new= NULL;
         DBUG_ASSERT(0);
         break;
       }
 
       et->mark_last_executed(thd);
       if (et->compute_next_execution_time())
-        et->status= Event_timed::DISABLED;
+        et->status= Event_queue_element::DISABLED;
       DBUG_PRINT("info", ("event's status is %d", et->status));
 
-      et->update_fields(thd);
+      et->update_timing_fields(thd);
       if (((et->execute_at.year && !et->expression) || et->execute_at_null) ||
-          (et->status == Event_timed::DISABLED))
+          (et->status == Event_queue_element::DISABLED))
       {
         DBUG_PRINT("info", ("removing from the queue"));
         if (et->dropped)
@@ -857,12 +824,122 @@ Event_queue::get_top_for_execution_if_ti
   } while (0);
   UNLOCK_QUEUE_DATA();
   
-  DBUG_PRINT("info", ("returning. et_new=%p abstime.tv_sec=%d ", et_new,
+  DBUG_PRINT("info", ("returning. et_new=0x%lx abstime.tv_sec=%d ", et_new,
              abstime->tv_sec));
   if (et_new)
-    DBUG_PRINT("info", ("db=%s  name=%s definer=%s "
-               "et_new.execute_at=%lld", et_new->dbname.str, et_new->name.str,
-               et_new->definer.str,
-               TIME_to_ulonglong_datetime(&et_new->execute_at)));
+    DBUG_PRINT("info", ("db=%s  name=%s definer=%s",
+               et_new->dbname.str, et_new->name.str, et_new->definer.str));
   DBUG_RETURN(et_new);
+}
+
+
+/*
+  Auxiliary function for locking LOCK_event_queue. Used by the
+  LOCK_QUEUE_DATA macro
+
+  SYNOPSIS
+    Event_queue::lock_data()
+      func  Which function is requesting mutex lock
+      line  On which line mutex lock is requested
+*/
+
+void
+Event_queue::lock_data(const char *func, uint line)
+{
+  DBUG_ENTER("Event_queue::lock_data");
+  DBUG_PRINT("enter", ("func=%s line=%u", func, line));
+  pthread_mutex_lock(&LOCK_event_queue);
+  mutex_last_locked_in_func= func;
+  mutex_last_locked_at_line= line;
+  mutex_queue_data_locked= TRUE;
+  DBUG_VOID_RETURN;
+}
+
+
+/*
+  Auxiliary function for unlocking LOCK_event_queue. Used by the
+  UNLOCK_QUEUE_DATA macro
+
+  SYNOPSIS
+    Event_queue::unlock_data()
+      func  Which function is requesting mutex unlock
+      line  On which line mutex unlock is requested
+*/
+
+void
+Event_queue::unlock_data(const char *func, uint line)
+{
+  DBUG_ENTER("Event_queue::unlock_data");
+  DBUG_PRINT("enter", ("func=%s line=%u", func, line));
+  mutex_last_unlocked_at_line= line;
+  mutex_queue_data_locked= FALSE;
+  mutex_last_unlocked_in_func= func;
+  pthread_mutex_unlock(&LOCK_event_queue);
+  DBUG_VOID_RETURN;
+}
+
+
+/*
+  Dumps the internal status of the queue
+
+  SYNOPSIS
+    Event_queue::dump_internal_status()
+      thd  Thread
+
+  RETURN VALUE
+    FALSE  OK
+    TRUE   Error
+*/
+
+bool
+Event_queue::dump_internal_status(THD *thd)
+{
+  DBUG_ENTER("Event_queue::dump_internal_status");
+#ifndef DBUG_OFF
+  CHARSET_INFO *scs= system_charset_info;
+  Protocol *protocol= thd->protocol;
+  List<Item> field_list;
+  int ret;
+  char tmp_buff[5*STRING_BUFFER_USUAL_SIZE];
+  char int_buff[STRING_BUFFER_USUAL_SIZE];
+  String tmp_string(tmp_buff, sizeof(tmp_buff), scs);
+  String int_string(int_buff, sizeof(int_buff), scs);
+  tmp_string.length(0);
+  int_string.length(0);
+
+  /* workers_count */
+  protocol->prepare_for_resend();
+  protocol->store(STRING_WITH_LEN("queue element count"), scs);
+  int_string.set((longlong) queue.elements, scs);
+  protocol->store(&int_string);
+  ret= protocol->write();
+
+  /* queue_data_locked */
+  protocol->prepare_for_resend();
+  protocol->store(STRING_WITH_LEN("queue data locked"), scs);
+  int_string.set((longlong) mutex_queue_data_locked, scs);
+  protocol->store(&int_string);
+  ret= protocol->write();
+
+  /* last locked at*/
+  protocol->prepare_for_resend();
+  protocol->store(STRING_WITH_LEN("queue last locked at"), scs);
+  tmp_string.length(scs->cset->snprintf(scs, (char*) tmp_string.ptr(),
+                                        tmp_string.alloced_length(), "%s::%d",
+                                        mutex_last_locked_in_func,
+                                        mutex_last_locked_at_line));
+  protocol->store(&tmp_string);
+  ret= protocol->write();
+
+  /* last unlocked at*/
+  protocol->prepare_for_resend();
+  protocol->store(STRING_WITH_LEN("queue last unlocked at"), scs);
+  tmp_string.length(scs->cset->snprintf(scs, (char*) tmp_string.ptr(),
+                                        tmp_string.alloced_length(), "%s::%d",
+                                        mutex_last_unlocked_in_func,
+                                        mutex_last_unlocked_at_line));
+  protocol->store(&tmp_string);
+  ret= protocol->write();
+#endif
+  DBUG_RETURN(FALSE);
 }

--- 1.4/sql/event_queue.h	2006-07-05 17:12:41 +02:00
+++ 1.5/sql/event_queue.h	2006-07-10 13:44:33 +02:00
@@ -17,13 +17,12 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
 class sp_name;
-class Event_timed;
+class Event_basic;
 class Event_db_repository;
 class Event_job_data;
+class Event_queue_element;
 
 class THD;
-typedef bool * (*event_timed_identifier_comparator)(Event_timed*, Event_timed*);
-
 class Event_scheduler_ng;
 
 class Event_queue
@@ -46,14 +45,14 @@ public:
   /* Methods for queue management follow */
 
   int
-  create_event(THD *thd, Event_parse_data *et);
+  create_event(THD *thd, LEX_STRING dbname, LEX_STRING name);
 
   int
-  update_event(THD *thd, Event_parse_data *et, LEX_STRING *new_schema,
-               LEX_STRING *new_name);
+  update_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
+               LEX_STRING *new_schema, LEX_STRING *new_name);
 
-  bool
-  drop_event(THD *thd, sp_name *name);
+  void
+  drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name);
 
   void
   drop_schema_events(THD *thd, LEX_STRING schema);
@@ -61,32 +60,20 @@ public:
   uint
   events_count();
 
-  uint
-  events_count_no_lock();
-
   static bool
   check_system_tables(THD *thd);
 
   void
-  recalculate_queue(THD *thd);
-  
-  void
-  empty_queue();
+  recalculate_activation_times(THD *thd);
 
-  Event_timed *
+  Event_job_data *
   get_top_for_execution_if_time(THD *thd, time_t now, struct timespec *abstime);
- 
-  Event_timed*
-  get_top();
-  
-  void
-  remove_top();
-  
-  void
-  top_changed();
+
+  bool
+  dump_internal_status(THD *thd);
 
 protected:
-  Event_timed *
+  Event_queue_element *
   find_event(LEX_STRING db, LEX_STRING name, bool remove_from_q);
 
   int
@@ -94,14 +81,16 @@ protected:
 
   void
   drop_matching_events(THD *thd, LEX_STRING pattern,
-                       bool (*)(Event_timed *,LEX_STRING *));
+                       bool (*)(LEX_STRING *, Event_basic *));
+
+  void
+  empty_queue();
 
   /* LOCK_event_queue is the mutex which protects the access to the queue. */
   pthread_mutex_t LOCK_event_queue;
 
   Event_db_repository *db_repository;
 
-  
   uint mutex_last_locked_at_line;
   uint mutex_last_unlocked_at_line;
   const char* mutex_last_locked_in_func;
@@ -123,10 +112,8 @@ protected:
 
   Event_scheduler_ng *scheduler;
 
-//public:
-  /* The sorted queue with the Event_timed objects */
+  /* The sorted queue with the Event_job_data objects */
   QUEUE queue;
-
 };
 
 #endif /* _EVENT_QUEUE_H_ */

--- 1.2/sql/event_scheduler_ng.cc	2006-07-05 17:12:41 +02:00
+++ 1.3/sql/event_scheduler_ng.cc	2006-07-10 13:44:33 +02:00
@@ -30,6 +30,7 @@
 
 #define LOCK_SCHEDULER_DATA()   lock_data(SCHED_FUNC, __LINE__)
 #define UNLOCK_SCHEDULER_DATA() unlock_data(SCHED_FUNC, __LINE__)
+#define COND_STATE_WAIT(timer)  cond_wait(timer, SCHED_FUNC, __LINE__)
 
 extern pthread_attr_t connection_attrib;
 
@@ -52,28 +53,6 @@ LEX_STRING scheduler_states_names[] =
 };
 
 
-class Worker_thread_param
-{
-public:
-  Event_timed *et;
-  pthread_mutex_t LOCK_started;
-  pthread_cond_t COND_started;
-  bool started;
-
-  Worker_thread_param(Event_timed *etn):et(etn), started(FALSE)
-  {
-    pthread_mutex_init(&LOCK_started, MY_MUTEX_INIT_FAST);
-    pthread_cond_init(&COND_started, NULL);  
-  }
-
-  ~Worker_thread_param()
-  {
-    pthread_mutex_destroy(&LOCK_started);
-    pthread_cond_destroy(&COND_started);
-  }
-};
-
-
 /*
   Prints the stack of infos, warnings, errors from thd to
   the console so it can be fetched by the logs-into-tables and
@@ -81,12 +60,12 @@ public:
 
   SYNOPSIS
     evex_print_warnings
-      thd    - thread used during the execution of the event
-      et     - the event itself
+      thd  Thread used during the execution of the event
+      et   The event itself
 */
 
 static void
-evex_print_warnings(THD *thd, Event_timed *et)
+evex_print_warnings(THD *thd, Event_job_data *et)
 {
   MYSQL_ERROR *err;
   DBUG_ENTER("evex_print_warnings");
@@ -148,23 +127,22 @@ init_scheduler_thread(THD* thd)
   thd->security_ctx->db_access= 0;
   thd->security_ctx->host_or_ip= (char*)my_localhost;
   thd->security_ctx->set_user((char*)"event_scheduler");
-  my_net_init(&thd->net, 0);
+  my_net_init(&thd->net, NULL);
   thd->net.read_timeout= slave_net_timeout;
   thd->slave_thread= 0;
   thd->options|= OPTION_AUTO_IS_NULL;
   thd->client_capabilities|= CLIENT_MULTI_RESULTS;
-  VOID(pthread_mutex_lock(&LOCK_thread_count));
+  pthread_mutex_lock(&LOCK_thread_count);
   thd->thread_id= thread_id++;
   threads.append(thd);
   thread_count++;
   thread_running++;
-  VOID(pthread_mutex_unlock(&LOCK_thread_count));
+  pthread_mutex_unlock(&LOCK_thread_count);
 
   /*
     Guarantees that we will see the thread in SHOW PROCESSLIST though its
     vio is NULL.
   */
-  thd->system_thread= SYSTEM_THREAD_EVENT_SCHEDULER;
 
   thd->proc_info= "Initialized";
   thd->version= refresh_version;
@@ -174,6 +152,41 @@ init_scheduler_thread(THD* thd)
 }
 
 
+/*
+  Cleans up the THD and the threaded environment of the thread.
+
+  SYNOPSIS
+    deinit_event_thread()
+      thd  Thread
+*/
+
+static void
+deinit_event_thread(THD *thd)
+{
+  thd->proc_info= "Clearing";
+  DBUG_ASSERT(thd->net.buff != 0);
+  net_end(&thd->net);
+  DBUG_PRINT("exit", ("Scheduler thread finishing"));
+  pthread_mutex_lock(&LOCK_thread_count);
+  thread_count--;
+  thread_running--;
+  delete thd;
+  pthread_mutex_unlock(&LOCK_thread_count);
+
+  my_thread_end();
+}
+
+/*
+  Function that executes the scheduler,
+
+  SYNOPSIS
+    event_scheduler_ng_thread()
+      arg  Pointer to `struct scheduler_param`
+
+  RETURN VALUE
+    0  OK
+*/
+
 pthread_handler_t
 event_scheduler_ng_thread(void *arg)
 {
@@ -201,17 +214,8 @@ event_scheduler_ng_thread(void *arg)
   ((struct scheduler_param *) arg)->scheduler->run(thd);
 
 end:
-  thd->proc_info= "Clearing";
-  DBUG_ASSERT(thd->net.buff != 0);
-  net_end(&thd->net);
-  DBUG_PRINT("exit", ("Scheduler thread finishing"));
-  pthread_mutex_lock(&LOCK_thread_count);
-  thread_count--;
-  thread_running--;
-  delete thd;
-  pthread_mutex_unlock(&LOCK_thread_count);
+  deinit_event_thread(thd);
 
-  my_thread_end();
   DBUG_RETURN(0);                               // Against gcc warnings
 }
 
@@ -222,7 +226,7 @@ end:
 
   SYNOPSIS
     event_worker_ng_thread()
-      arg  The Event_timed object to be processed
+      arg  The Event_job_data object to be processed
 
   RETURN VALUE
     0  OK
@@ -233,14 +237,12 @@ event_worker_ng_thread(void *arg)
 {
   /* needs to be first for thread_stack */
   THD *thd; 
-  Event_timed *event= (Event_timed *)arg;
+  Event_job_data *event= (Event_job_data *)arg;
   int ret;
 
   thd= event->thd;
   thd->thread_stack= (char *) &thd;
 
-  DBUG_ENTER("event_worker_thread");
-  DBUG_PRINT("enter", ("event=[%s.%s]", event->dbname.str, event->name.str));
 
   my_thread_init();
   pthread_detach_this_thread();
@@ -251,62 +253,68 @@ event_worker_ng_thread(void *arg)
     goto end;
   }
 
+
 #if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
   sigset_t set;
   VOID(sigemptyset(&set));			// Get mask in use
   VOID(pthread_sigmask(SIG_UNBLOCK, &set, &thd->block_signals));
 #endif
+  thd->init_for_queries();
+
+  DBUG_ENTER("event_worker_ng_thread");
+  DBUG_PRINT("info", ("Baikonur, time is %d, BURAN reporting and operational."
+             "THD=0x%lx", time(NULL), thd));
+
   sql_print_information("SCHEDULER: [%s.%s of %s] executing in thread %lu",
                         event->dbname.str, event->name.str,
                         event->definer.str, thd->thread_id);
 
-  thd->init_for_queries();
   thd->enable_slow_log= TRUE;
 
   ret= event->execute(thd, thd->mem_root);
 
   evex_print_warnings(thd, event);
 
-  sql_print_information("SCHEDULER: [%s.%s of %s] executed. RetCode=%d",
+  sql_print_information("SCHEDULER: [%s.%s of %s] executed "
+                        " in thread thread %lu. RetCode=%d",
                         event->dbname.str, event->name.str,
-                        event->definer.str, ret);
+                        event->definer.str, thd->thread_id, ret);
   if (ret == EVEX_COMPILE_ERROR)
     sql_print_information("SCHEDULER: COMPILE ERROR for event %s.%s of %s",
                           event->dbname.str, event->name.str,
                           event->definer.str);
   else if (ret == EVEX_MICROSECOND_UNSUP)
     sql_print_information("SCHEDULER: MICROSECOND is not supported");
-  
-  DBUG_PRINT("info", ("master_access=%d db_access=%d",
-             thd->security_ctx->master_access, thd->security_ctx->db_access));
 
 end:
-  thd->proc_info= "Clearing";
-  DBUG_ASSERT(thd->net.buff != 0);
-  /*
-    Free it here because net.vio is NULL for us => THD::~THD will check it
-    and won't call net_end(&net); See also replication code.
-  */
-  net_end(&thd->net);
-  DBUG_PRINT("info", ("Worker thread %lu exiting", thd->thread_id));
-  VOID(pthread_mutex_lock(&LOCK_thread_count));
-  thread_count--;
-  thread_running--;
-  delete thd;
-  VOID(pthread_mutex_unlock(&LOCK_thread_count));
+  DBUG_PRINT("info", ("BURAN %s.%s is landing!", event->dbname.str,
+             event->name.str));
   delete event;
 
-  my_thread_end();
+  deinit_event_thread(thd);
+
   DBUG_RETURN(0);                               // Against gcc warnings
 }
 
 
+/*
+  Performs initialization of the scheduler data, outside of the
+  threading primitives.
+
+  SYNOPSIS
+    Event_scheduler_ng::init_scheduler()
+*/
+
 bool
 Event_scheduler_ng::init_scheduler(Event_queue *q)
 {
+  LOCK_SCHEDULER_DATA();
   thread_id= 0;
   state= INITIALIZED;
   queue= q;
+  started_events= 0;
+  UNLOCK_SCHEDULER_DATA();
+
   return FALSE;
 }
 
@@ -315,6 +323,13 @@ void
 Event_scheduler_ng::deinit_scheduler() {}
 
 
+/*
+  Inits scheduler's threading primitives.
+
+  SYNOPSIS
+    Event_scheduler_ng::init_mutexes()
+*/
+
 void
 Event_scheduler_ng::init_mutexes()
 {
@@ -323,6 +338,13 @@ Event_scheduler_ng::init_mutexes()
 }
 
 
+/*
+  Deinits scheduler's threading primitives.
+
+  SYNOPSIS
+    Event_scheduler_ng::deinit_mutexes()
+*/
+
 void
 Event_scheduler_ng::deinit_mutexes()
 {
@@ -331,6 +353,21 @@ Event_scheduler_ng::deinit_mutexes()
 }
 
 
+/*
+  Starts the scheduler (again). Creates a new THD and passes it to
+  a forked thread. Does not wait for acknowledgement from the new
+  thread that it has started. Asynchronous starting. Most of the
+  needed initializations are done in the current thread to minimize
+  the chance of failure in the spawned thread.
+
+  SYNOPSIS
+    Event_scheduler_ng::start()
+
+  RETURN VALUE
+    FALSE  OK
+    TRUE   Error (not reported)
+*/
+
 bool
 Event_scheduler_ng::start()
 {
@@ -340,6 +377,7 @@ Event_scheduler_ng::start()
   DBUG_ENTER("Event_scheduler_ng::start");
 
   LOCK_SCHEDULER_DATA();
+  DBUG_PRINT("info", ("state before action %s", scheduler_states_names[state]));
   if (state > INITIALIZED)
     goto end;
 
@@ -349,10 +387,13 @@ Event_scheduler_ng::start()
     ret= TRUE;
     goto end;
   }
+  new_thd->system_thread= SYSTEM_THREAD_EVENT_SCHEDULER;
+  new_thd->command= COM_DAEMON;
 
   scheduler_param_value.thd= new_thd;
   scheduler_param_value.scheduler= this;
 
+  DBUG_PRINT("info", ("Forking new thread for scheduduler. THD=0x%lx", new_thd));
   if (pthread_create(&th, &connection_attrib, event_scheduler_ng_thread,
                     (void*)&scheduler_param_value))
   {
@@ -360,13 +401,14 @@ Event_scheduler_ng::start()
     state= INITIALIZED;
     ret= TRUE;
   }
-
+  DBUG_PRINT("info", ("Setting state go RUNNING"));
   state= RUNNING;
 end:
   UNLOCK_SCHEDULER_DATA();
 
   if (ret && new_thd)
   {
+    DBUG_PRINT("info", ("There was an error during THD creation. Clean up"));
     new_thd->proc_info= "Clearing";
     DBUG_ASSERT(new_thd->net.buff != 0);
     net_end(&new_thd->net);
@@ -380,14 +422,27 @@ end:
 }
 
 
+/*
+  Stops the scheduler (again). Waits for acknowledgement from the
+  scheduler that it has stopped - synchronous stopping.
+
+  SYNOPSIS
+    Event_scheduler_ng::stop()
+
+  RETURN VALUE
+    FALSE  OK
+    TRUE   Error (not reported)
+*/
+
 bool
 Event_scheduler_ng::stop()
 {
   THD *thd= current_thd;
   DBUG_ENTER("Event_scheduler_ng::stop");
-  DBUG_PRINT("enter", ("thd=%p", current_thd));
+  DBUG_PRINT("enter", ("thd=0x%lx", current_thd));
 
   LOCK_SCHEDULER_DATA();
+  DBUG_PRINT("info", ("state before action %s", scheduler_states_names[state]));
   if (state != RUNNING)
     goto end;
 
@@ -406,48 +461,75 @@ Event_scheduler_ng::stop()
                         "workers count=%d", scheduler_states_names[state].str,
                         workers_count()));
     /* thd could be 0x0, when shutting down */
-    pthread_cond_wait(&COND_state, &LOCK_scheduler_state);
+    COND_STATE_WAIT(NULL);
   } while (state == STOPPING);
   DBUG_PRINT("info", ("Manager thread has cleaned up. Set state to INIT"));
+
+  thread_id= 0;
 end:
   UNLOCK_SCHEDULER_DATA();
   DBUG_RETURN(FALSE);
 }
 
 
+/*
+  The main loop of the scheduler.
+
+  SYNOPSIS
+    Event_scheduler_ng::run()
+      thd  Thread
+
+  RETURN VALUE
+    FALSE  OK
+    TRUE   Error (Serious error)
+*/
+
 bool
 Event_scheduler_ng::run(THD *thd)
 {
+  int res;
   struct timespec abstime;
-  Event_timed *job_data;
+  Event_job_data *job_data;
+  DBUG_ENTER("Event_scheduler_ng::run");
 
   LOCK_SCHEDULER_DATA();
 
   thread_id= thd->thread_id;
   sql_print_information("SCHEDULER: Manager thread started with id %lu",
                         thread_id);
+  /*
+    Recalculate the values in the queue because there could have been stops
+    in executions of the scheduler and some times could have passed by.
+  */
+  queue->recalculate_activation_times(thd);
   while (state == RUNNING)
   {
     thd->end_time();
     /* Gets a minimized version */
-    job_data= queue->get_top_for_execution_if_time(thd, thd->query_start(),
-                                                   &abstime);
-    DBUG_PRINT("info", ("get_top returned job_data=%p now=%d abs_time.tv_sec=%d",
-               job_data, thd->query_start(), abstime.tv_sec));
+    job_data= queue->
+            get_top_for_execution_if_time(thd, thd->query_start(), &abstime);
+
+    DBUG_PRINT("info", ("get_top returned job_data=0x%lx now=%d "
+                        "abs_time.tv_sec=%d",
+                        job_data, thd->query_start(), abstime.tv_sec));
     if (!job_data && !abstime.tv_sec)
     {
+      DBUG_PRINT("info", ("The queue is empty. Going to sleep"));
       thd->enter_cond(&COND_state, &LOCK_scheduler_state,
                       "Waiting on empty queue");
-      pthread_cond_wait(&COND_state, &LOCK_scheduler_state);
+      COND_STATE_WAIT(NULL);
       thd->exit_cond("");
       DBUG_PRINT("info", ("Woke up. Got COND_state"));
       LOCK_SCHEDULER_DATA();
     }
     else if (abstime.tv_sec)
     {
+      DBUG_PRINT("info", ("Have to sleep some time %u till",
+                 abstime.tv_sec - thd->query_start(), abstime.tv_sec));
+
       thd->enter_cond(&COND_state, &LOCK_scheduler_state,
                       "Waiting for next activation");
-      pthread_cond_timedwait(&COND_state, &LOCK_scheduler_state, &abstime);
+      COND_STATE_WAIT(&abstime);
       /*
         If we get signal we should recalculate the whether it's the right time
         because there could be :
@@ -461,12 +543,12 @@ Event_scheduler_ng::run(THD *thd)
     }
     else
     {
-      int res;
       UNLOCK_SCHEDULER_DATA();
       res= execute_top(thd, job_data);
       LOCK_SCHEDULER_DATA();
       if (res)
         break;
+      ++started_events;
     }
     DBUG_PRINT("info", ("state=%s", scheduler_states_names[state].str));
   }
@@ -477,29 +559,47 @@ error:
   UNLOCK_SCHEDULER_DATA();
   sql_print_information("SCHEDULER: Stopped");
 
-  return FALSE;
+  DBUG_RETURN(res);
 }
 
 
+/*
+  Creates a new THD instance and then forks a new thread, while passing
+  the THD pointer and job_data to it.
+
+  SYNOPSIS
+    Event_scheduler_ng::execute_top()
+
+  RETURN VALUE
+    FALSE  OK
+    TRUE   Error (Serious error)
+*/
+
 bool
-Event_scheduler_ng::execute_top(THD *thd, Event_timed *job_data)
+Event_scheduler_ng::execute_top(THD *thd, Event_job_data *job_data)
 {
   THD *new_thd;
   pthread_t th;
+  int res= 0;
   DBUG_ENTER("Event_scheduler_ng::execute_top");
   if (!(new_thd= new THD) || init_scheduler_thread(new_thd))
     goto error;
 
-  /* Major failure */
+  new_thd->system_thread= SYSTEM_THREAD_EVENT_WORKER;
   job_data->thd= new_thd;
-  DBUG_PRINT("info", ("Starting new thread for %s@%s",
+  DBUG_PRINT("info", ("BURAN %s@%s ready for start t-3..2..1..0..ignition",
              job_data->dbname.str, job_data->name.str));
-  if (pthread_create(&th, &connection_attrib, event_worker_ng_thread, job_data))
+
+  /* Major failure */
+  if ((res= pthread_create(&th, &connection_attrib, event_worker_ng_thread,
+                           job_data)))
     goto error;
 
+  DBUG_PRINT("info", ("Launch succeeded. BURAN is in THD=0x%lx", new_thd));
   DBUG_RETURN(FALSE);
 
 error:
+  DBUG_PRINT("error", ("Baikonur, we have a problem! res=%d", res));
   if (new_thd)
   {
     new_thd->proc_info= "Clearing";
@@ -511,10 +611,21 @@ error:
     delete new_thd;
     pthread_mutex_unlock(&LOCK_thread_count);
   }
+  delete job_data;
   DBUG_RETURN(TRUE);
 }
 
 
+/*
+  Returns the current state of the scheduler
+
+  SYNOPSIS
+    Event_scheduler_ng::get_state()
+
+  RETURN VALUE
+    The state of the scheduler (INITIALIZED | RUNNING | STOPPING)
+*/
+
 enum Event_scheduler_ng::enum_state
 Event_scheduler_ng::get_state()
 {
@@ -526,13 +637,12 @@ Event_scheduler_ng::get_state()
 }
 
 
-int
-Event_scheduler_ng::dump_internal_status(THD *thd)
-{
-  return 1;
-
-}
+/*
+  Returns the number of living event worker threads.
 
+  SYNOPSIS
+    Event_scheduler_ng::workers_count()
+*/
 
 uint
 Event_scheduler_ng::workers_count()
@@ -541,7 +651,7 @@ Event_scheduler_ng::workers_count()
   uint count= 0;
   
   DBUG_ENTER("Event_scheduler_ng::workers_count");
-  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
+  pthread_mutex_lock(&LOCK_thread_count);       // For unlink from list
   I_List_iterator<THD> it(threads);
   while ((tmp=it++))
   {
@@ -550,7 +660,7 @@ Event_scheduler_ng::workers_count()
     if (tmp->system_thread == SYSTEM_THREAD_EVENT_WORKER)
       ++count;
   }
-  VOID(pthread_mutex_unlock(&LOCK_thread_count));
+  pthread_mutex_unlock(&LOCK_thread_count);
   DBUG_PRINT("exit", ("%d", count));
   DBUG_RETURN(count);
 }
@@ -568,16 +678,27 @@ void
 Event_scheduler_ng::queue_changed()
 {
   DBUG_ENTER("Event_scheduler_ng::queue_changed");
-  DBUG_PRINT("info", ("Sending COND_state"));
+  DBUG_PRINT("info", ("Sending COND_state. state (read wo lock)=%s ",
+             scheduler_states_names[state].str));
   pthread_cond_signal(&COND_state);
   DBUG_VOID_RETURN;
 }
 
 
+/*
+  Auxiliary function for locking LOCK_scheduler_state. Used
+  by the LOCK_SCHEDULER_DATA macro.
+
+  SYNOPSIS
+    Event_scheduler_ng::lock_data()
+      func  Which function is requesting mutex lock
+      line  On which line mutex lock is requested
+*/
+
 void
 Event_scheduler_ng::lock_data(const char *func, uint line)
 {
-  DBUG_ENTER("Event_scheduler_ng::lock_mutex");
+  DBUG_ENTER("Event_scheduler_ng::lock_data");
   DBUG_PRINT("enter", ("func=%s line=%u", func, line));
   pthread_mutex_lock(&LOCK_scheduler_state);
   mutex_last_locked_in_func= func;
@@ -587,14 +708,168 @@ Event_scheduler_ng::lock_data(const char
 }
 
 
+/*
+  Auxiliary function for unlocking LOCK_scheduler_state. Used
+  by the UNLOCK_SCHEDULER_DATA macro.
+
+  SYNOPSIS
+    Event_scheduler_ng::unlock_data()
+      func  Which function is requesting mutex unlock
+      line  On which line mutex unlock is requested
+*/
+
 void
 Event_scheduler_ng::unlock_data(const char *func, uint line)
 {
-  DBUG_ENTER("Event_scheduler_ng::unlock_mutex");
+  DBUG_ENTER("Event_scheduler_ng::unlock_data");
   DBUG_PRINT("enter", ("func=%s line=%u", func, line));
   mutex_last_unlocked_at_line= line;
   mutex_scheduler_data_locked= FALSE;
   mutex_last_unlocked_in_func= func;
   pthread_mutex_unlock(&LOCK_scheduler_state);
   DBUG_VOID_RETURN;
+}
+
+
+/*
+  Wrapper for pthread_cond_wait/timedwait
+
+  SYNOPSIS
+    Event_scheduler_ng::cond_wait()
+      cond   Conditional to wait for
+      mutex  Mutex of the conditional
+
+  RETURN VALUE
+    Error code of pthread_cond_wait()
+*/
+
+void
+Event_scheduler_ng::cond_wait(struct timespec *abstime,
+                              const char *func, uint line)
+{
+  DBUG_ENTER("Event_scheduler_ng::cond_wait");
+  waiting_on_cond= TRUE;
+  mutex_last_unlocked_at_line= line;
+  mutex_scheduler_data_locked= FALSE;
+  mutex_last_unlocked_in_func= func;
+
+  if (abstime)
+    pthread_cond_timedwait(&COND_state, &LOCK_scheduler_state, abstime);
+  else
+    pthread_cond_wait(&COND_state, &LOCK_scheduler_state);
+
+  mutex_last_locked_in_func= func;
+  mutex_last_locked_at_line= line;
+  mutex_scheduler_data_locked= TRUE;
+  waiting_on_cond= FALSE;
+
+  DBUG_VOID_RETURN;
+}
+
+
+/*
+  Dumps the internal status of the scheduler
+
+  SYNOPSIS
+    Event_scheduler_ng::dump_internal_status()
+      thd  Thread
+
+  RETURN VALUE
+    FALSE  OK
+    TRUE   Error
+*/
+
+bool
+Event_scheduler_ng::dump_internal_status(THD *thd)
+{
+  int ret= 0;
+  DBUG_ENTER("Event_scheduler_ng::dump_internal_status");
+
+#ifndef DBUG_OFF
+  CHARSET_INFO *scs= system_charset_info;
+  Protocol *protocol= thd->protocol;
+  char tmp_buff[5*STRING_BUFFER_USUAL_SIZE];
+  char int_buff[STRING_BUFFER_USUAL_SIZE];
+  String tmp_string(tmp_buff, sizeof(tmp_buff), scs);
+  String int_string(int_buff, sizeof(int_buff), scs);
+  tmp_string.length(0);
+  int_string.length(0);
+
+  protocol->prepare_for_resend();
+  protocol->store(STRING_WITH_LEN("scheduler state"), scs);
+  protocol->store(scheduler_states_names[state].str,
+                  scheduler_states_names[state].length, scs);
+
+  if ((ret= protocol->write()))
+    goto end;
+
+  /* thread_id */
+  protocol->prepare_for_resend();
+  protocol->store(STRING_WITH_LEN("thread_id"), scs);
+  if (thread_id)
+  {
+    int_string.set((longlong) thread_id, scs);
+    protocol->store(&int_string);
+  }
+  else
+    protocol->store_null();
+  if ((ret= protocol->write()))
+    goto end;
+
+  /* last locked at*/
+  protocol->prepare_for_resend();
+  protocol->store(STRING_WITH_LEN("scheduler last locked at"), scs);
+  tmp_string.length(scs->cset->snprintf(scs, (char*) tmp_string.ptr(),
+                                        tmp_string.alloced_length(), "%s::%d",
+                                        mutex_last_locked_in_func,
+                                        mutex_last_locked_at_line));
+  protocol->store(&tmp_string);
+  if ((ret= protocol->write()))
+    goto end;
+
+  /* last unlocked at*/
+  protocol->prepare_for_resend();
+  protocol->store(STRING_WITH_LEN("scheduler last unlocked at"), scs);
+  tmp_string.length(scs->cset->snprintf(scs, (char*) tmp_string.ptr(),
+                                        tmp_string.alloced_length(), "%s::%d",
+                                        mutex_last_unlocked_in_func,
+                                        mutex_last_unlocked_at_line));
+  protocol->store(&tmp_string);
+  if ((ret= protocol->write()))
+    goto end;
+
+  /* waiting on */
+  protocol->prepare_for_resend();
+  protocol->store(STRING_WITH_LEN("scheduler waiting on condition"), scs);
+  int_string.set((longlong) waiting_on_cond, scs);
+  protocol->store(&int_string);
+  if ((ret= protocol->write()))
+    goto end;
+
+  /* workers_count */
+  protocol->prepare_for_resend();
+  protocol->store(STRING_WITH_LEN("scheduler workers count"), scs);
+  int_string.set((longlong) workers_count(), scs);
+  protocol->store(&int_string);
+  if ((ret= protocol->write()))
+    goto end;
+
+  /* workers_count */
+  protocol->prepare_for_resend();
+  protocol->store(STRING_WITH_LEN("scheduler executed events"), scs);
+  int_string.set((longlong) started_events, scs);
+  protocol->store(&int_string);
+  if ((ret= protocol->write()))
+    goto end;
+
+  /* scheduler_data_locked */
+  protocol->prepare_for_resend();
+  protocol->store(STRING_WITH_LEN("scheduler data locked"), scs);
+  int_string.set((longlong) mutex_scheduler_data_locked, scs);
+  protocol->store(&int_string);
+  ret= protocol->write();
+end:
+#endif
+
+  DBUG_RETURN(ret);
 }

--- 1.2/sql/event_scheduler_ng.h	2006-07-05 17:12:41 +02:00
+++ 1.3/sql/event_scheduler_ng.h	2006-07-10 13:44:33 +02:00
@@ -16,8 +16,8 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
-class Event_timed;
 class Event_queue;
+class Event_job_data;
 
 class Event_scheduler_ng
 {
@@ -67,7 +67,7 @@ public:
   void
   queue_changed();
 
-  static int
+  bool
   dump_internal_status(THD *thd);
 
 private:
@@ -76,7 +76,7 @@ private:
 
   /* helper functions */
   bool
-  execute_top(THD *thd, Event_timed *job_data);
+  execute_top(THD *thd, Event_job_data *job_data);
 
   /* helper functions for working with mutexes & conditionals */
   void
@@ -84,7 +84,10 @@ private:
 
   void
   unlock_data(const char *func, uint line);
-  
+
+  void
+  cond_wait(struct timespec *abstime, const char *func, uint line);
+
   pthread_mutex_t LOCK_scheduler_state;
 
   /* This is the current status of the life-cycle of the scheduler. */
@@ -107,6 +110,9 @@ private:
   const char* mutex_last_locked_in_func;
   const char* mutex_last_unlocked_in_func;
   bool mutex_scheduler_data_locked;
+  bool waiting_on_cond;
+  
+  ulonglong started_events;
 
 private:
   /* Prevent use of these */

--- 1.66/sql/event_data_objects.cc	2006-07-05 17:12:41 +02:00
+++ 1.67/sql/event_data_objects.cc	2006-07-10 13:44:33 +02:00
@@ -22,7 +22,7 @@
 #include "sp_head.h"
 
 
-#define EVEX_MAX_INTERVAL_VALUE 2147483647L
+#define EVEX_MAX_INTERVAL_VALUE 1000000000L
 
 
 /*
@@ -54,6 +54,8 @@ Event_parse_data::new_instance(THD *thd)
 
 Event_parse_data::Event_parse_data()
 {
+  DBUG_ENTER("Event_parse_data::Event_parse_data");
+
   item_execute_at= item_expression= item_starts= item_ends= NULL;
   status= ENABLED;
   on_completion= ON_COMPLETION_DROP;
@@ -65,8 +67,10 @@ Event_parse_data::Event_parse_data()
   set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
   starts_null= ends_null= execute_at_null= TRUE;
 
-  body.str= comment.str= 0;
+  body.str= comment.str= NULL;
   body.length= comment.length= 0;
+
+  DBUG_VOID_RETURN;
 }
 
 
@@ -120,7 +124,7 @@ void
 Event_parse_data::init_body(THD *thd)
 {
   DBUG_ENTER("Event_parse_data::init_body");
-  DBUG_PRINT("info", ("body=[%s] body_begin=0x%ld end=0x%ld", body_begin,
+  DBUG_PRINT("info", ("body=[%s] body_begin=0x%lx end=0x%lx", body_begin,
              body_begin, thd->lex->ptr));
 
   body.length= thd->lex->ptr - body_begin;
@@ -138,7 +142,7 @@ Event_parse_data::init_body(THD *thd)
       continue;
     }
 
-    /*  
+    /*
        consume closing comments
 
        This is arguably wrong, but it's the best we have until the parser is
@@ -235,17 +239,20 @@ Event_parse_data::init_definer(THD *thd)
 */
 
 int
-Event_parse_data::init_execute_at(THD *thd, Item *expr)
+Event_parse_data::init_execute_at(THD *thd)
 {
   my_bool not_used;
   TIME ltime;
   my_time_t t;
-
   TIME time_tmp;
+
   DBUG_ENTER("Event_parse_data::init_execute_at");
 
-  if (expr->fix_fields(thd, &expr))
-    DBUG_RETURN(EVEX_PARSE_ERROR);
+  if (!item_execute_at)
+    DBUG_RETURN(0);
+
+  if (item_execute_at->fix_fields(thd, &item_execute_at))
+    goto wrong_value;
   
   /* no starts and/or ends in case of execute_at */
   DBUG_PRINT("info", ("starts_null && ends_null should be 1 is %d",
@@ -256,12 +263,15 @@ Event_parse_data::init_execute_at(THD *t
   thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, 
                                             (my_time_t) thd->query_start());
 
-  if ((not_used= expr->get_date(&ltime, TIME_NO_ZERO_DATE)))
-    DBUG_RETURN(ER_WRONG_VALUE);
+  if ((not_used= item_execute_at->get_date(&ltime, TIME_NO_ZERO_DATE)))
+    goto wrong_value;
 
   if (TIME_to_ulonglong_datetime(&ltime) <
       TIME_to_ulonglong_datetime(&time_tmp))
-    DBUG_RETURN(EVEX_BAD_PARAMS);
+  {
+    my_error(ER_EVENT_EXEC_TIME_IN_THE_PAST, MYF(0));
+    DBUG_RETURN(ER_WRONG_VALUE);
+  }
 
   /*
     This may result in a 1970-01-01 date if ltime is > 2037-xx-xx.
@@ -273,12 +283,16 @@ Event_parse_data::init_execute_at(THD *t
   if (!t)
   {
     DBUG_PRINT("error", ("Execute AT after year 2037"));
-    DBUG_RETURN(ER_WRONG_VALUE);
+    goto wrong_value;
   }
 
   execute_at_null= FALSE;
   execute_at= ltime;
   DBUG_RETURN(0);
+
+wrong_value:
+  report_bad_value("AT", item_execute_at);
+  DBUG_RETURN(ER_WRONG_VALUE);
 }
 
 
@@ -291,30 +305,44 @@ Event_parse_data::init_execute_at(THD *t
       new_interval  what is the interval
 
   RETURN VALUE
-    0                  OK
-    EVEX_PARSE_ERROR   fix_fields failed
-    EVEX_BAD_PARAMS    Interval is not positive
-    EVEX_MICROSECOND_UNSUP  Microseconds are not supported.
+    0                       OK
+    EVEX_PARSE_ERROR        fix_fields failed (reported)
+    EVEX_BAD_PARAMS         Interval is not positive (reported)
+    EVEX_MICROSECOND_UNSUP  Microseconds are not supported (reported)
 */
 
 int
-Event_parse_data::init_interval(THD *thd, Item *expr, interval_type new_interval)
+Event_parse_data::init_interval(THD *thd)
 {
   String value;
   INTERVAL interval_tmp;
 
   DBUG_ENTER("Event_parse_data::init_interval");
+  if (!item_expression)
+    DBUG_RETURN(0);
+
+  switch (interval) {
+  case INTERVAL_MINUTE_MICROSECOND:
+  case INTERVAL_HOUR_MICROSECOND:
+  case INTERVAL_DAY_MICROSECOND:
+  case INTERVAL_SECOND_MICROSECOND:
+  case INTERVAL_MICROSECOND:
+    my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND");
+    DBUG_RETURN(EVEX_BAD_PARAMS);
+  default:
+    break;
+  }
 
-  if (expr->fix_fields(thd, &expr))
-    DBUG_RETURN(EVEX_PARSE_ERROR);
+  if (item_expression->fix_fields(thd, &item_expression))
+    goto wrong_value;
 
   value.alloc(MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN);
-  if (get_interval_value(expr, new_interval, &value, &interval_tmp))
-    DBUG_RETURN(EVEX_PARSE_ERROR);
+  if (get_interval_value(item_expression, interval, &value, &interval_tmp))
+    goto wrong_value;
 
   expression= 0;
 
-  switch (new_interval) {
+  switch (interval) {
   case INTERVAL_YEAR:
     expression= interval_tmp.year;
     break;
@@ -352,39 +380,33 @@ Event_parse_data::init_interval(THD *thd
                   interval_tmp.minute)*60
                  + interval_tmp.second;
     break;
-  case INTERVAL_MINUTE_MICROSECOND: /* day and hour are 0 */
-  case INTERVAL_HOUR_MICROSECOND:   /* day is anyway 0    */
-  case INTERVAL_DAY_MICROSECOND:
-    DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
-    expression= ((((interval_tmp.day*24) + interval_tmp.hour)*60+
-                  interval_tmp.minute)*60 +
-                 interval_tmp.second) * 1000000L + interval_tmp.second_part;
-    break;
   case INTERVAL_HOUR_MINUTE:
     expression= interval_tmp.hour * 60 + interval_tmp.minute;
     break;
   case INTERVAL_MINUTE_SECOND:
     expression= interval_tmp.minute * 60 + interval_tmp.second;
     break;
-  case INTERVAL_SECOND_MICROSECOND:
-    DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
-    expression= interval_tmp.second * 1000000L + interval_tmp.second_part;
-    break;
-  case INTERVAL_MICROSECOND:
-    DBUG_RETURN(EVEX_MICROSECOND_UNSUP);  
   case INTERVAL_LAST:
     DBUG_ASSERT(0);
+  default:
+    ;/* these are the microsec stuff */
   }
   if (interval_tmp.neg || expression > EVEX_MAX_INTERVAL_VALUE)
+  {
+    my_error(ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG, MYF(0));
     DBUG_RETURN(EVEX_BAD_PARAMS);
+  }
 
-  interval= new_interval;
   DBUG_RETURN(0);
+
+wrong_value:
+  report_bad_value("INTERVAL", item_execute_at);
+  DBUG_RETURN(ER_WRONG_VALUE);
 }
 
 
 /*
-  Set activation time.
+  Sets activation time.
 
   SYNOPSIS
     Event_parse_data::init_starts()
@@ -406,19 +428,21 @@ Event_parse_data::init_interval(THD *thd
 */
 
 int
-Event_parse_data::init_starts(THD *thd, Item *new_starts)
+Event_parse_data::init_starts(THD *thd)
 {
   my_bool not_used;
   TIME ltime, time_tmp;
   my_time_t t;
 
   DBUG_ENTER("Event_parse_data::init_starts");
+  if (!item_starts)
+    DBUG_RETURN(0);
 
-  if (new_starts->fix_fields(thd, &new_starts))
-    DBUG_RETURN(EVEX_PARSE_ERROR);
+  if (item_starts->fix_fields(thd, &item_starts))
+    goto wrong_value;
 
-  if ((not_used= new_starts->get_date(&ltime, TIME_NO_ZERO_DATE)))
-    DBUG_RETURN(EVEX_BAD_PARAMS);
+  if ((not_used= item_starts->get_date(&ltime, TIME_NO_ZERO_DATE)))
+    goto wrong_value;
 
   /* Let's check whether time is in the past */
   thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,
@@ -428,7 +452,7 @@ Event_parse_data::init_starts(THD *thd, 
   DBUG_PRINT("info",("starts=%lld", TIME_to_ulonglong_datetime(&ltime)));
   if (TIME_to_ulonglong_datetime(&ltime) <
       TIME_to_ulonglong_datetime(&time_tmp))
-    DBUG_RETURN(EVEX_BAD_PARAMS);
+    goto wrong_value;
 
   /*
     This may result in a 1970-01-01 date if ltime is > 2037-xx-xx.
@@ -438,24 +462,25 @@ Event_parse_data::init_starts(THD *thd, 
   */
   my_tz_UTC->gmt_sec_to_TIME(&ltime,t=TIME_to_timestamp(thd, &ltime, &not_used));
   if (!t)
-  {
-    DBUG_PRINT("error", ("STARTS after year 2037"));
-    DBUG_RETURN(EVEX_BAD_PARAMS);
-  }
+    goto wrong_value;
 
   starts= ltime;
   starts_null= FALSE;
   DBUG_RETURN(0);
+
+wrong_value:
+  report_bad_value("STARTS", item_starts);
+  DBUG_RETURN(ER_WRONG_VALUE);
 }
 
 
 /*
-  Set deactivation time.
+  Sets deactivation time.
 
   SYNOPSIS
     Event_parse_data::init_ends()
       thd       THD
-      new_ends  when?
+      new_ends  When?
 
   NOTES
     Note that activation time is not execution time.
@@ -467,26 +492,26 @@ Event_parse_data::init_starts(THD *thd, 
 
   RETURN VALUE
     0                  OK
-    EVEX_PARSE_ERROR   fix_fields failed
-    ER_WRONG_VALUE     starts distant date (after year 2037)
-    EVEX_BAD_PARAMS    ENDS before STARTS
+    EVEX_BAD_PARAMS    Error (reported)
 */
 
 int
-Event_parse_data::init_ends(THD *thd, Item *new_ends)
+Event_parse_data::init_ends(THD *thd)
 {
   TIME ltime, ltime_now;
   my_bool not_used;
   my_time_t t;
 
   DBUG_ENTER("Event_parse_data::init_ends");
+  if (!item_ends)
+    DBUG_RETURN(0);
 
-  if (new_ends->fix_fields(thd, &new_ends))
-    DBUG_RETURN(EVEX_PARSE_ERROR);
+  if (item_ends->fix_fields(thd, &item_ends))
+    goto error_bad_params;
 
   DBUG_PRINT("info", ("convert to TIME"));
-  if ((not_used= new_ends->get_date(&ltime, TIME_NO_ZERO_DATE)))
-    DBUG_RETURN(EVEX_BAD_PARAMS);
+  if ((not_used= item_ends->get_date(&ltime, TIME_NO_ZERO_DATE)))
+    goto error_bad_params;
 
   /*
     This may result in a 1970-01-01 date if ltime is > 2037-xx-xx.
@@ -497,15 +522,12 @@ Event_parse_data::init_ends(THD *thd, It
   DBUG_PRINT("info", ("get the UTC time"));
   my_tz_UTC->gmt_sec_to_TIME(&ltime,t=TIME_to_timestamp(thd, &ltime, &not_used));
   if (!t)
-  {
-    DBUG_PRINT("error", ("ENDS after year 2037"));
-    DBUG_RETURN(EVEX_BAD_PARAMS);
-  }
+    goto error_bad_params;
 
   /* Check whether ends is after starts */
   DBUG_PRINT("info", ("ENDS after STARTS?"));
   if (!starts_null && my_time_compare(&starts, &ltime) != -1)
-    DBUG_RETURN(EVEX_BAD_PARAMS);
+    goto error_bad_params;
 
   /*
     The parser forces starts to be provided but one day STARTS could be
@@ -515,11 +537,173 @@ Event_parse_data::init_ends(THD *thd, It
   DBUG_PRINT("info", ("ENDS after NOW?"));
   my_tz_UTC->gmt_sec_to_TIME(&ltime_now, thd->query_start());
   if (my_time_compare(&ltime_now, &ltime) == 1)
-    DBUG_RETURN(EVEX_BAD_PARAMS);
+    goto error_bad_params;
 
   ends= ltime;
   ends_null= FALSE;
   DBUG_RETURN(0);
+
+error_bad_params:
+  my_error(ER_EVENT_ENDS_BEFORE_STARTS, MYF(0));
+  DBUG_RETURN(EVEX_BAD_PARAMS);
+}
+
+
+/*
+  Prints an error message about invalid value. Internally used
+  during input data verification
+
+  SYNOPSIS
+    Event_parse_data::report_bad_value()
+      item_name The name of the parameter
+      bad_item  The parameter
+*/
+
+void
+Event_parse_data::report_bad_value(const char *item_name, Item *bad_item)
+{
+  char buff[120];
+  String str(buff,(uint32) sizeof(buff), system_charset_info);
+  String *str2= bad_item->fixed? bad_item->val_str(&str):NULL;
+  my_error(ER_WRONG_VALUE, MYF(0), item_name, str2? str2->c_ptr_safe():"NULL");
+}
+
+
+/*
+  Performs checking of the data gathered during the parsing phase.
+
+  SYNOPSIS
+    Event_parse_data::check_parse_data()
+      thd  Thread
+
+  RETURN VALUE
+    FALSE  OK
+    TRUE   Error (reported)
+*/
+
+bool
+Event_parse_data::check_parse_data(THD *thd)
+{
+  bool ret;
+  DBUG_ENTER("Event_parse_data::check_parse_data");
+  DBUG_PRINT("info", ("execute_at=0x%lx expr=0x%lx starts=0x%lx ends=0x%lx",
+             item_execute_at, item_expression, item_starts, item_ends));
+
+  init_name(thd, identifier);
+
+  init_definer(thd);
+
+  ret= init_execute_at(thd) || init_interval(thd) || init_starts(thd) ||
+       init_ends(thd);
+  DBUG_RETURN(ret);
+}
+
+/*
+  Constructor
+
+  SYNOPSIS
+    Event_basic::Event_basic()
+*/
+
+Event_basic::Event_basic()
+{
+  DBUG_ENTER("Event_basic::Event_basic");
+  /* init memory root */
+  init_alloc_root(&mem_root, 256, 512);
+  dbname.str= name.str= NULL;
+  dbname.length= name.length= 0;
+  DBUG_VOID_RETURN;
+}
+  
+
+/*
+  Destructor
+
+  SYNOPSIS
+    Event_basic::Event_basic()
+*/
+
+Event_basic::~Event_basic()
+{
+  DBUG_ENTER("Event_basic::~Event_basic");
+  free_root(&mem_root, MYF(0));
+  DBUG_VOID_RETURN;
+}
+
+
+/*
+  Short function to load a char column into a LEX_STRING
+
+  SYNOPSIS
+    Event_basic::load_string_field()
+      field_name  The field( enum_events_table_field is not actually used
+                  because it's unknown in event_data_objects.h)
+      fields      The Field array
+      field_value The value
+*/
+
+bool
+Event_basic::load_string_fields(Field **fields, ...)
+{
+  bool ret= FALSE;
+  va_list args;
+  enum enum_events_table_field field_name;
+  LEX_STRING *field_value;
+
+  DBUG_ENTER("Event_basic::load_string_fields");
+  
+  va_start(args, fields);
+  field_name= (enum enum_events_table_field) va_arg(args, int);
+  while (field_name != ET_FIELD_COUNT)
+  {
+    field_value= va_arg(args, LEX_STRING *);
+    if ((field_value->str= get_field(&mem_root, fields[field_name])) == NullS)
+    {
+      ret= TRUE;
+      break;
+    }
+    field_value->length= strlen(field_value->str);  
+
+    field_name= (enum enum_events_table_field) va_arg(args, int);
+  }
+  va_end(args);
+  
+  DBUG_RETURN(ret);
+}
+
+
+/*
+  Constructor
+
+  SYNOPSIS
+    Event_queue_element::Event_queue_element()
+*/
+
+Event_queue_element::Event_queue_element():
+  status_changed(FALSE), last_executed_changed(FALSE),
+  on_completion(ON_COMPLETION_DROP), status(ENABLED),
+  expression(0), dropped(FALSE), flags(0)
+{
+  DBUG_ENTER("Event_queue_element::Event_queue_element");
+
+  set_zero_time(&starts, MYSQL_TIMESTAMP_DATETIME);
+  set_zero_time(&ends, MYSQL_TIMESTAMP_DATETIME);
+  set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
+  set_zero_time(&last_executed, MYSQL_TIMESTAMP_DATETIME);
+  starts_null= ends_null= execute_at_null= TRUE;
+
+  DBUG_VOID_RETURN;
+}
+
+
+/*
+  Destructor
+
+  SYNOPSIS
+    Event_queue_element::Event_queue_element()
+*/
+Event_queue_element::~Event_queue_element()
+{
 }
 
 
@@ -530,15 +714,12 @@ Event_parse_data::init_ends(THD *thd, It
     Event_timed::Event_timed()
 */
 
-Event_timed::Event_timed():status_changed(false),
-                           last_executed_changed(false), expression(0),
-                           created(0), modified(0),
-                           on_completion(Event_timed::ON_COMPLETION_DROP),
-                           status(Event_timed::ENABLED), sphead(0),
-                           sql_mode(0), dropped(false), flags(0)
-                
+Event_timed::Event_timed():
+  created(0), modified(0), sql_mode(0)
 {
+  DBUG_ENTER("Event_timed::Event_timed");
   init();
+  DBUG_VOID_RETURN;
 }
 
 
@@ -551,7 +732,31 @@ Event_timed::Event_timed():status_change
 
 Event_timed::~Event_timed()
 {    
-  free_root(&mem_root, MYF(0));
+}
+
+
+/*
+  Constructor
+
+  SYNOPSIS
+    Event_job_data::Event_job_data()
+*/
+
+Event_job_data::Event_job_data():
+  thd(NULL), sphead(0), sql_mode(0)
+{
+}
+
+
+/*
+  Destructor
+
+  SYNOPSIS
+    Event_timed::~Event_timed()
+*/
+
+Event_job_data::~Event_job_data()
+{    
   free_sp();
 }
 
@@ -568,31 +773,23 @@ Event_timed::init()
 {
   DBUG_ENTER("Event_timed::init");
 
-  dbname.str= name.str= body.str= comment.str= 0;
-  dbname.length= name.length= body.length= comment.length= 0;
-
-  set_zero_time(&starts, MYSQL_TIMESTAMP_DATETIME);
-  set_zero_time(&ends, MYSQL_TIMESTAMP_DATETIME);
-  set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
-  set_zero_time(&last_executed, MYSQL_TIMESTAMP_DATETIME);
-  starts_null= ends_null= execute_at_null= TRUE;
+  body.str= comment.str= NULL;
+  body.length= comment.length= 0;
 
   definer_user.str= definer_host.str= 0;
   definer_user.length= definer_host.length= 0;
 
   sql_mode= 0;
-  /* init memory root */
-  init_alloc_root(&mem_root, 256, 512);
 
   DBUG_VOID_RETURN;
 }
 
 
 /*
-  Loads an event from a row from mysql.event
+  Loads an event's body from a row from mysql.event
 
   SYNOPSIS
-    Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
+    Event_job_data::load_from_row(MEM_ROOT *mem_root, TABLE *table)
 
   RETURN VALUE
     0                      OK
@@ -605,78 +802,127 @@ Event_timed::init()
 */
 
 int
-Event_timed::load_from_row(TABLE *table)
+Event_job_data::load_from_row(TABLE *table)
 {
   char *ptr;
-  Event_timed *et;
   uint len;
-  bool res1, res2;
-
-  DBUG_ENTER("Event_timed::load_from_row");
+  DBUG_ENTER("Event_job_data::load_from_row");
 
   if (!table)
     goto error;
 
-  et= this;
-
   if (table->s->fields != ET_FIELD_COUNT)
     goto error;
 
-  if ((et->dbname.str= get_field(&mem_root, table->field[ET_FIELD_DB])) == NULL)
-    goto error;
+  load_string_fields(table->field, ET_FIELD_DB, &dbname, ET_FIELD_NAME, &name,
+                     ET_FIELD_BODY, &body, ET_FIELD_DEFINER, &definer,
+                     ET_FIELD_COUNT);
 
-  et->dbname.length= strlen(et->dbname.str);
+/*  
+  if ((dbname.str= get_field(&mem_root, table->field[ET_FIELD_DB])) == NullS)
+    goto error;
+  dbname.length= strlen(dbname.str);
 
-  if ((et->name.str= get_field(&mem_root, table->field[ET_FIELD_NAME])) == NULL)
+  if ((name.str= get_field(&mem_root, table->field[ET_FIELD_NAME])) == NullS)
     goto error;
+  name.length= strlen(name.str);
 
-  et->name.length= strlen(et->name.str);
+  if ((body.str= get_field(&mem_root, table->field[ET_FIELD_BODY])) == NullS)
+    goto error;
+  body.length= strlen(body.str);
 
-  if ((et->body.str= get_field(&mem_root, table->field[ET_FIELD_BODY])) == NULL)
+  if ((definer.str= get_field(&mem_root,
+                              table->field[ET_FIELD_DEFINER])) == NullS)
     goto error;
 
-  et->body.length= strlen(et->body.str);
+  definer.length= strlen(definer.str);
+*/
+  ptr= strchr(definer.str, '@');
+
+  if (! ptr)
+    ptr= definer.str;
+
+  len= ptr - definer.str;
+  definer_user.str= strmake_root(&mem_root, definer.str, len);
+  definer_user.length= len;
+  len= definer.length - len - 1;
+  /* 1:because of @ */
+  definer_host.str= strmake_root(&mem_root, ptr + 1,  len);
+  definer_host.length= len;
+
+  sql_mode= (ulong) table->field[ET_FIELD_SQL_MODE]->val_int();
+
+  DBUG_RETURN(0);
+error:
+  DBUG_RETURN(EVEX_GET_FIELD_FAILED);
+}
+
+
+/*
+  Loads an event from a row from mysql.event
+
+  SYNOPSIS
+    Event_queue_element::load_from_row(MEM_ROOT *mem_root, TABLE *table)
+
+  RETURN VALUE
+    0                      OK
+    EVEX_GET_FIELD_FAILED  Error
+
+  NOTES
+    This method is silent on errors and should behave like that. Callers
+    should handle throwing of error messages. The reason is that the class
+    should not know about how to deal with communication.
+*/
+
+int
+Event_queue_element::load_from_row(TABLE *table)
+{
+  char *ptr;
+  bool res1, res2;
+
+  DBUG_ENTER("Event_queue_element::load_from_row");
 
-  if ((et->definer.str= get_field(&mem_root,
-                                  table->field[ET_FIELD_DEFINER])) == NullS)
+  if (!table)
     goto error;
-  et->definer.length= strlen(et->definer.str);
 
-  ptr= strchr(et->definer.str, '@');
+  if (table->s->fields != ET_FIELD_COUNT)
+    goto error;
 
-  if (! ptr)
-    ptr= et->definer.str;
+  load_string_fields(table->field, ET_FIELD_DB, &dbname, ET_FIELD_NAME, &name,
+                     ET_FIELD_DEFINER, &definer, ET_FIELD_COUNT);
+/*
+  if ((dbname.str= get_field(&mem_root, table->field[ET_FIELD_DB])) == NullS)
+    goto error;
+  dbname.length= strlen(dbname.str);
 
-  len= ptr - et->definer.str;
+  if ((name.str= get_field(&mem_root, table->field[ET_FIELD_NAME])) == NullS)
+    goto error;
+  name.length= strlen(name.str);
 
-  et->definer_user.str= strmake_root(&mem_root, et->definer.str, len);
-  et->definer_user.length= len;
-  len= et->definer.length - len - 1;            //1 is because of @
-  et->definer_host.str= strmake_root(&mem_root, ptr + 1, len);/* 1:because of @*/
-  et->definer_host.length= len;
-  
-  et->starts_null= table->field[ET_FIELD_STARTS]->is_null();
-  res1= table->field[ET_FIELD_STARTS]->
-                                    get_date(&et->starts,TIME_NO_ZERO_DATE);
+  if ((definer.str= get_field(&mem_root,
+                              table->field[ET_FIELD_DEFINER])) == NullS)
+    goto error;
+  definer.length= strlen(definer.str);
+*/
+  starts_null= table->field[ET_FIELD_STARTS]->is_null();
+  res1= table->field[ET_FIELD_STARTS]->get_date(&starts, TIME_NO_ZERO_DATE);
 
-  et->ends_null= table->field[ET_FIELD_ENDS]->is_null();
-  res2= table->field[ET_FIELD_ENDS]->get_date(&et->ends, TIME_NO_ZERO_DATE);
+  ends_null= table->field[ET_FIELD_ENDS]->is_null();
+  res2= table->field[ET_FIELD_ENDS]->get_date(&ends, TIME_NO_ZERO_DATE);
   
   if (!table->field[ET_FIELD_INTERVAL_EXPR]->is_null())
-    et->expression= table->field[ET_FIELD_INTERVAL_EXPR]->val_int();
+    expression= table->field[ET_FIELD_INTERVAL_EXPR]->val_int();
   else
-    et->expression= 0;
+    expression= 0;
   /*
-    If res1 and res2 are true then both fields are empty.
+    If res1 and res2 are TRUE then both fields are empty.
     Hence if ET_FIELD_EXECUTE_AT is empty there is an error.
   */
-  et->execute_at_null=
-            table->field[ET_FIELD_EXECUTE_AT]->is_null();
-  DBUG_ASSERT(!(et->starts_null && et->ends_null && !et->expression &&
-              et->execute_at_null));
-  if (!et->expression &&
-      table->field[ET_FIELD_EXECUTE_AT]-> get_date(&et->execute_at,
-                                                        TIME_NO_ZERO_DATE))
+  execute_at_null= table->field[ET_FIELD_EXECUTE_AT]->is_null();
+  DBUG_ASSERT(!(starts_null && ends_null && !expression && execute_at_null));
+  if (!expression &&
+      table->field[ET_FIELD_EXECUTE_AT]->get_date(&execute_at,
+                                                  TIME_NO_ZERO_DATE))
     goto error;
 
   /*
@@ -684,41 +930,94 @@ Event_timed::load_from_row(TABLE *table)
     from 0
   */
   if (!table->field[ET_FIELD_TRANSIENT_INTERVAL]->is_null())
-    et->interval= (interval_type) ((ulonglong)
+    interval= (interval_type) ((ulonglong)
           table->field[ET_FIELD_TRANSIENT_INTERVAL]->val_int() - 1);
   else
-    et->interval= (interval_type) 0;
-
-  et->created= table->field[ET_FIELD_CREATED]->val_int();
-  et->modified= table->field[ET_FIELD_MODIFIED]->val_int();
+    interval= (interval_type) 0;
 
-  table->field[ET_FIELD_LAST_EXECUTED]->
-                     get_date(&et->last_executed, TIME_NO_ZERO_DATE);
+  table->field[ET_FIELD_LAST_EXECUTED]->get_date(&last_executed,
+                                                 TIME_NO_ZERO_DATE);
+  last_executed_changed= FALSE;
 
-  last_executed_changed= false;
 
-  /* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
   if ((ptr= get_field(&mem_root, table->field[ET_FIELD_STATUS])) == NullS)
     goto error;
 
-  DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", et->name.str, ptr));
-  et->status= (ptr[0]=='E'? Event_timed::ENABLED:Event_timed::DISABLED);
+  DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", name.str, ptr));
+  status= (ptr[0]=='E'? Event_queue_element::ENABLED:
+                        Event_queue_element::DISABLED);
 
   /* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
   if ((ptr= get_field(&mem_root,
-                  table->field[ET_FIELD_ON_COMPLETION])) == NullS)
+                      table->field[ET_FIELD_ON_COMPLETION])) == NullS)
+    goto error;
+
+  on_completion= (ptr[0]=='D'? Event_queue_element::ON_COMPLETION_DROP:
+                               Event_queue_element::ON_COMPLETION_PRESERVE);
+
+  DBUG_RETURN(0);
+error:
+  DBUG_RETURN(EVEX_GET_FIELD_FAILED);
+}
+
+
+/*
+  Loads an event from a row from mysql.event
+
+  SYNOPSIS
+    Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
+
+  RETURN VALUE
+    0                      OK
+    EVEX_GET_FIELD_FAILED  Error
+
+  NOTES
+    This method is silent on errors and should behave like that. Callers
+    should handle throwing of error messages. The reason is that the class
+    should not know about how to deal with communication.
+*/
+
+int
+Event_timed::load_from_row(TABLE *table)
+{
+  char *ptr;
+  uint len;
+
+  DBUG_ENTER("Event_timed::load_from_row");
+
+  if (Event_queue_element::load_from_row(table))
+    goto error;
+
+  load_string_fields(table->field, ET_FIELD_BODY, &body, ET_FIELD_COUNT);
+/*
+  if ((body.str= get_field(&mem_root, table->field[ET_FIELD_BODY])) == NullS)
     goto error;
 
-  et->on_completion= (ptr[0]=='D'? Event_timed::ON_COMPLETION_DROP:
-                                   Event_timed::ON_COMPLETION_PRESERVE);
+  body.length= strlen(body.str);
+*/
+  ptr= strchr(definer.str, '@');
+
+  if (! ptr)
+    ptr= definer.str;
 
-  et->comment.str= get_field(&mem_root, table->field[ET_FIELD_COMMENT]);
-  if (et->comment.str != NullS)
-    et->comment.length= strlen(et->comment.str);
+  len= ptr - definer.str;
+  definer_user.str= strmake_root(&mem_root, definer.str, len);
+  definer_user.length= len;
+  len= definer.length - len - 1;
+  /* 1:because of @ */
+  definer_host.str= strmake_root(&mem_root, ptr + 1,  len);
+  definer_host.length= len;
+
+  created= table->field[ET_FIELD_CREATED]->val_int();
+  modified= table->field[ET_FIELD_MODIFIED]->val_int();
+
+  comment.str= get_field(&mem_root, table->field[ET_FIELD_COMMENT]);
+  if (comment.str != NullS)
+    comment.length= strlen(comment.str);
   else
-    et->comment.length= 0;
+    comment.length= 0;
 
-  et->sql_mode= (ulong) table->field[ET_FIELD_SQL_MODE]->val_int();
+  sql_mode= (ulong) table->field[ET_FIELD_SQL_MODE]->val_int();
 
   DBUG_RETURN(0);
 error:
@@ -872,7 +1171,7 @@ bool get_next_time(TIME *next, TIME *sta
     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)
     { 
@@ -896,7 +1195,7 @@ done:
   Computes next execution time.
 
   SYNOPSIS
-    Event_timed::compute_next_execution_time()
+    Event_queue_element::compute_next_execution_time()
 
   RETURN VALUE
     FALSE  OK
@@ -908,18 +1207,18 @@ done:
 */
 
 bool
-Event_timed::compute_next_execution_time()
+Event_queue_element::compute_next_execution_time()
 {
   TIME time_now;
   int tmp;
 
-  DBUG_ENTER("Event_timed::compute_next_execution_time");
-  DBUG_PRINT("enter", ("starts=%llu ends=%llu last_executed=%llu this=%p",
+  DBUG_ENTER("Event_queue_element::compute_next_execution_time");
+  DBUG_PRINT("enter", ("starts=%llu ends=%llu last_executed=%llu this=0x%lx",
                         TIME_to_ulonglong_datetime(&starts),
                         TIME_to_ulonglong_datetime(&ends),
                         TIME_to_ulonglong_datetime(&last_executed), this));
 
-  if (status == Event_timed::DISABLED)
+  if (status == Event_queue_element::DISABLED)
   {
     DBUG_PRINT("compute_next_execution_time",
                   ("Event %s is DISABLED", name.str));
@@ -933,11 +1232,11 @@ Event_timed::compute_next_execution_time
     {
       DBUG_PRINT("info",("One-time event %s.%s of was already executed",
                          dbname.str, name.str, definer.str));
-      dropped= (on_completion == Event_timed::ON_COMPLETION_DROP);
+      dropped= (on_completion == Event_queue_element::ON_COMPLETION_DROP);
       DBUG_PRINT("info",("One-time event will be dropped=%d.", dropped));
 
-      status= Event_timed::DISABLED;
-      status_changed= true;
+      status= Event_queue_element::DISABLED;
+      status_changed= TRUE;
     }
     goto ret;
   }
@@ -953,11 +1252,11 @@ Event_timed::compute_next_execution_time
     /* time_now is after ends. don't execute anymore */
     set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
     execute_at_null= TRUE;
-    if (on_completion == Event_timed::ON_COMPLETION_DROP)
-      dropped= true;
+    if (on_completion == Event_queue_element::ON_COMPLETION_DROP)
+      dropped= TRUE;
     DBUG_PRINT("info", ("Dropped=%d", dropped));
-    status= Event_timed::DISABLED;
-    status_changed= true;
+    status= Event_queue_element::DISABLED;
+    status_changed= TRUE;
 
     goto ret;
   }
@@ -1019,10 +1318,10 @@ Event_timed::compute_next_execution_time
         /* Next execution after ends. No more executions */
         set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
         execute_at_null= TRUE;
-        if (on_completion == Event_timed::ON_COMPLETION_DROP)
-          dropped= true;
-        status= Event_timed::DISABLED;
-        status_changed= true;
+        if (on_completion == Event_queue_element::ON_COMPLETION_DROP)
+          dropped= TRUE;
+        status= Event_queue_element::DISABLED;
+        status_changed= TRUE;
       }
       else
       {
@@ -1112,10 +1411,10 @@ Event_timed::compute_next_execution_time
           DBUG_PRINT("info", ("Next execution after ENDS. Stop executing."));
           set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
           execute_at_null= TRUE;
-          status= Event_timed::DISABLED;
-          status_changed= true;
-          if (on_completion == Event_timed::ON_COMPLETION_DROP)
-            dropped= true;
+          status= Event_queue_element::DISABLED;
+          status_changed= TRUE;
+          if (on_completion == Event_queue_element::ON_COMPLETION_DROP)
+            dropped= TRUE;
         }
         else
         {
@@ -1131,10 +1430,10 @@ Event_timed::compute_next_execution_time
 ret:
   DBUG_PRINT("info", ("ret=0 execute_at=%llu",
              TIME_to_ulonglong_datetime(&execute_at)));
-  DBUG_RETURN(false);
+  DBUG_RETURN(FALSE);
 err:
   DBUG_PRINT("info", ("ret=1"));
-  DBUG_RETURN(true);
+  DBUG_RETURN(TRUE);
 }
 
 
@@ -1143,12 +1442,12 @@ err:
   time according to thd->query_start(), so the THD's clock.
 
   SYNOPSIS
-    Event_timed::drop()
+    Event_queue_element::mark_last_executed()
       thd   thread context
 */
 
 void
-Event_timed::mark_last_executed(THD *thd)
+Event_queue_element::mark_last_executed(THD *thd)
 {
   TIME time_now;
 
@@ -1156,16 +1455,15 @@ Event_timed::mark_last_executed(THD *thd
   my_tz_UTC->gmt_sec_to_TIME(&time_now, (my_time_t) thd->query_start());
 
   last_executed= time_now; /* was execute_at */
-  last_executed_changed= true;
+  last_executed_changed= TRUE;
 }
 
 
-
 /*
   Drops the event
 
   SYNOPSIS
-    Event_timed::drop()
+    Event_queue_element::drop()
       thd   thread context
 
   RETURN VALUE
@@ -1178,13 +1476,13 @@ Event_timed::mark_last_executed(THD *thd
 */
 
 int
-Event_timed::drop(THD *thd)
+Event_queue_element::drop(THD *thd)
 {
   uint tmp= 0;
-  DBUG_ENTER("Event_timed::drop");
+  DBUG_ENTER("Event_queue_element::drop");
 
-  DBUG_RETURN(Events::get_instance()->
-                db_repository->drop_event(thd, dbname, name, false, &tmp));
+  DBUG_RETURN(Events::get_instance()->drop_event(thd, dbname, name, FALSE,
+                                                 &tmp, TRUE));
 }
 
 
@@ -1192,12 +1490,12 @@ Event_timed::drop(THD *thd)
   Saves status and last_executed_at to the disk if changed.
 
   SYNOPSIS
-    Event_timed::update_fields()
+    Event_queue_element::update_timing_fields()
       thd - thread context
 
   RETURN VALUE
     0   OK
-    EVEX_OPEN_TABLE_FAILED    Error while opening mysql.event for writing
+    EVEX_OPEN_TABLE_FAILED  Error while opening mysql.event for writing
     EVEX_WRITE_ROW_FAILED   On error to write to disk
 
    others                   return code from SE in case deletion of the event
@@ -1205,13 +1503,13 @@ Event_timed::drop(THD *thd)
 */
 
 bool
-Event_timed::update_fields(THD *thd)
+Event_queue_element::update_timing_fields(THD *thd)
 {
   TABLE *table;
   Open_tables_state backup;
   int ret;
 
-  DBUG_ENTER("Event_timed::update_fields");
+  DBUG_ENTER("Event_queue_element::update_timing_fields");
 
   DBUG_PRINT("enter", ("name: %*s", name.length, name.str));
 
@@ -1227,8 +1525,8 @@ Event_timed::update_fields(THD *thd)
     goto done;
   }
 
-
-  if ((ret= evex_db_find_event_by_name(thd, dbname, name, table)))
+  if ((ret= Events::get_instance()->db_repository->
+                        find_event_by_name(thd, dbname, name, table)))
     goto done;
 
   store_record(table,record[1]);
@@ -1240,13 +1538,13 @@ Event_timed::update_fields(THD *thd)
     table->field[ET_FIELD_LAST_EXECUTED]->set_notnull();
     table->field[ET_FIELD_LAST_EXECUTED]->store_time(&last_executed,
                                                MYSQL_TIMESTAMP_DATETIME);
-    last_executed_changed= false;
+    last_executed_changed= FALSE;
   }
   if (status_changed)
   {
     table->field[ET_FIELD_STATUS]->set_notnull();
-    table->field[ET_FIELD_STATUS]->store((longlong)status, true);
-    status_changed= false;
+    table->field[ET_FIELD_STATUS]->store((longlong)status, TRUE);
+    status_changed= FALSE;
   }
 
   if ((table->file->ha_update_row(table->record[1],table->record[0])))
@@ -1279,8 +1577,8 @@ int
 Event_timed::get_create_event(THD *thd, String *buf)
 {
   int multipl= 0;
-  char tmp_buff[128];
-  String expr_buf(tmp_buff, sizeof(tmp_buff), system_charset_info);
+  char tmp_buf[2 * STRING_BUFFER_USUAL_SIZE];
+  String expr_buf(tmp_buf, sizeof(tmp_buf), system_charset_info);
   expr_buf.length(0);
 
   DBUG_ENTER("get_create_event");
@@ -1337,10 +1635,37 @@ Event_timed::get_create_event(THD *thd, 
 
 
 /*
+  Get SHOW CREATE EVENT as string
+
+  SYNOPSIS
+    Event_job_data::get_create_event(THD *thd, String *buf)
+      thd    Thread
+      buf    String*, should be already allocated. CREATE EVENT goes inside.
+
+  RETURN VALUE
+    0                       OK
+    EVEX_MICROSECOND_UNSUP  Error (for now if mysql.event has been
+                            tampered and MICROSECONDS interval or
+                            derivative has been put there.
+*/
+
+int
+Event_job_data::get_fake_create_event(THD *thd, String *buf)
+{
+  DBUG_ENTER("Event_job_data::get_create_event");
+  buf->append(STRING_WITH_LEN("CREATE EVENT test.anonymous ON SCHEDULE "
+                              "EVERY 3337 HOUR DO "));
+  buf->append(body.str, body.length);
+
+  DBUG_RETURN(0);
+}
+
+
+/*
   Executes the event (the underlying sp_head object);
 
   SYNOPSIS
-    Event_timed::execute()
+    Event_job_data::execute()
       thd       THD
       mem_root  If != NULL use it to compile the event on it
 
@@ -1352,16 +1677,15 @@ Event_timed::get_create_event(THD *thd, 
 */
 
 int
-Event_timed::execute(THD *thd, MEM_ROOT *mem_root)
+Event_job_data::execute(THD *thd, MEM_ROOT *mem_root)
 {
   Security_context *save_ctx;
   /* this one is local and not needed after exec */
   Security_context security_ctx;
   int ret= 0;
 
-  DBUG_ENTER("Event_timed::execute");
-  DBUG_PRINT("info", ("    EVEX EXECUTING event %s.%s [EXPR:%d]",
-               dbname.str, name.str, (int) expression));
+  DBUG_ENTER("Event_job_data::execute");
+  DBUG_PRINT("info", ("EXECUTING %s.%s", dbname.str, name.str));
 
   thd->change_security_context(definer_user, definer_host, dbname,
                                &security_ctx, &save_ctx);
@@ -1406,8 +1730,7 @@ done:
     delete sphead;
     sphead= 0;
   }
-  DBUG_PRINT("info", ("    EVEX EXECUTED event %s.%s  [EXPR:%d]. RetCode=%d",
-                      dbname.str, name.str, (int) expression, ret));
+  DBUG_PRINT("info", ("EXECUTED %s.%s ret=%d", dbname.str, name.str, ret));
 
   DBUG_RETURN(ret);
 }
@@ -1416,14 +1739,14 @@ done:
 /*
   Frees the memory of the sp_head object we hold
   SYNOPSIS
-    Event_timed::free_sp()
+    Event_job_data::free_sp()
 */
 
 void
-Event_timed::free_sp()
+Event_job_data::free_sp()
 {
   delete sphead;
-  sphead= 0;
+  sphead= NULL;
 }
 
 
@@ -1432,7 +1755,7 @@ Event_timed::free_sp()
   sp_head object held by the event
 
   SYNOPSIS
-    Event_timed::compile()
+    Event_job_data::compile()
       thd        thread context, used for memory allocation mostly
       mem_root   if != NULL then this memory root is used for allocs
                  instead of thd->mem_root
@@ -1444,7 +1767,7 @@ Event_timed::free_sp()
 */
 
 int
-Event_timed::compile(THD *thd, MEM_ROOT *mem_root)
+Event_job_data::compile(THD *thd, MEM_ROOT *mem_root)
 {
   int ret= 0;
   MEM_ROOT *tmp_mem_root= 0;
@@ -1454,7 +1777,7 @@ Event_timed::compile(THD *thd, MEM_ROOT 
   char *old_query;
   uint old_query_len;
   ulong old_sql_mode= thd->variables.sql_mode;
-  char create_buf[2048];
+  char create_buf[15 * STRING_BUFFER_USUAL_SIZE];
   String show_create(create_buf, sizeof(create_buf), system_charset_info);
   CHARSET_INFO *old_character_set_client,
                *old_collation_connection,
@@ -1463,11 +1786,11 @@ Event_timed::compile(THD *thd, MEM_ROOT 
   /* this one is local and not needed after exec */
   Security_context security_ctx;
 
-  DBUG_ENTER("Event_timed::compile");
+  DBUG_ENTER("Event_job_data::compile");
 
   show_create.length(0);
 
-  switch (get_create_event(thd, &show_create)) {
+  switch (get_fake_create_event(thd, &show_create)) {
   case EVEX_MICROSECOND_UNSUP:
     sql_print_error("Scheduler");
     DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
@@ -1503,7 +1826,7 @@ Event_timed::compile(THD *thd, MEM_ROOT 
   thd->db= dbname.str;
   thd->db_length= dbname.length;
 
-  thd->query= show_create.c_ptr();
+  thd->query= show_create.c_ptr_safe();
   thd->query_length= show_create.length();
   DBUG_PRINT("info", ("query:%s",thd->query));
 
@@ -1566,36 +1889,18 @@ done:
 
 
 /*
-  Checks whether two events have the same name
-
-  SYNOPSIS
-    event_timed_name_equal()
-
-  RETURN VALUE
-    TRUE  names are equal
-    FALSE names are not equal
-*/
-
-bool
-event_timed_name_equal(Event_timed *et, LEX_STRING *name)
-{
-  return !sortcmp_lex_string(et->name, *name, system_charset_info);
-}
-
-
-/*
   Checks whether two events are in the same schema
 
   SYNOPSIS
-    event_timed_db_equal()
+    event_basic_db_equal()
 
   RETURN VALUE
-    TRUE  schemas are equal
-    FALSE schemas are not equal
+    TRUE   Equal
+    FALSE  Not equal
 */
 
 bool
-event_timed_db_equal(Event_timed *et, LEX_STRING *db)
+event_basic_db_equal(LEX_STRING *db, Event_basic *et)
 {
   return !sortcmp_lex_string(et->dbname, *db, system_charset_info);
 }
@@ -1605,17 +1910,16 @@ event_timed_db_equal(Event_timed *et, LE
   Checks whether two events are equal by identifiers
 
   SYNOPSIS
-    event_timed_identifier_equal()
+    event_basic_identifier_equal()
 
   RETURN VALUE
-    TRUE   equal
-    FALSE  not equal
+    TRUE   Equal
+    FALSE  Not equal
 */
 
 bool
-event_timed_identifier_equal(LEX_STRING db, LEX_STRING name, Event_timed *b)
+event_basic_identifier_equal(LEX_STRING db, LEX_STRING name, Event_basic *b)
 {
   return !sortcmp_lex_string(name, b->name, system_charset_info) &&
          !sortcmp_lex_string(db, b->dbname, system_charset_info);
 }
-

--- 1.8/sql/event_data_objects.h	2006-07-05 17:12:41 +02:00
+++ 1.9/sql/event_data_objects.h	2006-07-10 13:44:33 +02:00
@@ -47,30 +47,46 @@
 
 class sp_head;
 class Sql_alloc;
-
-class Event_timed;
+class Event_basic;
 
 /* Compares only the schema part of the identifier */
 bool
-event_timed_db_equal(Event_timed *et, LEX_STRING *db);
+event_basic_db_equal( LEX_STRING *db, Event_basic *et);
 
 /* Compares the whole identifier*/
 bool
-event_timed_identifier_equal(LEX_STRING db, LEX_STRING name, Event_timed *b);
-
+event_basic_identifier_equal(LEX_STRING db, LEX_STRING name, Event_basic *b);
 
-class Event_timed
+class Event_basic
 {
-  Event_timed(const Event_timed &);	/* Prevent use of these */
-  void operator=(Event_timed &);
+protected:
+  MEM_ROOT mem_root;
 
+public:
+  LEX_STRING dbname;
+  LEX_STRING name;
+  LEX_STRING definer;// combination of user and host
+  
+  Event_basic();
+  virtual ~Event_basic();
+
+  virtual int
+  load_from_row(TABLE *table) = 0;
+
+protected:
+  bool
+  load_string_fields(Field **fields, ...);
+};
+
+
+
+class Event_queue_element : public Event_basic
+{
+protected:
   bool status_changed;
   bool last_executed_changed;
-  
-  MEM_ROOT mem_root;
 
 public:
-  THD *thd;
   enum enum_status
   {
     ENABLED = 1,
@@ -83,17 +99,10 @@ public:
     ON_COMPLETION_PRESERVE
   };
 
+  enum enum_on_completion on_completion;
+  enum enum_status status;
   TIME last_executed;
 
-  LEX_STRING dbname;
-  LEX_STRING name;
-  LEX_STRING body;
-
-  LEX_STRING definer_user;
-  LEX_STRING definer_host;
-  LEX_STRING definer;// combination of user and host
-
-  LEX_STRING comment;
   TIME starts;
   TIME ends;
   TIME execute_at;
@@ -104,20 +113,32 @@ public:
   longlong expression;
   interval_type interval;
 
-  ulonglong created;
-  ulonglong modified;
-  enum enum_on_completion on_completion;
-  enum enum_status status;
-  sp_head *sphead;
-  ulong sql_mode;
+  uint flags;//all kind of purposes
 
   bool dropped;
-  uint flags;//all kind of purposes
+
+  Event_queue_element();
+  virtual ~Event_queue_element();
+  
+  virtual int
+  load_from_row(TABLE *table);
+
+  bool
+  compute_next_execution_time();
+
+  int
+  drop(THD *thd);
+
+  void
+  mark_last_executed(THD *thd);
+
+  bool
+  update_timing_fields(THD *thd);
 
   static void *operator new(size_t size)
   {
     void *p;
-    DBUG_ENTER("Event_timed::new(size)");
+    DBUG_ENTER("Event_queue_element::new(size)");
     p= my_malloc(size, MYF(0));
     DBUG_PRINT("info", ("alloc_ptr=0x%lx", p));
     DBUG_RETURN(p);
@@ -125,54 +146,84 @@ public:
 
   static void operator delete(void *ptr, size_t size)
   {
-    DBUG_ENTER("Event_timed::delete(ptr,size)");
+    DBUG_ENTER("Event_queue_element::delete(ptr,size)");
     DBUG_PRINT("enter", ("free_ptr=0x%lx", ptr));
     TRASH(ptr, size);
     my_free((gptr) ptr, MYF(0));
     DBUG_VOID_RETURN;
   }
+};
 
-  Event_timed();
 
-  ~Event_timed();
+class Event_timed : public Event_queue_element
+{
+  Event_timed(const Event_timed &);	/* Prevent use of these */
+  void operator=(Event_timed &);
 
-  void
-  init();
+public:
+  LEX_STRING body;
 
-  int
-  load_from_row(TABLE *table);
+  LEX_STRING definer_user;
+  LEX_STRING definer_host;
 
-  bool
-  compute_next_execution_time();
+  LEX_STRING comment;
 
-  int
-  drop(THD *thd);
+  ulonglong created;
+  ulonglong modified;
+
+  ulong sql_mode;
+
+  Event_timed();
+  virtual ~Event_timed();
 
   void
-  mark_last_executed(THD *thd);
+  init();
 
-  bool
-  update_fields(THD *thd);
+  virtual int
+  load_from_row(TABLE *table);
 
   int
   get_create_event(THD *thd, String *buf);
+};
+
+
+class Event_job_data : public Event_basic
+{
+public:
+  THD *thd;
+  sp_head *sphead;
+
+  LEX_STRING body;
+  LEX_STRING definer_user;
+  LEX_STRING definer_host;
+
+  ulong sql_mode;
+
+  Event_job_data();
+  virtual ~Event_job_data();
+
+  virtual int
+  load_from_row(TABLE *table);
 
   int
   execute(THD *thd, MEM_ROOT *mem_root);
+private:
+  int
+  get_fake_create_event(THD *thd, String *buf);
 
   int
   compile(THD *thd, MEM_ROOT *mem_root);
-  
+
   void
   free_sp();
+
+  Event_job_data(const Event_job_data &);	/* Prevent use of these */
+  void operator=(Event_job_data &);
 };
 
 
 class Event_parse_data : public Sql_alloc
 {
-  Event_parse_data(const Event_parse_data &);	/* Prevent use of these */
-  void operator=(Event_parse_data &);
-
 public:
   enum enum_status
   {
@@ -185,7 +236,6 @@ public:
     ON_COMPLETION_DROP = 1,
     ON_COMPLETION_PRESERVE
   };
-
   enum enum_on_completion on_completion;
   enum enum_status status;
 
@@ -193,8 +243,8 @@ public:
 
   LEX_STRING dbname;
   LEX_STRING name;
-  LEX_STRING body;
   LEX_STRING definer;// combination of user and host
+  LEX_STRING body;
   LEX_STRING comment;
 
   Item* item_starts;
@@ -216,59 +266,41 @@ public:
   static Event_parse_data *
   new_instance(THD *thd);
 
-  Event_parse_data();
-  ~Event_parse_data();
+  bool
+  check_parse_data(THD *);
 
-  int
-  init_definer(THD *thd);
+  void
+  init_body(THD *thd);
 
-  int
-  init_execute_at(THD *thd, Item *expr);
+private:
 
   int
-  init_interval(THD *thd, Item *expr, interval_type new_interval);
+  init_definer(THD *thd);
 
   void
   init_name(THD *thd, sp_name *spn);
 
   int
-  init_starts(THD *thd, Item *starts);
+  init_execute_at(THD *thd);
 
   int
-  init_ends(THD *thd, Item *ends);
-
-  void
-  init_body(THD *thd);
-};
-
-
-class Event_job_data
-{
-public:
-  LEX_STRING dbname;
-  LEX_STRING name;
-  sp_head *sphead;
-  LEX_STRING definer;
-  LEX_STRING body;
-  ulong sql_mode;
-
-  THD *thd;
-  
-  Event_job_data(){}
-  ~Event_job_data(){}
+  init_interval(THD *thd);
 
   int
-  execute();
+  init_starts(THD *thd);
 
-private:
-  int
-  load_from_disk();
-  
   int
-  compile();
+  init_ends(THD *thd);
+
+  Event_parse_data();
+  ~Event_parse_data();
 
+  void
+  report_bad_value(const char *item_name, Item *bad_item);
 
-  Event_job_data(const Event_job_data &);	/* Prevent use of these */
-  void operator=(Event_job_data &);
+  Event_parse_data(const Event_parse_data &);	/* Prevent use of these */
+  void operator=(Event_parse_data &);
 };
+
+
 #endif /* _EVENT_DATA_OBJECTS_H_ */

--- 1.114/sql/share/errmsg.txt	2006-07-04 18:44:17 +02:00
+++ 1.115/sql/share/errmsg.txt	2006-07-10 13:44:33 +02:00
@@ -5829,7 +5829,7 @@ ER_CANT_CHANGE_TX_ISOLATION 25001
 ER_DUP_ENTRY_AUTOINCREMENT_CASE
         eng "ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '%-.64s' for key '%-.64s'"
 ER_EVENT_MODIFY_QUEUE_ERROR
-        eng "Internal scheduler error %d"
+        eng "Error during loading event from disk. mysql.event damaged?"
 ER_EVENT_SET_VAR_ERROR
         eng "Error during starting/stopping of the scheduler."
 ER_PARTITION_MERGE_ERROR
Thread
bk commit into 5.1 tree (andrey:1.2229)ahristov10 Jul