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. mysql-test/r/events.result: update results mysql-test/r/events_bugs.result: update results mysql-test/r/events_logs_tests.result: update results mysql-test/r/events_scheduling.result: update results mysql-test/t/events.test: 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_bugs.test: 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_logs_tests.test: make the test shorter by time mysql-test/t/events_scheduling.test: when selecting always use ORDER BY mysql-test/t/events_stress.test: sleep 2.5secs for shorter stress test sql/event_data_objects.cc: 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.h: 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_db_repository.cc: 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_db_repository.h: Event_db_repository depends only on Event_basic's interface sql/event_queue.cc: 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.h: 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_scheduler_ng.cc: 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_scheduler_ng.h: Add back Event_scheduler::cond_wait() Add back Event_scheduler::dump_internal_status() Using Event_job_data for execution. sql/events.cc: Documentation Add LOCK_event_metadata sql/events.h: Change the signature of Events::drop_event() not to use sp_name but LEX_STRING sql/share/errmsg.txt: Fix error message sql/sql_parse.cc: Events::drop_event() has new signature
This commit is contained in:
parent
b9a7fe2757
commit
974eecc246
@ -87,7 +87,6 @@ events_test event_starts_test root@localhost RECURRING NULL 20 SECOND # # ENABLE
|
||||
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't yet support 'MICROSECOND'
|
||||
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 every 10 hour do select get_lock("test_l
|
||||
"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 schedule every 10 hour do select get_lock("test
|
||||
"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:"
|
||||
|
@ -24,8 +24,19 @@ create event e_55 on schedule every 10 hour starts 99990101000000 do drop table
|
||||
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_mode from information_schema.events order b
|
||||
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 char(10), a date) engine=myisam;
|
||||
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-19-02' for column 'a' at row 1
|
||||
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
|
||||
|
@ -9,7 +9,7 @@ SELECT user_host, argument FROM mysql.general_log WHERE argument LIKE '%alabala%
|
||||
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 SLEEP(2)
|
||||
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"
|
||||
|
@ -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
|
||||
|
@ -18,7 +18,7 @@ CREATE EVENT e_x2 ON SCHEDULE EVERY 1 SECOND DO DROP TABLE x_table;
|
||||
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;
|
||||
|
@ -45,6 +45,19 @@ create event e_55 on schedule at 99990101000000 do drop table t;
|
||||
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 minute ends 99990101000000 do drop table
|
||||
# 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 ('test','1980-19-02')|
|
||||
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() begin insert into events_test.events_smode
|
||||
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;
|
||||
|
@ -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_text FROM mysql.slow_log;
|
||||
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"
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 &);
|
||||
|
||||
bool status_changed;
|
||||
bool last_executed_changed;
|
||||
|
||||
protected:
|
||||
MEM_ROOT mem_root;
|
||||
|
||||
public:
|
||||
THD *thd;
|
||||
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;
|
||||
|
||||
public:
|
||||
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,42 +113,14 @@ 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;
|
||||
|
||||
bool dropped;
|
||||
uint flags;//all kind of purposes
|
||||
|
||||
static void *operator new(size_t size)
|
||||
{
|
||||
void *p;
|
||||
DBUG_ENTER("Event_timed::new(size)");
|
||||
p= my_malloc(size, MYF(0));
|
||||
DBUG_PRINT("info", ("alloc_ptr=0x%lx", p));
|
||||
DBUG_RETURN(p);
|
||||
}
|
||||
bool dropped;
|
||||
|
||||
static void operator delete(void *ptr, size_t size)
|
||||
{
|
||||
DBUG_ENTER("Event_timed::delete(ptr,size)");
|
||||
DBUG_PRINT("enter", ("free_ptr=0x%lx", ptr));
|
||||
TRASH(ptr, size);
|
||||
my_free((gptr) ptr, MYF(0));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
Event_queue_element();
|
||||
virtual ~Event_queue_element();
|
||||
|
||||
Event_timed();
|
||||
|
||||
~Event_timed();
|
||||
|
||||
void
|
||||
init();
|
||||
|
||||
int
|
||||
virtual int
|
||||
load_from_row(TABLE *table);
|
||||
|
||||
bool
|
||||
@ -152,27 +133,97 @@ public:
|
||||
mark_last_executed(THD *thd);
|
||||
|
||||
bool
|
||||
update_fields(THD *thd);
|
||||
update_timing_fields(THD *thd);
|
||||
|
||||
static void *operator new(size_t size)
|
||||
{
|
||||
void *p;
|
||||
DBUG_ENTER("Event_queue_element::new(size)");
|
||||
p= my_malloc(size, MYF(0));
|
||||
DBUG_PRINT("info", ("alloc_ptr=0x%lx", p));
|
||||
DBUG_RETURN(p);
|
||||
}
|
||||
|
||||
static void operator delete(void *ptr, size_t 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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Event_timed : public Event_queue_element
|
||||
{
|
||||
Event_timed(const Event_timed &); /* Prevent use of these */
|
||||
void operator=(Event_timed &);
|
||||
|
||||
public:
|
||||
LEX_STRING body;
|
||||
|
||||
LEX_STRING definer_user;
|
||||
LEX_STRING definer_host;
|
||||
|
||||
LEX_STRING comment;
|
||||
|
||||
ulonglong created;
|
||||
ulonglong modified;
|
||||
|
||||
ulong sql_mode;
|
||||
|
||||
Event_timed();
|
||||
virtual ~Event_timed();
|
||||
|
||||
void
|
||||
init();
|
||||
|
||||
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 *);
|
||||
|
||||
void
|
||||
init_body(THD *thd);
|
||||
|
||||
private:
|
||||
|
||||
int
|
||||
init_definer(THD *thd);
|
||||
|
||||
int
|
||||
init_execute_at(THD *thd, Item *expr);
|
||||
|
||||
int
|
||||
init_interval(THD *thd, Item *expr, interval_type new_interval);
|
||||
|
||||
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);
|
||||
init_interval(THD *thd);
|
||||
|
||||
int
|
||||
init_starts(THD *thd);
|
||||
|
||||
int
|
||||
init_ends(THD *thd);
|
||||
|
||||
Event_parse_data();
|
||||
~Event_parse_data();
|
||||
|
||||
void
|
||||
init_body(THD *thd);
|
||||
report_bad_value(const char *item_name, Item *bad_item);
|
||||
|
||||
Event_parse_data(const Event_parse_data &); /* Prevent use of these */
|
||||
void operator=(Event_parse_data &);
|
||||
};
|
||||
|
||||
|
||||
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(){}
|
||||
|
||||
int
|
||||
execute();
|
||||
|
||||
private:
|
||||
int
|
||||
load_from_disk();
|
||||
|
||||
int
|
||||
compile();
|
||||
|
||||
|
||||
Event_job_data(const Event_job_data &); /* Prevent use of these */
|
||||
void operator=(Event_job_data &);
|
||||
};
|
||||
#endif /* _EVENT_DATA_OBJECTS_H_ */
|
||||
|
@ -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_FIELD_COUNT] = {
|
||||
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]->
|
||||
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, Event_parse_data *et, my_bool is_update)
|
||||
*/
|
||||
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,47 +230,23 @@ evex_fill_row(THD *thd, TABLE *table, Event_parse_data *et, my_bool is_update)
|
||||
*/
|
||||
}
|
||||
|
||||
((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]->
|
||||
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.
|
||||
|
||||
@ -313,7 +283,7 @@ Event_db_repository::index_read_for_db_for_i_s(THD *thd, TABLE *schema_table,
|
||||
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
|
||||
{
|
||||
@ -440,100 +410,14 @@ Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *tables, char *db)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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(THD *thd, enum thr_lock_type lock_type,
|
||||
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_data *parse_data)
|
||||
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 *thd, Event_parse_data *parse_data,
|
||||
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 *thd, Event_parse_data *parse_data,
|
||||
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 *thd, Event_parse_data *parse_data,
|
||||
((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 *thd, Event_parse_data *parse_data,
|
||||
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 *thd, Event_parse_data *parse_data,
|
||||
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 *thd, Event_parse_data *parse_data,
|
||||
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 *thd, Event_parse_data *parse_data,
|
||||
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, LEX_STRING db, LEX_STRING name,
|
||||
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, LEX_STRING db, LEX_STRING name,
|
||||
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,6 +863,19 @@ Event_db_repository::find_event_by_name(THD *thd, LEX_STRING db,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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_schema_events(THD *thd, LEX_STRING schema)
|
||||
{
|
||||
@ -1050,18 +883,11 @@ Event_db_repository::drop_schema_events(THD *thd, LEX_STRING schema)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Event_db_repository::drop_user_events(THD *thd, LEX_STRING definer)
|
||||
{
|
||||
return drop_events_by_field(thd, ET_FIELD_DEFINER, definer);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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_field(THD *thd,
|
||||
|
||||
|
||||
/*
|
||||
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));
|
||||
|
||||
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 (et_loaded->status != Event_timed::ENABLED)
|
||||
if (open_event_table(thd, TL_READ, &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_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
||||
ret= EVEX_GENERAL_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
et_loaded->compute_next_execution_time();
|
||||
*etn_new= et_loaded;
|
||||
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
|
||||
|
||||
DBUG_RETURN(OP_OK);
|
||||
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 (table)
|
||||
close_thread_tables(thd);
|
||||
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
|
||||
|
||||
@ -1174,50 +1007,34 @@ Event_db_repository::load_named_event_timed(THD *thd, LEX_STRING dbname,
|
||||
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);
|
||||
}
|
||||
|
@ -38,11 +38,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 *schema_table, TABLE *event_table);
|
||||
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);
|
||||
find_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_basic *et);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
1269
sql/event_queue.cc
1269
sql/event_queue.cc
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
recalculate_activation_times(THD *thd);
|
||||
|
||||
void
|
||||
empty_queue();
|
||||
|
||||
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_ */
|
||||
|
@ -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,25 +253,32 @@ 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,
|
||||
@ -277,36 +286,35 @@ event_worker_ng_thread(void *arg)
|
||||
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= 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,10 +708,20 @@ Event_scheduler_ng::lock_data(const char *func, uint line)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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;
|
||||
@ -598,3 +729,147 @@ Event_scheduler_ng::unlock_data(const char *func, uint line)
|
||||
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);
|
||||
}
|
||||
|
@ -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
|
||||
@ -85,6 +85,9 @@ 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 */
|
||||
|
414
sql/events.cc
414
sql/events.cc
@ -291,11 +291,11 @@ Events::open_event_table(THD *thd, enum thr_lock_type lock_type,
|
||||
|
||||
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_parse_data *parse_data, bool if_not_exists,
|
||||
{
|
||||
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_parse_data *parse_data, bool if_not_exists,
|
||||
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_parse_data *parse_data, sp_name *new_name,
|
||||
{
|
||||
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_parse_data *parse_data, sp_name *new_name,
|
||||
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_parse_data *parse_data, sp_name *new_name,
|
||||
*/
|
||||
|
||||
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)
|
||||
@ -462,154 +514,6 @@ err:
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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));
|
||||
|
||||
event_queue->drop_schema_events(thd, db_lex);
|
||||
ret= db_repository->drop_schema_events(thd, db_lex);
|
||||
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Inits the scheduler's structures.
|
||||
|
||||
SYNOPSIS
|
||||
Events::init()
|
||||
|
||||
NOTES
|
||||
This function is not synchronized.
|
||||
|
||||
RETURN VALUE
|
||||
0 OK
|
||||
1 Error
|
||||
*/
|
||||
|
||||
int
|
||||
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);
|
||||
|
||||
/* it should be an assignment! */
|
||||
if (opt_event_scheduler)
|
||||
{
|
||||
DBUG_ASSERT(opt_event_scheduler == 1 || opt_event_scheduler == 2);
|
||||
if (opt_event_scheduler == 1)
|
||||
DBUG_RETURN(scheduler_ng->start());
|
||||
}
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Cleans up scheduler's resources. Called at server shutdown.
|
||||
|
||||
SYNOPSIS
|
||||
Events::deinit()
|
||||
|
||||
NOTES
|
||||
This function is not synchronized.
|
||||
*/
|
||||
|
||||
void
|
||||
Events::deinit()
|
||||
{
|
||||
DBUG_ENTER("Events::deinit");
|
||||
|
||||
scheduler_ng->stop();
|
||||
scheduler_ng->deinit_scheduler();
|
||||
|
||||
event_queue->deinit_queue();
|
||||
db_repository->deinit_repository();
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Inits Events mutexes
|
||||
|
||||
SYNOPSIS
|
||||
Events::init_mutexes()
|
||||
thd Thread
|
||||
*/
|
||||
|
||||
void
|
||||
Events::init_mutexes()
|
||||
{
|
||||
db_repository= new Event_db_repository;
|
||||
|
||||
event_queue= new Event_queue;
|
||||
event_queue->init_mutexes();
|
||||
|
||||
scheduler_ng= new Event_scheduler_ng();
|
||||
scheduler_ng->init_mutexes();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Destroys Events mutexes
|
||||
|
||||
SYNOPSIS
|
||||
Events::destroy_mutexes()
|
||||
*/
|
||||
|
||||
void
|
||||
Events::destroy_mutexes()
|
||||
{
|
||||
event_queue->deinit_mutexes();
|
||||
scheduler_ng->deinit_mutexes();
|
||||
|
||||
delete scheduler_ng;
|
||||
delete db_repository;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Proxy for Event_scheduler::dump_internal_status
|
||||
|
||||
SYNOPSIS
|
||||
Events::dump_internal_status()
|
||||
thd Thread
|
||||
|
||||
RETURN VALUE
|
||||
0 OK
|
||||
!0 Error
|
||||
*/
|
||||
|
||||
int
|
||||
Events::dump_internal_status(THD *thd)
|
||||
{
|
||||
return Event_scheduler_ng::dump_internal_status(thd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Proxy for Event_db_repository::fill_schema_events.
|
||||
Callback for I_S from sql_show.cc
|
||||
@ -646,6 +550,153 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Inits the scheduler's structures.
|
||||
|
||||
SYNOPSIS
|
||||
Events::init()
|
||||
|
||||
NOTES
|
||||
This function is not synchronized.
|
||||
|
||||
RETURN VALUE
|
||||
0 OK
|
||||
1 Error
|
||||
*/
|
||||
|
||||
int
|
||||
Events::init()
|
||||
{
|
||||
int ret= 0;
|
||||
Event_db_repository *db_repo;
|
||||
DBUG_ENTER("Events::init");
|
||||
event_queue->init_queue(db_repository, scheduler_ng);
|
||||
scheduler_ng->init_scheduler(event_queue);
|
||||
|
||||
/* it should be an assignment! */
|
||||
if (opt_event_scheduler)
|
||||
{
|
||||
DBUG_ASSERT(opt_event_scheduler == 1 || opt_event_scheduler == 2);
|
||||
if (opt_event_scheduler == 1)
|
||||
DBUG_RETURN(scheduler_ng->start());
|
||||
}
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Cleans up scheduler's resources. Called at server shutdown.
|
||||
|
||||
SYNOPSIS
|
||||
Events::deinit()
|
||||
|
||||
NOTES
|
||||
This function is not synchronized.
|
||||
*/
|
||||
|
||||
void
|
||||
Events::deinit()
|
||||
{
|
||||
DBUG_ENTER("Events::deinit");
|
||||
|
||||
scheduler_ng->stop();
|
||||
scheduler_ng->deinit_scheduler();
|
||||
|
||||
event_queue->deinit_queue();
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Inits Events mutexes
|
||||
|
||||
SYNOPSIS
|
||||
Events::init_mutexes()
|
||||
thd Thread
|
||||
*/
|
||||
|
||||
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;
|
||||
event_queue->init_mutexes();
|
||||
|
||||
scheduler_ng= new Event_scheduler_ng();
|
||||
scheduler_ng->init_mutexes();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Destroys Events mutexes
|
||||
|
||||
SYNOPSIS
|
||||
Events::destroy_mutexes()
|
||||
*/
|
||||
|
||||
void
|
||||
Events::destroy_mutexes()
|
||||
{
|
||||
event_queue->deinit_mutexes();
|
||||
scheduler_ng->deinit_mutexes();
|
||||
|
||||
delete scheduler_ng;
|
||||
delete db_repository;
|
||||
|
||||
pthread_mutex_destroy(&LOCK_event_metadata);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Proxy for Event_scheduler::dump_internal_status
|
||||
|
||||
SYNOPSIS
|
||||
Events::dump_internal_status()
|
||||
thd Thread
|
||||
|
||||
RETURN VALUE
|
||||
FALSE OK
|
||||
TRUE Error
|
||||
*/
|
||||
|
||||
bool
|
||||
Events::dump_internal_status(THD *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);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Starts execution of events by the scheduler
|
||||
|
||||
SYNOPSIS
|
||||
Events::start_execution_of_events()
|
||||
|
||||
RETURN VALUE
|
||||
FALSE OK
|
||||
TRUE Error
|
||||
*/
|
||||
|
||||
bool
|
||||
Events::start_execution_of_events()
|
||||
{
|
||||
@ -654,6 +705,19 @@ 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()
|
||||
{
|
||||
@ -661,6 +725,18 @@ 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()
|
||||
{
|
||||
|
17
sql/events.h
17
sql/events.h
@ -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_STRING t, CHARSET_INFO *cs);
|
||||
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(){}
|
||||
@ -117,6 +116,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 &);
|
||||
void operator=(Events &);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user