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(<ime, TIME_NO_ZERO_DATE)))
- DBUG_RETURN(ER_WRONG_VALUE);
+ if ((not_used= item_execute_at->get_date(<ime, TIME_NO_ZERO_DATE)))
+ goto wrong_value;
if (TIME_to_ulonglong_datetime(<ime) <
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(<ime, TIME_NO_ZERO_DATE)))
- DBUG_RETURN(EVEX_BAD_PARAMS);
+ if ((not_used= item_starts->get_date(<ime, 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(<ime)));
if (TIME_to_ulonglong_datetime(<ime) <
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(<ime,t=TIME_to_timestamp(thd, <ime, ¬_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(<ime, TIME_NO_ZERO_DATE)))
- DBUG_RETURN(EVEX_BAD_PARAMS);
+ if ((not_used= item_ends->get_date(<ime, 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(<ime,t=TIME_to_timestamp(thd, <ime, ¬_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, <ime) != -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(<ime_now, thd->query_start());
if (my_time_compare(<ime_now, <ime) == 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) | ahristov | 10 Jul |