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;
|
DROP EVENT event_starts_test;
|
||||||
create table test_nested(a int);
|
create table test_nested(a int);
|
||||||
create event e_43 on schedule every 1 second do set @a = 5;
|
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;
|
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
|
ERROR HY000: Recursivity of EVENT DDL statements is forbidden when body is present
|
||||||
alter event e_43 do
|
alter event e_43 do
|
||||||
@ -207,6 +206,10 @@ ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
|
|||||||
SHOW EVENTS;
|
SHOW EVENTS;
|
||||||
ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
|
ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
|
||||||
drop event root22;
|
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 root6;
|
||||||
drop event root7;
|
drop event root7;
|
||||||
drop event root8;
|
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"
|
"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;
|
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
|
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)
|
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."
|
||||||
"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"
|
"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;
|
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
|
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)
|
root localhost events_test Connect User lock select get_lock("test_lock2_1", 20)
|
||||||
set global event_scheduler=2;
|
set global event_scheduler=2;
|
||||||
"Should have only our process now:"
|
"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'
|
ERROR HY000: Incorrect STARTS value: '99990101000000'
|
||||||
create event e_55 on schedule every 10 minute ends 99990101000000 do drop table t;
|
create event e_55 on schedule every 10 minute ends 99990101000000 do drop table t;
|
||||||
ERROR HY000: ENDS is either invalid or before STARTS
|
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;
|
set global event_scheduler=2;
|
||||||
"Wait a bit to settle down"
|
|
||||||
delete from mysql.event;
|
delete from mysql.event;
|
||||||
set global event_scheduler= 1;
|
set global event_scheduler= 1;
|
||||||
set @old_sql_mode:=@@sql_mode;
|
set @old_sql_mode:=@@sql_mode;
|
||||||
@ -41,7 +52,7 @@ end|
|
|||||||
"Now if everything is fine the event has compiled and is locked
|
"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 /*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
|
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)
|
root localhost events_test Connect User lock select get_lock('test_bug16407', 60)
|
||||||
select release_lock('test_bug16407');
|
select release_lock('test_bug16407');
|
||||||
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
|
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
|
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;
|
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"
|
"Another sql_mode test"
|
||||||
set sql_mode="traditional";
|
set sql_mode="traditional";
|
||||||
create table events_smode_test(ev_name char(10), a date) engine=myisam;
|
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
|
create event ee_16407_2 on schedule every 60 second do
|
||||||
begin
|
begin
|
||||||
select get_lock('ee_16407_2', 60) /*ee_16407_2*/;
|
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');
|
insert into events_test.events_smode_test values('ee_16407_2','1980-19-02');
|
||||||
end|
|
end|
|
||||||
insert into events_smode_test values ('test','1980-19-02')|
|
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
|
create event ee_16407_3 on schedule every 60 second do
|
||||||
begin
|
begin
|
||||||
select get_lock('ee_16407_2', 60) /*ee_16407_3*/;
|
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-19');
|
||||||
insert into events_test.events_smode_test values ('ee_16407_3','1980-02-29');
|
insert into events_test.events_smode_test values ('ee_16407_3','1980-02-29');
|
||||||
end|
|
end|
|
||||||
@ -80,6 +98,7 @@ set sql_mode=""|
|
|||||||
create event ee_16407_4 on schedule every 60 second do
|
create event ee_16407_4 on schedule every 60 second do
|
||||||
begin
|
begin
|
||||||
select get_lock('ee_16407_2', 60) /*ee_16407_4*/;
|
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');
|
insert into events_test.events_smode_test values ('ee_16407_4','10-11-1956');
|
||||||
end|
|
end|
|
||||||
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
|
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_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_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
|
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;
|
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
|
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_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_3*/
|
||||||
root localhost events_test Connect User lock select get_lock('ee_16407_2', 60) /*ee_16407_4*/
|
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
|
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;
|
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
|
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;
|
set global event_scheduler= 2;
|
||||||
select * from events_smode_test order by ev_name, a;
|
select * from events_smode_test order by ev_name, a;
|
||||||
ev_name a
|
ev_name a
|
||||||
@ -121,28 +135,30 @@ drop event ee_16407_3;
|
|||||||
drop event ee_16407_4;
|
drop event ee_16407_4;
|
||||||
"And now one last test regarding sql_mode and call of SP from an event"
|
"And now one last test regarding sql_mode and call of SP from an event"
|
||||||
delete from events_smode_test;
|
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';
|
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_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 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
|
create event ee_16407_5 on schedule every 60 second do
|
||||||
begin
|
begin
|
||||||
select get_lock('ee_16407_5', 60) /*ee_16407_5*/;
|
select get_lock('ee_16407_5', 60) /*ee_16407_5*/;
|
||||||
|
select release_lock('ee_16407_5');
|
||||||
call events_test.ee_16407_5_pendant();
|
call events_test.ee_16407_5_pendant();
|
||||||
end|
|
end|
|
||||||
create event ee_16407_6 on schedule every 60 second do
|
create event ee_16407_6 on schedule every 60 second do
|
||||||
begin
|
begin
|
||||||
select get_lock('ee_16407_5', 60) /*ee_16407_6*/;
|
select get_lock('ee_16407_5', 60) /*ee_16407_6*/;
|
||||||
|
select release_lock('ee_16407_5');
|
||||||
call events_test.ee_16407_6_pendant();
|
call events_test.ee_16407_6_pendant();
|
||||||
end|
|
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"
|
"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 /*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
|
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_5*/
|
||||||
root localhost events_test Connect User lock select get_lock('ee_16407_5', 60) /*ee_16407_6*/
|
root localhost events_test Connect User lock select get_lock('ee_16407_5', 60) /*ee_16407_6*/
|
||||||
select release_lock('ee_16407_5');
|
select release_lock('ee_16407_5');
|
||||||
@ -151,7 +167,7 @@ release_lock('ee_16407_5')
|
|||||||
"Should have 0 processes locked"
|
"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 /*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
|
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;
|
select * from events_smode_test order by ev_name, a;
|
||||||
ev_name a
|
ev_name a
|
||||||
ee_16407_6 2004-02-29
|
ee_16407_6 2004-02-29
|
||||||
|
@ -9,7 +9,7 @@ SELECT user_host, argument FROM mysql.general_log WHERE argument LIKE '%alabala%
|
|||||||
END|
|
END|
|
||||||
"Check General Query Log"
|
"Check General Query Log"
|
||||||
SET GLOBAL event_scheduler=2;
|
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;
|
TRUNCATE mysql.general_log;
|
||||||
"1 row, the current statement!"
|
"1 row, the current statement!"
|
||||||
call select_general_log();
|
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"
|
"Should see 3 rows - the 'SELect' is in the middle. The other two are selects from general_log"
|
||||||
call select_general_log();
|
call select_general_log();
|
||||||
user_host argument
|
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 PROCEDURE select_general_log;
|
||||||
DROP EVENT log_general;
|
DROP EVENT log_general;
|
||||||
SET GLOBAL event_scheduler=2;
|
SET GLOBAL event_scheduler=2;
|
||||||
@ -49,13 +49,13 @@ USER_HOST SLEEPVAL events_test SELECT SLEEP(2)
|
|||||||
SET SESSION long_query_time=300;
|
SET SESSION long_query_time=300;
|
||||||
"Make it quite long"
|
"Make it quite long"
|
||||||
TRUNCATE mysql.slow_log;
|
TRUNCATE mysql.slow_log;
|
||||||
SET SESSION long_query_time=1;
|
|
||||||
CREATE TABLE slow_event_test (slo_val tinyint, val tinyint);
|
CREATE TABLE slow_event_test (slo_val tinyint, val tinyint);
|
||||||
"This won't go to the slow log"
|
"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;
|
SELECT * FROM slow_event_test;
|
||||||
slo_val val
|
slo_val val
|
||||||
|
SET SESSION long_query_time=1;
|
||||||
SET GLOBAL event_scheduler=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"
|
"Sleep some more time than the actual event run will take"
|
||||||
SHOW VARIABLES LIKE 'event_scheduler';
|
SHOW VARIABLES LIKE 'event_scheduler';
|
||||||
Variable_name Value
|
Variable_name Value
|
||||||
@ -64,7 +64,7 @@ event_scheduler 1
|
|||||||
SELECT * FROM slow_event_test;
|
SELECT * FROM slow_event_test;
|
||||||
slo_val val
|
slo_val val
|
||||||
4 0
|
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;
|
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
|
||||||
user_host query_time db sql_text
|
user_host query_time db sql_text
|
||||||
"This should go to the slow log"
|
"This should go to the slow log"
|
||||||
|
@ -39,7 +39,7 @@ DROP EVENT start_n_end;
|
|||||||
DROP EVENT only_one_time;
|
DROP EVENT only_one_time;
|
||||||
ERROR HY000: Unknown event 'only_one_time'
|
ERROR HY000: Unknown event 'only_one_time'
|
||||||
"Should be preserved"
|
"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
|
EVENT_NAME STATUS
|
||||||
E19170 ENABLED
|
E19170 ENABLED
|
||||||
two_time DISABLED
|
two_time DISABLED
|
||||||
|
@ -18,7 +18,7 @@ CREATE EVENT e_x2 ON SCHEDULE EVERY 1 SECOND DO DROP TABLE x_table;
|
|||||||
connection default;
|
connection default;
|
||||||
SHOW DATABASES LIKE 'db_x';
|
SHOW DATABASES LIKE 'db_x';
|
||||||
SET GLOBAL event_scheduler=1;
|
SET GLOBAL event_scheduler=1;
|
||||||
--sleep 1.5
|
--sleep 0.8
|
||||||
SHOW DATABASES LIKE 'db_x';
|
SHOW DATABASES LIKE 'db_x';
|
||||||
SHOW TABLES FROM db_x;
|
SHOW TABLES FROM db_x;
|
||||||
SET GLOBAL event_scheduler=2;
|
SET GLOBAL event_scheduler=2;
|
||||||
@ -83,7 +83,6 @@ DROP EVENT event_starts_test;
|
|||||||
#
|
#
|
||||||
create table test_nested(a int);
|
create table test_nested(a int);
|
||||||
create event e_43 on schedule every 1 second do set @a = 5;
|
create event e_43 on schedule every 1 second do set @a = 5;
|
||||||
set global event_scheduler = 1;
|
|
||||||
--error 1562
|
--error 1562
|
||||||
alter event e_43 do alter event e_43 do set @a = 4;
|
alter event e_43 do alter event e_43 do set @a = 4;
|
||||||
delimiter |;
|
delimiter |;
|
||||||
@ -94,7 +93,7 @@ begin
|
|||||||
end|
|
end|
|
||||||
delimiter ;|
|
delimiter ;|
|
||||||
set global event_scheduler = 1;
|
set global event_scheduler = 1;
|
||||||
--sleep 1
|
--sleep 3
|
||||||
select db, name, body, status, interval_field, interval_value from mysql.event;
|
select db, name, body, status, interval_field, interval_value from mysql.event;
|
||||||
drop event e_43;
|
drop event e_43;
|
||||||
drop table test_nested;
|
drop table test_nested;
|
||||||
@ -102,7 +101,7 @@ drop table test_nested;
|
|||||||
--echo "Let's check whether we can use non-qualified names"
|
--echo "Let's check whether we can use non-qualified names"
|
||||||
create table non_qualif(a int);
|
create table non_qualif(a int);
|
||||||
create event non_qualif_ev on schedule every 10 minute do insert into non_qualif values (800219);
|
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;
|
select * from non_qualif;
|
||||||
drop event non_qualif_ev;
|
drop event non_qualif_ev;
|
||||||
drop table non_qualif;
|
drop table non_qualif;
|
||||||
@ -165,6 +164,10 @@ show create event root22;
|
|||||||
--error ER_NOT_SUPPORTED_YET
|
--error ER_NOT_SUPPORTED_YET
|
||||||
SHOW EVENTS;
|
SHOW EVENTS;
|
||||||
drop event root22;
|
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 root6;
|
||||||
drop event root7;
|
drop event root7;
|
||||||
drop event root8;
|
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"
|
--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);
|
create event закачка on schedule every 10 hour do select get_lock("test_lock2", 20);
|
||||||
--echo "Let some time pass to the event starts"
|
--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"
|
--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."
|
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."
|
--echo "Release the mutex, the event worker should finish."
|
||||||
@ -312,10 +315,11 @@ drop event закачка;
|
|||||||
set global event_scheduler=1;
|
set global event_scheduler=1;
|
||||||
select get_lock("test_lock2_1", 20);
|
select get_lock("test_lock2_1", 20);
|
||||||
create event закачка21 on schedule every 10 hour do 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"
|
--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;
|
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;
|
set global event_scheduler=2;
|
||||||
|
--sleep 0.3
|
||||||
--echo "Should have only our process now:"
|
--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;
|
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;
|
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;
|
create event e_55 on schedule every 10 hour starts 99990101000000 do drop table t;
|
||||||
--error ER_EVENT_ENDS_BEFORE_STARTS
|
--error ER_EVENT_ENDS_BEFORE_STARTS
|
||||||
create event e_55 on schedule every 10 minute ends 99990101000000 do drop table t;
|
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
|
# 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
|
# Start - 16407: Events: Changes in sql_mode won't be taken into account
|
||||||
#
|
#
|
||||||
set global event_scheduler=2;
|
set global event_scheduler=2;
|
||||||
--echo "Wait a bit to settle down"
|
|
||||||
--sleep 1
|
|
||||||
delete from mysql.event;
|
delete from mysql.event;
|
||||||
set global event_scheduler= 1;
|
set global event_scheduler= 1;
|
||||||
set @old_sql_mode:=@@sql_mode;
|
set @old_sql_mode:=@@sql_mode;
|
||||||
@ -67,11 +78,13 @@ begin
|
|||||||
drop table "hashed_num";
|
drop table "hashed_num";
|
||||||
end|
|
end|
|
||||||
delimiter ;|
|
delimiter ;|
|
||||||
--sleep 1
|
--sleep 0.5
|
||||||
--echo "Now if everything is fine the event has compiled and is locked
|
--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 /*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');
|
select release_lock('test_bug16407');
|
||||||
|
|
||||||
set global event_scheduler= 2;
|
set global event_scheduler= 2;
|
||||||
|
|
||||||
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
|
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"
|
--echo "Let's check whether we change the sql_mode on ALTER EVENT"
|
||||||
set sql_mode='traditional';
|
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;
|
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
|
||||||
drop event e_16407;
|
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"
|
--echo "Another sql_mode test"
|
||||||
set sql_mode="traditional";
|
set sql_mode="traditional";
|
||||||
create table events_smode_test(ev_name char(10), a date) engine=myisam;
|
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
|
create event ee_16407_2 on schedule every 60 second do
|
||||||
begin
|
begin
|
||||||
select get_lock('ee_16407_2', 60) /*ee_16407_2*/;
|
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');
|
insert into events_test.events_smode_test values('ee_16407_2','1980-19-02');
|
||||||
end|
|
end|
|
||||||
--error ER_TRUNCATED_WRONG_VALUE
|
--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
|
create event ee_16407_3 on schedule every 60 second do
|
||||||
begin
|
begin
|
||||||
select get_lock('ee_16407_2', 60) /*ee_16407_3*/;
|
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-19');
|
||||||
insert into events_test.events_smode_test values ('ee_16407_3','1980-02-29');
|
insert into events_test.events_smode_test values ('ee_16407_3','1980-02-29');
|
||||||
end|
|
end|
|
||||||
@ -103,17 +122,15 @@ set sql_mode=""|
|
|||||||
create event ee_16407_4 on schedule every 60 second do
|
create event ee_16407_4 on schedule every 60 second do
|
||||||
begin
|
begin
|
||||||
select get_lock('ee_16407_2', 60) /*ee_16407_4*/;
|
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');
|
insert into events_test.events_smode_test values ('ee_16407_4','10-11-1956');
|
||||||
end|
|
end|
|
||||||
delimiter ;|
|
delimiter ;|
|
||||||
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
|
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
|
||||||
set sql_mode="ansi";
|
--sleep 0.5
|
||||||
select get_lock('ee_16407_2', 60);
|
|
||||||
set global event_scheduler= 1;
|
|
||||||
--sleep 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;
|
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');
|
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;
|
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;
|
set global event_scheduler= 2;
|
||||||
select * from events_smode_test order by ev_name, a;
|
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"
|
--echo "And now one last test regarding sql_mode and call of SP from an event"
|
||||||
delete from events_smode_test;
|
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';
|
set sql_mode='traditional';
|
||||||
delimiter |;
|
delimiter |;
|
||||||
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_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
|
create event ee_16407_5 on schedule every 60 second do
|
||||||
begin
|
begin
|
||||||
select get_lock('ee_16407_5', 60) /*ee_16407_5*/;
|
select get_lock('ee_16407_5', 60) /*ee_16407_5*/;
|
||||||
|
select release_lock('ee_16407_5');
|
||||||
call events_test.ee_16407_5_pendant();
|
call events_test.ee_16407_5_pendant();
|
||||||
end|
|
end|
|
||||||
create event ee_16407_6 on schedule every 60 second do
|
create event ee_16407_6 on schedule every 60 second do
|
||||||
begin
|
begin
|
||||||
select get_lock('ee_16407_5', 60) /*ee_16407_6*/;
|
select get_lock('ee_16407_5', 60) /*ee_16407_6*/;
|
||||||
|
select release_lock('ee_16407_5');
|
||||||
call events_test.ee_16407_6_pendant();
|
call events_test.ee_16407_6_pendant();
|
||||||
end|
|
end|
|
||||||
delimiter ;|
|
delimiter ;|
|
||||||
set sql_mode='ansi';
|
--sleep 0.5
|
||||||
select get_lock('ee_16407_5', 60);
|
|
||||||
set global event_scheduler= 1;
|
|
||||||
--sleep 1
|
|
||||||
--echo "Should have 2 locked processes"
|
--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 /*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');
|
select release_lock('ee_16407_5');
|
||||||
--sleep 2
|
--sleep 0.8
|
||||||
--echo "Should have 0 processes locked"
|
--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 /*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;
|
select * from events_smode_test order by ev_name, a;
|
||||||
|
@ -14,7 +14,7 @@ END|
|
|||||||
delimiter ;|
|
delimiter ;|
|
||||||
--echo "Check General Query Log"
|
--echo "Check General Query Log"
|
||||||
SET GLOBAL event_scheduler=2;
|
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;
|
TRUNCATE mysql.general_log;
|
||||||
--echo "1 row, the current statement!"
|
--echo "1 row, the current statement!"
|
||||||
--replace_column 1 USER_HOST
|
--replace_column 1 USER_HOST
|
||||||
@ -22,13 +22,12 @@ call select_general_log();
|
|||||||
SET GLOBAL event_scheduler=1;
|
SET GLOBAL event_scheduler=1;
|
||||||
--echo "Wait the scheduler to start"
|
--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"
|
--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
|
--replace_column 1 USER_HOST
|
||||||
call select_general_log();
|
call select_general_log();
|
||||||
DROP PROCEDURE select_general_log;
|
DROP PROCEDURE select_general_log;
|
||||||
DROP EVENT log_general;
|
DROP EVENT log_general;
|
||||||
SET GLOBAL event_scheduler=2;
|
SET GLOBAL event_scheduler=2;
|
||||||
--sleep 1
|
|
||||||
|
|
||||||
--echo "Check slow query log"
|
--echo "Check slow query log"
|
||||||
--disable_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;
|
SET SESSION long_query_time=300;
|
||||||
--echo "Make it quite long"
|
--echo "Make it quite long"
|
||||||
TRUNCATE mysql.slow_log;
|
TRUNCATE mysql.slow_log;
|
||||||
SET SESSION long_query_time=1;
|
|
||||||
CREATE TABLE slow_event_test (slo_val tinyint, val tinyint);
|
CREATE TABLE slow_event_test (slo_val tinyint, val tinyint);
|
||||||
--echo "This won't go to the slow log"
|
--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;
|
SELECT * FROM slow_event_test;
|
||||||
|
SET SESSION long_query_time=1;
|
||||||
SET GLOBAL event_scheduler=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"
|
--echo "Sleep some more time than the actual event run will take"
|
||||||
--sleep 5
|
--sleep 2
|
||||||
SHOW VARIABLES LIKE 'event_scheduler';
|
SHOW VARIABLES LIKE 'event_scheduler';
|
||||||
--echo "Check our table. Should see 1 row"
|
--echo "Check our table. Should see 1 row"
|
||||||
SELECT * FROM slow_event_test;
|
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;
|
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
|
||||||
--echo "This should go to the slow log"
|
--echo "This should go to the slow log"
|
||||||
DROP EVENT long_event;
|
DROP EVENT long_event;
|
||||||
@ -88,7 +87,7 @@ SET SESSION long_query_time=10;
|
|||||||
SET GLOBAL long_query_time=1;
|
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);
|
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"
|
--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"
|
--echo "Check our table. Should see 2 rows"
|
||||||
SELECT * FROM slow_event_test;
|
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"
|
--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
|
--error ER_EVENT_DOES_NOT_EXIST
|
||||||
DROP EVENT only_one_time;
|
DROP EVENT only_one_time;
|
||||||
--echo "Should be preserved"
|
--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 EVENT two_time;
|
||||||
DROP TABLE table_1;
|
DROP TABLE table_1;
|
||||||
DROP TABLE table_2;
|
DROP TABLE table_2;
|
||||||
|
@ -61,7 +61,7 @@ while ($1)
|
|||||||
--enable_query_log
|
--enable_query_log
|
||||||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
|
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
|
||||||
SET GLOBAL event_scheduler=1;
|
SET GLOBAL event_scheduler=1;
|
||||||
--sleep 12
|
--sleep 2.5
|
||||||
DROP DATABASE events_conn1_test2;
|
DROP DATABASE events_conn1_test2;
|
||||||
|
|
||||||
SET GLOBAL event_scheduler=2;
|
SET GLOBAL event_scheduler=2;
|
||||||
@ -100,7 +100,7 @@ while ($1)
|
|||||||
}
|
}
|
||||||
--enable_query_log
|
--enable_query_log
|
||||||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
|
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
|
||||||
--sleep 12
|
--sleep 2.5
|
||||||
connection conn2;
|
connection conn2;
|
||||||
--send
|
--send
|
||||||
DROP DATABASE events_conn2_db;
|
DROP DATABASE events_conn2_db;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -47,30 +47,46 @@
|
|||||||
|
|
||||||
class sp_head;
|
class sp_head;
|
||||||
class Sql_alloc;
|
class Sql_alloc;
|
||||||
|
class Event_basic;
|
||||||
class Event_timed;
|
|
||||||
|
|
||||||
/* Compares only the schema part of the identifier */
|
/* Compares only the schema part of the identifier */
|
||||||
bool
|
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*/
|
/* Compares the whole identifier*/
|
||||||
bool
|
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_basic
|
||||||
class Event_timed
|
|
||||||
{
|
{
|
||||||
Event_timed(const Event_timed &); /* Prevent use of these */
|
protected:
|
||||||
void operator=(Event_timed &);
|
|
||||||
|
|
||||||
bool status_changed;
|
|
||||||
bool last_executed_changed;
|
|
||||||
|
|
||||||
MEM_ROOT mem_root;
|
MEM_ROOT mem_root;
|
||||||
|
|
||||||
public:
|
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
|
enum enum_status
|
||||||
{
|
{
|
||||||
ENABLED = 1,
|
ENABLED = 1,
|
||||||
@ -83,17 +99,10 @@ public:
|
|||||||
ON_COMPLETION_PRESERVE
|
ON_COMPLETION_PRESERVE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum enum_on_completion on_completion;
|
||||||
|
enum enum_status status;
|
||||||
TIME last_executed;
|
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 starts;
|
||||||
TIME ends;
|
TIME ends;
|
||||||
TIME execute_at;
|
TIME execute_at;
|
||||||
@ -104,42 +113,14 @@ public:
|
|||||||
longlong expression;
|
longlong expression;
|
||||||
interval_type interval;
|
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
|
uint flags;//all kind of purposes
|
||||||
|
|
||||||
static void *operator new(size_t size)
|
bool dropped;
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void operator delete(void *ptr, size_t size)
|
Event_queue_element();
|
||||||
{
|
virtual ~Event_queue_element();
|
||||||
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_timed();
|
virtual int
|
||||||
|
|
||||||
~Event_timed();
|
|
||||||
|
|
||||||
void
|
|
||||||
init();
|
|
||||||
|
|
||||||
int
|
|
||||||
load_from_row(TABLE *table);
|
load_from_row(TABLE *table);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -152,27 +133,97 @@ public:
|
|||||||
mark_last_executed(THD *thd);
|
mark_last_executed(THD *thd);
|
||||||
|
|
||||||
bool
|
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
|
int
|
||||||
get_create_event(THD *thd, String *buf);
|
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
|
int
|
||||||
execute(THD *thd, MEM_ROOT *mem_root);
|
execute(THD *thd, MEM_ROOT *mem_root);
|
||||||
|
private:
|
||||||
|
int
|
||||||
|
get_fake_create_event(THD *thd, String *buf);
|
||||||
|
|
||||||
int
|
int
|
||||||
compile(THD *thd, MEM_ROOT *mem_root);
|
compile(THD *thd, MEM_ROOT *mem_root);
|
||||||
|
|
||||||
void
|
void
|
||||||
free_sp();
|
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
|
class Event_parse_data : public Sql_alloc
|
||||||
{
|
{
|
||||||
Event_parse_data(const Event_parse_data &); /* Prevent use of these */
|
|
||||||
void operator=(Event_parse_data &);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum enum_status
|
enum enum_status
|
||||||
{
|
{
|
||||||
@ -185,7 +236,6 @@ public:
|
|||||||
ON_COMPLETION_DROP = 1,
|
ON_COMPLETION_DROP = 1,
|
||||||
ON_COMPLETION_PRESERVE
|
ON_COMPLETION_PRESERVE
|
||||||
};
|
};
|
||||||
|
|
||||||
enum enum_on_completion on_completion;
|
enum enum_on_completion on_completion;
|
||||||
enum enum_status status;
|
enum enum_status status;
|
||||||
|
|
||||||
@ -193,8 +243,8 @@ public:
|
|||||||
|
|
||||||
LEX_STRING dbname;
|
LEX_STRING dbname;
|
||||||
LEX_STRING name;
|
LEX_STRING name;
|
||||||
LEX_STRING body;
|
|
||||||
LEX_STRING definer;// combination of user and host
|
LEX_STRING definer;// combination of user and host
|
||||||
|
LEX_STRING body;
|
||||||
LEX_STRING comment;
|
LEX_STRING comment;
|
||||||
|
|
||||||
Item* item_starts;
|
Item* item_starts;
|
||||||
@ -216,59 +266,41 @@ public:
|
|||||||
static Event_parse_data *
|
static Event_parse_data *
|
||||||
new_instance(THD *thd);
|
new_instance(THD *thd);
|
||||||
|
|
||||||
Event_parse_data();
|
bool
|
||||||
~Event_parse_data();
|
check_parse_data(THD *);
|
||||||
|
|
||||||
|
void
|
||||||
|
init_body(THD *thd);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
int
|
int
|
||||||
init_definer(THD *thd);
|
init_definer(THD *thd);
|
||||||
|
|
||||||
int
|
|
||||||
init_execute_at(THD *thd, Item *expr);
|
|
||||||
|
|
||||||
int
|
|
||||||
init_interval(THD *thd, Item *expr, interval_type new_interval);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
init_name(THD *thd, sp_name *spn);
|
init_name(THD *thd, sp_name *spn);
|
||||||
|
|
||||||
int
|
int
|
||||||
init_starts(THD *thd, Item *starts);
|
init_execute_at(THD *thd);
|
||||||
|
|
||||||
int
|
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
|
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_ */
|
#endif /* _EVENT_DATA_OBJECTS_H_ */
|
||||||
|
@ -29,7 +29,8 @@
|
|||||||
time_t mysql_event_last_create_time= 0L;
|
time_t mysql_event_last_create_time= 0L;
|
||||||
|
|
||||||
static
|
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("db")},
|
||||||
{(char *) STRING_WITH_LEN("char(64)")},
|
{(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.
|
Puts some data common to CREATE and ALTER EVENT into a row.
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
evex_fill_row()
|
mysql_event_fill_row()
|
||||||
thd THD
|
thd THD
|
||||||
table The row to fill out
|
table The row to fill out
|
||||||
et Event's data
|
et Event's data
|
||||||
is_update CREATE EVENT or ALTER EVENT
|
is_update CREATE EVENT or ALTER EVENT
|
||||||
|
|
||||||
RETURN VALUE
|
RETURN VALUE
|
||||||
0 - OK
|
0 OK
|
||||||
EVEX_GENERAL_ERROR - bad data
|
EVEX_GENERAL_ERROR Bad data
|
||||||
EVEX_GET_FIELD_FAILED - field count does not match. table corrupted?
|
EVEX_GET_FIELD_FAILED Field count does not match. table corrupted?
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
Used both when an event is created and when it is altered.
|
Used both when an event is created and when it is altered.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
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;
|
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", ("dbname=[%s]", et->dbname.str));
|
||||||
DBUG_PRINT("info", ("name =[%s]", et->name.str));
|
DBUG_PRINT("info", ("name =[%s]", et->name.str));
|
||||||
DBUG_PRINT("info", ("body =[%s]", et->body.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))
|
store(et->definer.str, et->definer.length, scs))
|
||||||
goto err_truncate;
|
goto err_truncate;
|
||||||
|
|
||||||
if (table->field[field_num= ET_FIELD_DB]->
|
if (fields[f_num= ET_FIELD_DB]->store(et->dbname.str, et->dbname.length, scs))
|
||||||
store(et->dbname.str, et->dbname.length, scs))
|
|
||||||
goto err_truncate;
|
goto err_truncate;
|
||||||
|
|
||||||
if (table->field[field_num= ET_FIELD_NAME]->
|
if (fields[f_num= ET_FIELD_NAME]->store(et->name.str, et->name.length, scs))
|
||||||
store(et->name.str, et->name.length, scs))
|
|
||||||
goto err_truncate;
|
goto err_truncate;
|
||||||
|
|
||||||
/* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()*/
|
/* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()*/
|
||||||
table->field[ET_FIELD_ON_COMPLETION]->
|
fields[ET_FIELD_ON_COMPLETION]->store((longlong)et->on_completion, TRUE);
|
||||||
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
|
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)
|
if (et->body.str)
|
||||||
{
|
{
|
||||||
table->field[ET_FIELD_SQL_MODE]->
|
fields[ET_FIELD_SQL_MODE]->store((longlong)thd->variables.sql_mode, TRUE);
|
||||||
store((longlong)thd->variables.sql_mode, true);
|
if (fields[f_num= ET_FIELD_BODY]->store(et->body.str, et->body.length, scs))
|
||||||
|
|
||||||
if (table->field[field_num= ET_FIELD_BODY]->
|
|
||||||
store(et->body.str, et->body.length, scs))
|
|
||||||
goto err_truncate;
|
goto err_truncate;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (et->expression)
|
if (et->expression)
|
||||||
{
|
{
|
||||||
table->field[ET_FIELD_INTERVAL_EXPR]->set_notnull();
|
fields[ET_FIELD_INTERVAL_EXPR]->set_notnull();
|
||||||
table->field[ET_FIELD_INTERVAL_EXPR]->store((longlong)et->expression, true);
|
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
|
In the enum (C) intervals start from 0 but in mysql enum valid values
|
||||||
from 1. Thus +1 offset is needed!
|
start from 1. Thus +1 offset is needed!
|
||||||
*/
|
*/
|
||||||
table->field[ET_FIELD_TRANSIENT_INTERVAL]->
|
fields[ET_FIELD_TRANSIENT_INTERVAL]->store((longlong)et->interval+1, TRUE);
|
||||||
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)
|
if (!et->starts_null)
|
||||||
{
|
{
|
||||||
table->field[ET_FIELD_STARTS]->set_notnull();
|
fields[ET_FIELD_STARTS]->set_notnull();
|
||||||
table->field[ET_FIELD_STARTS]->
|
fields[ET_FIELD_STARTS]->store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
|
||||||
store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!et->ends_null)
|
if (!et->ends_null)
|
||||||
{
|
{
|
||||||
table->field[ET_FIELD_ENDS]->set_notnull();
|
fields[ET_FIELD_ENDS]->set_notnull();
|
||||||
table->field[ET_FIELD_ENDS]->
|
fields[ET_FIELD_ENDS]->store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
|
||||||
store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (et->execute_at.year)
|
else if (et->execute_at.year)
|
||||||
{
|
{
|
||||||
table->field[ET_FIELD_INTERVAL_EXPR]->set_null();
|
fields[ET_FIELD_INTERVAL_EXPR]->set_null();
|
||||||
table->field[ET_FIELD_TRANSIENT_INTERVAL]->set_null();
|
fields[ET_FIELD_TRANSIENT_INTERVAL]->set_null();
|
||||||
table->field[ET_FIELD_STARTS]->set_null();
|
fields[ET_FIELD_STARTS]->set_null();
|
||||||
table->field[ET_FIELD_ENDS]->set_null();
|
fields[ET_FIELD_ENDS]->set_null();
|
||||||
|
|
||||||
table->field[ET_FIELD_EXECUTE_AT]->set_notnull();
|
fields[ET_FIELD_EXECUTE_AT]->set_notnull();
|
||||||
table->field[ET_FIELD_EXECUTE_AT]->
|
fields[ET_FIELD_EXECUTE_AT]->
|
||||||
store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME);
|
store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME);
|
||||||
}
|
}
|
||||||
else
|
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 (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))
|
store(et->comment.str, et->comment.length, scs))
|
||||||
goto err_truncate;
|
goto err_truncate;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
err_truncate:
|
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);
|
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.
|
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)))
|
if (!(key_buf= (byte *)alloc_root(thd->mem_root, key_len)))
|
||||||
{
|
{
|
||||||
ret= 1;
|
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
|
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
|
Open mysql.event table for read
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
Events::open_event_table()
|
Events::open_event_table()
|
||||||
thd Thread context
|
thd [in] Thread context
|
||||||
lock_type How to lock the table
|
lock_type [in] How to lock the table
|
||||||
table We will store the open table here
|
table [out] We will store the open table here
|
||||||
|
|
||||||
RETURN VALUE
|
RETURN VALUE
|
||||||
1 Cannot lock table
|
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.
|
Checks parameters which we got from the parsing phase.
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
evex_check_params()
|
check_parse_params()
|
||||||
thd THD
|
thd THD
|
||||||
et event's data
|
et event's data
|
||||||
|
|
||||||
RETURNS
|
RETURNS
|
||||||
0 OK
|
0 OK
|
||||||
EVEX_BAD_PARAMS Error
|
EVEX_BAD_PARAMS Error (reported)
|
||||||
|
|
||||||
REMARKS
|
|
||||||
Issues error messages
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
static int
|
||||||
evex_check_params(THD *thd, Event_parse_data *parse_data)
|
check_parse_params(THD *thd, Event_parse_data *parse_data)
|
||||||
{
|
{
|
||||||
const char *pos= NULL;
|
const char *pos= NULL;
|
||||||
Item *bad_item;
|
Item *bad_item;
|
||||||
|
int res;
|
||||||
|
|
||||||
DBUG_ENTER("evex_check_params");
|
DBUG_ENTER("check_parse_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));
|
|
||||||
|
|
||||||
parse_data->init_name(thd, parse_data->identifier);
|
if (parse_data->check_parse_data(thd))
|
||||||
parse_data->init_definer(thd);
|
DBUG_RETURN(EVEX_BAD_PARAMS);
|
||||||
|
|
||||||
if (!parse_data->dbname.str ||
|
if (!parse_data->dbname.str ||
|
||||||
(thd->lex->sql_command == SQLCOM_ALTER_EVENT && thd->lex->spname &&
|
(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)))))
|
is_schema_db(thd->lex->spname->m_db.str)))))
|
||||||
DBUG_RETURN(EVEX_BAD_PARAMS);
|
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);
|
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
|
SYNOPSIS
|
||||||
Event_db_repository::create_event()
|
Event_db_repository::create_event()
|
||||||
thd THD
|
thd [in] THD
|
||||||
et Event_timed object containing information for the event
|
et [in] Object containing info about the event
|
||||||
create_if_not If an warning should be generated in case event exists
|
create_if_not [in] Whether to generate anwarning in case event exists
|
||||||
rows_affected How many rows were affected
|
rows_affected [out] How many rows were affected
|
||||||
|
|
||||||
RETURN VALUE
|
RETURN VALUE
|
||||||
0 - OK
|
0 - OK
|
||||||
EVEX_GENERAL_ERROR - Failure
|
EVEX_GENERAL_ERROR - Failure
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
Creates an event. Relies on evex_fill_row which is shared with
|
Creates an event. Relies on mysql_event_fill_row which is shared with
|
||||||
db_update_event. The name of the event is inside "et".
|
::update_event. The name of the event is inside "et".
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -709,7 +525,7 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
|
|||||||
CHARSET_INFO *scs= system_charset_info;
|
CHARSET_INFO *scs= system_charset_info;
|
||||||
TABLE *table;
|
TABLE *table;
|
||||||
char olddb[128];
|
char olddb[128];
|
||||||
bool dbchanged= false;
|
bool dbchanged= FALSE;
|
||||||
DBUG_ENTER("Event_db_repository::create_event");
|
DBUG_ENTER("Event_db_repository::create_event");
|
||||||
|
|
||||||
*rows_affected= 0;
|
*rows_affected= 0;
|
||||||
@ -720,15 +536,14 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (evex_check_params(thd, parse_data))
|
if (check_parse_params(thd, parse_data))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
DBUG_PRINT("info", ("name: %.*s", parse_data->name.length,
|
DBUG_PRINT("info", ("name: %.*s", parse_data->name.length,
|
||||||
parse_data->name.str));
|
parse_data->name.str));
|
||||||
|
|
||||||
DBUG_PRINT("info", ("check existance of an event with the same name"));
|
DBUG_PRINT("info", ("check existance of an event with the same name"));
|
||||||
if (!evex_db_find_event_by_name(thd, parse_data->dbname,
|
if (!find_event_by_name(thd, parse_data->dbname, parse_data->name, table))
|
||||||
parse_data->name, table))
|
|
||||||
{
|
{
|
||||||
if (create_if_not)
|
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();
|
((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
|
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;
|
goto err;
|
||||||
|
|
||||||
/* Close active transaction only if We are going to modify disk */
|
/* 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;
|
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;
|
*rows_affected= 1;
|
||||||
ok:
|
ok:
|
||||||
if (dbchanged)
|
if (dbchanged)
|
||||||
@ -838,7 +643,7 @@ err:
|
|||||||
|
|
||||||
RETURN VALUE
|
RETURN VALUE
|
||||||
0 OK
|
0 OK
|
||||||
EVEX_GENERAL_ERROR Error occured (my_error() called)
|
EVEX_GENERAL_ERROR Error occured and reported
|
||||||
|
|
||||||
NOTES
|
NOTES
|
||||||
sp_name is passed since this is the name of the event to
|
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;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (evex_check_params(thd, parse_data))
|
if (check_parse_params(thd, parse_data))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
DBUG_PRINT("info", ("dbname: %s", parse_data->dbname.str));
|
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;
|
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);
|
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->m_name.str);
|
||||||
goto err;
|
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;
|
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
|
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;
|
goto err;
|
||||||
|
|
||||||
if (new_name)
|
if (new_name)
|
||||||
@ -944,11 +749,12 @@ err:
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
Event_db_repository::drop_event()
|
Event_db_repository::drop_event()
|
||||||
thd THD
|
thd [in] THD
|
||||||
db database name
|
db [in] Database name
|
||||||
name event's name
|
name [in] Event's name
|
||||||
drop_if_exists if set and the event not existing => warning onto the stack
|
drop_if_exists [in] If set and the event not existing => warning
|
||||||
rows_affected affected number of rows is returned heres
|
onto the stack
|
||||||
|
rows_affected [out] Affected number of rows is returned heres
|
||||||
|
|
||||||
RETURN VALUE
|
RETURN VALUE
|
||||||
0 OK
|
0 OK
|
||||||
@ -974,17 +780,16 @@ Event_db_repository::drop_event(THD *thd, LEX_STRING db, LEX_STRING name,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(ret= evex_db_find_event_by_name(thd, db, name, table)))
|
switch ((ret= find_event_by_name(thd, db, name, table))) {
|
||||||
{
|
case 0:
|
||||||
/* Close active transaction only if We are going to modify disk */
|
/* Close active transaction only if we are actually going to modify disk */
|
||||||
if ((ret= end_active_trans(thd)))
|
if ((ret= end_active_trans(thd)))
|
||||||
goto done;
|
break;
|
||||||
|
|
||||||
if ((ret= table->file->ha_delete_row(table->record[0])))
|
if ((ret= table->file->ha_delete_row(table->record[0])))
|
||||||
my_error(ER_EVENT_CANNOT_DELETE, MYF(0));
|
my_error(ER_EVENT_CANNOT_DELETE, MYF(0));
|
||||||
}
|
break;
|
||||||
else if (ret == EVEX_KEY_NOT_FOUND)
|
case EVEX_KEY_NOT_FOUND:
|
||||||
{
|
|
||||||
if (drop_if_exists)
|
if (drop_if_exists)
|
||||||
{
|
{
|
||||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
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;
|
ret= 0;
|
||||||
} else
|
} else
|
||||||
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
|
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
/*
|
|
||||||
evex_drop_event() is used by Event_timed::drop therefore
|
|
||||||
we have to close our thread tables.
|
|
||||||
*/
|
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
thd->restore_backup_open_tables_state(&backup);
|
thd->restore_backup_open_tables_state(&backup);
|
||||||
DBUG_RETURN(ret);
|
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
|
int
|
||||||
Event_db_repository::find_event_by_name(THD *thd, LEX_STRING db,
|
Event_db_repository::find_event_by_name(THD *thd, LEX_STRING db,
|
||||||
LEX_STRING name, TABLE *table)
|
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
|
int
|
||||||
Event_db_repository::drop_schema_events(THD *thd, LEX_STRING schema)
|
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
|
SYNOPSIS
|
||||||
drop_events_from_table_by_field()
|
Event_db_repository::drop_events_by_field()
|
||||||
thd Thread
|
thd Thread
|
||||||
table mysql.event TABLE
|
table mysql.event TABLE
|
||||||
field Which field of the row to use for matching
|
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
|
Looks for a named event in mysql.event and in case of success returns
|
||||||
the table, compiles and inserts it into the cache.
|
an object will data loaded from the table.
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
Event_db_repository::load_named_event_timed()
|
Event_db_repository::find_event()
|
||||||
thd THD
|
thd [in] THD
|
||||||
etn The name of the event to load and compile on scheduler's root
|
name [in] The name of the event to find
|
||||||
etn_new The loaded event
|
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
|
RETURN VALUE
|
||||||
NULL Error during compile or the event is non-enabled.
|
0 ok In this case *ett is set to the event
|
||||||
otherwise Address
|
# error *ett == 0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
Event_db_repository::load_named_event_timed(THD *thd, LEX_STRING dbname,
|
Event_db_repository::find_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
|
||||||
LEX_STRING name,
|
Event_basic *et)
|
||||||
Event_timed **etn_new)
|
|
||||||
{
|
{
|
||||||
int ret= 0;
|
TABLE *table;
|
||||||
MEM_ROOT *tmp_mem_root;
|
int ret;
|
||||||
Event_timed *et_loaded= NULL;
|
DBUG_ENTER("Event_db_repository::find_event");
|
||||||
Open_tables_state backup;
|
DBUG_PRINT("enter", ("name: %*s", name.length, name.str));
|
||||||
|
|
||||||
DBUG_ENTER("Event_db_repository::load_named_event_timed");
|
if (open_event_table(thd, TL_READ, &table))
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
/*
|
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
||||||
We don't load non-enabled events.
|
ret= EVEX_GENERAL_ERROR;
|
||||||
In db_find_event() `et_new` was allocated on the heap and not on
|
goto done;
|
||||||
scheduler_root therefore we delete it here.
|
|
||||||
*/
|
|
||||||
delete et_loaded;
|
|
||||||
DBUG_RETURN(OP_DISABLED_EVENT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
et_loaded->compute_next_execution_time();
|
if ((ret= find_event_by_name(thd, dbname, name, table)))
|
||||||
*etn_new= et_loaded;
|
{
|
||||||
|
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.
|
the table, compiles and inserts it into the cache.
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
Event_db_repository::load_named_event_job()
|
Event_db_repository::load_named_event()
|
||||||
thd THD
|
thd [in] THD
|
||||||
etn The name of the event to load and compile on scheduler's root
|
dbname [in] Event's db name
|
||||||
etn_new The loaded event
|
name [in] Event's name
|
||||||
|
etn_new [out] The loaded event
|
||||||
|
|
||||||
RETURN VALUE
|
RETURN VALUE
|
||||||
NULL Error during compile or the event is non-enabled.
|
OP_OK OK
|
||||||
otherwise Address
|
OP_LOAD_ERROR Error during loading from disk
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
Event_db_repository::load_named_event_job(THD *thd, LEX_STRING dbname,
|
Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname,
|
||||||
LEX_STRING name,
|
LEX_STRING name, Event_basic *etn)
|
||||||
Event_job_data **etn_new)
|
|
||||||
{
|
{
|
||||||
int ret= 0;
|
int ret= 0;
|
||||||
MEM_ROOT *tmp_mem_root;
|
|
||||||
Event_timed *et_loaded= NULL;
|
|
||||||
Open_tables_state backup;
|
Open_tables_state backup;
|
||||||
|
|
||||||
DBUG_ENTER("Event_db_repository::load_named_event_job");
|
DBUG_ENTER("Event_db_repository::load_named_event");
|
||||||
DBUG_PRINT("enter",("thd=%p name:%*s",thd, name.length, name.str));
|
DBUG_PRINT("enter",("thd=0x%lx name:%*s",thd, name.length, name.str));
|
||||||
#if 0
|
|
||||||
thd->reset_n_backup_open_tables_state(&backup);
|
thd->reset_n_backup_open_tables_state(&backup);
|
||||||
/* No need to use my_error() here because db_find_event() has done it */
|
/* No need to use my_error() here because find_event() has done it */
|
||||||
ret= find_event(thd, dbname, name, &et_loaded, NULL);
|
ret= find_event(thd, dbname, name, etn);
|
||||||
thd->restore_backup_open_tables_state(&backup);
|
thd->restore_backup_open_tables_state(&backup);
|
||||||
/* In this case no memory was allocated so we don't need to clean */
|
/* In this case no memory was allocated so we don't need to clean */
|
||||||
if (ret)
|
if (ret)
|
||||||
DBUG_RETURN(OP_LOAD_ERROR);
|
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);
|
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
|
int
|
||||||
events_table_index_read_for_db(THD *thd, TABLE *schema_table,
|
events_table_index_read_for_db(THD *thd, TABLE *schema_table,
|
||||||
TABLE *event_table);
|
TABLE *event_table);
|
||||||
@ -53,22 +48,13 @@ events_table_scan_all(THD *thd, TABLE *schema_table, TABLE *event_table);
|
|||||||
int
|
int
|
||||||
fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */);
|
fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */);
|
||||||
|
|
||||||
class Event_timed;
|
class Event_basic;
|
||||||
class Event_parse_data;
|
class Event_parse_data;
|
||||||
class Event_queue_element;
|
|
||||||
class Event_job_data;
|
|
||||||
|
|
||||||
class Event_db_repository
|
class Event_db_repository
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Event_db_repository(){}
|
Event_db_repository(){}
|
||||||
~Event_db_repository(){}
|
|
||||||
|
|
||||||
int
|
|
||||||
init_repository();
|
|
||||||
|
|
||||||
void
|
|
||||||
deinit_repository();
|
|
||||||
|
|
||||||
int
|
int
|
||||||
create_event(THD *thd, Event_parse_data *parse_data, my_bool create_if_not,
|
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);
|
drop_schema_events(THD *thd, LEX_STRING schema);
|
||||||
|
|
||||||
int
|
int
|
||||||
drop_user_events(THD *thd, LEX_STRING definer);
|
find_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_basic *et);
|
||||||
|
|
||||||
int
|
int
|
||||||
find_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_timed **ett,
|
load_named_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_basic *et);
|
||||||
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);
|
|
||||||
|
|
||||||
int
|
int
|
||||||
find_event_by_name(THD *thd, LEX_STRING db, LEX_STRING name, TABLE *table);
|
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 */
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||||
|
|
||||||
class sp_name;
|
class sp_name;
|
||||||
class Event_timed;
|
class Event_basic;
|
||||||
class Event_db_repository;
|
class Event_db_repository;
|
||||||
class Event_job_data;
|
class Event_job_data;
|
||||||
|
class Event_queue_element;
|
||||||
|
|
||||||
class THD;
|
class THD;
|
||||||
typedef bool * (*event_timed_identifier_comparator)(Event_timed*, Event_timed*);
|
|
||||||
|
|
||||||
class Event_scheduler_ng;
|
class Event_scheduler_ng;
|
||||||
|
|
||||||
class Event_queue
|
class Event_queue
|
||||||
@ -46,14 +45,14 @@ public:
|
|||||||
/* Methods for queue management follow */
|
/* Methods for queue management follow */
|
||||||
|
|
||||||
int
|
int
|
||||||
create_event(THD *thd, Event_parse_data *et);
|
create_event(THD *thd, LEX_STRING dbname, LEX_STRING name);
|
||||||
|
|
||||||
int
|
int
|
||||||
update_event(THD *thd, Event_parse_data *et, LEX_STRING *new_schema,
|
update_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
|
||||||
LEX_STRING *new_name);
|
LEX_STRING *new_schema, LEX_STRING *new_name);
|
||||||
|
|
||||||
bool
|
void
|
||||||
drop_event(THD *thd, sp_name *name);
|
drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name);
|
||||||
|
|
||||||
void
|
void
|
||||||
drop_schema_events(THD *thd, LEX_STRING schema);
|
drop_schema_events(THD *thd, LEX_STRING schema);
|
||||||
@ -61,32 +60,20 @@ public:
|
|||||||
uint
|
uint
|
||||||
events_count();
|
events_count();
|
||||||
|
|
||||||
uint
|
|
||||||
events_count_no_lock();
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
check_system_tables(THD *thd);
|
check_system_tables(THD *thd);
|
||||||
|
|
||||||
void
|
void
|
||||||
recalculate_queue(THD *thd);
|
recalculate_activation_times(THD *thd);
|
||||||
|
|
||||||
void
|
Event_job_data *
|
||||||
empty_queue();
|
|
||||||
|
|
||||||
Event_timed *
|
|
||||||
get_top_for_execution_if_time(THD *thd, time_t now, struct timespec *abstime);
|
get_top_for_execution_if_time(THD *thd, time_t now, struct timespec *abstime);
|
||||||
|
|
||||||
Event_timed*
|
bool
|
||||||
get_top();
|
dump_internal_status(THD *thd);
|
||||||
|
|
||||||
void
|
|
||||||
remove_top();
|
|
||||||
|
|
||||||
void
|
|
||||||
top_changed();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Event_timed *
|
Event_queue_element *
|
||||||
find_event(LEX_STRING db, LEX_STRING name, bool remove_from_q);
|
find_event(LEX_STRING db, LEX_STRING name, bool remove_from_q);
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -94,14 +81,16 @@ protected:
|
|||||||
|
|
||||||
void
|
void
|
||||||
drop_matching_events(THD *thd, LEX_STRING pattern,
|
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. */
|
/* LOCK_event_queue is the mutex which protects the access to the queue. */
|
||||||
pthread_mutex_t LOCK_event_queue;
|
pthread_mutex_t LOCK_event_queue;
|
||||||
|
|
||||||
Event_db_repository *db_repository;
|
Event_db_repository *db_repository;
|
||||||
|
|
||||||
|
|
||||||
uint mutex_last_locked_at_line;
|
uint mutex_last_locked_at_line;
|
||||||
uint mutex_last_unlocked_at_line;
|
uint mutex_last_unlocked_at_line;
|
||||||
const char* mutex_last_locked_in_func;
|
const char* mutex_last_locked_in_func;
|
||||||
@ -123,10 +112,8 @@ protected:
|
|||||||
|
|
||||||
Event_scheduler_ng *scheduler;
|
Event_scheduler_ng *scheduler;
|
||||||
|
|
||||||
//public:
|
/* The sorted queue with the Event_job_data objects */
|
||||||
/* The sorted queue with the Event_timed objects */
|
|
||||||
QUEUE queue;
|
QUEUE queue;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _EVENT_QUEUE_H_ */
|
#endif /* _EVENT_QUEUE_H_ */
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#define LOCK_SCHEDULER_DATA() lock_data(SCHED_FUNC, __LINE__)
|
#define LOCK_SCHEDULER_DATA() lock_data(SCHED_FUNC, __LINE__)
|
||||||
#define UNLOCK_SCHEDULER_DATA() unlock_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;
|
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
|
Prints the stack of infos, warnings, errors from thd to
|
||||||
the console so it can be fetched by the logs-into-tables and
|
the console so it can be fetched by the logs-into-tables and
|
||||||
@ -81,12 +60,12 @@ public:
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
evex_print_warnings
|
evex_print_warnings
|
||||||
thd - thread used during the execution of the event
|
thd Thread used during the execution of the event
|
||||||
et - the event itself
|
et The event itself
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
evex_print_warnings(THD *thd, Event_timed *et)
|
evex_print_warnings(THD *thd, Event_job_data *et)
|
||||||
{
|
{
|
||||||
MYSQL_ERROR *err;
|
MYSQL_ERROR *err;
|
||||||
DBUG_ENTER("evex_print_warnings");
|
DBUG_ENTER("evex_print_warnings");
|
||||||
@ -148,23 +127,22 @@ init_scheduler_thread(THD* thd)
|
|||||||
thd->security_ctx->db_access= 0;
|
thd->security_ctx->db_access= 0;
|
||||||
thd->security_ctx->host_or_ip= (char*)my_localhost;
|
thd->security_ctx->host_or_ip= (char*)my_localhost;
|
||||||
thd->security_ctx->set_user((char*)"event_scheduler");
|
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->net.read_timeout= slave_net_timeout;
|
||||||
thd->slave_thread= 0;
|
thd->slave_thread= 0;
|
||||||
thd->options|= OPTION_AUTO_IS_NULL;
|
thd->options|= OPTION_AUTO_IS_NULL;
|
||||||
thd->client_capabilities|= CLIENT_MULTI_RESULTS;
|
thd->client_capabilities|= CLIENT_MULTI_RESULTS;
|
||||||
VOID(pthread_mutex_lock(&LOCK_thread_count));
|
pthread_mutex_lock(&LOCK_thread_count);
|
||||||
thd->thread_id= thread_id++;
|
thd->thread_id= thread_id++;
|
||||||
threads.append(thd);
|
threads.append(thd);
|
||||||
thread_count++;
|
thread_count++;
|
||||||
thread_running++;
|
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
|
Guarantees that we will see the thread in SHOW PROCESSLIST though its
|
||||||
vio is NULL.
|
vio is NULL.
|
||||||
*/
|
*/
|
||||||
thd->system_thread= SYSTEM_THREAD_EVENT_SCHEDULER;
|
|
||||||
|
|
||||||
thd->proc_info= "Initialized";
|
thd->proc_info= "Initialized";
|
||||||
thd->version= refresh_version;
|
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
|
pthread_handler_t
|
||||||
event_scheduler_ng_thread(void *arg)
|
event_scheduler_ng_thread(void *arg)
|
||||||
{
|
{
|
||||||
@ -201,17 +214,8 @@ event_scheduler_ng_thread(void *arg)
|
|||||||
((struct scheduler_param *) arg)->scheduler->run(thd);
|
((struct scheduler_param *) arg)->scheduler->run(thd);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
thd->proc_info= "Clearing";
|
deinit_event_thread(thd);
|
||||||
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();
|
|
||||||
DBUG_RETURN(0); // Against gcc warnings
|
DBUG_RETURN(0); // Against gcc warnings
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +226,7 @@ end:
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
event_worker_ng_thread()
|
event_worker_ng_thread()
|
||||||
arg The Event_timed object to be processed
|
arg The Event_job_data object to be processed
|
||||||
|
|
||||||
RETURN VALUE
|
RETURN VALUE
|
||||||
0 OK
|
0 OK
|
||||||
@ -233,14 +237,12 @@ event_worker_ng_thread(void *arg)
|
|||||||
{
|
{
|
||||||
/* needs to be first for thread_stack */
|
/* needs to be first for thread_stack */
|
||||||
THD *thd;
|
THD *thd;
|
||||||
Event_timed *event= (Event_timed *)arg;
|
Event_job_data *event= (Event_job_data *)arg;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
thd= event->thd;
|
thd= event->thd;
|
||||||
thd->thread_stack= (char *) &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();
|
my_thread_init();
|
||||||
pthread_detach_this_thread();
|
pthread_detach_this_thread();
|
||||||
@ -251,25 +253,32 @@ event_worker_ng_thread(void *arg)
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
|
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
VOID(sigemptyset(&set)); // Get mask in use
|
VOID(sigemptyset(&set)); // Get mask in use
|
||||||
VOID(pthread_sigmask(SIG_UNBLOCK, &set, &thd->block_signals));
|
VOID(pthread_sigmask(SIG_UNBLOCK, &set, &thd->block_signals));
|
||||||
#endif
|
#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",
|
sql_print_information("SCHEDULER: [%s.%s of %s] executing in thread %lu",
|
||||||
event->dbname.str, event->name.str,
|
event->dbname.str, event->name.str,
|
||||||
event->definer.str, thd->thread_id);
|
event->definer.str, thd->thread_id);
|
||||||
|
|
||||||
thd->init_for_queries();
|
|
||||||
thd->enable_slow_log= TRUE;
|
thd->enable_slow_log= TRUE;
|
||||||
|
|
||||||
ret= event->execute(thd, thd->mem_root);
|
ret= event->execute(thd, thd->mem_root);
|
||||||
|
|
||||||
evex_print_warnings(thd, event);
|
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->dbname.str, event->name.str,
|
||||||
event->definer.str, ret);
|
event->definer.str, thd->thread_id, ret);
|
||||||
if (ret == EVEX_COMPILE_ERROR)
|
if (ret == EVEX_COMPILE_ERROR)
|
||||||
sql_print_information("SCHEDULER: COMPILE ERROR for event %s.%s of %s",
|
sql_print_information("SCHEDULER: COMPILE ERROR for event %s.%s of %s",
|
||||||
event->dbname.str, event->name.str,
|
event->dbname.str, event->name.str,
|
||||||
@ -277,36 +286,35 @@ event_worker_ng_thread(void *arg)
|
|||||||
else if (ret == EVEX_MICROSECOND_UNSUP)
|
else if (ret == EVEX_MICROSECOND_UNSUP)
|
||||||
sql_print_information("SCHEDULER: MICROSECOND is not supported");
|
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:
|
end:
|
||||||
thd->proc_info= "Clearing";
|
DBUG_PRINT("info", ("BURAN %s.%s is landing!", event->dbname.str,
|
||||||
DBUG_ASSERT(thd->net.buff != 0);
|
event->name.str));
|
||||||
/*
|
|
||||||
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));
|
|
||||||
delete event;
|
delete event;
|
||||||
|
|
||||||
my_thread_end();
|
deinit_event_thread(thd);
|
||||||
|
|
||||||
DBUG_RETURN(0); // Against gcc warnings
|
DBUG_RETURN(0); // Against gcc warnings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Performs initialization of the scheduler data, outside of the
|
||||||
|
threading primitives.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
Event_scheduler_ng::init_scheduler()
|
||||||
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Event_scheduler_ng::init_scheduler(Event_queue *q)
|
Event_scheduler_ng::init_scheduler(Event_queue *q)
|
||||||
{
|
{
|
||||||
|
LOCK_SCHEDULER_DATA();
|
||||||
thread_id= 0;
|
thread_id= 0;
|
||||||
state= INITIALIZED;
|
state= INITIALIZED;
|
||||||
queue= q;
|
queue= q;
|
||||||
|
started_events= 0;
|
||||||
|
UNLOCK_SCHEDULER_DATA();
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,6 +323,13 @@ void
|
|||||||
Event_scheduler_ng::deinit_scheduler() {}
|
Event_scheduler_ng::deinit_scheduler() {}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Inits scheduler's threading primitives.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
Event_scheduler_ng::init_mutexes()
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
Event_scheduler_ng::init_mutexes()
|
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
|
void
|
||||||
Event_scheduler_ng::deinit_mutexes()
|
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
|
bool
|
||||||
Event_scheduler_ng::start()
|
Event_scheduler_ng::start()
|
||||||
{
|
{
|
||||||
@ -340,6 +377,7 @@ Event_scheduler_ng::start()
|
|||||||
DBUG_ENTER("Event_scheduler_ng::start");
|
DBUG_ENTER("Event_scheduler_ng::start");
|
||||||
|
|
||||||
LOCK_SCHEDULER_DATA();
|
LOCK_SCHEDULER_DATA();
|
||||||
|
DBUG_PRINT("info", ("state before action %s", scheduler_states_names[state]));
|
||||||
if (state > INITIALIZED)
|
if (state > INITIALIZED)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
@ -349,10 +387,13 @@ Event_scheduler_ng::start()
|
|||||||
ret= TRUE;
|
ret= TRUE;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
new_thd->system_thread= SYSTEM_THREAD_EVENT_SCHEDULER;
|
||||||
|
new_thd->command= COM_DAEMON;
|
||||||
|
|
||||||
scheduler_param_value.thd= new_thd;
|
scheduler_param_value.thd= new_thd;
|
||||||
scheduler_param_value.scheduler= this;
|
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,
|
if (pthread_create(&th, &connection_attrib, event_scheduler_ng_thread,
|
||||||
(void*)&scheduler_param_value))
|
(void*)&scheduler_param_value))
|
||||||
{
|
{
|
||||||
@ -360,13 +401,14 @@ Event_scheduler_ng::start()
|
|||||||
state= INITIALIZED;
|
state= INITIALIZED;
|
||||||
ret= TRUE;
|
ret= TRUE;
|
||||||
}
|
}
|
||||||
|
DBUG_PRINT("info", ("Setting state go RUNNING"));
|
||||||
state= RUNNING;
|
state= RUNNING;
|
||||||
end:
|
end:
|
||||||
UNLOCK_SCHEDULER_DATA();
|
UNLOCK_SCHEDULER_DATA();
|
||||||
|
|
||||||
if (ret && new_thd)
|
if (ret && new_thd)
|
||||||
{
|
{
|
||||||
|
DBUG_PRINT("info", ("There was an error during THD creation. Clean up"));
|
||||||
new_thd->proc_info= "Clearing";
|
new_thd->proc_info= "Clearing";
|
||||||
DBUG_ASSERT(new_thd->net.buff != 0);
|
DBUG_ASSERT(new_thd->net.buff != 0);
|
||||||
net_end(&new_thd->net);
|
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
|
bool
|
||||||
Event_scheduler_ng::stop()
|
Event_scheduler_ng::stop()
|
||||||
{
|
{
|
||||||
THD *thd= current_thd;
|
THD *thd= current_thd;
|
||||||
DBUG_ENTER("Event_scheduler_ng::stop");
|
DBUG_ENTER("Event_scheduler_ng::stop");
|
||||||
DBUG_PRINT("enter", ("thd=%p", current_thd));
|
DBUG_PRINT("enter", ("thd=0x%lx", current_thd));
|
||||||
|
|
||||||
LOCK_SCHEDULER_DATA();
|
LOCK_SCHEDULER_DATA();
|
||||||
|
DBUG_PRINT("info", ("state before action %s", scheduler_states_names[state]));
|
||||||
if (state != RUNNING)
|
if (state != RUNNING)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
@ -406,48 +461,75 @@ Event_scheduler_ng::stop()
|
|||||||
"workers count=%d", scheduler_states_names[state].str,
|
"workers count=%d", scheduler_states_names[state].str,
|
||||||
workers_count()));
|
workers_count()));
|
||||||
/* thd could be 0x0, when shutting down */
|
/* thd could be 0x0, when shutting down */
|
||||||
pthread_cond_wait(&COND_state, &LOCK_scheduler_state);
|
COND_STATE_WAIT(NULL);
|
||||||
} while (state == STOPPING);
|
} while (state == STOPPING);
|
||||||
DBUG_PRINT("info", ("Manager thread has cleaned up. Set state to INIT"));
|
DBUG_PRINT("info", ("Manager thread has cleaned up. Set state to INIT"));
|
||||||
|
|
||||||
|
thread_id= 0;
|
||||||
end:
|
end:
|
||||||
UNLOCK_SCHEDULER_DATA();
|
UNLOCK_SCHEDULER_DATA();
|
||||||
DBUG_RETURN(FALSE);
|
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
|
bool
|
||||||
Event_scheduler_ng::run(THD *thd)
|
Event_scheduler_ng::run(THD *thd)
|
||||||
{
|
{
|
||||||
|
int res;
|
||||||
struct timespec abstime;
|
struct timespec abstime;
|
||||||
Event_timed *job_data;
|
Event_job_data *job_data;
|
||||||
|
DBUG_ENTER("Event_scheduler_ng::run");
|
||||||
|
|
||||||
LOCK_SCHEDULER_DATA();
|
LOCK_SCHEDULER_DATA();
|
||||||
|
|
||||||
thread_id= thd->thread_id;
|
thread_id= thd->thread_id;
|
||||||
sql_print_information("SCHEDULER: Manager thread started with id %lu",
|
sql_print_information("SCHEDULER: Manager thread started with id %lu",
|
||||||
thread_id);
|
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)
|
while (state == RUNNING)
|
||||||
{
|
{
|
||||||
thd->end_time();
|
thd->end_time();
|
||||||
/* Gets a minimized version */
|
/* Gets a minimized version */
|
||||||
job_data= queue->get_top_for_execution_if_time(thd, thd->query_start(),
|
job_data= queue->
|
||||||
&abstime);
|
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",
|
|
||||||
|
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));
|
job_data, thd->query_start(), abstime.tv_sec));
|
||||||
if (!job_data && !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,
|
thd->enter_cond(&COND_state, &LOCK_scheduler_state,
|
||||||
"Waiting on empty queue");
|
"Waiting on empty queue");
|
||||||
pthread_cond_wait(&COND_state, &LOCK_scheduler_state);
|
COND_STATE_WAIT(NULL);
|
||||||
thd->exit_cond("");
|
thd->exit_cond("");
|
||||||
DBUG_PRINT("info", ("Woke up. Got COND_state"));
|
DBUG_PRINT("info", ("Woke up. Got COND_state"));
|
||||||
LOCK_SCHEDULER_DATA();
|
LOCK_SCHEDULER_DATA();
|
||||||
}
|
}
|
||||||
else if (abstime.tv_sec)
|
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,
|
thd->enter_cond(&COND_state, &LOCK_scheduler_state,
|
||||||
"Waiting for next activation");
|
"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
|
If we get signal we should recalculate the whether it's the right time
|
||||||
because there could be :
|
because there could be :
|
||||||
@ -461,12 +543,12 @@ Event_scheduler_ng::run(THD *thd)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int res;
|
|
||||||
UNLOCK_SCHEDULER_DATA();
|
UNLOCK_SCHEDULER_DATA();
|
||||||
res= execute_top(thd, job_data);
|
res= execute_top(thd, job_data);
|
||||||
LOCK_SCHEDULER_DATA();
|
LOCK_SCHEDULER_DATA();
|
||||||
if (res)
|
if (res)
|
||||||
break;
|
break;
|
||||||
|
++started_events;
|
||||||
}
|
}
|
||||||
DBUG_PRINT("info", ("state=%s", scheduler_states_names[state].str));
|
DBUG_PRINT("info", ("state=%s", scheduler_states_names[state].str));
|
||||||
}
|
}
|
||||||
@ -477,29 +559,47 @@ error:
|
|||||||
UNLOCK_SCHEDULER_DATA();
|
UNLOCK_SCHEDULER_DATA();
|
||||||
sql_print_information("SCHEDULER: Stopped");
|
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
|
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;
|
THD *new_thd;
|
||||||
pthread_t th;
|
pthread_t th;
|
||||||
|
int res= 0;
|
||||||
DBUG_ENTER("Event_scheduler_ng::execute_top");
|
DBUG_ENTER("Event_scheduler_ng::execute_top");
|
||||||
if (!(new_thd= new THD) || init_scheduler_thread(new_thd))
|
if (!(new_thd= new THD) || init_scheduler_thread(new_thd))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* Major failure */
|
new_thd->system_thread= SYSTEM_THREAD_EVENT_WORKER;
|
||||||
job_data->thd= new_thd;
|
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));
|
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;
|
goto error;
|
||||||
|
|
||||||
|
DBUG_PRINT("info", ("Launch succeeded. BURAN is in THD=0x%lx", new_thd));
|
||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
DBUG_PRINT("error", ("Baikonur, we have a problem! res=%d", res));
|
||||||
if (new_thd)
|
if (new_thd)
|
||||||
{
|
{
|
||||||
new_thd->proc_info= "Clearing";
|
new_thd->proc_info= "Clearing";
|
||||||
@ -511,10 +611,21 @@ error:
|
|||||||
delete new_thd;
|
delete new_thd;
|
||||||
pthread_mutex_unlock(&LOCK_thread_count);
|
pthread_mutex_unlock(&LOCK_thread_count);
|
||||||
}
|
}
|
||||||
|
delete job_data;
|
||||||
DBUG_RETURN(TRUE);
|
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
|
enum Event_scheduler_ng::enum_state
|
||||||
Event_scheduler_ng::get_state()
|
Event_scheduler_ng::get_state()
|
||||||
{
|
{
|
||||||
@ -526,13 +637,12 @@ Event_scheduler_ng::get_state()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
/*
|
||||||
Event_scheduler_ng::dump_internal_status(THD *thd)
|
Returns the number of living event worker threads.
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
Event_scheduler_ng::workers_count()
|
||||||
|
*/
|
||||||
|
|
||||||
uint
|
uint
|
||||||
Event_scheduler_ng::workers_count()
|
Event_scheduler_ng::workers_count()
|
||||||
@ -541,7 +651,7 @@ Event_scheduler_ng::workers_count()
|
|||||||
uint count= 0;
|
uint count= 0;
|
||||||
|
|
||||||
DBUG_ENTER("Event_scheduler_ng::workers_count");
|
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);
|
I_List_iterator<THD> it(threads);
|
||||||
while ((tmp=it++))
|
while ((tmp=it++))
|
||||||
{
|
{
|
||||||
@ -550,7 +660,7 @@ Event_scheduler_ng::workers_count()
|
|||||||
if (tmp->system_thread == SYSTEM_THREAD_EVENT_WORKER)
|
if (tmp->system_thread == SYSTEM_THREAD_EVENT_WORKER)
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
VOID(pthread_mutex_unlock(&LOCK_thread_count));
|
pthread_mutex_unlock(&LOCK_thread_count);
|
||||||
DBUG_PRINT("exit", ("%d", count));
|
DBUG_PRINT("exit", ("%d", count));
|
||||||
DBUG_RETURN(count);
|
DBUG_RETURN(count);
|
||||||
}
|
}
|
||||||
@ -568,16 +678,27 @@ void
|
|||||||
Event_scheduler_ng::queue_changed()
|
Event_scheduler_ng::queue_changed()
|
||||||
{
|
{
|
||||||
DBUG_ENTER("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);
|
pthread_cond_signal(&COND_state);
|
||||||
DBUG_VOID_RETURN;
|
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
|
void
|
||||||
Event_scheduler_ng::lock_data(const char *func, uint line)
|
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));
|
DBUG_PRINT("enter", ("func=%s line=%u", func, line));
|
||||||
pthread_mutex_lock(&LOCK_scheduler_state);
|
pthread_mutex_lock(&LOCK_scheduler_state);
|
||||||
mutex_last_locked_in_func= func;
|
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
|
void
|
||||||
Event_scheduler_ng::unlock_data(const char *func, uint line)
|
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));
|
DBUG_PRINT("enter", ("func=%s line=%u", func, line));
|
||||||
mutex_last_unlocked_at_line= line;
|
mutex_last_unlocked_at_line= line;
|
||||||
mutex_scheduler_data_locked= FALSE;
|
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);
|
pthread_mutex_unlock(&LOCK_scheduler_state);
|
||||||
DBUG_VOID_RETURN;
|
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
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||||
|
|
||||||
class Event_timed;
|
|
||||||
class Event_queue;
|
class Event_queue;
|
||||||
|
class Event_job_data;
|
||||||
|
|
||||||
class Event_scheduler_ng
|
class Event_scheduler_ng
|
||||||
{
|
{
|
||||||
@ -67,7 +67,7 @@ public:
|
|||||||
void
|
void
|
||||||
queue_changed();
|
queue_changed();
|
||||||
|
|
||||||
static int
|
bool
|
||||||
dump_internal_status(THD *thd);
|
dump_internal_status(THD *thd);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -76,7 +76,7 @@ private:
|
|||||||
|
|
||||||
/* helper functions */
|
/* helper functions */
|
||||||
bool
|
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 */
|
/* helper functions for working with mutexes & conditionals */
|
||||||
void
|
void
|
||||||
@ -85,6 +85,9 @@ private:
|
|||||||
void
|
void
|
||||||
unlock_data(const char *func, uint line);
|
unlock_data(const char *func, uint line);
|
||||||
|
|
||||||
|
void
|
||||||
|
cond_wait(struct timespec *abstime, const char *func, uint line);
|
||||||
|
|
||||||
pthread_mutex_t LOCK_scheduler_state;
|
pthread_mutex_t LOCK_scheduler_state;
|
||||||
|
|
||||||
/* This is the current status of the life-cycle of the scheduler. */
|
/* 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_locked_in_func;
|
||||||
const char* mutex_last_unlocked_in_func;
|
const char* mutex_last_unlocked_in_func;
|
||||||
bool mutex_scheduler_data_locked;
|
bool mutex_scheduler_data_locked;
|
||||||
|
bool waiting_on_cond;
|
||||||
|
|
||||||
|
ulonglong started_events;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* Prevent use of these */
|
/* 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
|
RETURN VALUE
|
||||||
0 OK
|
0 OK
|
||||||
!0 Error
|
!0 Error (Reported)
|
||||||
|
|
||||||
NOTES
|
NOTES
|
||||||
- in case there is an event with the same name (db) and
|
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.
|
IF NOT EXISTS is specified, an warning is put into the stack.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -304,13 +304,20 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, bool if_not_exists,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
DBUG_ENTER("Events::create_event");
|
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,
|
if (!(ret= db_repository->create_event(thd, parse_data, if_not_exists,
|
||||||
rows_affected)))
|
rows_affected)))
|
||||||
{
|
{
|
||||||
if ((ret= event_queue->create_event(thd, parse_data)))
|
if ((ret= event_queue->create_event(thd, parse_data->dbname,
|
||||||
my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
|
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);
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
@ -322,8 +329,8 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, bool if_not_exists,
|
|||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
Events::update_event()
|
Events::update_event()
|
||||||
thd THD
|
thd THD
|
||||||
et event's data
|
et Event's data from parsing stage
|
||||||
new_name set in case of RENAME TO.
|
new_name Set in case of RENAME TO.
|
||||||
|
|
||||||
RETURN VALUE
|
RETURN VALUE
|
||||||
0 OK
|
0 OK
|
||||||
@ -341,18 +348,23 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, sp_name *new_name,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
DBUG_ENTER("Events::update_event");
|
DBUG_ENTER("Events::update_event");
|
||||||
/*
|
|
||||||
db_update_event() opens & closes the table to prevent
|
pthread_mutex_lock(&LOCK_event_metadata);
|
||||||
crash later in the code when loading and compiling the new definition.
|
/* On error conditions my_error() is called so no need to handle here */
|
||||||
Also 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= 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_db: NULL,
|
||||||
new_name? &new_name->m_name: 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);
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,10 +375,15 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, sp_name *new_name,
|
|||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
Events::drop_event()
|
Events::drop_event()
|
||||||
thd THD
|
thd THD
|
||||||
|
dbname Event's schema
|
||||||
name Event's name
|
name Event's name
|
||||||
if_exists When set and the event does not exist => warning onto
|
if_exists When set and the event does not exist => warning onto
|
||||||
the stack
|
the stack
|
||||||
rows_affected Affected number of rows is returned heres
|
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
|
RETURN VALUE
|
||||||
0 OK
|
0 OK
|
||||||
@ -374,17 +391,52 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, sp_name *new_name,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
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;
|
int ret;
|
||||||
DBUG_ENTER("Events::drop_event");
|
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)))
|
rows_affected)))
|
||||||
{
|
{
|
||||||
if ((ret= event_queue->drop_event(thd, name)))
|
if (!only_from_disk)
|
||||||
my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
|
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);
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,14 +458,14 @@ int
|
|||||||
Events::show_create_event(THD *thd, sp_name *spn)
|
Events::show_create_event(THD *thd, sp_name *spn)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
Event_timed *et= NULL;
|
Event_timed *et= new Event_timed();
|
||||||
Open_tables_state backup;
|
Open_tables_state backup;
|
||||||
|
|
||||||
DBUG_ENTER("Events::show_create_event");
|
DBUG_ENTER("Events::show_create_event");
|
||||||
DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str));
|
DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str));
|
||||||
|
|
||||||
thd->reset_n_backup_open_tables_state(&backup);
|
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);
|
thd->restore_backup_open_tables_state(&backup);
|
||||||
|
|
||||||
if (!ret)
|
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.
|
Proxy for Event_db_repository::fill_schema_events.
|
||||||
Callback for I_S from sql_show.cc
|
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
|
bool
|
||||||
Events::start_execution_of_events()
|
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
|
bool
|
||||||
Events::stop_execution_of_events()
|
Events::stop_execution_of_events()
|
||||||
{
|
{
|
||||||
@ -661,6 +725,18 @@ Events::stop_execution_of_events()
|
|||||||
DBUG_RETURN(scheduler_ng->stop());
|
DBUG_RETURN(scheduler_ng->stop());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Checks whether the scheduler is running or not.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
Events::is_started()
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
TRUE Yes
|
||||||
|
FALSE No
|
||||||
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Events::is_started()
|
Events::is_started()
|
||||||
{
|
{
|
||||||
|
17
sql/events.h
17
sql/events.h
@ -20,6 +20,7 @@ class sp_name;
|
|||||||
class Event_parse_data;
|
class Event_parse_data;
|
||||||
class Event_db_repository;
|
class Event_db_repository;
|
||||||
class Event_queue;
|
class Event_queue;
|
||||||
|
class Event_queue_element;
|
||||||
class Event_scheduler_ng;
|
class Event_scheduler_ng;
|
||||||
|
|
||||||
/* Return codes */
|
/* Return codes */
|
||||||
@ -41,6 +42,7 @@ sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
|
|||||||
class Events
|
class Events
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
friend class Event_queue_element;
|
||||||
/*
|
/*
|
||||||
Quite NOT the best practice and will be removed once
|
Quite NOT the best practice and will be removed once
|
||||||
Event_timed::drop() and Event_timed is fixed not do drop directly
|
Event_timed::drop() and Event_timed is fixed not do drop directly
|
||||||
@ -83,7 +85,8 @@ public:
|
|||||||
uint *rows_affected);
|
uint *rows_affected);
|
||||||
|
|
||||||
int
|
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
|
int
|
||||||
drop_schema_events(THD *thd, char *db);
|
drop_schema_events(THD *thd, char *db);
|
||||||
@ -102,13 +105,9 @@ public:
|
|||||||
static int
|
static int
|
||||||
fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */);
|
fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */);
|
||||||
|
|
||||||
int
|
bool
|
||||||
dump_internal_status(THD *thd);
|
dump_internal_status(THD *thd);
|
||||||
|
|
||||||
Event_queue *event_queue;
|
|
||||||
Event_scheduler_ng *scheduler_ng;
|
|
||||||
Event_db_repository *db_repository;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* Singleton DP is used */
|
/* Singleton DP is used */
|
||||||
Events(){}
|
Events(){}
|
||||||
@ -117,6 +116,12 @@ private:
|
|||||||
/* Singleton instance */
|
/* Singleton instance */
|
||||||
static Events singleton;
|
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 */
|
/* Prevent use of these */
|
||||||
Events(const Events &);
|
Events(const Events &);
|
||||||
void operator=(Events &);
|
void operator=(Events &);
|
||||||
|
@ -5829,7 +5829,7 @@ ER_CANT_CHANGE_TX_ISOLATION 25001
|
|||||||
ER_DUP_ENTRY_AUTOINCREMENT_CASE
|
ER_DUP_ENTRY_AUTOINCREMENT_CASE
|
||||||
eng "ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '%-.64s' for key '%-.64s'"
|
eng "ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '%-.64s' for key '%-.64s'"
|
||||||
ER_EVENT_MODIFY_QUEUE_ERROR
|
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
|
ER_EVENT_SET_VAR_ERROR
|
||||||
eng "Error during starting/stopping of the scheduler."
|
eng "Error during starting/stopping of the scheduler."
|
||||||
ER_PARTITION_MERGE_ERROR
|
ER_PARTITION_MERGE_ERROR
|
||||||
|
@ -3886,8 +3886,12 @@ end_with_restore_list:
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint affected= 1;
|
uint affected= 1;
|
||||||
if (!(res= Events::get_instance()->
|
if (!(res= Events::get_instance()->drop_event(thd,
|
||||||
drop_event(thd, lex->spname, lex->drop_if_exists, &affected)))
|
lex->spname->m_db,
|
||||||
|
lex->spname->m_name,
|
||||||
|
lex->drop_if_exists,
|
||||||
|
&affected,
|
||||||
|
FALSE)))
|
||||||
send_ok(thd, affected);
|
send_ok(thd, affected);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user