Merge bk-internal.mysql.com:/data0/bk/mysql-5.1-runtime

into  bk-internal.mysql.com:/data0/bk/mysql-5.1-wl3337


client/mysqltest.c:
  Auto merged
libmysqld/Makefile.am:
  Auto merged
mysql-test/mysql-test-run.pl:
  Auto merged
mysql-test/r/events.result:
  Auto merged
mysql-test/r/not_embedded_server.result:
  Auto merged
mysql-test/t/events.test:
  Auto merged
sql/CMakeLists.txt:
  Auto merged
sql/Makefile.am:
  Auto merged
sql/mysqld.cc:
  Auto merged
sql/set_var.cc:
  Auto merged
sql/sp_head.cc:
  Auto merged
sql/sql_class.cc:
  Auto merged
sql/sql_lex.cc:
  Auto merged
sql/sql_parse.cc:
  Auto merged
sql/sql_show.cc:
  Auto merged
sql/sql_yacc.yy:
  Auto merged
sql/table.cc:
  Auto merged
sql/table.h:
  Auto merged
This commit is contained in:
unknown 2006-09-06 14:35:27 +02:00
commit 23a46f410f
57 changed files with 6182 additions and 4973 deletions

1107
.bzrignore

File diff suppressed because it is too large Load Diff

View File

@ -155,6 +155,7 @@ static my_bool ps_protocol= 0, ps_protocol_enabled= 0;
static my_bool sp_protocol= 0, sp_protocol_enabled= 0;
static my_bool view_protocol= 0, view_protocol_enabled= 0;
static my_bool cursor_protocol= 0, cursor_protocol_enabled= 0;
static my_bool opt_valgrind_test= 0;
static int parsing_disabled= 0;
static char **default_argv;
@ -3286,6 +3287,8 @@ static struct my_option my_long_options[] =
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"user", 'u', "User for login.", (gptr*) &user, (gptr*) &user, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"valgrind", 'N', "Define VALGRIND_TEST to 1.", (gptr*) &opt_valgrind_test,
(gptr*) &opt_valgrind_test, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"verbose", 'v', "Write more.", (gptr*) &verbose, (gptr*) &verbose, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"version", 'V', "Output version information and exit.",
@ -5060,6 +5063,9 @@ static void init_var_hash(MYSQL *mysql)
die("Variable hash initialization failed");
my_hash_insert(&var_hash, (byte*) var_init(0,"BIG_TEST", 0,
(opt_big_test) ? "1" : "0", 0));
my_hash_insert(&var_hash, (byte*) var_init(0,"VALGRIND_TEST", 0,
(opt_valgrind_test) ? "1" : "0",
0));
v= var_init(0,"MAX_TABLES", 0, (sizeof(ulong) == 4) ? "31" : "62",0);
my_hash_insert(&var_hash, (byte*) v);
v= var_init(0,"SERVER_VERSION", 0, mysql_get_server_info(mysql), 0);

View File

@ -67,7 +67,8 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
spatial.cc gstream.cc sql_help.cc tztime.cc sql_cursor.cc \
sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \
parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \
event_scheduler.cc events.cc event_timed.cc \
event_scheduler.cc events.cc event_data_objects.cc \
event_queue.cc event_db_repository.cc \
rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \
sql_tablespace.cc \
rpl_injector.cc my_user.c partition_info.cc

View File

@ -0,0 +1,4 @@
--require r/not_valgrind.require
--disable_query_log
eval select $VALGRIND_TEST as using_valgrind;
--enable_query_log

View File

@ -3635,6 +3635,11 @@ sub run_mysqltest ($) {
mtr_add_arg($args, "--big-test");
}
if ( $opt_valgrind )
{
mtr_add_arg($args, "--valgrind");
}
if ( $opt_compress )
{
mtr_add_arg($args, "--compress");

View File

@ -17,13 +17,13 @@ db_x
SHOW TABLES FROM db_x;
Tables_in_db_x
x_table
SET GLOBAL event_scheduler=2;
SET GLOBAL event_scheduler=off;
DROP EVENT e_x1;
DROP EVENT e_x2;
DROP DATABASE db_x;
DROP USER pauline@localhost;
USE events_test;
SET GLOBAL event_scheduler=2;
SET GLOBAL event_scheduler=off;
drop event if exists event1;
Warnings:
Note 1305 Event event1 does not exist
@ -85,13 +85,24 @@ SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost RECURRING NULL 20 SECOND # # ENABLED
DROP EVENT event_starts_test;
create table test_nested(a int);
create event e_43 on schedule every 1 second do set @a = 5;
set global event_scheduler = 1;
alter event e_43 do alter event e_43 do set @a = 4;
ERROR HY000: Recursivity of EVENT DDL statements is forbidden when body is present
alter event e_43 do
begin
alter event e_43 on schedule every 5 minute;
insert into test_nested values(1);
end|
set global event_scheduler = on;
select db, name, body, status, interval_field, interval_value from mysql.event;
db name body status interval_field interval_value
events_test e_43 set @a = 4 ENABLED SECOND 1
events_test e_43 begin
alter event e_43 on schedule every 5 minute;
insert into test_nested values(1);
end ENABLED MINUTE 5
drop event e_43;
drop table test_nested;
"Let's check whether we can use non-qualified names"
create table non_qualif(a int);
create event non_qualif_ev on schedule every 10 minute do insert into non_qualif values (800219);
@ -100,7 +111,15 @@ a
800219
drop event non_qualif_ev;
drop table non_qualif;
set global event_scheduler = 2;
alter event non_existant rename to non_existant_too;
ERROR HY000: Unknown event 'non_existant'
set global event_scheduler = off;
create event existant on schedule at now() + interval 1 year do select 12;
alter event non_existant rename to existant;
ERROR HY000: Event 'existant' already exists
alter event existant rename to events_test.existant;
ERROR HY000: Same old and new event name
drop event existant;
create table t_event3 (a int, b float);
drop event if exists event3;
Warnings:
@ -195,6 +214,10 @@ ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
SHOW EVENTS;
ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
drop event root22;
create event root23 on schedule every -100 year do select 1;
ERROR HY000: INTERVAL is either not positive or too big
create event root23 on schedule every 222222222222222222222 year do select 1;
ERROR HY000: INTERVAL is either not positive or too big
drop event root6;
drop event root7;
drop event root8;
@ -285,19 +308,21 @@ select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_comp
db name body definer convert_tz(execute_at, 'UTC', 'SYSTEM') on_completion
events_test e_26 set @a = 5 root@localhost 2017-01-01 00:00:00 DROP
drop event e_26;
create event e_26 on schedule at NULL disabled do set @a = 5;
create event e_26 on schedule at NULL disable do set @a = 5;
ERROR HY000: Incorrect AT value: 'NULL'
create event e_26 on schedule at 'definitely not a datetime' disabled do set @a = 5;
create event e_26 on schedule at 'definitely not a datetime' disable do set @a = 5;
ERROR HY000: Incorrect AT value: 'definitely not a datetime'
set names utf8;
create event задачка on schedule every 123 minute starts now() ends now() + interval 1 month do select 1;
drop event задачка;
set event_scheduler=2;
set event_scheduler=off;
ERROR HY000: Variable 'event_scheduler' is a GLOBAL variable and should be set with SET GLOBAL
set global event_scheduler=3;
ERROR 42000: Variable 'event_scheduler' can't be set to the value of '3'
set global event_scheduler=disabled;
ERROR 42000: Variable 'event_scheduler' can't be set to the value of 'disabled'
"DISABLE the scheduler. Testing that it does not work when the variable is 0"
set global event_scheduler=2;
set global event_scheduler=off;
select definer, name, db from mysql.event;
definer name db
select get_lock("test_lock1", 20);
@ -311,7 +336,6 @@ root@localhost закачка events_test
"Should be only 1 process"
select /*1*/ user, host, db, command, state, info from information_schema.processlist where command!='Daemon' and (info is null or info not like '%processlist%') order by info;
user host db command state info
event_scheduler localhost NULL Connect Suspended NULL
select release_lock("test_lock1");
release_lock("test_lock1")
1
@ -321,7 +345,7 @@ select count(*) from mysql.event;
count(*)
0
"ENABLE the scheduler and get a lock"
set global event_scheduler=1;
set global event_scheduler=on;
select get_lock("test_lock2", 20);
get_lock("test_lock2", 20)
1
@ -331,7 +355,7 @@ create event закачка on schedule every 10 hour do select get_lock("test_l
"Should have only 2 processes: the scheduler and the locked event"
select /*2*/ user, host, db, command, state, info from information_schema.processlist where command!='Daemon' and (info is null or info not like '%processlist%') order by info;
user host db command state info
event_scheduler localhost NULL Connect Sleeping NULL
event_scheduler localhost NULL Daemon Waiting for next activation NULL
root localhost events_test Connect User lock select get_lock("test_lock2", 20)
"Release the mutex, the event worker should finish."
"Release the mutex, the event worker should finish."
@ -347,18 +371,17 @@ create event закачка21 on schedule every 10 hour do select get_lock("test
"Should have only 3 processes: the scheduler, our conn and the locked event"
select /*3*/ user, host, db, command, state, info from information_schema.processlist where command!='Daemon' and (info is null or info not like '%processlist%') order by info;
user host db command state info
event_scheduler localhost NULL Connect Sleeping NULL
event_scheduler localhost NULL Daemon Waiting for next activation NULL
root localhost events_test Connect User lock select get_lock("test_lock2_1", 20)
set global event_scheduler=2;
set global event_scheduler=off;
"Should have only our process now:"
select /*4*/ user, host, db, command, state, info from information_schema.processlist where command!='Daemon' and (info is null or info not like '%processlist%') order by info;
user host db command state info
event_scheduler localhost NULL Connect Suspended NULL
root localhost events_test Connect User lock select get_lock("test_lock2_1", 20)
drop event закачка21;
create table t_16 (s1 int);
create trigger t_16_bi before insert on t_16 for each row create event e_16 on schedule every 1 second do set @a=5;
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
ERROR HY000: Recursivity of EVENT DDL statements is forbidden when body is present
drop table t_16;
create event white_space
on schedule every 10 hour

View File

@ -17,28 +17,28 @@ DROP EVENT ДОЛЕН_регистър_утф8;
SET NAMES latin1;
set @a=3;
CREATE PROCEDURE p_16 () CREATE EVENT e_16 ON SCHEDULE EVERY @a SECOND DO SET @a=5;
call p_16();
"Here we used to crash!"
call p_16();
ERROR HY000: Event 'e_16' already exists
call p_16();
ERROR HY000: Event 'e_16' already exists
DROP EVENT e_16;
CALL p_16();
CALL p_16();
ERROR HY000: Event 'e_16' already exists
DROP PROCEDURE p_16;
DROP EVENT e_16;
ERROR HY000: Recursivity of EVENT DDL statements is forbidden when body is present
create event e_55 on schedule at 99990101000000 do drop table t;
ERROR HY000: Incorrect AT value: '99990101000000'
create event e_55 on schedule every 10 hour starts 99990101000000 do drop table t;
ERROR HY000: Incorrect STARTS value: '99990101000000'
create event e_55 on schedule every 10 minute ends 99990101000000 do drop table t;
ERROR HY000: ENDS is either invalid or before STARTS
set global event_scheduler=2;
"Wait a bit to settle down"
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=off;
delete from mysql.event;
set global event_scheduler= 1;
set global event_scheduler= on;
set @old_sql_mode:=@@sql_mode;
set sql_mode=ansi;
select get_lock('test_bug16407', 60);
@ -50,14 +50,14 @@ select get_lock('test_bug16407', 60);
drop table "hashed_num";
end|
"Now if everything is fine the event has compiled and is locked
select /*1*/ user, host, db, command, state, info from information_schema.processlist where command!='Daemon' and (info is null or info not like '%processlist%') order by info;
user host db command state info
event_scheduler localhost NULL Connect Sleeping NULL
root localhost events_test Connect User lock select get_lock('test_bug16407', 60)
select /*1*/ user, host, db, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db info
event_scheduler localhost NULL NULL
root localhost events_test select get_lock('test_bug16407', 60)
select release_lock('test_bug16407');
release_lock('test_bug16407')
1
set global event_scheduler= 2;
set global event_scheduler= off;
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
event_schema event_name sql_mode
events_test e_16407 REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI
@ -68,6 +68,11 @@ select event_schema, event_name, sql_mode from information_schema.events order b
event_schema event_name sql_mode
events_test e_16407 STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER
drop event e_16407;
set sql_mode="ansi";
select get_lock('ee_16407_2', 60);
get_lock('ee_16407_2', 60)
1
set global event_scheduler= 1;
"Another sql_mode test"
set sql_mode="traditional";
create table events_smode_test(ev_name char(10), a date) engine=myisam;
@ -75,6 +80,7 @@ create table events_smode_test(ev_name char(10), a date) engine=myisam;
create event ee_16407_2 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_2*/;
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values('ee_16407_2','1980-19-02');
end|
insert into events_smode_test values ('test','1980-19-02')|
@ -83,6 +89,7 @@ ERROR 22007: Incorrect date value: '1980-19-02' for column 'a' at row 1
create event ee_16407_3 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_3*/;
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values ('ee_16407_3','1980-02-19');
insert into events_test.events_smode_test values ('ee_16407_3','1980-02-29');
end|
@ -91,6 +98,7 @@ set sql_mode=""|
create event ee_16407_4 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_4*/;
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values ('ee_16407_4','10-11-1956');
end|
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
@ -98,24 +106,19 @@ event_schema event_name sql_mode
events_test ee_16407_2 STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER
events_test ee_16407_3 STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER
events_test ee_16407_4
set sql_mode="ansi";
select get_lock('ee_16407_2', 60);
get_lock('ee_16407_2', 60)
1
set global event_scheduler= 1;
select /*2*/ user, host, db, command, state, info from information_schema.processlist where command!='Daemon' and (info is null or info not like '%processlist%') order by info;
user host db command state info
event_scheduler localhost NULL Connect Sleeping NULL
root localhost events_test Connect User lock select get_lock('ee_16407_2', 60)
root localhost events_test Connect User lock select get_lock('ee_16407_2', 60)
root localhost events_test Connect User lock select get_lock('ee_16407_2', 60)
select /*2*/ user, host, db, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db info
event_scheduler localhost NULL NULL
root localhost events_test select get_lock('ee_16407_2', 60)
root localhost events_test select get_lock('ee_16407_2', 60)
root localhost events_test select get_lock('ee_16407_2', 60)
select release_lock('ee_16407_2');
release_lock('ee_16407_2')
1
select /*3*/ user, host, db, command, state, info from information_schema.processlist where command!='Daemon' and (info is null or info not like '%processlist%') order by info;
user host db command state info
event_scheduler localhost NULL Connect Sleeping NULL
set global event_scheduler= 2;
select /*3*/ user, host, db, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db info
event_scheduler localhost NULL NULL
set global event_scheduler= off;
select * from events_smode_test order by ev_name, a;
ev_name a
ee_16407_3 1980-02-19
@ -132,37 +135,39 @@ drop event ee_16407_3;
drop event ee_16407_4;
"And now one last test regarding sql_mode and call of SP from an event"
delete from events_smode_test;
set sql_mode='ansi';
select get_lock('ee_16407_5', 60);
get_lock('ee_16407_5', 60)
1
set global event_scheduler= on;
set sql_mode='traditional';
create procedure ee_16407_5_pendant() begin insert into events_test.events_smode_test values('ee_16407_5','2001-02-29'); end|
create procedure ee_16407_6_pendant() begin insert into events_test.events_smode_test values('ee_16407_6','2004-02-29'); end|
create event ee_16407_5 on schedule every 60 second do
begin
select get_lock('ee_16407_5', 60) /*ee_16407_5*/;
select release_lock('ee_16407_5');
call events_test.ee_16407_5_pendant();
end|
create event ee_16407_6 on schedule every 60 second do
begin
select get_lock('ee_16407_5', 60) /*ee_16407_6*/;
select release_lock('ee_16407_5');
call events_test.ee_16407_6_pendant();
end|
set sql_mode='ansi';
select get_lock('ee_16407_5', 60);
get_lock('ee_16407_5', 60)
1
set global event_scheduler= 1;
"Should have 2 locked processes"
select /*4*/ user, host, db, command, state, info from information_schema.processlist where command!='Daemon' and (info is null or info not like '%processlist%') order by info;
user host db command state info
event_scheduler localhost NULL Connect Sleeping NULL
root localhost events_test Connect User lock select get_lock('ee_16407_5', 60)
root localhost events_test Connect User lock select get_lock('ee_16407_5', 60)
select /*4*/ user, host, db, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db info
event_scheduler localhost NULL NULL
root localhost events_test select get_lock('ee_16407_5', 60)
root localhost events_test select get_lock('ee_16407_5', 60)
select release_lock('ee_16407_5');
release_lock('ee_16407_5')
1
"Should have 0 processes locked"
select /*5*/ user, host, db, command, state, info from information_schema.processlist where command!='Daemon' and (info is null or info not like '%processlist%') order by info;
user host db command state info
event_scheduler localhost NULL Connect Sleeping NULL
select /*5*/ user, host, db, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db info
event_scheduler localhost NULL NULL
select * from events_smode_test order by ev_name, a;
ev_name a
ee_16407_6 2004-02-29
@ -175,10 +180,10 @@ drop event ee_16407_5;
drop event ee_16407_6;
drop procedure ee_16407_5_pendant;
drop procedure ee_16407_6_pendant;
set global event_scheduler= 2;
set global event_scheduler= off;
drop table events_smode_test;
set sql_mode=@old_sql_mode;
set global event_scheduler=2;
set global event_scheduler=off;
delete from mysql.user where User like 'mysqltest_%';
delete from mysql.db where User like 'mysqltest_%';
flush privileges;
@ -201,4 +206,12 @@ events_test mysqltest_user1 mysqltest_user1@localhost RECURRING ENABLED
drop event events_test.mysqltest_user1;
drop user mysqltest_user1@localhost;
drop database mysqltest_db1;
create event e_53 on schedule at (select s1 from ttx) 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 'select s1 from ttx) do drop table t' at line 1
create event e_53 on schedule every (select s1 from ttx) second 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 'select s1 from ttx) second do drop table t' at line 1
create event e_53 on schedule every 5 second starts (select s1 from ttx) 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 'select s1 from ttx) do drop table t' at line 1
create event e_53 on schedule every 5 second ends (select s1 from ttx) 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 'select s1 from ttx) do drop table t' at line 1
drop database events_test;

View File

@ -1,5 +1,5 @@
create database if not exists events_test;
use events_test;
CREATE DATABASE IF NOT EXISTS events_test;
USE events_test;
"We use procedure here because its statements won't be logged into the general log"
"If we had used normal select that are logged in different ways depending on whether"
"the test suite is run in normal mode or with --ps-protocol"
@ -8,21 +8,24 @@ BEGIN
SELECT user_host, argument FROM mysql.general_log WHERE argument LIKE '%alabala%';
END|
"Check General Query Log"
SET GLOBAL event_scheduler=2;
create event log_general on schedule every 1 minute do SELect 'alabala', sleep(3) from dual;
CALL select_general_log();
user_host argument
USER_HOST CREATE procedure select_general_log()
BEGIN
SELECT user_host, argument FROM mysql.general_log WHERE argument LIKE '%alabala%';
END
SET GLOBAL event_scheduler=on;
TRUNCATE mysql.general_log;
"1 row, the current statement!"
call select_general_log();
user_host argument
SET GLOBAL event_scheduler=1;
CREATE EVENT log_general ON SCHEDULE EVERY 1 MINUTE DO SELECT 'alabala', SLEEP(1) FROM DUAL;
"Wait the scheduler to start"
"Should see 3 rows - the 'SELect' is in the middle. The other two are selects from general_log"
call select_general_log();
"Should see 2 rows - the 'SELECT' is in the middle. The other two are selects from general_log"
CALL select_general_log();
user_host argument
USER_HOST SELect 'alabala', sleep(3) from dual
USER_HOST CREATE EVENT log_general ON SCHEDULE EVERY 1 MINUTE DO SELECT 'alabala', SLEEP(1) FROM DUAL
USER_HOST SELECT 'alabala', SLEEP(1) FROM DUAL
DROP PROCEDURE select_general_log;
DROP EVENT log_general;
SET GLOBAL event_scheduler=2;
SET GLOBAL event_scheduler=off;
"Check slow query log"
"Save the values"
SET @old_global_long_query_time:=(select get_value());
@ -52,19 +55,20 @@ TRUNCATE mysql.slow_log;
CREATE TABLE slow_event_test (slo_val tinyint, val tinyint);
SET SESSION long_query_time=1;
"This won't go to the slow log"
CREATE EVENT long_event ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(3);
SELECT * FROM slow_event_test;
slo_val val
SET GLOBAL event_scheduler=1;
SET SESSION long_query_time=1;
SET GLOBAL event_scheduler=on;
CREATE EVENT long_event ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(1.5);
"Sleep some more time than the actual event run will take"
SHOW VARIABLES LIKE 'event_scheduler';
Variable_name Value
event_scheduler 1
event_scheduler ON
"Check our table. Should see 1 row"
SELECT * FROM slow_event_test;
slo_val val
4 0
"Check slow log. Should not see anything because 3 is under the threshold of 4 for GLOBAL, though over SESSION which is 2"
"Check slow log. Should not see anything because 1.5 is under the threshold of 300 for GLOBAL, though over SESSION which is 2"
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
user_host query_time db sql_text
"This should go to the slow log"
@ -89,4 +93,4 @@ TRUNCATE mysql.slow_log;
DROP TABLE slow_event_test;
SET GLOBAL long_query_time =@old_global_long_query_time;
SET SESSION long_query_time =@old_session_long_query_time;
drop database events_test;
DROP DATABASE events_test;

View File

@ -0,0 +1,12 @@
create database if not exists mysqltest_events_test;
use mysqltest_events_test;
set global event_scheduler=off;
create table execution_log(name char(10));
create event abc1 on schedule every 1 second do insert into execution_log value('abc1');
create event abc2 on schedule every 1 second do insert into execution_log value('abc2');
create event abc3 on schedule every 1 second do insert into execution_log value('abc3');
select name from execution_log;
name
insert into mysql.event values ('db1','bad','select 42','root@localhost',NULL,1000,'MICROSECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment1');
insert into mysql.event values ('db1','bad2','sect','root@localhost',NULL,1000,'SECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment2');
"Now we restart the server"

View File

@ -0,0 +1,6 @@
use mysqltest_events_test;
"Should get 0 rows because the queue aborted run
select distinct name from execution_log order by name;
name
delete from mysql.event where name like 'bad%';
"Now restart the server again"

View File

@ -0,0 +1,12 @@
use mysqltest_events_test;
"Should get 3 rows : abc1, abc2, abc3
select distinct name from execution_log order by name;
name
abc1
abc2
abc3
drop event abc1;
drop event abc2;
drop event abc3;
drop table execution_log;
drop database mysqltest_events_test;

View File

@ -1,12 +1,47 @@
CREATE DATABASE IF NOT EXISTS events_test;
USE events_test;
SET GLOBAL event_scheduler=OFF;
SHOW VARIABLES LIKE 'event_scheduler';
Variable_name Value
event_scheduler OFF
SET GLOBAL event_scheduler=1;
SHOW VARIABLES LIKE 'event_scheduler';
Variable_name Value
event_scheduler ON
SET GLOBAL event_scheduler=0;
SHOW VARIABLES LIKE 'event_scheduler';
Variable_name Value
event_scheduler OFF
SET GLOBAL event_scheduler=ON;
SHOW VARIABLES LIKE 'event_scheduler';
Variable_name Value
event_scheduler ON
SET GLOBAL event_scheduler=DISABLED;
ERROR 42000: Variable 'event_scheduler' can't be set to the value of 'DISABLED'
SHOW VARIABLES LIKE 'event_scheduler';
Variable_name Value
event_scheduler ON
SET GLOBAL event_scheduler=-1;
ERROR 42000: Variable 'event_scheduler' can't be set to the value of '-1'
SHOW VARIABLES LIKE 'event_scheduler';
Variable_name Value
event_scheduler ON
SET GLOBAL event_scheduler=2;
ERROR 42000: Variable 'event_scheduler' can't be set to the value of '2'
SHOW VARIABLES LIKE 'event_scheduler';
Variable_name Value
event_scheduler ON
SET GLOBAL event_scheduler=5;
ERROR 42000: Variable 'event_scheduler' can't be set to the value of '5'
SHOW VARIABLES LIKE 'event_scheduler';
Variable_name Value
event_scheduler ON
CREATE TABLE table_1(a int);
CREATE TABLE table_2(a int);
CREATE TABLE table_3(a int);
CREATE TABLE table_4(a int);
CREATE TABLE T19170(s1 TIMESTAMP);
SET GLOBAL event_scheduler=1;
CREATE EVENT E19170 ON SCHEDULE EVERY 2 SECOND DO INSERT INTO T19170 VALUES(CURRENT_TIMESTAMP);
SET GLOBAL event_scheduler=ON;
CREATE EVENT two_sec ON SCHEDULE EVERY 2 SECOND DO INSERT INTO table_1 VALUES(1);
CREATE EVENT start_n_end
ON SCHEDULE EVERY 1 SECOND
@ -39,17 +74,12 @@ DROP EVENT start_n_end;
DROP EVENT only_one_time;
ERROR HY000: Unknown event 'only_one_time'
"Should be preserved"
SELECT EVENT_NAME, STATUS FROM INFORMATION_SCHEMA.EVENTS;
SELECT EVENT_NAME, STATUS FROM INFORMATION_SCHEMA.EVENTS ORDER BY EVENT_NAME;
EVENT_NAME STATUS
E19170 ENABLED
two_time DISABLED
DROP EVENT two_time;
DROP TABLE table_1;
DROP TABLE table_2;
DROP TABLE table_3;
DROP TABLE table_4;
"Checking for multiple executions in one second, should not happen -> 0 as result"
SELECT COUNT(*) FROM (SELECT s1, COUNT(*) AS cnt FROM T19170 GROUP BY s1) AS tmp WHERE tmp.cnt > 1;
COUNT(*)
0
DROP DATABASE events_test;

View File

@ -32,15 +32,15 @@ USE events_conn1_test2;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
COUNT(*)
50
SET GLOBAL event_scheduler=1;
SET GLOBAL event_scheduler=on;
DROP DATABASE events_conn1_test2;
SET GLOBAL event_scheduler=2;
SET GLOBAL event_scheduler=off;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
COUNT(*)
0
CREATE DATABASE events_conn1_test3;
USE events_conn1_test3;
SET GLOBAL event_scheduler=1;
SET GLOBAL event_scheduler=on;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test3';
COUNT(*)
50
@ -55,9 +55,9 @@ DROP DATABASE events_conn2_db;
DROP DATABASE events_conn3_db;
DROP DATABASE events_conn1_test2;
DROP DATABASE events_conn1_test3;
SET GLOBAL event_scheduler=2;
SET GLOBAL event_scheduler=off;
DROP DATABASE events_conn1_test4;
SET GLOBAL event_scheduler=1;
SET GLOBAL event_scheduler=on;
USE events_test;
DROP TABLE fill_it1;
DROP TABLE fill_it2;

View File

@ -2,5 +2,4 @@ prepare stmt1 from ' SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND!
execute stmt1;
ID USER HOST DB COMMAND TIME STATE INFO
number root localhost test Query time preparing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND!='Daemon'
number event_scheduler localhost NULL Connect time Suspended NULL
deallocate prepare stmt1;

View File

@ -0,0 +1,2 @@
using_valgrind
0

View File

@ -10,6 +10,5 @@ user()
#
show processlist;
Id User Host db Command Time State Info
<id> event_scheduler <host> NULL <command> <time> <state> <info>
<id> root <host> test <command> <time> <state> <info>
<id> root <host> test <command> <time> <state> <info>

View File

@ -34,7 +34,6 @@ lock tables t2 write;
call bug9486();
show processlist;
Id User Host db Command Time State Info
# event_scheduler localhost NULL Connect # Suspended NULL
# root localhost test Sleep # NULL
# root localhost test Query # Locked update t1, t2 set val= 1 where id1=id2
# root localhost test Query # NULL show processlist

View File

@ -18,11 +18,9 @@ show processlist;
end|
call bug4902_2()|
Id User Host db Command Time State Info
# event_scheduler localhost NULL Connect # Suspended NULL
# root localhost test Query # NULL show processlist
call bug4902_2()|
Id User Host db Command Time State Info
# event_scheduler localhost NULL Connect # Suspended NULL
# root localhost test Query # NULL show processlist
drop procedure bug4902_2|
drop table if exists t1|

View File

@ -52,22 +52,22 @@ drop table t1;
FLUSH STATUS;
SHOW STATUS LIKE 'max_used_connections';
Variable_name Value
Max_used_connections 2
Max_used_connections 1
SET @save_thread_cache_size=@@thread_cache_size;
SET GLOBAL thread_cache_size=3;
SHOW STATUS LIKE 'max_used_connections';
Variable_name Value
Max_used_connections 4
Max_used_connections 3
FLUSH STATUS;
SHOW STATUS LIKE 'max_used_connections';
Variable_name Value
Max_used_connections 2
SHOW STATUS LIKE 'max_used_connections';
Variable_name Value
Max_used_connections 3
SHOW STATUS LIKE 'max_used_connections';
Variable_name Value
Max_used_connections 4
SHOW STATUS LIKE 'max_used_connections';
Variable_name Value
Max_used_connections 5
SET GLOBAL thread_cache_size=@save_thread_cache_size;
show status like 'com_show_status';
Variable_name Value

View File

@ -18,10 +18,10 @@ CREATE EVENT e_x2 ON SCHEDULE EVERY 1 SECOND DO DROP TABLE x_table;
connection default;
SHOW DATABASES LIKE 'db_x';
SET GLOBAL event_scheduler=1;
--sleep 1.5
--sleep 1.2
SHOW DATABASES LIKE 'db_x';
SHOW TABLES FROM db_x;
SET GLOBAL event_scheduler=2;
SET GLOBAL event_scheduler=off;
connection priv_conn;
DROP EVENT e_x1;
DROP EVENT e_x2;
@ -33,7 +33,7 @@ USE events_test;
#
# END: BUG #17289 Events: missing privilege check for drop database
#
SET GLOBAL event_scheduler=2;
SET GLOBAL event_scheduler=off;
drop event if exists event1;
create event event1 on schedule every 15 minute starts now() ends date_add(now(), interval 5 hour) DO begin end;
alter event event1 rename to event2 enable;
@ -81,23 +81,42 @@ SHOW EVENTS;
DROP EVENT event_starts_test;
#
#
create table test_nested(a int);
create event e_43 on schedule every 1 second do set @a = 5;
set global event_scheduler = 1;
--sleep 2
--error ER_EVENT_RECURSIVITY_FORBIDDEN
alter event e_43 do alter event e_43 do set @a = 4;
--sleep 2
delimiter |;
alter event e_43 do
begin
alter event e_43 on schedule every 5 minute;
insert into test_nested values(1);
end|
delimiter ;|
set global event_scheduler = on;
--sleep 3
select db, name, body, status, interval_field, interval_value from mysql.event;
drop event e_43;
--sleep 1
drop table test_nested;
--echo "Let's check whether we can use non-qualified names"
create table non_qualif(a int);
create event non_qualif_ev on schedule every 10 minute do insert into non_qualif values (800219);
--sleep 1
--sleep 1.1
select * from non_qualif;
drop event non_qualif_ev;
drop table non_qualif;
set global event_scheduler = 2;
--error ER_EVENT_DOES_NOT_EXIST
alter event non_existant rename to non_existant_too;
set global event_scheduler = off;
create event existant on schedule at now() + interval 1 year do select 12;
--error ER_EVENT_ALREADY_EXISTS
alter event non_existant rename to existant;
--error ER_EVENT_SAME_NAME
alter event existant rename to events_test.existant;
drop event existant;
create table t_event3 (a int, b float);
drop event if exists event3;
@ -156,6 +175,10 @@ show create event root22;
--error ER_NOT_SUPPORTED_YET
SHOW EVENTS;
drop event root22;
--error ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG
create event root23 on schedule every -100 year do select 1;
--error ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG
create event root23 on schedule every 222222222222222222222 year do select 1;
drop event root6;
drop event root7;
drop event root8;
@ -201,34 +224,34 @@ SHOW EVENTS;
CREATE TABLE event_like LIKE mysql.event;
INSERT INTO event_like SELECT * FROM mysql.event;
#sleep a bit or we won't catch the change of time
--sleep 1
--sleep 1.1
ALTER TABLE mysql.event MODIFY db char(64) character set cp1251 default '';
--error ER_CANNOT_LOAD_FROM_TABLE
SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
ALTER TABLE mysql.event MODIFY db char(20) character set utf8 collate utf8_bin default '';
#wait a bit or we won't see the difference because of seconds resolution
--sleep 1
--sleep 1.1
SHOW CREATE TABLE mysql.event;
--error ER_CANNOT_LOAD_FROM_TABLE
SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
--sleep 1
--sleep 1.1
ALTER TABLE mysql.event MODIFY db char(64) character set utf8 collate utf8_bin default '';
--sleep 1
--sleep 1.1
--echo "This should work"
--replace_column 8 # 9 #
SHOW EVENTS;
--sleep 1
--sleep 1.1
ALTER TABLE mysql.event MODIFY db char(64) character set cp1251 default '';
--error ER_CANNOT_LOAD_FROM_TABLE
SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
--sleep 1
--sleep 1.1
ALTER TABLE mysql.event MODIFY db varchar(64) character set utf8 collate utf8_bin default '';
--sleep 1
--sleep 1.1
--error ER_CANNOT_LOAD_FROM_TABLE
SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
--sleep 1
--sleep 1.1
ALTER TABLE mysql.event DROP comment, DROP starts;
--sleep 1
--sleep 1.1
--error ER_COL_COUNT_DOESNT_MATCH_CORRUPTED
SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
DROP TABLE mysql.event;
@ -246,9 +269,9 @@ create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5;
select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event;
drop event e_26;
--error ER_WRONG_VALUE
create event e_26 on schedule at NULL disabled do set @a = 5;
create event e_26 on schedule at NULL disable do set @a = 5;
--error ER_WRONG_VALUE
create event e_26 on schedule at 'definitely not a datetime' disabled do set @a = 5;
create event e_26 on schedule at 'definitely not a datetime' disable do set @a = 5;
set names utf8;
create event задачка on schedule every 123 minute starts now() ends now() + interval 1 month do select 1;
@ -256,13 +279,15 @@ drop event задачка;
# event_scheduler is a global var
--error ER_GLOBAL_VARIABLE
set event_scheduler=2;
set event_scheduler=off;
# event_scheduler could be only either 1 or 2
--error ER_WRONG_VALUE_FOR_VAR
set global event_scheduler=3;
--error ER_WRONG_VALUE_FOR_VAR
set global event_scheduler=disabled;
--echo "DISABLE the scheduler. Testing that it does not work when the variable is 0"
set global event_scheduler=2;
set global event_scheduler=off;
select definer, name, db from mysql.event;
select get_lock("test_lock1", 20);
create event закачка on schedule every 10 hour do select get_lock("test_lock1", 20);
@ -280,7 +305,7 @@ select count(*) from mysql.event;
#
#
--echo "ENABLE the scheduler and get a lock"
set global event_scheduler=1;
set global event_scheduler=on;
select get_lock("test_lock2", 20);
--echo "Create an event which tries to acquire a mutex. The event locks on the mutex"
create event закачка on schedule every 10 hour do select get_lock("test_lock2", 20);
@ -306,7 +331,8 @@ create event закачка21 on schedule every 10 hour do select get_lock("test
--sleep 1
--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 command!='Daemon' and (info is null or info not like '%processlist%') order by info;
set global event_scheduler=2;
set global event_scheduler=off;
--sleep 0.8
--echo "Should have only our process now:"
select /*4*/ user, host, db, command, state, info from information_schema.processlist where command!='Daemon' and (info is null or info not like '%processlist%') order by info;
drop event закачка21;
@ -315,7 +341,7 @@ drop event закачка21;
# Bug #16410 Events: CREATE EVENT is legal in a CREATE TRIGGER statement
#
create table t_16 (s1 int);
--error 1422
--error ER_EVENT_RECURSIVITY_FORBIDDEN
create trigger t_16_bi before insert on t_16 for each row create event e_16 on schedule every 1 second do set @a=5;
drop table t_16;
#
@ -372,7 +398,7 @@ drop event e1;
##drop event закачка4;
##select release_lock("test_lock4");
##set global event_scheduler=2;
##set global event_scheduler=off;
##select sleep(2);
##--replace_column 1 # 6 #
##show processlist;

View File

@ -30,19 +30,8 @@ SET NAMES latin1;
# START - BUG#16408: Events: crash for an event in a procedure
#
set @a=3;
--error ER_EVENT_RECURSIVITY_FORBIDDEN
CREATE PROCEDURE p_16 () CREATE EVENT e_16 ON SCHEDULE EVERY @a SECOND DO SET @a=5;
call p_16();
--echo "Here we used to crash!"
--error ER_EVENT_ALREADY_EXISTS
call p_16();
--error ER_EVENT_ALREADY_EXISTS
call p_16();
DROP EVENT e_16;
CALL p_16();
--error ER_EVENT_ALREADY_EXISTS
CALL p_16();
DROP PROCEDURE p_16;
DROP EVENT e_16;
#
# END - BUG#16408: Events: crash for an event in a procedure
#
@ -56,6 +45,19 @@ create event e_55 on schedule at 99990101000000 do drop table t;
create event e_55 on schedule every 10 hour starts 99990101000000 do drop table t;
--error ER_EVENT_ENDS_BEFORE_STARTS
create event e_55 on schedule every 10 minute ends 99990101000000 do drop table t;
--error ER_EVENT_EXEC_TIME_IN_THE_PAST
create event e_55 on schedule at 10000101000000 do drop table t;
--error ER_EVENT_EXEC_TIME_IN_THE_PAST
create event e_55 on schedule at 20000101000000 do drop table t;
--error ER_PARSE_ERROR
create event e_55 on schedule at 20200101000000 starts 10000101000000 do drop table t;
--error ER_PARSE_ERROR
create event e_55 on schedule at 20200101000000 ends 10000101000000 do drop table t;
--error ER_PARSE_ERROR
create event e_55 on schedule at 20200101000000 starts 10000101000000 ends 10000101000000 do drop table t;
--error ER_WRONG_VALUE
create event e_55 on schedule every 10 hour starts 10000101000000 do drop table t;
#
# End - 16396: Events: Distant-future dates become past dates
#
@ -63,11 +65,9 @@ create event e_55 on schedule every 10 minute ends 99990101000000 do drop table
#
# Start - 16407: Events: Changes in sql_mode won't be taken into account
#
set global event_scheduler=2;
--echo "Wait a bit to settle down"
--sleep 1
set global event_scheduler=off;
delete from mysql.event;
set global event_scheduler= 1;
set global event_scheduler= on;
set @old_sql_mode:=@@sql_mode;
set sql_mode=ansi;
select get_lock('test_bug16407', 60);
@ -78,11 +78,13 @@ begin
drop table "hashed_num";
end|
delimiter ;|
--sleep 1
--sleep 0.8
--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 command!='Daemon' and (info is null or info not like '%processlist%') order by info;
select /*1*/ user, host, db, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock('test_bug16407');
set global event_scheduler= 2;
set global event_scheduler= off;
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
--echo "Let's check whether we change the sql_mode on ALTER EVENT"
set sql_mode='traditional';
@ -90,6 +92,10 @@ alter event e_16407 do select 1;
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
drop event e_16407;
set sql_mode="ansi";
select get_lock('ee_16407_2', 60);
set global event_scheduler= 1;
--echo "Another sql_mode test"
set sql_mode="traditional";
create table events_smode_test(ev_name char(10), a date) engine=myisam;
@ -98,6 +104,7 @@ delimiter |;
create event ee_16407_2 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_2*/;
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values('ee_16407_2','1980-19-02');
end|
--error ER_TRUNCATED_WRONG_VALUE
@ -106,6 +113,7 @@ insert into events_smode_test values ('test','1980-19-02')|
create event ee_16407_3 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_3*/;
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values ('ee_16407_3','1980-02-19');
insert into events_test.events_smode_test values ('ee_16407_3','1980-02-29');
end|
@ -114,19 +122,17 @@ set sql_mode=""|
create event ee_16407_4 on schedule every 60 second do
begin
select get_lock('ee_16407_2', 60) /*ee_16407_4*/;
select release_lock('ee_16407_2');
insert into events_test.events_smode_test values ('ee_16407_4','10-11-1956');
end|
delimiter ;|
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
set sql_mode="ansi";
select get_lock('ee_16407_2', 60);
set global event_scheduler= 1;
--sleep 1
select /*2*/ user, host, db, command, state, info from information_schema.processlist where command!='Daemon' and (info is null or info not like '%processlist%') order by info;
select /*2*/ user, host, db, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock('ee_16407_2');
--sleep 2
select /*3*/ user, host, db, command, state, info from information_schema.processlist where command!='Daemon' and (info is null or info not like '%processlist%') order by info;
set global event_scheduler= 2;
--sleep 1.2
select /*3*/ user, host, db, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
set global event_scheduler= off;
select * from events_smode_test order by ev_name, a;
--echo "OK, last check before we drop them"
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
@ -137,6 +143,11 @@ drop event ee_16407_4;
--echo "And now one last test regarding sql_mode and call of SP from an event"
delete from events_smode_test;
set sql_mode='ansi';
select get_lock('ee_16407_5', 60);
set global event_scheduler= on;
set sql_mode='traditional';
delimiter |;
create procedure ee_16407_5_pendant() begin insert into events_test.events_smode_test values('ee_16407_5','2001-02-29'); end|
@ -144,24 +155,23 @@ create procedure ee_16407_6_pendant() begin insert into events_test.events_smode
create event ee_16407_5 on schedule every 60 second do
begin
select get_lock('ee_16407_5', 60) /*ee_16407_5*/;
select release_lock('ee_16407_5');
call events_test.ee_16407_5_pendant();
end|
create event ee_16407_6 on schedule every 60 second do
begin
select get_lock('ee_16407_5', 60) /*ee_16407_6*/;
select release_lock('ee_16407_5');
call events_test.ee_16407_6_pendant();
end|
delimiter ;|
set sql_mode='ansi';
select get_lock('ee_16407_5', 60);
set global event_scheduler= 1;
--sleep 1
--echo "Should have 2 locked processes"
select /*4*/ user, host, db, command, state, info from information_schema.processlist where command!='Daemon' and (info is null or info not like '%processlist%') order by info;
select /*4*/ user, host, db, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock('ee_16407_5');
--sleep 2
--sleep 1.3
--echo "Should have 0 processes locked"
select /*5*/ user, host, db, command, state, info from information_schema.processlist where command!='Daemon' and (info is null or info not like '%processlist%') order by info;
select /*5*/ user, host, db, 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;
--echo "And here we check one more time before we drop the events"
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
@ -169,7 +179,7 @@ drop event ee_16407_5;
drop event ee_16407_6;
drop procedure ee_16407_5_pendant;
drop procedure ee_16407_6_pendant;
set global event_scheduler= 2;
set global event_scheduler= off;
drop table events_smode_test;
set sql_mode=@old_sql_mode;
#
@ -179,7 +189,7 @@ set sql_mode=@old_sql_mode;
#
# START - 18897: Events: unauthorized action possible with alter event rename
#
set global event_scheduler=2;
set global event_scheduler=off;
--disable_warnings
delete from mysql.user where User like 'mysqltest_%';
delete from mysql.db where User like 'mysqltest_%';
@ -209,4 +219,19 @@ drop database mysqltest_db1;
# END - 18897: Events: unauthorized action possible with alter event rename
#
#
# START - BUG#16394: Events: Crash if schedule contains SELECT
#
--error ER_PARSE_ERROR
create event e_53 on schedule at (select s1 from ttx) do drop table t;
--error ER_PARSE_ERROR
create event e_53 on schedule every (select s1 from ttx) second do drop table t;
--error ER_PARSE_ERROR
create event e_53 on schedule every 5 second starts (select s1 from ttx) do drop table t;
--error ER_PARSE_ERROR
create event e_53 on schedule every 5 second ends (select s1 from ttx) do drop table t;
#
# END - BUG#16394: Events: Crash if schedule contains SELECT
#
drop database events_test;

View File

@ -1,8 +1,8 @@
# Can't test with embedded server that doesn't support grants
-- source include/not_embedded.inc
create database if not exists events_test;
use events_test;
CREATE DATABASE IF NOT EXISTS events_test;
USE events_test;
--echo "We use procedure here because its statements won't be logged into the general log"
--echo "If we had used normal select that are logged in different ways depending on whether"
--echo "the test suite is run in normal mode or with --ps-protocol"
@ -13,22 +13,19 @@ BEGIN
END|
delimiter ;|
--echo "Check General Query Log"
SET GLOBAL event_scheduler=2;
create event log_general on schedule every 1 minute do SELect 'alabala', sleep(3) from dual;
--replace_column 1 USER_HOST
CALL select_general_log();
SET GLOBAL event_scheduler=on;
TRUNCATE mysql.general_log;
--echo "1 row, the current statement!"
--replace_column 1 USER_HOST
call select_general_log();
SET GLOBAL event_scheduler=1;
CREATE EVENT log_general ON SCHEDULE EVERY 1 MINUTE DO SELECT 'alabala', SLEEP(1) FROM DUAL;
--echo "Wait the scheduler to start"
--echo "Should see 3 rows - the 'SELect' is in the middle. The other two are selects from general_log"
--sleep 2
--sleep 1.5
--echo "Should see 2 rows - the 'SELECT' is in the middle. The other two are selects from general_log"
--replace_column 1 USER_HOST
call select_general_log();
CALL select_general_log();
DROP PROCEDURE select_general_log;
DROP EVENT log_general;
SET GLOBAL event_scheduler=2;
--sleep 1
SET GLOBAL event_scheduler=off;
--echo "Check slow query log"
--disable_query_log
@ -72,15 +69,16 @@ TRUNCATE mysql.slow_log;
CREATE TABLE slow_event_test (slo_val tinyint, val tinyint);
SET SESSION long_query_time=1;
--echo "This won't go to the slow log"
CREATE EVENT long_event ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(3);
SELECT * FROM slow_event_test;
SET GLOBAL event_scheduler=1;
SET SESSION long_query_time=1;
SET GLOBAL event_scheduler=on;
CREATE EVENT long_event ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(1.5);
--echo "Sleep some more time than the actual event run will take"
--sleep 5
--sleep 2
SHOW VARIABLES LIKE 'event_scheduler';
--echo "Check our table. Should see 1 row"
SELECT * FROM slow_event_test;
--echo "Check slow log. Should not see anything because 3 is under the threshold of 4 for GLOBAL, though over SESSION which is 2"
--echo "Check slow log. Should not see anything because 1.5 is under the threshold of 300 for GLOBAL, though over SESSION which is 2"
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
--echo "This should go to the slow log"
DROP EVENT long_event;
@ -88,7 +86,7 @@ SET SESSION long_query_time=10;
SET GLOBAL long_query_time=1;
CREATE EVENT long_event2 ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(2);
--echo "Sleep some more time than the actual event run will take"
--sleep 3
--sleep 2.5
--echo "Check our table. Should see 2 rows"
SELECT * FROM slow_event_test;
--echo "Check slow log. Should see 1 row because 4 is over the threshold of 3 for GLOBAL, though under SESSION which is 10"
@ -102,4 +100,4 @@ DROP TABLE slow_event_test;
SET GLOBAL long_query_time =@old_global_long_query_time;
SET SESSION long_query_time =@old_session_long_query_time;
drop database events_test;
DROP DATABASE events_test;

View File

@ -0,0 +1,19 @@
# Can't test with embedded server that doesn't support grants
-- source include/not_embedded.inc
--disable_warnings
create database if not exists mysqltest_events_test;
--enable_warnings
use mysqltest_events_test;
set global event_scheduler=off;
create table execution_log(name char(10));
create event abc1 on schedule every 1 second do insert into execution_log value('abc1');
create event abc2 on schedule every 1 second do insert into execution_log value('abc2');
create event abc3 on schedule every 1 second do insert into execution_log value('abc3');
--sleep 1.5
select name from execution_log;
insert into mysql.event values ('db1','bad','select 42','root@localhost',NULL,1000,'MICROSECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment1');
insert into mysql.event values ('db1','bad2','sect','root@localhost',NULL,1000,'SECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment2');
--echo "Now we restart the server"

View File

@ -0,0 +1 @@
--event-scheduler=on

View File

@ -0,0 +1,9 @@
# Can't test with embedded server that doesn't support grants
-- source include/not_embedded.inc
use mysqltest_events_test;
--sleep 1.5
--echo "Should get 0 rows because the queue aborted run
select distinct name from execution_log order by name;
delete from mysql.event where name like 'bad%';
--echo "Now restart the server again"

View File

@ -0,0 +1 @@
--event-scheduler=1

View File

@ -0,0 +1,14 @@
# Can't test with embedded server that doesn't support grants
-- source include/not_embedded.inc
use mysqltest_events_test;
--sleep 2
--echo "Should get 3 rows : abc1, abc2, abc3
select distinct name from execution_log order by name;
drop event abc1;
drop event abc2;
drop event abc3;
drop table execution_log;
drop database mysqltest_events_test;

View File

@ -1,17 +1,39 @@
# Can't test with embedded server that doesn't support grants
-- source include/not_embedded.inc
-- source include/not_valgrind.inc
CREATE DATABASE IF NOT EXISTS events_test;
USE events_test;
SET GLOBAL event_scheduler=OFF;
SHOW VARIABLES LIKE 'event_scheduler';
SET GLOBAL event_scheduler=1;
SHOW VARIABLES LIKE 'event_scheduler';
SET GLOBAL event_scheduler=0;
SHOW VARIABLES LIKE 'event_scheduler';
SET GLOBAL event_scheduler=ON;
SHOW VARIABLES LIKE 'event_scheduler';
--error ER_WRONG_VALUE_FOR_VAR
SET GLOBAL event_scheduler=DISABLED;
SHOW VARIABLES LIKE 'event_scheduler';
--error ER_WRONG_VALUE_FOR_VAR
SET GLOBAL event_scheduler=-1;
SHOW VARIABLES LIKE 'event_scheduler';
--error ER_WRONG_VALUE_FOR_VAR
SET GLOBAL event_scheduler=2;
SHOW VARIABLES LIKE 'event_scheduler';
--error ER_WRONG_VALUE_FOR_VAR
SET GLOBAL event_scheduler=5;
SHOW VARIABLES LIKE 'event_scheduler';
CREATE TABLE table_1(a int);
CREATE TABLE table_2(a int);
CREATE TABLE table_3(a int);
CREATE TABLE table_4(a int);
CREATE TABLE T19170(s1 TIMESTAMP);
SET GLOBAL event_scheduler=1;
SET GLOBAL event_scheduler=ON;
# We need to have 2 to make it safe with valgrind. This is probably because
# of when we calculate the timestamp value
CREATE EVENT E19170 ON SCHEDULE EVERY 2 SECOND DO INSERT INTO T19170 VALUES(CURRENT_TIMESTAMP);
CREATE EVENT two_sec ON SCHEDULE EVERY 2 SECOND DO INSERT INTO table_1 VALUES(1);
CREATE EVENT start_n_end
ON SCHEDULE EVERY 1 SECOND
@ -34,12 +56,10 @@ DROP EVENT start_n_end;
--error ER_EVENT_DOES_NOT_EXIST
DROP EVENT only_one_time;
--echo "Should be preserved"
SELECT EVENT_NAME, STATUS FROM INFORMATION_SCHEMA.EVENTS;
SELECT EVENT_NAME, STATUS FROM INFORMATION_SCHEMA.EVENTS ORDER BY EVENT_NAME;
DROP EVENT two_time;
DROP TABLE table_1;
DROP TABLE table_2;
DROP TABLE table_3;
DROP TABLE table_4;
--echo "Checking for multiple executions in one second, should not happen -> 0 as result"
SELECT COUNT(*) FROM (SELECT s1, COUNT(*) AS cnt FROM T19170 GROUP BY s1) AS tmp WHERE tmp.cnt > 1;
DROP DATABASE events_test;

View File

@ -61,11 +61,11 @@ while ($1)
}
--enable_query_log
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
SET GLOBAL event_scheduler=1;
--sleep 6
SET GLOBAL event_scheduler=on;
--sleep 2.5
DROP DATABASE events_conn1_test2;
SET GLOBAL event_scheduler=2;
SET GLOBAL event_scheduler=off;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
CREATE DATABASE events_conn1_test3;
USE events_conn1_test3;
@ -77,7 +77,7 @@ while ($1)
dec $1;
}
--enable_query_log
SET GLOBAL event_scheduler=1;
SET GLOBAL event_scheduler=on;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test3';
CREATE DATABASE events_conn1_test4;
USE events_conn1_test4;
@ -101,7 +101,7 @@ while ($1)
}
--enable_query_log
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
--sleep 6
--sleep 2.5
connection conn2;
--send
DROP DATABASE events_conn2_db;
@ -112,9 +112,9 @@ connection default;
--send
DROP DATABASE events_conn1_test2;
DROP DATABASE events_conn1_test3;
SET GLOBAL event_scheduler=2;
SET GLOBAL event_scheduler=off;
DROP DATABASE events_conn1_test4;
SET GLOBAL event_scheduler=1;
SET GLOBAL event_scheduler=on;
connection conn2;
reap;
disconnect conn2;

View File

@ -50,7 +50,8 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc
sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc
sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc
time.cc tztime.cc uniques.cc unireg.cc item_xmlfunc.cc
rpl_tblmap.cc sql_binlog.cc event_scheduler.cc event_timed.cc
rpl_tblmap.cc sql_binlog.cc event_scheduler.cc event_data_objects.cc
event_queue.cc event_db_repository.cc
sql_tablespace.cc events.cc ../sql-common/my_user.c
partition_info.cc rpl_injector.cc sql_locale.cc
${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc

View File

@ -64,8 +64,9 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
tztime.h my_decimal.h\
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
parse_file.h sql_view.h sql_trigger.h \
sql_array.h sql_cursor.h events.h events_priv.h \
sql_plugin.h authors.h sql_partition.h event_timed.h \
sql_array.h sql_cursor.h events.h \
event_db_repository.h event_queue.h \
sql_plugin.h authors.h sql_partition.h event_data_objects.h \
partition_info.h partition_element.h event_scheduler.h \
contributors.h
mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
@ -102,7 +103,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
tztime.cc my_time.c my_user.c my_decimal.cc\
sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
sp_cache.cc parse_file.cc sql_trigger.cc \
event_scheduler.cc events.cc event_timed.cc \
event_scheduler.cc event_data_objects.cc \
event_queue.cc event_db_repository.cc events.cc \
sql_plugin.cc sql_binlog.cc \
sql_builtin.cc sql_tablespace.cc partition_info.cc

File diff suppressed because it is too large Load Diff

285
sql/event_data_objects.h Normal file
View File

@ -0,0 +1,285 @@
#ifndef _EVENT_DATA_OBJECTS_H_
#define _EVENT_DATA_OBJECTS_H_
/* Copyright (C) 2004-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define EVEX_GET_FIELD_FAILED -2
#define EVEX_COMPILE_ERROR -3
#define EVEX_GENERAL_ERROR -4
#define EVEX_BAD_PARAMS -5
#define EVEX_MICROSECOND_UNSUP -6
class sp_head;
class Sql_alloc;
class Event_basic
{
protected:
MEM_ROOT mem_root;
public:
LEX_STRING dbname;
LEX_STRING name;
LEX_STRING definer;// combination of user and host
Event_basic();
virtual ~Event_basic();
virtual int
load_from_row(TABLE *table) = 0;
protected:
bool
load_string_fields(Field **fields, ...);
};
class Event_queue_element : public Event_basic
{
protected:
bool status_changed;
bool last_executed_changed;
public:
enum enum_status
{
ENABLED = 1,
DISABLED
};
enum enum_on_completion
{
ON_COMPLETION_DROP = 1,
ON_COMPLETION_PRESERVE
};
enum enum_on_completion on_completion;
enum enum_status status;
TIME last_executed;
TIME execute_at;
TIME starts;
TIME ends;
my_bool starts_null;
my_bool ends_null;
my_bool execute_at_null;
longlong expression;
interval_type interval;
bool dropped;
uint execution_count;
Event_queue_element();
virtual ~Event_queue_element();
virtual int
load_from_row(TABLE *table);
bool
compute_next_execution_time();
int
drop(THD *thd);
void
mark_last_executed(THD *thd);
bool
update_timing_fields(THD *thd);
static void *operator new(size_t size)
{
void *p;
DBUG_ENTER("Event_queue_element::new(size)");
p= my_malloc(size, MYF(0));
DBUG_PRINT("info", ("alloc_ptr=0x%lx", p));
DBUG_RETURN(p);
}
static void operator delete(void *ptr, size_t size)
{
DBUG_ENTER("Event_queue_element::delete(ptr,size)");
DBUG_PRINT("enter", ("free_ptr=0x%lx", ptr));
TRASH(ptr, size);
my_free((gptr) ptr, MYF(0));
DBUG_VOID_RETURN;
}
};
class Event_timed : public Event_queue_element
{
Event_timed(const Event_timed &); /* Prevent use of these */
void operator=(Event_timed &);
public:
LEX_STRING body;
LEX_STRING definer_user;
LEX_STRING definer_host;
LEX_STRING comment;
ulonglong created;
ulonglong modified;
ulong sql_mode;
Event_timed();
virtual ~Event_timed();
void
init();
virtual int
load_from_row(TABLE *table);
int
get_create_event(THD *thd, String *buf);
};
class Event_job_data : public Event_basic
{
public:
THD *thd;
sp_head *sphead;
LEX_STRING body;
LEX_STRING definer_user;
LEX_STRING definer_host;
ulong sql_mode;
uint execution_count;
Event_job_data();
virtual ~Event_job_data();
virtual int
load_from_row(TABLE *table);
int
execute(THD *thd);
int
compile(THD *thd, MEM_ROOT *mem_root);
private:
int
get_fake_create_event(THD *thd, String *buf);
Event_job_data(const Event_job_data &); /* Prevent use of these */
void operator=(Event_job_data &);
};
class Event_parse_data : public Sql_alloc
{
public:
enum enum_status
{
ENABLED = 1,
DISABLED
};
enum enum_on_completion
{
ON_COMPLETION_DROP = 1,
ON_COMPLETION_PRESERVE
};
enum enum_on_completion on_completion;
enum enum_status status;
const uchar *body_begin;
LEX_STRING dbname;
LEX_STRING name;
LEX_STRING definer;// combination of user and host
LEX_STRING body;
LEX_STRING comment;
Item* item_starts;
Item* item_ends;
Item* item_execute_at;
TIME starts;
TIME ends;
TIME execute_at;
my_bool starts_null;
my_bool ends_null;
my_bool execute_at_null;
sp_name *identifier;
Item* item_expression;
longlong expression;
interval_type interval;
static Event_parse_data *
new_instance(THD *thd);
bool
check_parse_data(THD *thd);
void
init_body(THD *thd);
private:
void
init_definer(THD *thd);
void
init_name(THD *thd, sp_name *spn);
int
init_execute_at(THD *thd);
int
init_interval(THD *thd);
int
init_starts(THD *thd);
int
init_ends(THD *thd);
Event_parse_data();
~Event_parse_data();
void
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 &);
};
/* Compares only the schema part of the identifier */
bool
event_basic_db_equal(LEX_STRING db, Event_basic *et);
/* Compares the whole identifier*/
bool
event_basic_identifier_equal(LEX_STRING db, LEX_STRING name, Event_basic *b);
#endif /* _EVENT_DATA_OBJECTS_H_ */

979
sql/event_db_repository.cc Normal file
View File

@ -0,0 +1,979 @@
/* Copyright (C) 2004-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysql_priv.h"
#include "event_db_repository.h"
#include "event_data_objects.h"
#include "events.h"
#include "sql_show.h"
#include "sp.h"
#include "sp_head.h"
static
time_t mysql_event_last_create_time= 0L;
static
const TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] =
{
{
{ C_STRING_WITH_LEN("db") },
{ C_STRING_WITH_LEN("char(64)") },
{ C_STRING_WITH_LEN("utf8") }
},
{
{ C_STRING_WITH_LEN("name") },
{ C_STRING_WITH_LEN("char(64)") },
{ C_STRING_WITH_LEN("utf8") }
},
{
{ C_STRING_WITH_LEN("body") },
{ C_STRING_WITH_LEN("longblob") },
{NULL, 0}
},
{
{ C_STRING_WITH_LEN("definer") },
{ C_STRING_WITH_LEN("char(77)") },
{ C_STRING_WITH_LEN("utf8") }
},
{
{ C_STRING_WITH_LEN("execute_at") },
{ C_STRING_WITH_LEN("datetime") },
{NULL, 0}
},
{
{ C_STRING_WITH_LEN("interval_value") },
{ C_STRING_WITH_LEN("int(11)") },
{NULL, 0}
},
{
{ C_STRING_WITH_LEN("interval_field") },
{ C_STRING_WITH_LEN("enum('YEAR','QUARTER','MONTH','DAY',"
"'HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR',"
"'DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND',"
"'DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND',"
"'SECOND_MICROSECOND')") },
{NULL, 0}
},
{
{ C_STRING_WITH_LEN("created") },
{ C_STRING_WITH_LEN("timestamp") },
{NULL, 0}
},
{
{ C_STRING_WITH_LEN("modified") },
{ C_STRING_WITH_LEN("timestamp") },
{NULL, 0}
},
{
{ C_STRING_WITH_LEN("last_executed") },
{ C_STRING_WITH_LEN("datetime") },
{NULL, 0}
},
{
{ C_STRING_WITH_LEN("starts") },
{ C_STRING_WITH_LEN("datetime") },
{NULL, 0}
},
{
{ C_STRING_WITH_LEN("ends") },
{ C_STRING_WITH_LEN("datetime") },
{NULL, 0}
},
{
{ C_STRING_WITH_LEN("status") },
{ C_STRING_WITH_LEN("enum('ENABLED','DISABLED')") },
{NULL, 0}
},
{
{ C_STRING_WITH_LEN("on_completion") },
{ C_STRING_WITH_LEN("enum('DROP','PRESERVE')") },
{NULL, 0}
},
{
{ C_STRING_WITH_LEN("sql_mode") },
{ C_STRING_WITH_LEN("set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES',"
"'IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION',"
"'NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB',"
"'NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40',"
"'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES',"
"'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES',"
"'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER',"
"'HIGH_NOT_PRECEDENCE')") },
{NULL, 0}
},
{
{ C_STRING_WITH_LEN("comment") },
{ C_STRING_WITH_LEN("char(64)") },
{ C_STRING_WITH_LEN("utf8") }
}
};
/*
Puts some data common to CREATE and ALTER EVENT into a row.
SYNOPSIS
mysql_event_fill_row()
thd THD
table The row to fill out
et Event's data
is_update CREATE EVENT or ALTER EVENT
RETURN VALUE
0 OK
EVEX_GENERAL_ERROR Bad data
EVEX_GET_FIELD_FAILED Field count does not match. table corrupted?
DESCRIPTION
Used both when an event is created and when it is altered.
*/
static int
mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et,
my_bool is_update)
{
CHARSET_INFO *scs= system_charset_info;
enum enum_events_table_field f_num;
Field **fields= table->field;
DBUG_ENTER("mysql_event_fill_row");
DBUG_PRINT("info", ("dbname=[%s]", et->dbname.str));
DBUG_PRINT("info", ("name =[%s]", et->name.str));
DBUG_PRINT("info", ("body =[%s]", et->body.str));
if (fields[f_num= ET_FIELD_DEFINER]->
store(et->definer.str, et->definer.length, scs))
goto err_truncate;
if (fields[f_num= ET_FIELD_DB]->store(et->dbname.str, et->dbname.length, scs))
goto err_truncate;
if (fields[f_num= ET_FIELD_NAME]->store(et->name.str, et->name.length, scs))
goto err_truncate;
/* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()*/
fields[ET_FIELD_ON_COMPLETION]->store((longlong)et->on_completion, 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
always during CREATE EVENT.
*/
if (et->body.str)
{
fields[ET_FIELD_SQL_MODE]->store((longlong)thd->variables.sql_mode, TRUE);
if (fields[f_num= ET_FIELD_BODY]->store(et->body.str, et->body.length, scs))
goto err_truncate;
}
if (et->expression)
{
fields[ET_FIELD_INTERVAL_EXPR]->set_notnull();
fields[ET_FIELD_INTERVAL_EXPR]->store((longlong)et->expression, TRUE);
fields[ET_FIELD_TRANSIENT_INTERVAL]->set_notnull();
/*
In the enum (C) intervals start from 0 but in mysql enum valid values
start from 1. Thus +1 offset is needed!
*/
fields[ET_FIELD_TRANSIENT_INTERVAL]->store((longlong)et->interval+1, TRUE);
fields[ET_FIELD_EXECUTE_AT]->set_null();
if (!et->starts_null)
{
fields[ET_FIELD_STARTS]->set_notnull();
fields[ET_FIELD_STARTS]->store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
}
if (!et->ends_null)
{
fields[ET_FIELD_ENDS]->set_notnull();
fields[ET_FIELD_ENDS]->store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
}
}
else if (et->execute_at.year)
{
fields[ET_FIELD_INTERVAL_EXPR]->set_null();
fields[ET_FIELD_TRANSIENT_INTERVAL]->set_null();
fields[ET_FIELD_STARTS]->set_null();
fields[ET_FIELD_ENDS]->set_null();
fields[ET_FIELD_EXECUTE_AT]->set_notnull();
fields[ET_FIELD_EXECUTE_AT]->
store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME);
}
else
{
DBUG_ASSERT(is_update);
/*
it is normal to be here when the action is update
this is an error if the action is create. something is borked
*/
}
((Field_timestamp *)fields[ET_FIELD_MODIFIED])->set_time();
if (et->comment.str)
{
if (fields[f_num= ET_FIELD_COMMENT]->
store(et->comment.str, et->comment.length, scs))
goto err_truncate;
}
DBUG_RETURN(0);
err_truncate:
my_error(ER_EVENT_DATA_TOO_LONG, MYF(0), fields[f_num]->field_name);
DBUG_RETURN(EVEX_GENERAL_ERROR);
}
/*
Performs an index scan of event_table (mysql.event) and fills schema_table.
SYNOPSIS
Event_db_repository::index_read_for_db_for_i_s()
thd Thread
schema_table The I_S.EVENTS table
event_table The event table to use for loading (mysql.event)
db For which schema to do an index scan.
RETURN VALUE
0 OK
1 Error
*/
bool
Event_db_repository::index_read_for_db_for_i_s(THD *thd, TABLE *schema_table,
TABLE *event_table,
const char *db)
{
int ret=0;
CHARSET_INFO *scs= system_charset_info;
KEY *key_info;
uint key_len;
byte *key_buf= NULL;
LINT_INIT(key_buf);
DBUG_ENTER("Event_db_repository::index_read_for_db_for_i_s");
DBUG_PRINT("info", ("Using prefix scanning on PK"));
event_table->file->ha_index_init(0, 1);
event_table->field[ET_FIELD_DB]->store(db, strlen(db), scs);
key_info= event_table->key_info;
key_len= key_info->key_part[0].store_length;
if (!(key_buf= (byte *)alloc_root(thd->mem_root, key_len)))
{
ret= 1;
/* Don't send error, it would be done by sql_alloc_error_handler() */
}
else
{
key_copy(key_buf, event_table->record[0], key_info, key_len);
if (!(ret= event_table->file->index_read(event_table->record[0], key_buf,
key_len, HA_READ_PREFIX)))
{
DBUG_PRINT("info",("Found rows. Let's retrieve them. ret=%d", ret));
do
{
ret= copy_event_to_schema_table(thd, schema_table, event_table);
if (ret == 0)
ret= event_table->file->index_next_same(event_table->record[0],
key_buf, key_len);
} while (ret == 0);
}
DBUG_PRINT("info", ("Scan finished. ret=%d", ret));
}
event_table->file->ha_index_end();
/* ret is guaranteed to be != 0 */
if (ret == HA_ERR_END_OF_FILE || ret == HA_ERR_KEY_NOT_FOUND)
DBUG_RETURN(FALSE);
DBUG_RETURN(TRUE);
}
/*
Performs a table scan of event_table (mysql.event) and fills schema_table.
SYNOPSIS
Events_db_repository::table_scan_all_for_i_s()
thd Thread
schema_table The I_S.EVENTS in memory table
event_table The event table to use for loading.
RETURN VALUE
FALSE OK
TRUE Error
*/
bool
Event_db_repository::table_scan_all_for_i_s(THD *thd, TABLE *schema_table,
TABLE *event_table)
{
int ret;
READ_RECORD read_record_info;
DBUG_ENTER("Event_db_repository::table_scan_all_for_i_s");
init_read_record(&read_record_info, thd, event_table, NULL, 1, 0);
/*
rr_sequential, in read_record(), returns 137==HA_ERR_END_OF_FILE,
but rr_handle_error returns -1 for that reason. Thus, read_record()
returns -1 eventually.
*/
do
{
ret= read_record_info.read_record(&read_record_info);
if (ret == 0)
ret= copy_event_to_schema_table(thd, schema_table, event_table);
} while (ret == 0);
DBUG_PRINT("info", ("Scan finished. ret=%d", ret));
end_read_record(&read_record_info);
/* ret is guaranteed to be != 0 */
DBUG_RETURN(ret == -1? FALSE:TRUE);
}
/*
Fills I_S.EVENTS with data loaded from mysql.event. Also used by
SHOW EVENTS
SYNOPSIS
Event_db_repository::fill_schema_events()
thd Thread
tables The schema table
db If not NULL then get events only from this schema
RETURN VALUE
FALSE OK
TRUE Error
*/
int
Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *tables,
const char *db)
{
TABLE *schema_table= tables->table;
TABLE *event_table= NULL;
Open_tables_state backup;
int ret= 0;
DBUG_ENTER("Event_db_repository::fill_schema_events");
DBUG_PRINT("info",("db=%s", db? db:"(null)"));
thd->reset_n_backup_open_tables_state(&backup);
if (open_event_table(thd, TL_READ, &event_table))
{
sql_print_error("Table mysql.event is damaged.");
thd->restore_backup_open_tables_state(&backup);
DBUG_RETURN(1);
}
/*
1. SELECT I_S => use table scan. I_S.EVENTS does not guarantee order
thus we won't order it. OTOH, SHOW EVENTS will be
ordered.
2. SHOW EVENTS => PRIMARY KEY with prefix scanning on (db)
Reasoning: Events are per schema, therefore a scan over an index
will save use from doing a table scan and comparing
every single row's `db` with the schema which we show.
*/
if (db)
ret= index_read_for_db_for_i_s(thd, schema_table, event_table, db);
else
ret= table_scan_all_for_i_s(thd, schema_table, event_table);
close_thread_tables(thd);
thd->restore_backup_open_tables_state(&backup);
DBUG_PRINT("info", ("Return code=%d", ret));
DBUG_RETURN(ret);
}
/*
Open mysql.event table for read
SYNOPSIS
Events::open_event_table()
thd [in] Thread context
lock_type [in] How to lock the table
table [out] We will store the open table here
RETURN VALUE
1 Cannot lock table
2 The table is corrupted - different number of fields
0 OK
*/
int
Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type,
TABLE **table)
{
TABLE_LIST tables;
DBUG_ENTER("Event_db_repository::open_event_table");
bzero((char*) &tables, sizeof(tables));
tables.db= (char*) "mysql";
tables.table_name= tables.alias= (char*) "event";
tables.lock_type= lock_type;
if (simple_open_n_lock_tables(thd, &tables))
DBUG_RETURN(1);
if (table_check_intact(tables.table, ET_FIELD_COUNT,
event_table_fields,
&mysql_event_last_create_time,
ER_CANNOT_LOAD_FROM_TABLE))
{
close_thread_tables(thd);
DBUG_RETURN(2);
}
*table= tables.table;
tables.table->use_all_columns();
DBUG_RETURN(0);
}
/*
Checks parameters which we got from the parsing phase.
SYNOPSIS
check_parse_params()
thd Thread context
parse_data Event's data
RETURN VALUE
FALSE OK
TRUE Error (reported)
*/
static int
check_parse_params(THD *thd, Event_parse_data *parse_data)
{
DBUG_ENTER("check_parse_params");
if (parse_data->check_parse_data(thd))
DBUG_RETURN(EVEX_BAD_PARAMS);
if (!parse_data->dbname.str ||
(thd->lex->sql_command == SQLCOM_ALTER_EVENT && thd->lex->spname &&
!thd->lex->spname->m_db.str))
{
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
DBUG_RETURN(EVEX_BAD_PARAMS);
}
if (check_access(thd, EVENT_ACL, parse_data->dbname.str, 0, 0, 0,
is_schema_db(parse_data->dbname.str)) ||
(thd->lex->sql_command == SQLCOM_ALTER_EVENT && thd->lex->spname &&
(check_access(thd, EVENT_ACL, thd->lex->spname->m_db.str, 0, 0, 0,
is_schema_db(thd->lex->spname->m_db.str)))))
DBUG_RETURN(EVEX_BAD_PARAMS);
DBUG_RETURN(0);
}
/*
Creates an event in mysql.event
SYNOPSIS
Event_db_repository::create_event()
thd [in] THD
parse_data [in] Object containing info about the event
create_if_not [in] Whether to generate anwarning in case event exists
RETURN VALUE
0 OK
EVEX_GENERAL_ERROR Failure
DESCRIPTION
Creates an event. Relies on mysql_event_fill_row which is shared with
::update_event. The name of the event is inside "et".
*/
bool
Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
my_bool create_if_not)
{
int ret= 0;
CHARSET_INFO *scs= system_charset_info;
TABLE *table= NULL;
char old_db_buf[NAME_LEN+1];
LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) };
bool dbchanged= FALSE;
DBUG_ENTER("Event_db_repository::create_event");
if (check_parse_params(thd, parse_data))
goto err;
DBUG_PRINT("info", ("open mysql.event for update"));
if (open_event_table(thd, TL_WRITE, &table))
{
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
goto err;
}
DBUG_PRINT("info", ("name: %.*s", parse_data->name.length,
parse_data->name.str));
DBUG_PRINT("info", ("check existance of an event with the same name"));
if (!find_named_event(thd, parse_data->dbname, parse_data->name, table))
{
if (create_if_not)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_EVENT_ALREADY_EXISTS, ER(ER_EVENT_ALREADY_EXISTS),
parse_data->name.str);
goto ok;
}
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), parse_data->name.str);
goto err;
}
DBUG_PRINT("info", ("non-existant, go forward"));
if ((ret= sp_use_new_db(thd, parse_data->dbname, &old_db, 0, &dbchanged)))
{
my_error(ER_BAD_DB_ERROR, MYF(0));
goto err;
}
restore_record(table, s->default_values); // Get default values for fields
if (system_charset_info->cset->
numchars(system_charset_info, parse_data->dbname.str,
parse_data->dbname.str + parse_data->dbname.length) >
table->field[ET_FIELD_DB]->char_length())
{
my_error(ER_TOO_LONG_IDENT, MYF(0), parse_data->dbname.str);
goto err;
}
if (system_charset_info->cset->
numchars(system_charset_info, parse_data->name.str,
parse_data->name.str + parse_data->name.length) >
table->field[ET_FIELD_NAME]->char_length())
{
my_error(ER_TOO_LONG_IDENT, MYF(0), parse_data->name.str);
goto err;
}
if (parse_data->body.length > table->field[ET_FIELD_BODY]->field_length)
{
my_error(ER_TOO_LONG_BODY, MYF(0), parse_data->name.str);
goto err;
}
if (!(parse_data->expression) && !(parse_data->execute_at.year))
{
DBUG_PRINT("error", ("neither expression nor execute_at are set!"));
my_error(ER_EVENT_NEITHER_M_EXPR_NOR_M_AT, MYF(0));
goto err;
}
((Field_timestamp *)table->field[ET_FIELD_CREATED])->set_time();
/*
mysql_event_fill_row() calls my_error() in case of error so no need to
handle it here
*/
if ((ret= mysql_event_fill_row(thd, table, parse_data, FALSE)))
goto err;
/* Close active transaction only if We are going to modify disk */
if (end_active_trans(thd))
goto err;
if (table->file->ha_write_row(table->record[0]))
{
my_error(ER_EVENT_STORE_FAILED, MYF(0), parse_data->name.str, ret);
goto err;
}
ok:
if (dbchanged)
(void) mysql_change_db(thd, old_db.str, 1);
/*
This statement may cause a spooky valgrind warning at startup
inside init_key_cache on my system (ahristov, 2006/08/10)
*/
close_thread_tables(thd);
DBUG_RETURN(FALSE);
err:
if (dbchanged)
(void) mysql_change_db(thd, old_db.str, 1);
if (table)
close_thread_tables(thd);
DBUG_RETURN(TRUE);
}
/*
Used to execute ALTER EVENT. Pendant to Events::update_event().
SYNOPSIS
Event_db_repository::update_event()
thd THD
sp_name the name of the event to alter
et event's data
RETURN VALUE
FALSE OK
TRUE Error (reported)
NOTES
sp_name is passed since this is the name of the event to
alter in case of RENAME TO.
*/
bool
Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
LEX_STRING *new_dbname, LEX_STRING *new_name)
{
CHARSET_INFO *scs= system_charset_info;
TABLE *table= NULL;
DBUG_ENTER("Event_db_repository::update_event");
if (open_event_table(thd, TL_WRITE, &table))
{
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
goto err;
}
if (check_parse_params(thd, parse_data))
goto err;
DBUG_PRINT("info", ("dbname: %s", parse_data->dbname.str));
DBUG_PRINT("info", ("name: %s", parse_data->name.str));
DBUG_PRINT("info", ("user: %s", parse_data->definer.str));
if (new_dbname)
DBUG_PRINT("info", ("rename to: %s@%s", new_dbname->str, new_name->str));
/* first look whether we overwrite */
if (new_name)
{
if (!sortcmp_lex_string(parse_data->name, *new_name, scs) &&
!sortcmp_lex_string(parse_data->dbname, *new_dbname, scs))
{
my_error(ER_EVENT_SAME_NAME, MYF(0), parse_data->name.str);
goto err;
}
if (!find_named_event(thd, *new_dbname, *new_name, table))
{
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->str);
goto err;
}
}
/*
...and then if there is such an event. Don't exchange the blocks
because you will get error 120 from table handler because new_name will
overwrite the key and SE will tell us that it cannot find the already found
row (copied into record[1] later
*/
if (find_named_event(thd, parse_data->dbname, parse_data->name, table))
{
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), parse_data->name.str);
goto err;
}
store_record(table,record[1]);
/* Don't update create on row update. */
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
/*
mysql_event_fill_row() calls my_error() in case of error so no need to
handle it here
*/
if (mysql_event_fill_row(thd, table, parse_data, TRUE))
goto err;
if (new_dbname)
{
table->field[ET_FIELD_DB]->store(new_dbname->str, new_dbname->length, scs);
table->field[ET_FIELD_NAME]->store(new_name->str, new_name->length, scs);
}
/* Close active transaction only if We are going to modify disk */
if (end_active_trans(thd))
goto err;
int res;
if ((res= table->file->ha_update_row(table->record[1], table->record[0])))
{
my_error(ER_EVENT_STORE_FAILED, MYF(0), parse_data->name.str, res);
goto err;
}
/* close mysql.event or we crash later when loading the event from disk */
close_thread_tables(thd);
DBUG_RETURN(FALSE);
err:
if (table)
close_thread_tables(thd);
DBUG_RETURN(TRUE);
}
/*
Drops an event
SYNOPSIS
Event_db_repository::drop_event()
thd [in] THD
db [in] Database name
name [in] Event's name
drop_if_exists [in] If set and the event not existing => warning
onto the stack
RETURN VALUE
FALSE OK
TRUE Error (reported)
*/
bool
Event_db_repository::drop_event(THD *thd, LEX_STRING db, LEX_STRING name,
bool drop_if_exists)
{
TABLE *table= NULL;
Open_tables_state backup;
int ret;
DBUG_ENTER("Event_db_repository::drop_event");
DBUG_PRINT("enter", ("%s@%s", db.str, name.str));
thd->reset_n_backup_open_tables_state(&backup);
if ((ret= open_event_table(thd, TL_WRITE, &table)))
{
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
goto done;
}
if (!(ret= find_named_event(thd, db, name, table)))
{
/* Close active transaction only if we are actually going to modify disk */
if (!(ret= end_active_trans(thd)) &&
(ret= table->file->ha_delete_row(table->record[0])))
my_error(ER_EVENT_CANNOT_DELETE, MYF(0));
}
else
{
if (drop_if_exists)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
"Event", name.str);
ret= 0;
} else
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
}
done:
if (table)
close_thread_tables(thd);
thd->restore_backup_open_tables_state(&backup);
DBUG_RETURN(ret);
}
/*
Positions the internal pointer of `table` to the place where (db, name)
is stored.
SYNOPSIS
Event_db_repository::find_named_event()
thd Thread
db Schema
name Event name
table Opened mysql.event
RETURN VALUE
FALSE OK
TRUE No such event
*/
bool
Event_db_repository::find_named_event(THD *thd, LEX_STRING db, LEX_STRING name,
TABLE *table)
{
byte key[MAX_KEY_LENGTH];
DBUG_ENTER("Event_db_repository::find_named_event");
DBUG_PRINT("enter", ("name: %.*s", name.length, name.str));
/*
Create key to find row. We have to use field->store() to be able to
handle VARCHAR and CHAR fields.
Assumption here is that the two first fields in the table are
'db' and 'name' and the first key is the primary key over the
same fields.
*/
if (db.length > table->field[ET_FIELD_DB]->field_length ||
name.length > table->field[ET_FIELD_NAME]->field_length)
DBUG_RETURN(TRUE);
table->field[ET_FIELD_DB]->store(db.str, db.length, &my_charset_bin);
table->field[ET_FIELD_NAME]->store(name.str, name.length, &my_charset_bin);
key_copy(key, table->record[0], table->key_info, table->key_info->key_length);
if (table->file->index_read_idx(table->record[0], 0, key,
table->key_info->key_length,
HA_READ_KEY_EXACT))
{
DBUG_PRINT("info", ("Row not found"));
DBUG_RETURN(TRUE);
}
DBUG_PRINT("info", ("Row found!"));
DBUG_RETURN(FALSE);
}
/*
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
*/
void
Event_db_repository::drop_schema_events(THD *thd, LEX_STRING schema)
{
DBUG_ENTER("Event_db_repository::drop_schema_events");
drop_events_by_field(thd, ET_FIELD_DB, schema);
DBUG_VOID_RETURN;
}
/*
Drops all events by field which has specific value of the field
SYNOPSIS
Event_db_repository::drop_events_by_field()
thd Thread
table mysql.event TABLE
field Which field of the row to use for matching
field_value The value that should match
*/
void
Event_db_repository::drop_events_by_field(THD *thd,
enum enum_events_table_field field,
LEX_STRING field_value)
{
int ret= 0;
TABLE *table= NULL;
READ_RECORD read_record_info;
DBUG_ENTER("Event_db_repository::drop_events_by_field");
DBUG_PRINT("enter", ("field=%d field_value=%s", field, field_value.str));
if (open_event_table(thd, TL_WRITE, &table))
{
/*
Currently being used only for DROP DATABASE - In this case we don't need
error message since the OK packet has been sent. But for DROP USER we
could need it.
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
*/
DBUG_VOID_RETURN;
}
/* only enabled events are in memory, so we go now and delete the rest */
init_read_record(&read_record_info, thd, table, NULL, 1, 0);
while (!ret && !(read_record_info.read_record(&read_record_info)) )
{
char *et_field= get_field(thd->mem_root, table->field[field]);
LEX_STRING et_field_lex= { et_field, strlen(et_field) };
DBUG_PRINT("info", ("Current event %s name=%s", et_field,
get_field(thd->mem_root, table->field[ET_FIELD_NAME])));
if (!sortcmp_lex_string(et_field_lex, field_value, system_charset_info))
{
DBUG_PRINT("info", ("Dropping"));
ret= table->file->ha_delete_row(table->record[0]);
}
}
end_read_record(&read_record_info);
close_thread_tables(thd);
DBUG_VOID_RETURN;
}
/*
Looks for a named event in mysql.event and then loads it from
the table, compiles and inserts it into the cache.
SYNOPSIS
Event_db_repository::load_named_event()
thd [in] Thread context
dbname [in] Event's db name
name [in] Event's name
etn [out] The loaded event
RETURN VALUE
FALSE OK
TRUE Error (reported)
*/
bool
Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname,
LEX_STRING name, Event_basic *etn)
{
TABLE *table= NULL;
int ret= 0;
Open_tables_state backup;
DBUG_ENTER("Event_db_repository::load_named_event");
DBUG_PRINT("enter",("thd=0x%lx name:%*s",thd, name.length, name.str));
thd->reset_n_backup_open_tables_state(&backup);
if ((ret= open_event_table(thd, TL_READ, &table)))
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
else if ((ret= find_named_event(thd, dbname, name, table)))
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
else if ((ret= etn->load_from_row(table)))
my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
if (table)
close_thread_tables(thd);
thd->restore_backup_open_tables_state(&backup);
/* In this case no memory was allocated so we don't need to clean */
DBUG_RETURN(ret);
}

102
sql/event_db_repository.h Normal file
View File

@ -0,0 +1,102 @@
#ifndef _EVENT_DB_REPOSITORY_H_
#define _EVENT_DB_REPOSITORY_H_
/* Copyright (C) 2004-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define EVEX_OPEN_TABLE_FAILED -1
enum enum_events_table_field
{
ET_FIELD_DB = 0,
ET_FIELD_NAME,
ET_FIELD_BODY,
ET_FIELD_DEFINER,
ET_FIELD_EXECUTE_AT,
ET_FIELD_INTERVAL_EXPR,
ET_FIELD_TRANSIENT_INTERVAL,
ET_FIELD_CREATED,
ET_FIELD_MODIFIED,
ET_FIELD_LAST_EXECUTED,
ET_FIELD_STARTS,
ET_FIELD_ENDS,
ET_FIELD_STATUS,
ET_FIELD_ON_COMPLETION,
ET_FIELD_SQL_MODE,
ET_FIELD_COMMENT,
ET_FIELD_COUNT /* a cool trick to count the number of fields :) */
};
int
events_table_index_read_for_db(THD *thd, TABLE *schema_table,
TABLE *event_table);
int
events_table_scan_all(THD *thd, TABLE *schema_table, TABLE *event_table);
class Event_basic;
class Event_parse_data;
class Event_db_repository
{
public:
Event_db_repository(){}
bool
create_event(THD *thd, Event_parse_data *parse_data, my_bool create_if_not);
bool
update_event(THD *thd, Event_parse_data *parse_data, LEX_STRING *new_dbname,
LEX_STRING *new_name);
bool
drop_event(THD *thd, LEX_STRING db, LEX_STRING name, bool drop_if_exists);
void
drop_schema_events(THD *thd, LEX_STRING schema);
bool
find_named_event(THD *thd, LEX_STRING db, LEX_STRING name, TABLE *table);
bool
load_named_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_basic *et);
int
open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
int
fill_schema_events(THD *thd, TABLE_LIST *tables, const char *db);
private:
void
drop_events_by_field(THD *thd, enum enum_events_table_field field,
LEX_STRING field_value);
bool
index_read_for_db_for_i_s(THD *thd, TABLE *schema_table, TABLE *event_table,
const char *db);
bool
table_scan_all_for_i_s(THD *thd, TABLE *schema_table, TABLE *event_table);
static bool
check_system_tables(THD *thd);
/* Prevent use of these */
Event_db_repository(const Event_db_repository &);
void operator=(Event_db_repository &);
};
#endif /* _EVENT_DB_REPOSITORY_H_ */

1019
sql/event_queue.cc Normal file

File diff suppressed because it is too large Load Diff

120
sql/event_queue.h Normal file
View File

@ -0,0 +1,120 @@
#ifndef _EVENT_QUEUE_H_
#define _EVENT_QUEUE_H_
/* Copyright (C) 2004-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
class Event_basic;
class Event_db_repository;
class Event_job_data;
class Event_queue_element;
class THD;
class Event_scheduler;
class Event_queue
{
public:
Event_queue();
void
init_mutexes();
void
deinit_mutexes();
bool
init_queue(THD *thd, Event_db_repository *db_repo);
void
deinit_queue();
/* Methods for queue management follow */
int
create_event(THD *thd, LEX_STRING dbname, LEX_STRING name);
int
update_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
LEX_STRING *new_schema, LEX_STRING *new_name);
void
drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name);
void
drop_schema_events(THD *thd, LEX_STRING schema);
void
recalculate_activation_times(THD *thd);
bool
get_top_for_execution_if_time(THD *thd, Event_job_data **job_data);
bool
dump_internal_status(THD *thd);
int
load_events_from_db(THD *thd);
protected:
void
find_n_remove_event(LEX_STRING db, LEX_STRING name);
void
drop_matching_events(THD *thd, LEX_STRING pattern,
bool (*)(LEX_STRING, Event_basic *));
void
empty_queue();
void
dbug_dump_queue(time_t now);
/* LOCK_event_queue is the mutex which protects the access to the queue. */
pthread_mutex_t LOCK_event_queue;
pthread_cond_t COND_queue_state;
Event_db_repository *db_repository;
Event_scheduler *scheduler;
/* The sorted queue with the Event_job_data objects */
QUEUE queue;
TIME next_activation_at;
uint mutex_last_locked_at_line;
uint mutex_last_unlocked_at_line;
uint mutex_last_attempted_lock_at_line;
const char* mutex_last_locked_in_func;
const char* mutex_last_unlocked_in_func;
const char* mutex_last_attempted_lock_in_func;
bool mutex_queue_data_locked;
bool mutex_queue_data_attempting_lock;
bool waiting_on_cond;
/* helper functions for working with mutexes & conditionals */
void
lock_data(const char *func, uint line);
void
unlock_data(const char *func, uint line);
void
cond_wait(THD *thd, struct timespec *abstime, const char* msg,
const char *func, uint line);
};
#endif /* _EVENT_QUEUE_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -16,225 +16,66 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
class Event_timed;
class THD;
typedef bool * (*event_timed_identifier_comparator)(Event_timed*, Event_timed*);
int
events_init();
class Event_queue;
class Event_job_data;
void
events_shutdown();
pre_init_event_thread(THD* thd);
bool
post_init_event_thread(THD* thd);
void
deinit_event_thread(THD *thd);
class Event_scheduler
{
public:
/* Return codes */
enum enum_error_code
{
OP_OK= 0,
OP_NOT_RUNNING,
OP_CANT_KILL,
OP_CANT_INIT,
OP_DISABLED_EVENT,
OP_LOAD_ERROR,
OP_ALREADY_EXISTS
};
enum enum_state
{
UNINITIALIZED= 0,
INITIALIZED,
COMMENCING,
CANTSTART,
RUNNING,
SUSPENDED,
IN_SHUTDOWN
};
enum enum_suspend_or_resume
{
SUSPEND= 1,
RESUME= 2
};
/* Singleton access */
static Event_scheduler*
get_instance();
/* Methods for queue management follow */
enum enum_error_code
create_event(THD *thd, Event_timed *et, bool check_existence);
enum enum_error_code
update_event(THD *thd, Event_timed *et, LEX_STRING *new_schema,
LEX_STRING *new_name);
bool
drop_event(THD *thd, Event_timed *et);
int
drop_schema_events(THD *thd, LEX_STRING *schema);
int
drop_user_events(THD *thd, LEX_STRING *definer, uint *dropped_num)
{ DBUG_ASSERT(0); return 0;}
uint
events_count();
Event_scheduler():state(UNINITIALIZED){}
~Event_scheduler(){}
/* State changing methods follow */
bool
start();
enum enum_error_code
bool
stop();
bool
start_suspended();
/*
Need to be public because has to be called from the function
passed to pthread_create.
*/
bool
run(THD *thd);
enum enum_error_code
suspend_or_resume(enum enum_suspend_or_resume action);
bool
init();
void
init_scheduler(Event_queue *queue);
void
destroy();
deinit_scheduler();
static void
void
init_mutexes();
static void
destroy_mutexes();
void
report_error_during_start();
deinit_mutexes();
/* Information retrieving methods follow */
enum enum_state
get_state();
bool
is_running();
bool
initialized();
static int
dump_internal_status(THD *thd);
static bool
check_system_tables(THD *thd);
private:
Event_timed *
find_event(Event_timed *etn, bool remove_from_q);
uint
workers_count();
bool
is_running_or_suspended();
/* helper functions */
bool
execute_top(THD *thd);
void
clean_queue(THD *thd);
void
stop_all_running_events(THD *thd);
enum enum_error_code
load_named_event(THD *thd, Event_timed *etn, Event_timed **etn_new);
int
load_events_from_db(THD *thd);
void
drop_matching_events(THD *thd, LEX_STRING *pattern,
bool (*)(Event_timed *,LEX_STRING *));
bool
check_n_suspend_if_needed(THD *thd);
bool
check_n_wait_for_non_empty_queue(THD *thd);
/* Singleton DP is used */
Event_scheduler();
enum enum_cond_vars
{
COND_NONE= -1,
/*
COND_new_work is a conditional used to signal that there is a change
of the queue that should inform the executor thread that new event should
be executed sooner than previously expected, because of add/replace event.
*/
COND_new_work= 0,
/*
COND_started is a conditional used to synchronize the thread in which
::start() was called and the spawned thread. ::start() spawns a new thread
and then waits on COND_started but also checks when awaken that `state` is
either RUNNING or CANTSTART. Then it returns back.
*/
COND_started_or_stopped,
/*
Conditional used for signalling from the scheduler thread back to the
thread that calls ::suspend() or ::resume. Synchronizing the calls.
*/
COND_suspend_or_resume,
/* Must be always last */
COND_LAST
};
/* Singleton instance */
static Event_scheduler singleton;
/* This is the current status of the life-cycle of the manager. */
enum enum_state state;
/* Set to start the scheduler in suspended state */
bool start_scheduler_suspended;
/*
LOCK_scheduler_data is the mutex which protects the access to the
manager's queue as well as used when signalling COND_new_work,
COND_started and COND_shutdown.
*/
pthread_mutex_t LOCK_scheduler_data;
/*
Holds the thread id of the executor thread or 0 if the executor is not
running. It is used by ::shutdown() to know which thread to kill with
kill_one_thread(). The latter wake ups a thread if it is waiting on a
conditional variable and sets thd->killed to non-zero.
*/
ulong thread_id;
pthread_cond_t cond_vars[COND_LAST];
static const char * const cond_vars_names[COND_LAST];
/* The MEM_ROOT of the object */
MEM_ROOT scheduler_root;
/* The sorted queue with the Event_timed objects */
QUEUE queue;
uint mutex_last_locked_at_line;
uint mutex_last_unlocked_at_line;
const char* mutex_last_locked_in_func;
const char* mutex_last_unlocked_in_func;
enum enum_cond_vars cond_waiting_on;
bool mutex_scheduler_data_locked;
execute_top(THD *thd, Event_job_data *job_data);
/* helper functions for working with mutexes & conditionals */
void
@ -243,8 +84,37 @@ private:
void
unlock_data(const char *func, uint line);
int
cond_wait(enum enum_cond_vars, pthread_mutex_t *mutex);
void
cond_wait(THD *thd, struct timespec *abstime, const char* msg,
const char *func, uint line);
pthread_mutex_t LOCK_scheduler_state;
enum enum_state
{
UNINITIALIZED = 0,
INITIALIZED,
RUNNING,
STOPPING
};
/* This is the current status of the life-cycle of the scheduler. */
enum enum_state state;
THD *scheduler_thd;
pthread_cond_t COND_state;
Event_queue *queue;
uint mutex_last_locked_at_line;
uint mutex_last_unlocked_at_line;
const char* mutex_last_locked_in_func;
const char* mutex_last_unlocked_in_func;
bool mutex_scheduler_data_locked;
bool waiting_on_cond;
ulonglong started_events;
private:
/* Prevent use of these */

View File

@ -1,217 +0,0 @@
#ifndef _EVENT_TIMED_H_
#define _EVENT_TIMED_H_
/* Copyright (C) 2004-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define EVEX_OK 0
#define EVEX_KEY_NOT_FOUND -1
#define EVEX_OPEN_TABLE_FAILED -2
#define EVEX_WRITE_ROW_FAILED -3
#define EVEX_DELETE_ROW_FAILED -4
#define EVEX_GET_FIELD_FAILED -5
#define EVEX_PARSE_ERROR -6
#define EVEX_INTERNAL_ERROR -7
#define EVEX_NO_DB_ERROR -8
#define EVEX_COMPILE_ERROR -19
#define EVEX_GENERAL_ERROR -20
#define EVEX_BAD_IDENTIFIER -21
#define EVEX_BODY_TOO_LONG -22
#define EVEX_BAD_PARAMS -23
#define EVEX_NOT_RUNNING -24
#define EVEX_MICROSECOND_UNSUP -25
#define EVEX_CANT_KILL -26
#define EVENT_EXEC_NO_MORE (1L << 0)
#define EVENT_NOT_USED (1L << 1)
#define EVENT_FREE_WHEN_FINISHED (1L << 2)
class sp_head;
class Event_timed
{
Event_timed(const Event_timed &); /* Prevent use of these */
void operator=(Event_timed &);
my_bool in_spawned_thread;
ulong locked_by_thread_id;
my_bool running;
ulong thread_id;
pthread_mutex_t LOCK_running;
pthread_cond_t COND_finished;
bool status_changed;
bool last_executed_changed;
public:
enum enum_status
{
ENABLED = 1,
DISABLED
};
enum enum_on_completion
{
ON_COMPLETION_DROP = 1,
ON_COMPLETION_PRESERVE
};
TIME last_executed;
LEX_STRING dbname;
LEX_STRING name;
LEX_STRING body;
LEX_STRING definer_user;
LEX_STRING definer_host;
LEX_STRING definer;// combination of user and host
LEX_STRING comment;
TIME starts;
TIME ends;
TIME execute_at;
my_bool starts_null;
my_bool ends_null;
my_bool execute_at_null;
longlong expression;
interval_type interval;
ulonglong created;
ulonglong modified;
enum enum_on_completion on_completion;
enum enum_status status;
sp_head *sphead;
ulong sql_mode;
const uchar *body_begin;
bool dropped;
bool free_sphead_on_delete;
uint flags;//all kind of purposes
static void *operator new(size_t size)
{
void *p;
DBUG_ENTER("Event_timed::new(size)");
p= my_malloc(size, MYF(0));
DBUG_PRINT("info", ("alloc_ptr=0x%lx", p));
DBUG_RETURN(p);
}
static void *operator new(size_t size, MEM_ROOT *mem_root)
{ return (void*) alloc_root(mem_root, (uint) size); }
static void operator delete(void *ptr, size_t size)
{
DBUG_ENTER("Event_timed::delete(ptr,size)");
DBUG_PRINT("enter", ("free_ptr=0x%lx", ptr));
TRASH(ptr, size);
my_free((gptr) ptr, MYF(0));
DBUG_VOID_RETURN;
}
static void operator delete(void *ptr, MEM_ROOT *mem_root)
{
/*
Don't free the memory it will be done by the mem_root but
we need to call the destructor because we free other resources
which are not allocated on the root but on the heap, or we
deinit mutexes.
*/
DBUG_ASSERT(0);
}
Event_timed();
~Event_timed();
void
init();
void
deinit_mutexes();
int
init_definer(THD *thd);
int
init_execute_at(THD *thd, Item *expr);
int
init_interval(THD *thd, Item *expr, interval_type new_interval);
void
init_name(THD *thd, sp_name *spn);
int
init_starts(THD *thd, Item *starts);
int
init_ends(THD *thd, Item *ends);
void
init_body(THD *thd);
void
init_comment(THD *thd, LEX_STRING *set_comment);
int
load_from_row(MEM_ROOT *mem_root, TABLE *table);
bool
compute_next_execution_time();
int
drop(THD *thd);
void
mark_last_executed(THD *thd);
bool
update_fields(THD *thd);
int
get_create_event(THD *thd, String *buf);
int
execute(THD *thd, MEM_ROOT *mem_root);
int
compile(THD *thd, MEM_ROOT *mem_root);
bool
is_running();
int
spawn_now(void * (*thread_func)(void*), void *arg);
bool
spawn_thread_finish(THD *thd);
void
free_sp();
bool
has_equal_db(Event_timed *etn);
int
kill_thread(THD *thd);
void
set_thread_id(ulong tid) { thread_id= tid; }
};
#endif /* _EVENT_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -16,78 +16,124 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
class sp_name;
class Event_parse_data;
class Event_db_repository;
class Event_queue;
class Event_queue_element;
class Event_scheduler;
/* Return codes */
enum enum_events_error_code
{
OP_OK= 0,
OP_NOT_RUNNING,
OP_CANT_KILL,
OP_CANT_INIT,
OP_DISABLED_EVENT,
OP_LOAD_ERROR,
OP_ALREADY_EXISTS
};
int
sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
class Event_timed;
class Events
{
public:
static ulong opt_event_scheduler;
static TYPELIB opt_typelib;
enum enum_table_field
/*
Quite NOT the best practice and will be removed once
Event_timed::drop() and Event_timed is fixed not do drop directly
or other scheme will be found.
*/
friend class Event_queue_element;
/* The order should match the order in opt_typelib */
enum enum_opt_event_scheduler
{
FIELD_DB = 0,
FIELD_NAME,
FIELD_BODY,
FIELD_DEFINER,
FIELD_EXECUTE_AT,
FIELD_INTERVAL_EXPR,
FIELD_TRANSIENT_INTERVAL,
FIELD_CREATED,
FIELD_MODIFIED,
FIELD_LAST_EXECUTED,
FIELD_STARTS,
FIELD_ENDS,
FIELD_STATUS,
FIELD_ON_COMPLETION,
FIELD_SQL_MODE,
FIELD_COMMENT,
FIELD_COUNT /* a cool trick to count the number of fields :) */
EVENTS_OFF= 0,
EVENTS_ON= 1,
EVENTS_DISABLED= 5,
};
static int
create_event(THD *thd, Event_timed *et, uint create_options,
uint *rows_affected);
static enum_opt_event_scheduler opt_event_scheduler;
static TYPELIB opt_typelib;
static TYPELIB var_typelib;
static int
update_event(THD *thd, Event_timed *et, sp_name *new_name,
uint *rows_affected);
bool
init();
static int
drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
uint *rows_affected);
void
deinit();
static int
void
init_mutexes();
void
destroy_mutexes();
bool
start_execution_of_events();
bool
stop_execution_of_events();
bool
is_execution_of_events_started();
static Events *
get_instance();
bool
create_event(THD *thd, Event_parse_data *parse_data, bool if_exists);
bool
update_event(THD *thd, Event_parse_data *parse_data, sp_name *rename_to);
bool
drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists,
bool only_from_disk);
void
drop_schema_events(THD *thd, char *db);
int
open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
static int
show_create_event(THD *thd, sp_name *spn);
bool
show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name);
/* Needed for both SHOW CREATE EVENT and INFORMATION_SCHEMA */
static int
reconstruct_interval_expression(String *buf, interval_type interval,
longlong expression);
static int
drop_schema_events(THD *thd, char *db);
static int
fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */);
bool
dump_internal_status(THD *thd);
static int
init();
static void
shutdown();
static void
init_mutexes();
static void
destroy_mutexes();
private:
bool
check_system_tables(THD *thd);
/* Singleton DP is used */
Events();
~Events(){}
/* Singleton instance */
static Events singleton;
Event_queue *event_queue;
Event_scheduler *scheduler;
Event_db_repository *db_repository;
pthread_mutex_t LOCK_event_metadata;
bool check_system_tables_error;
/* Prevent use of these */
Events(const Events &);
void operator=(Events &);

View File

@ -1,79 +0,0 @@
#ifndef _EVENT_PRIV_H_
#define _EVENT_PRIV_H_
/* Copyright (C) 2004-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define EVENT_EXEC_STARTED 0
#define EVENT_EXEC_ALREADY_EXEC 1
#define EVENT_EXEC_CANT_FORK 2
#define EVEX_DB_FIELD_LEN 64
#define EVEX_NAME_FIELD_LEN 64
#define EVEX_MAX_INTERVAL_VALUE 2147483647L
class Event_timed;
int
evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
const LEX_STRING ev_name,
TABLE *table);
int
db_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
uint *rows_affected);
int
db_find_event(THD *thd, sp_name *name, Event_timed **ett, TABLE *tbl,
MEM_ROOT *root);
int
db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
uint *rows_affected);
int
db_drop_events_from_table(THD *thd, LEX_STRING *db);
int
sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
/* Compares only the name part of the identifier */
bool
event_timed_name_equal(Event_timed *et, LEX_STRING *name);
/* Compares only the schema part of the identifier */
bool
event_timed_db_equal(Event_timed *et, LEX_STRING *db);
/*
Compares only the definer part of the identifier. Use during DROP USER
to drop user's events. (Still not implemented)
*/
bool
event_timed_definer_equal(Event_timed *et, LEX_STRING *definer);
/* Compares the whole identifier*/
bool
event_timed_identifier_equal(Event_timed *a, Event_timed *b);
bool
change_security_context(THD *thd, LEX_STRING user, LEX_STRING host,
LEX_STRING db, Security_context *s_ctx,
Security_context **backup);
void
restore_security_context(THD *thd, Security_context *backup);
#endif /* _EVENT_PRIV_H_ */

View File

@ -838,7 +838,7 @@ static void close_connections(void)
DBUG_PRINT("quit",("Informing thread %ld that it's time to die",
tmp->thread_id));
/* We skip slave threads & scheduler on this first loop through. */
if (tmp->slave_thread || tmp->system_thread == SYSTEM_THREAD_EVENT_SCHEDULER)
if (tmp->slave_thread)
continue;
tmp->killed= THD::KILL_CONNECTION;
@ -857,7 +857,7 @@ static void close_connections(void)
}
(void) pthread_mutex_unlock(&LOCK_thread_count); // For unlink from list
Events::shutdown();
Events::get_instance()->deinit();
end_slave();
if (thread_count)
@ -1295,7 +1295,7 @@ static void clean_up_mutexes()
(void) pthread_mutex_destroy(&LOCK_bytes_sent);
(void) pthread_mutex_destroy(&LOCK_bytes_received);
(void) pthread_mutex_destroy(&LOCK_user_conn);
Events::destroy_mutexes();
Events::get_instance()->destroy_mutexes();
#ifdef HAVE_OPENSSL
(void) pthread_mutex_destroy(&LOCK_des_key_file);
#ifndef HAVE_YASSL
@ -2873,7 +2873,7 @@ static int init_thread_environment()
(void) pthread_mutex_init(&LOCK_server_started, MY_MUTEX_INIT_FAST);
(void) pthread_cond_init(&COND_server_started,NULL);
sp_cache_init();
Events::init_mutexes();
Events::get_instance()->init_mutexes();
/* Parameter for threads created for connections */
(void) pthread_attr_init(&connection_attrib);
(void) pthread_attr_setdetachstate(&connection_attrib,
@ -3660,7 +3660,8 @@ we force server id to 2, but this MySQL server will not act as a slave.");
if (!opt_noacl)
{
Events::init();
if (Events::get_instance()->init())
unireg_abort(1);
}
#if defined(__NT__) || defined(HAVE_SMEM)
handle_connections_methods();
@ -5003,9 +5004,9 @@ struct my_option my_long_options[] =
(gptr*) &global_system_variables.engine_condition_pushdown,
(gptr*) &global_system_variables.engine_condition_pushdown,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
/* See how it's handled in get_one_option() */
{"event-scheduler", OPT_EVENT_SCHEDULER, "Enable/disable the event scheduler.",
(gptr*) &Events::opt_event_scheduler, (gptr*) &Events::opt_event_scheduler, 0, GET_ULONG,
REQUIRED_ARG, 2/*default*/, 0/*min-value*/, 2/*max-value*/, 0, 0, 0},
NULL, NULL, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"exit-info", 'T', "Used for debugging; Use at your own risk!", 0, 0, 0,
GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"external-locking", OPT_USE_LOCKING, "Use system (external) locking (disabled by default). With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running. Disable with --skip-external-locking.",
@ -7307,20 +7308,33 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
#endif
case OPT_EVENT_SCHEDULER:
if (!argument)
Events::opt_event_scheduler= 2;
Events::opt_event_scheduler= Events::EVENTS_DISABLED;
else
{
int type;
if ((type=find_type(argument, &Events::opt_typelib, 1)) <= 0)
{
fprintf(stderr,"Unknown option to event-scheduler: %s\n",argument);
exit(1);
}
/*
type= 1 2 3 4 5 6
(OFF | 0) - (ON | 1) - (2 | SUSPEND)
type= 5 1 2 3 4
(DISABLE ) - (OFF | ON) - (0 | 1)
*/
Events::opt_event_scheduler= (type-1) / 2;
switch ((type=find_type(argument, &Events::opt_typelib, 1))) {
case 0:
fprintf(stderr, "Unknown option to event-scheduler: %s\n",argument);
exit(1);
case 5: /* OPT_DISABLED */
Events::opt_event_scheduler= Events::EVENTS_DISABLED;
break;
case 2: /* OPT_ON */
case 4: /* 1 */
Events::opt_event_scheduler= Events::EVENTS_ON;
break;
case 1: /* OPT_OFF */
case 3: /* 0 */
Events::opt_event_scheduler= Events::EVENTS_OFF;
break;
default:
DBUG_ASSERT(0);
unireg_abort(1);
}
}
break;
case (int) OPT_SKIP_NEW:

View File

@ -57,7 +57,7 @@
#include <myisam.h>
#include <my_dir.h>
#include "event_scheduler.h"
#include "events.h"
/* WITH_INNOBASE_STORAGE_ENGINE */
extern uint innobase_flush_log_at_trx_commit;
@ -3899,6 +3899,7 @@ bool sys_var_thd_dbug::update(THD *thd, set_var *var)
return 0;
}
byte *sys_var_thd_dbug::value_ptr(THD *thd, enum_var_type type, LEX_STRING *b)
{
char buf[256];
@ -3910,6 +3911,12 @@ byte *sys_var_thd_dbug::value_ptr(THD *thd, enum_var_type type, LEX_STRING *b)
}
bool sys_var_event_scheduler::check(THD *thd, set_var *var)
{
return check_enum(thd, var, &Events::var_typelib);
}
/*
The update method of the global variable event_scheduler.
If event_scheduler is switched from 0 to 1 then the scheduler main
@ -3928,30 +3935,30 @@ byte *sys_var_thd_dbug::value_ptr(THD *thd, enum_var_type type, LEX_STRING *b)
bool
sys_var_event_scheduler::update(THD *thd, set_var *var)
{
enum Event_scheduler::enum_error_code res;
Event_scheduler *scheduler= Event_scheduler::get_instance();
int res;
/* here start the thread if not running. */
DBUG_ENTER("sys_var_event_scheduler::update");
if (Events::opt_event_scheduler == Events::EVENTS_DISABLED)
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--event-scheduler=DISABLED");
DBUG_RETURN(TRUE);
}
DBUG_PRINT("new_value", ("%lu", (bool)var->save_result.ulong_value));
if (!scheduler->initialized())
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--event-scheduler=0");
DBUG_RETURN(true);
}
if (var->save_result.ulonglong_value < 1 ||
var->save_result.ulonglong_value > 2)
Item_result var_type= var->value->result_type();
if (var->save_result.ulong_value == Events::EVENTS_ON)
res= Events::get_instance()->start_execution_of_events();
else if (var->save_result.ulong_value == Events::EVENTS_OFF)
res= Events::get_instance()->stop_execution_of_events();
else
{
char buf[64];
my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "event_scheduler",
llstr(var->save_result.ulonglong_value, buf));
DBUG_RETURN(true);
DBUG_ASSERT(0);
}
if ((res= scheduler->suspend_or_resume(var->save_result.ulonglong_value == 1?
Event_scheduler::RESUME :
Event_scheduler::SUSPEND)))
my_error(ER_EVENT_SET_VAR_ERROR, MYF(0), (uint) res);
if (res)
my_error(ER_EVENT_SET_VAR_ERROR, MYF(0));
DBUG_RETURN((bool) res);
}
@ -3959,16 +3966,15 @@ sys_var_event_scheduler::update(THD *thd, set_var *var)
byte *sys_var_event_scheduler::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
Event_scheduler *scheduler= Event_scheduler::get_instance();
if (!scheduler->initialized())
thd->sys_var_tmp.long_value= 0;
else if (scheduler->get_state() == Event_scheduler::RUNNING)
thd->sys_var_tmp.long_value= 1;
int state;
if (Events::opt_event_scheduler == Events::EVENTS_DISABLED)
state= Events::EVENTS_DISABLED; // This should be DISABLED
else if (Events::get_instance()->is_execution_of_events_started())
state= Events::EVENTS_ON; // This should be ON
else
thd->sys_var_tmp.long_value= 2;
state= Events::EVENTS_OFF; // This should be OFF
return (byte*) &thd->sys_var_tmp;
return (byte*) Events::opt_typelib.type_names[state];
}

View File

@ -932,6 +932,12 @@ public:
sys_var_long_ptr(name_arg, NULL, NULL) {};
bool update(THD *thd, set_var *var);
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
SHOW_TYPE type() { return SHOW_CHAR; }
bool check(THD *thd, set_var *var);
bool check_update_type(Item_result type)
{
return type != STRING_RESULT && type != INT_RESULT;
}
};
#ifdef HAVE_ROW_BASED_REPLICATION

View File

@ -657,10 +657,12 @@ sp_head::create(THD *thd)
sp_head::~sp_head()
{
DBUG_ENTER("sp_head::~sp_head");
destroy();
delete m_next_cached_sp;
if (m_thd)
restore_thd_mem_root(m_thd);
DBUG_VOID_RETURN;
}
void

View File

@ -2084,6 +2084,7 @@ bool Security_context::set_user(char *user_arg)
return user == 0;
}
/****************************************************************************
Handling of open and locked tables states.

View File

@ -949,7 +949,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
exit:
(void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */
error= Events::drop_schema_events(thd, db);
Events::get_instance()->drop_schema_events(thd, db);
/*
If this database was the client's selected database, we silently
change the client's selected database to nothing (to have an empty

View File

@ -169,14 +169,16 @@ void lex_start(THD *thd, const uchar *buf, uint length)
lex->sql_command= SQLCOM_END;
lex->duplicates= DUP_ERROR;
lex->ignore= 0;
lex->spname= NULL;
lex->sphead= NULL;
lex->spcont= NULL;
lex->proc_list.first= 0;
lex->escape_used= lex->et_compile_phase= FALSE;
lex->escape_used= FALSE;
lex->reset_query_tables_list(FALSE);
lex->expr_allows_subselect= TRUE;
lex->name= 0;
lex->et= NULL;
lex->event_parse_data= NULL;
lex->nest_level=0 ;
lex->allow_sum_func= 0;

View File

@ -27,7 +27,7 @@ class sp_instr;
class sp_pcontext;
class st_alter_tablespace;
class partition_info;
class Event_timed;
class Event_parse_data;
#ifdef MYSQL_SERVER
/*
@ -958,6 +958,14 @@ typedef struct st_lex : public Query_tables_list
*/
nesting_map allow_sum_func;
enum_sql_command sql_command;
/*
Usually `expr` rule of yacc is quite reused but some commands better
not support subqueries which comes standard with this rule, like
KILL, HA_READ, CREATE/ALTER EVENT etc. Set this to `false` to get
syntax error back.
*/
bool expr_allows_subselect;
thr_lock_type lock_option;
enum SSL_type ssl_type; /* defined in violite.h */
enum my_lex_states next_state;
@ -1035,8 +1043,7 @@ typedef struct st_lex : public Query_tables_list
st_sp_chistics sp_chistics;
Event_timed *et;
bool et_compile_phase;
Event_parse_data *event_parse_data;
bool only_view; /* used for SHOW CREATE TABLE/VIEW */
/*

View File

@ -27,7 +27,7 @@
#include "sp.h"
#include "sp_cache.h"
#include "events.h"
#include "event_timed.h"
#include "event_data_objects.h"
#ifdef HAVE_OPENSSL
/*
@ -3896,73 +3896,43 @@ end_with_restore_list:
}
case SQLCOM_CREATE_EVENT:
case SQLCOM_ALTER_EVENT:
case SQLCOM_DROP_EVENT:
{
uint rows_affected= 1;
DBUG_ASSERT(lex->et);
do {
if (! lex->et->dbname.str ||
(lex->sql_command == SQLCOM_ALTER_EVENT && lex->spname &&
!lex->spname->m_db.str))
{
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
res= true;
break;
}
DBUG_ASSERT(lex->event_parse_data);
switch (lex->sql_command) {
case SQLCOM_CREATE_EVENT:
res= Events::get_instance()->
create_event(thd, lex->event_parse_data,
lex->create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS);
break;
case SQLCOM_ALTER_EVENT:
res= Events::get_instance()->update_event(thd, lex->event_parse_data,
lex->spname);
break;
default:
DBUG_ASSERT(0);
}
DBUG_PRINT("info",("DDL error code=%d", res));
if (!res)
send_ok(thd);
if (check_access(thd, EVENT_ACL, lex->et->dbname.str, 0, 0, 0,
is_schema_db(lex->et->dbname.str)) ||
(lex->sql_command == SQLCOM_ALTER_EVENT && lex->spname &&
(check_access(thd, EVENT_ACL, lex->spname->m_db.str, 0, 0, 0,
is_schema_db(lex->spname->m_db.str)))))
break;
if (end_active_trans(thd))
{
res= -1;
break;
}
switch (lex->sql_command) {
case SQLCOM_CREATE_EVENT:
res= Events::create_event(thd, lex->et,
(uint) lex->create_info.options,
&rows_affected);
break;
case SQLCOM_ALTER_EVENT:
res= Events::update_event(thd, lex->et, lex->spname,
&rows_affected);
break;
case SQLCOM_DROP_EVENT:
res= Events::drop_event(thd, lex->et, lex->drop_if_exists,
&rows_affected);
default:;
}
DBUG_PRINT("info", ("CREATE/ALTER/DROP returned error code=%d af_rows=%d",
res, rows_affected));
if (!res)
send_ok(thd, rows_affected);
/* lex->unit.cleanup() is called outside, no need to call it here */
} while (0);
/* Don't do it, if we are inside a SP */
if (!thd->spcont)
{
lex->et->free_sphead_on_delete= true;
lex->et->free_sp();
lex->et->deinit_mutexes();
delete lex->sphead;
lex->sphead= NULL;
}
/* lex->unit.cleanup() is called outside, no need to call it here */
break;
}
case SQLCOM_DROP_EVENT:
case SQLCOM_SHOW_CREATE_EVENT:
{
DBUG_ASSERT(lex->spname);
DBUG_ASSERT(lex->et);
if (! lex->spname->m_db.str)
{
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
res= true;
break;
goto error;
}
if (check_access(thd, EVENT_ACL, lex->spname->m_db.str, 0, 0, 0,
is_schema_db(lex->spname->m_db.str)))
@ -3971,15 +3941,29 @@ end_with_restore_list:
if (lex->spname->m_name.length > NAME_LEN)
{
my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
/* this jumps to the end of the function and skips own messaging */
goto error;
}
res= Events::show_create_event(thd, lex->spname);
if (lex->sql_command == SQLCOM_SHOW_CREATE_EVENT)
res= Events::get_instance()->show_create_event(thd, lex->spname->m_db,
lex->spname->m_name);
else
{
uint affected= 1;
if (!(res= Events::get_instance()->drop_event(thd,
lex->spname->m_db,
lex->spname->m_name,
lex->drop_if_exists,
FALSE)))
send_ok(thd);
}
break;
}
#ifndef DBUG_OFF
case SQLCOM_SHOW_SCHEDULER_STATUS:
{
res= Events::dump_internal_status(thd);
res= Events::get_instance()->dump_internal_status(thd);
break;
}
#endif
@ -6073,14 +6057,6 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
{
delete lex->sphead;
lex->sphead= NULL;
if (lex->et)
{
lex->et->free_sphead_on_delete= true;
/* alloced on thd->mem_root so no real memory free but dtor call */
lex->et->free_sp();
lex->et->deinit_mutexes();
lex->et= NULL;
}
}
else
{
@ -6117,13 +6093,6 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
delete lex->sphead;
lex->sphead= NULL;
}
if (lex->et)
{
lex->et->free_sphead_on_delete= true;
lex->et->free_sp();
lex->et->deinit_mutexes();
lex->et= NULL;
}
}
thd->proc_info="freeing items";
thd->end_statement();

View File

@ -27,7 +27,7 @@
#include "authors.h"
#include "contributors.h"
#include "events.h"
#include "event_timed.h"
#include "event_data_objects.h"
#include <my_dir.h>
#ifdef WITH_PARTITION_STORAGE_ENGINE
@ -4217,7 +4217,7 @@ extern LEX_STRING interval_type_to_name[];
1 Error
*/
static int
int
copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
{
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
@ -4228,7 +4228,7 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
restore_record(sch_table, s->default_values);
if (et.load_from_row(thd->mem_root, event_table))
if (et.load_from_row(event_table))
{
my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0));
DBUG_RETURN(1);
@ -4352,183 +4352,6 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
}
/*
Performs an index scan of event_table (mysql.event) and fills schema_table.
Synopsis
events_table_index_read_for_db()
thd Thread
schema_table The I_S.EVENTS table
event_table The event table to use for loading (mysql.event)
Returns
0 OK
1 Error
*/
static
int events_table_index_read_for_db(THD *thd, TABLE *schema_table,
TABLE *event_table)
{
int ret=0;
CHARSET_INFO *scs= system_charset_info;
KEY *key_info;
uint key_len;
byte *key_buf= NULL;
LINT_INIT(key_buf);
DBUG_ENTER("schema_events_do_index_scan");
DBUG_PRINT("info", ("Using prefix scanning on PK"));
event_table->file->ha_index_init(0, 1);
event_table->field[Events::FIELD_DB]->
store(thd->lex->select_lex.db, strlen(thd->lex->select_lex.db), scs);
key_info= event_table->key_info;
key_len= key_info->key_part[0].store_length;
if (!(key_buf= (byte *)alloc_root(thd->mem_root, key_len)))
{
ret= 1;
/* don't send error, it would be done by sql_alloc_error_handler() */
}
else
{
key_copy(key_buf, event_table->record[0], key_info, key_len);
if (!(ret= event_table->file->index_read(event_table->record[0], key_buf,
key_len, HA_READ_PREFIX)))
{
DBUG_PRINT("info",("Found rows. Let's retrieve them. ret=%d", ret));
do
{
ret= copy_event_to_schema_table(thd, schema_table, event_table);
if (ret == 0)
ret= event_table->file->index_next_same(event_table->record[0],
key_buf, key_len);
} while (ret == 0);
}
DBUG_PRINT("info", ("Scan finished. ret=%d", ret));
}
event_table->file->ha_index_end();
/* ret is guaranteed to be != 0 */
if (ret == HA_ERR_END_OF_FILE || ret == HA_ERR_KEY_NOT_FOUND)
DBUG_RETURN(0);
DBUG_RETURN(1);
}
/*
Performs a table scan of event_table (mysql.event) and fills schema_table.
Synopsis
events_table_scan_all()
thd Thread
schema_table The I_S.EVENTS in memory table
event_table The event table to use for loading.
Returns
0 OK
1 Error
*/
static
int events_table_scan_all(THD *thd, TABLE *schema_table,
TABLE *event_table)
{
int ret;
READ_RECORD read_record_info;
DBUG_ENTER("schema_events_do_table_scan");
init_read_record(&read_record_info, thd, event_table, NULL, 1, 0);
/*
rr_sequential, in read_record(), returns 137==HA_ERR_END_OF_FILE,
but rr_handle_error returns -1 for that reason. Thus, read_record()
returns -1 eventually.
*/
do
{
ret= read_record_info.read_record(&read_record_info);
if (ret == 0)
ret= copy_event_to_schema_table(thd, schema_table, event_table);
}
while (ret == 0);
DBUG_PRINT("info", ("Scan finished. ret=%d", ret));
end_read_record(&read_record_info);
/* ret is guaranteed to be != 0 */
DBUG_RETURN(ret == -1? 0:1);
}
/*
Fills I_S.EVENTS with data loaded from mysql.event. Also used by
SHOW EVENTS
Synopsis
fill_schema_events()
thd Thread
tables The schema table
cond Unused
Returns
0 OK
1 Error
*/
int fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
{
TABLE *schema_table= tables->table;
TABLE *event_table= NULL;
Open_tables_state backup;
int ret= 0;
DBUG_ENTER("fill_schema_events");
/*
If it's SHOW EVENTS then thd->lex->select_lex.db is guaranteed not to
be NULL. Let's do an assert anyway.
*/
if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS)
{
DBUG_ASSERT(thd->lex->select_lex.db);
if (check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0,
is_schema_db(thd->lex->select_lex.db)))
DBUG_RETURN(1);
}
DBUG_PRINT("info",("db=%s", thd->lex->select_lex.db?
thd->lex->select_lex.db:"(null)"));
thd->reset_n_backup_open_tables_state(&backup);
if (Events::open_event_table(thd, TL_READ, &event_table))
{
sql_print_error("Table mysql.event is damaged.");
thd->restore_backup_open_tables_state(&backup);
DBUG_RETURN(1);
}
/*
1. SELECT I_S => use table scan. I_S.EVENTS does not guarantee order
thus we won't order it. OTOH, SHOW EVENTS will be
ordered.
2. SHOW EVENTS => PRIMARY KEY with prefix scanning on (db)
Reasoning: Events are per schema, therefore a scan over an index
will save use from doing a table scan and comparing
every single row's `db` with the schema which we show.
*/
if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS)
ret= events_table_index_read_for_db(thd, schema_table, event_table);
else
ret= events_table_scan_all(thd, schema_table, event_table);
close_thread_tables(thd);
thd->restore_backup_open_tables_state(&backup);
DBUG_PRINT("info", ("Return code=%d", ret));
DBUG_RETURN(ret);
}
int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
DBUG_ENTER("fill_open_tables");
@ -5631,7 +5454,7 @@ ST_SCHEMA_TABLE schema_tables[]=
{"ENGINES", engines_fields_info, create_schema_table,
fill_schema_engines, make_old_format, 0, -1, -1, 0},
{"EVENTS", events_fields_info, create_schema_table,
fill_schema_events, make_old_format, 0, -1, -1, 0},
Events::fill_schema_events, make_old_format, 0, -1, -1, 0},
{"FILES", files_fields_info, create_schema_table,
fill_schema_files, 0, 0, -1, -1, 0},
{"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table,

View File

@ -14,4 +14,6 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
HA_CREATE_INFO *create_info_arg);
int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff);
int copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table);
#endif /* SQL_SHOW_H */

View File

@ -38,7 +38,7 @@
#include "sp_pcontext.h"
#include "sp_rcontext.h"
#include "sp.h"
#include "event_timed.h"
#include "event_data_objects.h"
#include <myisam.h>
#include <myisammrg.h>
@ -907,7 +907,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
definer view_replace_or_algorithm view_replace view_algorithm_opt
view_algorithm view_or_trigger_or_sp view_or_trigger_or_sp_tail
view_algorithm view_or_trigger_or_sp_or_event
view_or_trigger_or_sp_or_event_tail
view_suid view_tail view_list_opt view_list view_select
view_check_option trigger_tail sp_tail
install uninstall partition_entry binlog_base64_event
@ -1284,29 +1285,41 @@ create:
lex->name=$4.str;
lex->create_info.options=$3;
}
| CREATE EVENT_SYM opt_if_not_exists sp_name
| CREATE
{
Lex->create_view_mode= VIEW_CREATE_NEW;
Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED;
Lex->create_view_suid= TRUE;
}
view_or_trigger_or_sp_or_event
{}
| CREATE USER clear_privileges grant_list
{
Lex->sql_command = SQLCOM_CREATE_USER;
}
| CREATE LOGFILE_SYM GROUP logfile_group_info
{
Lex->alter_tablespace_info->ts_cmd_type= CREATE_LOGFILE_GROUP;
}
| CREATE TABLESPACE tablespace_info
{
Lex->alter_tablespace_info->ts_cmd_type= CREATE_TABLESPACE;
}
;
event_tail:
EVENT_SYM opt_if_not_exists sp_name
/*
BE CAREFUL when you add a new rule to update the block where
YYTHD->client_capabilities is set back to original value
*/
{
LEX *lex=Lex;
Lex->create_info.options= $2;
if (lex->et)
{
/*
Recursive events are not possible because recursive SPs
are not also possible. lex->sp_head is not stacked.
*/
// ToDo Andrey : Change the error message
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "EVENT");
YYABORT;
}
lex->create_info.options= $3;
if (!(lex->et= new(YYTHD->mem_root) Event_timed())) // implicitly calls Event_timed::init()
if (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
YYABORT;
Lex->event_parse_data->identifier= $3;
/*
We have to turn of CLIENT_MULTI_QUERIES while parsing a
@ -1316,11 +1329,9 @@ create:
$<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES);
if (!lex->et_compile_phase)
{
lex->et->init_name(YYTHD, $4);
lex->et->init_definer(YYTHD);
}
Lex->sql_command= SQLCOM_CREATE_EVENT;
/* We need that for disallowing subqueries */
Lex->expr_allows_subselect= FALSE;
}
ON SCHEDULE_SYM ev_schedule_time
opt_ev_on_completion
@ -1330,160 +1341,62 @@ create:
{
/*
Restore flag if it was cleared above
$1 - CREATE
$2 - EVENT_SYM
$3 - opt_if_not_exists
$4 - sp_name
$5 - the block above
$1 - EVENT_SYM
$2 - opt_if_not_exists
$3 - sp_name
$4 - the block above
*/
YYTHD->client_capabilities |= $<ulong_num>5;
YYTHD->client_capabilities |= $<ulong_num>4;
/*
sql_command is set here because some rules in ev_sql_stmt
can overwrite it
*/
Lex->sql_command= SQLCOM_CREATE_EVENT;
Lex->expr_allows_subselect= TRUE;
}
| CREATE
{
Lex->create_view_mode= VIEW_CREATE_NEW;
Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED;
Lex->create_view_suid= TRUE;
}
view_or_trigger_or_sp
{}
| CREATE USER clear_privileges grant_list
{
Lex->sql_command = SQLCOM_CREATE_USER;
}
| CREATE LOGFILE_SYM GROUP logfile_group_info
{
LEX *lex= Lex;
lex->alter_tablespace_info->ts_cmd_type= CREATE_LOGFILE_GROUP;
}
| CREATE TABLESPACE tablespace_info
{
LEX *lex= Lex;
lex->alter_tablespace_info->ts_cmd_type= CREATE_TABLESPACE;
}
;
ev_schedule_time: EVERY_SYM expr interval
{
LEX *lex=Lex;
if (!lex->et_compile_phase)
{
switch (lex->et->init_interval(YYTHD , $2, $3)) {
case EVEX_PARSE_ERROR:
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
break;
case EVEX_BAD_PARAMS:
my_error(ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG, MYF(0));
case EVEX_MICROSECOND_UNSUP:
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND");
YYABORT;
break;
}
}
Lex->event_parse_data->item_expression= $2;
Lex->event_parse_data->interval= $3;
}
ev_starts
ev_ends
| AT_SYM expr
{
LEX *lex=Lex;
if (!lex->et_compile_phase)
{
switch (lex->et->init_execute_at(YYTHD, $2)) {
case EVEX_PARSE_ERROR:
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
break;
case ER_WRONG_VALUE:
{
char buff[120];
String str(buff,(uint32) sizeof(buff), system_charset_info);
String *str2= $2->val_str(&str);
my_error(ER_WRONG_VALUE, MYF(0), "AT",
str2? str2->c_ptr_safe():"NULL");
YYABORT;
break;
}
case EVEX_BAD_PARAMS:
my_error(ER_EVENT_EXEC_TIME_IN_THE_PAST, MYF(0));
YYABORT;
break;
}
}
Lex->event_parse_data->item_execute_at= $2;
}
;
opt_ev_status: /* empty */ { $$= 0; }
| ENABLE_SYM
{
LEX *lex=Lex;
if (!lex->et_compile_phase)
lex->et->status= Event_timed::ENABLED;
Lex->event_parse_data->status= Event_parse_data::ENABLED;
$$= 1;
}
| DISABLE_SYM
{
LEX *lex=Lex;
if (!lex->et_compile_phase)
lex->et->status= Event_timed::DISABLED;
Lex->event_parse_data->status= Event_parse_data::DISABLED;
$$= 1;
}
;
ev_starts: /* empty */
{
Lex->et->init_starts(YYTHD, new Item_func_now_local());
Lex->event_parse_data->item_starts= new Item_func_now_local();
}
| STARTS_SYM expr
{
LEX *lex= Lex;
if (!lex->et_compile_phase)
{
switch (lex->et->init_starts(YYTHD, $2)) {
case EVEX_PARSE_ERROR:
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
break;
case EVEX_BAD_PARAMS:
{
char buff[20];
String str(buff,(uint32) sizeof(buff), system_charset_info);
String *str2= $2->val_str(&str);
my_error(ER_WRONG_VALUE, MYF(0), "STARTS",
str2 ? str2->c_ptr_safe() : NULL);
YYABORT;
break;
}
}
}
Lex->event_parse_data->item_starts= $2;
}
;
ev_ends: /* empty */
| ENDS_SYM expr
{
LEX *lex= Lex;
if (!lex->et_compile_phase)
{
switch (lex->et->init_ends(YYTHD, $2)) {
case EVEX_PARSE_ERROR:
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
break;
case EVEX_BAD_PARAMS:
my_error(ER_EVENT_ENDS_BEFORE_STARTS, MYF(0));
YYABORT;
break;
}
}
Lex->event_parse_data->item_ends= $2;
}
;
@ -1494,16 +1407,14 @@ opt_ev_on_completion: /* empty */ { $$= 0; }
ev_on_completion:
ON COMPLETION_SYM PRESERVE_SYM
{
LEX *lex=Lex;
if (!lex->et_compile_phase)
lex->et->on_completion= Event_timed::ON_COMPLETION_PRESERVE;
Lex->event_parse_data->on_completion=
Event_parse_data::ON_COMPLETION_PRESERVE;
$$= 1;
}
| ON COMPLETION_SYM NOT_SYM PRESERVE_SYM
{
LEX *lex=Lex;
if (!lex->et_compile_phase)
lex->et->on_completion= Event_timed::ON_COMPLETION_DROP;
Lex->event_parse_data->on_completion=
Event_parse_data::ON_COMPLETION_DROP;
$$= 1;
}
;
@ -1511,64 +1422,65 @@ ev_on_completion:
opt_ev_comment: /* empty */ { $$= 0; }
| COMMENT_SYM TEXT_STRING_sys
{
LEX *lex= Lex;
if (!lex->et_compile_phase)
{
lex->comment= $2;
lex->et->init_comment(YYTHD, &$2);
}
$$= 1;
Lex->comment= Lex->event_parse_data->comment= $2;
}
;
ev_sql_stmt:
{
LEX *lex= Lex;
sp_head *sp;
$<sphead>$= lex->sphead;
if (!lex->sphead)
/*
This stops the following :
- CREATE EVENT ... DO CREATE EVENT ...;
- ALTER EVENT ... DO CREATE EVENT ...;
- CREATE EVENT ... DO ALTER EVENT DO ....;
- CREATE PROCEDURE ... BEGIN CREATE EVENT ... END|
This allows:
- CREATE EVENT ... DO DROP EVENT yyy;
- CREATE EVENT ... DO ALTER EVENT yyy;
(the nested ALTER EVENT can have anything but DO clause)
- ALTER EVENT ... DO ALTER EVENT yyy;
(the nested ALTER EVENT can have anything but DO clause)
- ALTER EVENT ... DO DROP EVENT yyy;
- CREATE PROCEDURE ... BEGIN ALTER EVENT ... END|
(the nested ALTER EVENT can have anything but DO clause)
- CREATE PROCEDURE ... BEGIN DROP EVENT ... END|
*/
if (lex->sphead)
{
if (!(sp= new sp_head()))
YYABORT;
sp->reset_thd_mem_root(YYTHD);
sp->init(lex);
sp->m_type= TYPE_ENUM_PROCEDURE;
lex->sphead= sp;
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
lex->sphead->m_chistics= &lex->sp_chistics;
lex->sphead->m_body_begin= lex->ptr;
my_error(ER_EVENT_RECURSIVITY_FORBIDDEN, MYF(0));
YYABORT;
}
if (!(lex->sphead= new sp_head()))
YYABORT;
lex->sphead->reset_thd_mem_root(YYTHD);
lex->sphead->init(lex);
lex->sphead->init_sp_name(YYTHD, Lex->event_parse_data->identifier);
lex->sphead->m_type= TYPE_ENUM_PROCEDURE;
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
lex->sphead->m_chistics= &lex->sp_chistics;
lex->sphead->m_body_begin= lex->ptr;
Lex->event_parse_data->body_begin= lex->ptr;
if (!lex->et_compile_phase)
lex->et->body_begin= lex->ptr;
}
ev_sql_stmt_inner
{
LEX *lex=Lex;
if (!$<sphead>1)
{
sp_head *sp= lex->sphead;
// return back to the original memory root ASAP
sp->init_strings(YYTHD, lex);
sp->restore_thd_mem_root(YYTHD);
/* return back to the original memory root ASAP */
lex->sphead->init_strings(YYTHD, lex);
lex->sphead->restore_thd_mem_root(YYTHD);
lex->sp_chistics.suid= SP_IS_SUID;//always the definer!
lex->sp_chistics.suid= SP_IS_SUID; //always the definer!
lex->et->sphead= lex->sphead;
lex->sphead= NULL;
}
if (!lex->et_compile_phase)
{
lex->et->init_body(YYTHD);
}
Lex->event_parse_data->init_body(YYTHD);
}
;
@ -1643,10 +1555,10 @@ create_function_tail:
if (lex->definer != NULL)
{
/*
DEFINER is a concept meaningful when interpreting SQL code.
UDF functions are compiled.
Using DEFINER with UDF has therefore no semantic,
and is considered a parsing error.
DEFINER is a concept meaningful when interpreting SQL code.
UDF functions are compiled.
Using DEFINER with UDF has therefore no semantic,
and is considered a parsing error.
*/
my_error(ER_WRONG_USAGE, MYF(0), "SONAME", "DEFINER");
YYABORT;
@ -1685,10 +1597,10 @@ create_function_tail:
sp->m_type= TYPE_ENUM_FUNCTION;
lex->sphead= sp;
/*
* We have to turn of CLIENT_MULTI_QUERIES while parsing a
* stored procedure, otherwise yylex will chop it into pieces
* at each ';'.
*/
We have to turn off CLIENT_MULTI_QUERIES while parsing a
stored procedure, otherwise yylex will chop it into pieces
at each ';'.
*/
$<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
lex->sphead->m_param_begin= lex->tok_start+1;
@ -4790,41 +4702,33 @@ alter:
{}
| ALTER EVENT_SYM sp_name
/*
BE CAREFUL when you add a new rule to update the block where
YYTHD->client_capabilities is set back to original value
BE CAREFUL when you add a new rule to update the block where
YYTHD->client_capabilities is set back to original value
*/
{
LEX *lex=Lex;
Event_timed *et;
/*
It is safe to use Lex->spname because
ALTER EVENT xxx RENATE TO yyy DO ALTER EVENT RENAME TO
is not allowed. Lex->spname is used in the case of RENAME TO
If it had to be supported spname had to be added to
Event_parse_data.
*/
if (lex->et)
{
/*
Recursive events are not possible because recursive SPs
are not also possible. lex->sp_head is not stacked.
*/
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "EVENT");
if (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
YYABORT;
}
lex->spname= 0;//defensive programming
if (!(et= new (YYTHD->mem_root) Event_timed()))// implicitly calls Event_timed::init()
YYABORT;
lex->et = et;
if (!lex->et_compile_phase)
{
et->init_definer(YYTHD);
et->init_name(YYTHD, $3);
}
Lex->event_parse_data->identifier= $3;
/*
We have to turn of CLIENT_MULTI_QUERIES while parsing a
stored procedure, otherwise yylex will chop it into pieces
at each ';'.
We have to turn off CLIENT_MULTI_QUERIES while parsing a
stored procedure, otherwise yylex will chop it into pieces
at each ';'.
*/
$<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
Lex->sql_command= SQLCOM_ALTER_EVENT;
/* we need that for disallowing subqueries */
Lex->expr_allows_subselect= FALSE;
}
ev_alter_on_schedule_completion
opt_ev_rename_to
@ -4840,16 +4744,17 @@ alter:
*/
YYTHD->client_capabilities |= $<ulong_num>4;
/*
sql_command is set here because some rules in ev_sql_stmt
can overwrite it
*/
if (!($5 || $6 || $7 || $8 || $9))
{
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
/*
sql_command is set here because some rules in ev_sql_stmt
can overwrite it
*/
Lex->sql_command= SQLCOM_ALTER_EVENT;
Lex->expr_allows_subselect= TRUE;
}
| ALTER TABLESPACE alter_tablespace_info
{
@ -4882,9 +4787,11 @@ ev_alter_on_schedule_completion: /* empty */ { $$= 0;}
opt_ev_rename_to: /* empty */ { $$= 0;}
| RENAME TO_SYM sp_name
{
LEX *lex=Lex;
lex->spname= $3; //use lex's spname to hold the new name
//the original name is in the Event_timed object
/*
Use lex's spname to hold the new name.
The original name is in the Event_parse_data object
*/
Lex->spname= $3;
$$= 1;
}
;
@ -4908,7 +4815,7 @@ alter_commands:
| remove_partitioning
| partitioning
/*
This part was added for release 5.1 by Mikael Ronström.
This part was added for release 5.1 by Mikael Ronström.
From here we insert a number of commands to manage the partitions of a
partitioned table such as adding partitions, dropping partitions,
reorganising partitions in various manners. In future releases the list
@ -7176,8 +7083,7 @@ select_derived2:
{
LEX *lex= Lex;
lex->derived_tables|= DERIVED_SUBQUERY;
if (lex->sql_command == (int)SQLCOM_HA_READ ||
lex->sql_command == (int)SQLCOM_KILL)
if (!lex->expr_allows_subselect)
{
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
@ -7796,29 +7702,9 @@ drop:
}
| DROP EVENT_SYM if_exists sp_name
{
LEX *lex=Lex;
if (lex->et)
{
/*
Recursive events are not possible because recursive SPs
are not also possible. lex->sp_head is not stacked.
*/
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "EVENT");
YYABORT;
}
if (!(lex->et= new (YYTHD->mem_root) Event_timed()))
YYABORT;
if (!lex->et_compile_phase)
{
lex->et->init_name(YYTHD, $4);
lex->et->init_definer(YYTHD);
}
lex->sql_command = SQLCOM_DROP_EVENT;
lex->drop_if_exists= $3;
Lex->drop_if_exists= $3;
Lex->spname= $4;
Lex->sql_command = SQLCOM_DROP_EVENT;
}
| DROP TRIGGER_SYM sp_name
{
@ -8511,12 +8397,8 @@ show_param:
}
| CREATE EVENT_SYM sp_name
{
Lex->sql_command = SQLCOM_SHOW_CREATE_EVENT;
Lex->spname= $3;
Lex->et= new (YYTHD->mem_root) Event_timed();
if (!Lex->et)
YYABORT;
Lex->et->init_definer(YYTHD);
Lex->sql_command = SQLCOM_SHOW_CREATE_EVENT;
}
;
@ -8696,11 +8578,17 @@ purge_option:
/* kill threads */
kill:
KILL_SYM { Lex->sql_command= SQLCOM_KILL; } kill_option expr
KILL_SYM
{
Lex->sql_command= SQLCOM_KILL;
Lex->expr_allows_subselect= FALSE;
}
kill_option expr
{
LEX *lex=Lex;
lex->value_list.empty();
lex->value_list.push_front($4);
Lex->expr_allows_subselect= TRUE;
};
kill_option:
@ -10187,6 +10075,7 @@ handler:
my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER");
YYABORT;
}
lex->expr_allows_subselect= FALSE;
lex->sql_command = SQLCOM_HA_READ;
lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */
lex->current_select->select_limit= new Item_int((int32) 1);
@ -10194,7 +10083,10 @@ handler:
if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0))
YYABORT;
}
handler_read_or_scan where_clause opt_limit_clause {}
handler_read_or_scan where_clause opt_limit_clause
{
Lex->expr_allows_subselect= TRUE;
}
;
handler_read_or_scan:
@ -10819,8 +10711,7 @@ subselect_start:
'(' SELECT_SYM
{
LEX *lex=Lex;
if (lex->sql_command == (int)SQLCOM_HA_READ ||
lex->sql_command == (int)SQLCOM_KILL)
if (!lex->expr_allows_subselect)
{
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
@ -10844,20 +10735,22 @@ subselect_end:
**************************************************************************/
view_or_trigger_or_sp:
definer view_or_trigger_or_sp_tail
view_or_trigger_or_sp_or_event:
definer view_or_trigger_or_sp_or_event_tail
{}
| view_replace_or_algorithm definer view_tail
{}
;
view_or_trigger_or_sp_tail:
view_or_trigger_or_sp_or_event_tail:
view_tail
{}
| trigger_tail
{}
| sp_tail
{}
| event_tail
{}
;
/**************************************************************************

View File

@ -2365,28 +2365,28 @@ bool check_column_name(const char *name)
Checks whether a table is intact. Should be done *just* after the table has
been opened.
Synopsis
SYNOPSIS
table_check_intact()
table - the table to check
table_f_count - expected number of columns in the table
table_def - expected structure of the table (column name and type)
last_create_time- the table->file->create_time of the table in memory
we have checked last time
error_num - ER_XXXX from the error messages file. When 0 no error
is sent to the client in case types does not match.
If different col number either
ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE or
ER_COL_COUNT_DOESNT_MATCH_CORRUPTED is used
table The table to check
table_f_count Expected number of columns in the table
table_def Expected structure of the table (column name and type)
last_create_time The table->file->create_time of the table in memory
we have checked last time
error_num ER_XXXX from the error messages file. When 0 no error
is sent to the client in case types does not match.
If different col number either
ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE or
ER_COL_COUNT_DOESNT_MATCH_CORRUPTED is used
RETURNS
0 - OK
1 - There was an error
FALSE OK
TRUE There was an error
*/
my_bool
table_check_intact(TABLE *table, uint table_f_count,
TABLE_FIELD_W_TYPE *table_def, time_t *last_create_time,
int error_num)
table_check_intact(TABLE *table, const uint table_f_count,
const TABLE_FIELD_W_TYPE *table_def,
time_t *last_create_time, int error_num)
{
uint i;
my_bool error= FALSE;
@ -2401,7 +2401,7 @@ table_check_intact(TABLE *table, uint table_f_count,
DBUG_PRINT("info", ("I am suspecting, checking table"));
if (fields_diff_count)
{
// previous MySQL version
/* previous MySQL version */
error= TRUE;
if (MYSQL_VERSION_ID > table->s->mysql_version)
{
@ -2424,22 +2424,22 @@ table_check_intact(TABLE *table, uint table_f_count,
else
{
/*
moving from newer mysql to older one -> let's say not an error but
Moving from newer mysql to older one -> let's say not an error but
will check the definition afterwards. If a column was added at the
end then we don't care much since it's not in the middle.
*/
error= FALSE;
}
}
//definitely something has changed
/* definitely something has changed */
char buffer[255];
for (i=0 ; i < table_f_count; i++, table_def++)
{
String sql_type(buffer, sizeof(buffer), system_charset_info);
sql_type.length(0);
/*
name changes are not fatal, we use sequence numbers => no prob for us
but this can show tampered table or broken table.
Name changes are not fatal, we use sequence numbers => no problem
for us but this can show tampered table or broken table.
*/
if (i < table->s->fields)
{
@ -2453,7 +2453,7 @@ table_check_intact(TABLE *table, uint table_f_count,
}
/*
IF the type does not match than something is really wrong
If the type does not match than something is really wrong
Check up to length - 1. Why?
1. datetime -> datetim -> the same
2. int(11) -> int(11 -> the same

View File

@ -1029,9 +1029,9 @@ typedef struct st_table_field_w_type
my_bool
table_check_intact(TABLE *table, uint table_f_count,
TABLE_FIELD_W_TYPE *table_def, time_t *last_create_time,
int error_num);
table_check_intact(TABLE *table, const uint table_f_count,
const TABLE_FIELD_W_TYPE * const table_def,
time_t *last_create_time, int error_num);
static inline my_bitmap_map *tmp_use_all_columns(TABLE *table,
MY_BITMAP *bitmap)